# Errors and retries

> How to read a failed answer, which answers to retry, and how to retry safely.

## Read `status` first

| status | What to do |
| --- | --- |
| `accepted`, `saved`, `held` | Done. Nothing to retry. |
| `pending` | The buyer has not decided yet. Do not resubmit. |
| `rejected` | A final decision (eligibility, cap, duplicate, buyer refusal). Do not retry the same lead to the same offer. |
| `invalid` | Fix the request (the `field` / `fields` say what) and send it again. |
| `failed` | Nothing was decided. Retry only when `retryable` is `true`. |

## Retryable answers

| code | reason | HTTP |
| --- | --- | --- |
| `RATE_LIMITED` | Too many requests | 429 |
| `CAP_UNAVAILABLE` | Cap check unavailable | 200, 503 |
| `TIMEOUT` | Timeout - Client | 200, 504 |
| `UNAVAILABLE` | Temporarily unavailable | 200, 503 |

## How to retry

- **Honour `Retry-After`.** A `RATE_LIMITED` answer (HTTP 429) carries a `Retry-After` header and `retry_after_seconds`: wait that long.
- **Back off.** Otherwise wait 1 s, then 2 s, then 4 s; give up after three retries and log the answer.
- **Retry with the same link to the lead.** Retry a result submit with the same `search_lead_id`, and a direct post with the `icon_lead_id` ICON returned. ICON then recognises an offer that already accepted the lead and answers `DUPLICATE` (`Duplicate - Offer`) instead of selling it twice.
- **A `DUPLICATE` on a retry** can mean your earlier attempt was accepted. Before you treat the lead as refused, ask your ICON contact with its `icon_lead_id`.
- **No answer at all** (a network error or your own timeout): retry once, as above. Give a submit a generous timeout (30 seconds or more): the school's system answers inside that call.
- **`INTERNAL_ERROR`** is not retryable as is. Send your ICON contact the time and the `icon_lead_id` (a submit's answer also carries a `request_id`).

## Error body

```json
{
  "code": "REQUIRED_FIELD_MISSING",
  "status": "invalid",
  "reason": "Missing HS grad year",
  "message": "Required field missing",
  "retryable": false,
  "field": "lead.education.high_school_graduation_year"
}
```

```json
{
  "code": "RATE_LIMITED",
  "status": "failed",
  "reason": "Too many requests",
  "message": "Too many requests",
  "retryable": true,
  "retry_after_seconds": 2
}
```
