# Responses and data formats

## Success

```json
{ "success": true, "data": { "id": "cm3o7rd0e0001h2j3k4l5m6n" } }
```

List endpoints add `meta` (see [Pagination](https://docs.rephut.com/developers/pagination)):

```json
{ "success": true, "data": [{ "id": "cm3o7rd0e0001h2j3k4l5m6n" }], "meta": { "total": 120, "page": 1, "limit": 50, "pageCount": 3 } }
```

A call that creates something returns `201` with the new resource. Other successful calls return `200`. Writes return the resource as it is after the change, exactly as the matching `GET` returns it where there is one (for example [`POST /v1/sku-mappings`](https://docs.rephut.com/developers/reference/sku-mappings#map-your-sku-to-one-of-your-products) returns a mapping summary).

## Errors

```json
{ "success": false, "error": "This shipment was updated. Please review it again.", "code": "shipment_changed" }
```

Validation errors add `details`, one entry per problem:

```json
{ "success": false, "error": "Quantities must be at least 1.", "code": "validation_failed", "details": [{ "path": "lines.0.qty", "message": "Quantities must be at least 1." }] }
```

See [Errors](https://docs.rephut.com/developers/errors).

## Headers on every response

| Header | Meaning |
|---|---|
| `X-Request-Id` | A unique id for this request. Quote it when you contact support. |
| `Cache-Control: no-store` | Responses are never cached. |
| `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` | Your current rate-limit window, except `403 api_not_enabled`, `403 account_action_required` and unknown paths. See [Rate limits](https://docs.rephut.com/developers/rate-limits). |
| `Retry-After` | On `429` only: seconds to wait. |
| `Idempotency-Replayed: true` | On a replayed response only. See [Idempotency](https://docs.rephut.com/developers/idempotency). |

The public OpenAPI document is the one exception: it may be cached and has no `X-Request-Id`.

## Sending requests

- Send request bodies as JSON with `Content-Type: application/json`. Another content type returns `415 unsupported_media_type`; JSON that doesn't parse returns `400 invalid_json`.
- A body can be at most 1 MB (`413 payload_too_large`) and nested at most 64 levels deep.
- Text can't contain NUL characters (`\u0000`).
- On endpoints that take a body, an empty body returns `422 validation_failed`, except on [`POST /v1/orders/preview`](https://docs.rephut.com/developers/reference/orders#check-a-new-order-without-saving-it) and [`POST /v1/orders/{id}/cancel`](https://docs.rephut.com/developers/reference/orders#cancel-an-order-that-needs-attention), where an empty body counts as `{}`. Endpoints that take no body, such as [`POST /v1/shipments/{id}/cancel`](https://docs.rephut.com/developers/reference/shipments#cancel-a-shipment-you-requested), ignore it.
- Fields the endpoint doesn't know are ignored. Text values are trimmed, and control characters are removed from most of them.
- Send each query parameter at most once: a repeated parameter returns `422 validation_failed` on every endpoint. Unknown query parameters are ignored.
- In a query string, encode `+` as `%2B` (for example in a time zone offset); otherwise it arrives as a space.

## Data formats

| Kind | Format |
|---|---|
| Money | Whole numbers of the smallest unit, in fields ending in `Cents`, with the currency in `currency`. Amounts are US dollars (cents), except the supplier reference price of a product, which is Chinese yuan (fen). |
| Times | ISO 8601 in UTC, for example `2026-11-09T02:00:00.000Z`. |
| Dates | Fields that are only a date (payment days, `neededBy`) are `YYYY-MM-DD` in China time (UTC+8). |
| Codes | `status`, `kind` and similar fields are stable uppercase codes such as `SHIPPED`. |
| Labels | Fields ending in `Label` are English text for display. They may change; don't use them in program logic. |
| Ids | Strings of letters, digits, `_` and `-`. Treat them as opaque. An id in a path that isn't in this format returns `404`. |
| Images and files | Not included in responses. |
| Empty values | Text without a value is `""`. Values that don't exist yet are `null`, as each field says. |

## HTTP status codes

| Status | Meaning |
|---|---|
| 200 / 201 | Success / created |
| 400 | Invalid JSON or a bad `Idempotency-Key` |
| 401 | Missing or invalid API key |
| 403 | API access off, an account step needed, a missing permission, or the account on hold |
| 404 | The resource doesn't exist or isn't yours (we don't tell the two apart), or the path doesn't exist |
| 405 | The path exists but not with this method; see `Allow` |
| 409 | The current state doesn't allow it, or the data changed; read it again and decide |
| 413 / 415 | Body over 1 MB / not JSON |
| 422 | The input or a business rule was rejected |
| 429 | Rate limited; wait for `Retry-After` |
| 500 | Unexpected error; quote `X-Request-Id` |
