Every failure returns the same envelope — never alongside data:
code and message are always present; details only appears on field-level
failures.
Branch on error.code, never on error.message. Messages are written for
humans and change without notice; codes are a contract.
Codes
Field codes
Inside details[].code on a VALIDATION_ERROR:
Partial success on bulk writes
Bulk endpoints are not all-or-nothing in the same way. create_brand_prompts
writes the valid rows and reports the rest in the response body — a 201 can
still contain failures:
Check prompts_failed and errors_and_warnings even on a success status.
The one exception is usage limits: if the batch as a whole would exceed
your subscription, the entire mutation is rolled back and you get a 422
USAGE_LIMIT_REACHED instead — no rows are written.
Handling errors
- 401 — stop retrying. The key is bad, revoked, or expired; retrying won’t
fix it.
- 403 — you’re calling an endpoint outside the public surface, or a brand
your org doesn’t own. Also not retryable.
- 404 — treat as terminal. A soft-deleted brand starts returning it
mid-integration, so handle it as “gone”, not as a transient failure.
- 422 — a bug in your payload. Log
details and fix the caller.
- 429 — back off exponentially and retry. Don’t rotate keys to get around
it; the per-IP backstop catches that too.
- 500 — retry with backoff, cap the attempts, and alert if it sticks.