Errors and credits
The error envelope
Section titled “The error envelope”Every error response — for every endpoint — uses the same structured envelope:
{ "error": { "code": "INSUFFICIENT_BALANCE", "message": "Account balance is below the cost of this request.", "request_id": "01JREQREQREQREQREQREQREQ00" }}code— a stable, machine-readable string. Branch on this, not on the message text.message— a human-readable explanation; wording may change.request_id— the 26-char ULID for this request, also returned on the202success envelope and recorded in your usage log. Quote it in support requests.
The codes you’ll encounter on a dispatch (see the per-endpoint responses in the API reference):
| HTTP | code | Meaning |
|---|---|---|
| 402 | INSUFFICIENT_BALANCE | The request cost exceeds your credit balance. No job is created and nothing is charged. |
| 422 | VALIDATION_ERROR | The request body or parameters failed validation. No credits charged. |
| 429 | RATE_LIMITED | Per-credential rate limit exceeded. Back off and retry. |
Credits
Section titled “Credits”Credits gate every dispatch. The cost is a flat, per-dispatch amount that is
deducted synchronously when you call a workflow endpoint and echoed back as
credits_cost in the 202 response. Authoritative, live costs are served by
GET /v1/operations (each entry carries name, op_class, credits_cost, and
an enabled flag) — query it rather than hard-coding prices. The current
defaults:
| Workflow | Class | Credits |
|---|---|---|
model-generator | generator | 5 |
background-generator | generator | 5 |
complementary-garment-generator | generator | 5 |
product-to-model-direct | compose | 10 |
product-to-model-phased | compose | 10 |
background-swap-with-image | edit | 5 |
background-swap-with-spec | edit | 5 |
model-swap-with-image | edit | 5 |
try-on | — | 10 |
extract | — | 1 |
look | — | 10 (placeholder; defaults to the try-on cost pending a pricing decision) |
Reads (GET /v1/jobs*, GET /v1/renders*, catalog, etc.) and uploads do not
cost credits.
Refund on failure
Section titled “Refund on failure”Credits are charged at dispatch, before the engine runs. If the job later fails
— or if the gateway accepted the request but studio never returned a job — the
charge is automatically refunded. A background reconciler sweeps for any
orphaned charge and refunds it, so a failed render never costs you credits. You
can confirm a refund in your usage log: the row’s status moves to REFUNDED
and credits_refunded reflects the amount returned.
Checking balance and usage
Section titled “Checking balance and usage”GET /v1/credits— your currentbalance,plan, today’s spend (daily_spend_today), the daily cap (daily_spend_cap_credits,0means unlimited), the monthly quota (monthly_credit_quota,0means pay-as-you-go), and your per-minute rate limit (rate_limit_per_min).GET /v1/usage— a paginated log of your requests, one row per call, withcredits_charged,credits_refunded, the resolvedstatus(PENDING | SUCCESS | FAILED | REFUNDED), therequest_id, and the linkedjob_id.
Rate limits
Section titled “Rate limits”Requests are rate-limited per credential. The ceiling is your
rate_limit_per_min, visible on GET /v1/credits. Exceeding it returns 429
with code RATE_LIMITED; retry after a short backoff. Daily and monthly spend
caps (daily_spend_cap_credits, monthly_credit_quota) bound total consumption
over longer windows — both reported on GET /v1/credits.