# Errors and retries

Canonical URL: https://docs.viralspy.com/docs/errors



REST errors use `application/problem+json` and stable machine-readable `code` values.

```json
{
  "type": "https://docs.viralspy.com/problems/rate_limited",
  "title": "Rate limit reached. Slow down and retry.",
  "status": 429,
  "code": "rate_limited",
  "request_id": "c45257cd-1e55-4550-b92f-e98ee450ee29"
}
```

|    Status | Retry?  | Meaning                                                                        |
| --------: | ------- | ------------------------------------------------------------------------------ |
| 400 / 422 | No      | Fix request parameters or JSON.                                                |
|       401 | No      | Missing, malformed, expired, or revoked credential.                            |
|       403 | No      | Scope, organisation entitlement, subscription, or OAuth grant is insufficient. |
|       404 | No      | Resource or route was not found.                                               |
|       409 | No      | An idempotency key was reused with different analyst input.                    |
|       429 | Yes     | Wait for `Retry-After`; do not busy-loop.                                      |
| 502 / 503 | Usually | Retry with backoff and the same analyst idempotency key.                       |

## Analyst idempotency [#analyst-idempotency]

Every `POST /v1/agent/answers` requires a caller-generated `Idempotency-Key` of 8–200 characters. Reuse it only for the same body. If the first request is still running, ViralSpy returns `202` plus a status URL. If it completed, the saved result is returned without consuming a second analyst request.

```bash
curl 'https://api.viralspy.com/v1/agent/answers' \
  --header "Authorization: Bearer $VIRALSPY_API_KEY" \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: 02d55b8e-075b-48d1-9379-72c6a534264d' \
  --data '{"question":"Compare the strongest recent skincare hooks."}'
```
