# Responses & Errors

> The success and error response envelopes, stable codes, and retry behavior.

Source: https://docs.toolzerhub.com/docs/responses-and-errors

## Success responses
Every successful response is wrapped in a `data` field:

```json
{
  "data": {
    "...": "endpoint-specific payload"
  }
}
```

The schema only guarantees `data.products[].product_id` for product-shaped
endpoints; everything else is source-specific. See each operation in the
[API reference](/reference) for its exact response shape.

## Error responses
Every error response is wrapped the same way, regardless of endpoint:

```json
{
  "error": {
    "code": "NOT_FOUND",
    "status": 404,
    "message": "User not found.",
    "retryable": false,
    "details": {}
  }
}
```

| Field       | Type    | Meaning                                         |
| ----------- | ------- | ----------------------------------------------- |
| `code`      | string  | Stable machine-readable code for the failure    |
| `status`    | number  | The matching HTTP status code                   |
| `message`   | string  | Human-readable description of what went wrong   |
| `retryable` | boolean | Whether retrying the same request could succeed |
| `details`   | object  | Optional extra context, shape varies by error   |

## Error codes
| Code                 | Typical meaning                                            |
| -------------------- | ---------------------------------------------------------- |
| `INVALID_REQUEST`    | The request was malformed — a missing or invalid parameter |
| `UNAUTHORIZED`       | The `x-api-key` header was missing or invalid              |
| `FORBIDDEN`          | The key is valid but not allowed to access this resource   |
| `PAYMENT_REQUIRED`   | Out of credits — see [Credits](/docs/credits)              |
| `NOT_FOUND`          | The requested resource doesn't exist                       |
| `RATE_LIMITED`       | Too many requests — see [Rate limits](/docs/rate-limits)   |
| `SOURCE_UNAVAILABLE` | The upstream public source is temporarily unreachable      |
| `SOURCE_ERROR`       | The upstream public source returned an unexpected error    |
| `INTERNAL_ERROR`     | Something went wrong on Toolzer Hub's side                 |

<Callout title="Check retryable before you retry" type="info">
  `SOURCE_UNAVAILABLE` and some `INTERNAL_ERROR` responses are typically
  `retryable: true` — a short backoff-and-retry is reasonable. Treat
  `INVALID_REQUEST`, `UNAUTHORIZED`, `FORBIDDEN`, and `NOT_FOUND` as not
  worth retrying without changing the request first.
</Callout>
