# Error reference

Every error the Agent Network returns, why it happens, and whether retrying is safe.

```json
{
  "error": {
    "code": "RYDE_ONE_REQUIRED",
    "message": "An active Ryde One membership is required to create this transaction.",
    "request_id": "req_9f2c41ab7d0e4c58",
    "details": {}
  }
}
```

Branch on code, never on message — messages are localized and may be reworded. details carries whatever is specific to that failure.

| Code | Status | Description | Retry safe | What to do |
| --- | --- | --- | --- | --- |
| `INVALID_REQUEST` | 400 | The request was malformed — a missing field, an unparseable body, or a parameter of the wrong type. | no | Correct the request. Retrying it unchanged will fail identically. |
| `UNAUTHORIZED` | 401 | No access token, an expired one, or one this API will not accept. | no | Refresh the access token. If the refresh also fails, send the customer through the authorization flow again. |
| `INSUFFICIENT_SCOPE` | 403 | The token is valid but does not carry the scope this operation requires. | no | Request the missing scope and have the customer approve it. Scopes are exact strings: holding food.read does not imply food.order. |
| `RYDE_ONE_REQUIRED` | 403 | Authorization is fine, but this customer has no active Ryde One membership and this operation would create a new transaction. | no | Show the customer join_url. Nothing about the request is wrong — reads, quotes, tracking and cancellation all keep working meanwhile, so the agent can present exactly what a membership would unlock. |
| `BUSINESS_AGREEMENT_REQUIRED` | 403 | The business surface needs an active Ryde One Business Agreement for the merchant or provider being acted for. | no | The merchant completes the business agreement from their Ryde portal. A developer cannot accept it on their behalf. |
| `FORBIDDEN` | 403 | Authenticated and entitled, but not permitted to act on this particular resource — it belongs to someone else. | no | Do not retry. Check the resource id. |
| `NOT_FOUND` | 404 | No such resource, or none this customer may see. The two are answered identically on purpose, so ids cannot be enumerated. | no | Check the id. Note this is also what you get for a resource that belongs to someone else, so a 404 is not proof the resource does not exist — do not retry, and do not probe. |
| `RESOURCE_STATE_CONFLICT` | 409 | The resource is not in a state that allows this — cancelling a delivered order, booking a slot someone else just took. | no | Re-read the resource and decide again from its current state. |
| `IDEMPOTENCY_KEY_REUSED` | 409 | This Idempotency-Key was already used with a different request body. | no | A key identifies one intended transaction. Use a fresh key for a genuinely different request. |
| `QUOTE_REQUIRED` | 422 | A transacting request arrived with no quote_id, an expired one, one issued for a different operation, or one whose parameters no longer match. | no | Quote again, show the customer the new price, and send the fresh quote_id. This is what stops an agent transacting on a figure nobody saw. |
| `VALIDATION_ERROR` | 422 | Well-formed, but the platform refused it — outside a serviceable area, a product that is out of stock, a slot in the past. | no | Read details; it names the field or rule that refused. |
| `RATE_LIMITED` | 429 | Too many requests for this application or this customer in the current window. | yes | Back off and retry after the interval in Retry-After. Do not retry immediately in a loop. |
| `INTERNAL_ERROR` | 500 | Something failed on Ryde's side. | no | Retry a read. Do NOT blindly retry a transacting call without its original Idempotency-Key — with the key, a retry is safe and replays the first outcome. |
| `SERVICE_UNAVAILABLE` | 503 | A dependency is temporarily unavailable. | yes | Retry with backoff. |

> **Important:** Never blindly retry a transacting call after a 500. Without its original Idempotency-Key a retry can create a second ride or a second order. With the key, the retry is safe and replays the first outcome.
