Skip to main content

Errors, rate limits and retries

Error format​

Every error is application/problem+json (RFC 9457) with a stable type:

{
"type": "https://developer.nasam.co/errors/invalid-request",
"title": "Invalid request",
"status": 400,
"detail": "brandId must be a positive integer",
"requestId": "4f6c2b0e-1d7a-4c55-9a43-7f1f3e8c2a10",
"errors": [{ "pointer": "/brandId", "detail": "must be a positive integer" }]
}

Branch on type (or status), not on detail or title: detail explains this occurrence and its wording can change. errors appears on invalid-request and points at each invalid field: a JSON Pointer into the body, or /name for a query or path parameter.

typeStatusMeaningRetry?
invalid-request400A parameter or body field is missing, has the wrong type, or has a value the operation does not accept.No. Fix the request.
unauthorized401The key is missing, unknown or revoked. See authentication.No.
forbidden403The key's user lacks the permission, or the request names a brand outside its scope.No.
not-found404The resource does not exist or is outside the key's scope, or the path is not an MM-API operation.No.
conflict409The request conflicts with the resource's current state.Read the resource again, then decide.
idempotency-in-progress409A request with the same Idempotency-Key is still running.Yes, after a short wait.
idempotency-key-reused422The Idempotency-Key was used with a different request.No. Use a new key for a new request.
payload-too-large413The request body is larger than the request size limit.No. Send a smaller body.
rate-limited429Too many requests.Yes, after Retry-After seconds.
internal500Nasam failed to complete the request.Yes, with backoff. Send an Idempotency-Key on writes so a retry cannot apply twice.

Ignore problem fields you do not recognise; new ones can be added.

Request IDs​

Every response carries X-Request-Id, and every error body repeats it as requestId. Log it with each failed call and include it when you write to support; it lets Nasam find the exact request.

You can send your own X-Request-Id (up to 128 characters) to tie Nasam's logs to yours. Nasam echoes a well-formed value and generates one otherwise.

Rate limit​

The current limit is 120 requests per fixed one-minute window per API key. Every authenticated request counts, whatever its status. Each response reports where you stand:

RateLimit-Policy: "default";q=120;w=60
RateLimit: "default";r=87;t=23

q is the quota and w the window in seconds. r is the number of requests left in this window and t the seconds until it resets. Over the limit, the API returns 429 rate-limited with Retry-After in seconds. Wait that long before the next request.

The limit is published as the current one, not a guarantee. Read it from RateLimit-Policy rather than hard-coding 120, and pace from RateLimit: when r is low, wait t seconds. Two keys on the same user each have their own window.

Requests that fail authentication are limited separately, at 60 a minute per client IP address. That 429 carries Retry-After only.

Retry writes safely with Idempotency-Key​

A timeout on a write leaves you unsure whether it ran. Send an Idempotency-Key header on POST, PUT, PATCH and DELETE, and you can repeat the request without applying it twice:

curl -X POST 'https://api.nasam.co/mm-api/v1/fulfillment/orders/packed' \
-H "Authorization: Bearer $NASAM_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: 8d0c3c4e-6a8f-4d53-9b8e-0f2f8b1f6d21' \
-d '{"orderIds": [88123]}'
  • Generate a new unique value (a UUID works) for each logical write, and reuse it only to retry that same write.
  • Within 24 hours, a retry with the same key, method, path and body returns the stored response with Idempotent-Replayed: true. The original status and body are replayed; X-Request-Id and RateLimit describe the retry.
  • A response with status below 500, including a 4xx error, is stored and replayed. After a 5xx the key is released, so retrying it runs the write again.
  • The same key with a different body returns 422 idempotency-key-reused.
  • The same key while the first request is still running returns 409 idempotency-in-progress. Wait and retry.

Idempotency keys belong to the API key that sent them, so two systems with different API keys cannot collide. After 24 hours a stored response is discarded and the value counts as new.

A retry policy that works​

  1. Retry 429, 500, idempotency-in-progress and network errors. Do not retry other 4xx.
  2. On 429, wait Retry-After seconds. Otherwise back off exponentially with jitter, for example 1, 2, 4, 8 seconds, and stop after a few attempts.
  3. Send an Idempotency-Key on every write, and keep it the same across retries of that write.
  4. Some batch writes, such as marking orders packed, report a result per item inside a 2xx response. Read the item results and resend only the items that failed, under a new key.