Errors
Every error response from the Seller API uses the same envelope:
{
"error": {
"code": "not_found",
"message": "Subscription not found."
}
}Some errors include a details object with structured context that can help your client recover or render a useful error message:
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded.",
"details": {
"tier": "B",
"retryAfterSeconds": 7
}
}
}Error codes
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | The request was malformed: missing required parameters, invalid types, value out of range, invalid cursor, or a body that failed schema validation. |
| 401 | unauthorized | Missing, malformed, or unknown API key. The key may have been revoked. |
| 403 | forbidden | The key is valid but does not have access to the requested resource. |
| 403 | plan_required | The server is not on the Max plan. The Seller API is gated behind Max. details.upgradeUrl points to the dashboard billing page. |
| 404 | not_found | The requested resource does not exist or does not belong to the server this key is scoped to. |
| 405 | method_not_allowed | The endpoint exists but does not accept this HTTP method. The response includes an Allow header. |
| 409 | conflict | The request could not be completed because of the current state of the resource (e.g. plan member limit reached when granting a subscription). |
| 409 | idempotency_conflict | The same Idempotency-Key was reused with a different request body. See Idempotency. |
| 413 | payload_too_large | The request body exceeds 16 KB. |
| 429 | rate_limited | Per-key or global rate limit exceeded. The response includes a Retry-After header. See Rate Limits. |
| 500 | internal_error | Something went wrong on our end. Safe to retry idempotent requests; for mutations, retry with the same Idempotency-Key. |
Validation details
When a request body fails Zod schema validation, the response includes a details.issues object describing which fields are wrong. The shape mirrors Zod's flatten() output:
{
"error": {
"code": "invalid_request",
"message": "Request body is invalid.",
"details": {
"issues": {
"formErrors": [],
"fieldErrors": {
"expiresAt": ["expiresAt must be a valid ISO 8601 date."]
}
}
}
}
}Recommended client behavior
| Status | What to do |
|---|---|
4xx (other than 429) | Do not retry without changing the request. The error is your fault. |
429 | Honor the Retry-After header (seconds), then retry. |
5xx | Retry with exponential backoff, capping at a reasonable limit (e.g. 5 attempts over ~1 minute). For mutations, always reuse the same Idempotency-Key so retries don't double-act. |
idempotency_conflict | Generate a fresh Idempotency-Key for the new request body. |
Logging tips
Log at minimum:
- HTTP status
error.codeerror.message- The endpoint and request ID (if you set one client-side)
Avoid logging full request or response bodies for mutations — they may contain customer data.