Error Codes
HTTP status codes and error response format for the Qamera AI API.
The Qamera AI API uses standard HTTP status codes to indicate the outcome of each request. Successful requests return 200. Error responses include a JSON body with an error field describing what went wrong.
Response Format
All error responses follow this structure:
{
"error": "A human-readable description of the problem."
}
Status Codes
200 OK
The request was processed successfully. The response body contains the requested data or confirmation of the completed action.
400 Bad Request
The request body is missing required fields, contains invalid values, or is malformed.
{
"error": "Validation failed: 'productId' is required."
}
Common causes:
- Missing required fields in a POST body.
- Invalid field types (e.g. string where a number is expected).
- Malformed JSON.
401 Unauthorized
The API key is missing, invalid, expired, or revoked.
{
"error": "Invalid API key."
}
Common causes:
- No
X-Api-KeyorAuthorizationheader provided. - Key has been revoked or has passed its expiration date.
- Typographical error in the key value.
402 Payment Required
The account associated with the API key does not have enough credits to complete the requested operation.
{
"error": "Insufficient credits. Required: 5, available: 2."
}
What to do:
- Purchase additional credits or a credit pack from your workspace billing settings.
- Check your current balance before submitting generation requests.
403 Forbidden
The API key does not have the required scope for this endpoint.
{
"error": "Missing required scope: 'content.register'."
}
Common causes:
- The key was issued without the scope needed for the requested action.
- Attempting a POST operation with a
content.read-only key.
404 Not Found
The requested resource does not exist, or your account does not have access to it.
{
"error": "Product not found."
}
Common causes:
- Incorrect resource ID in the URL.
- The resource belongs to a different account.
- The resource was deleted.
429 Too Many Requests
The API key has exceeded the rate limit of 60 requests per minute.
{
"error": "Too many requests. Please retry after a short delay."
}
What to do:
- Wait before retrying. Use exponential backoff with jitter.
- See the Rate Limiting page for detailed retry strategies.
500 Internal Server Error
An unexpected error occurred on the server.
{
"error": "An internal error occurred. Please try again later."
}
What to do:
- Retry the request after a short delay.
- If the error persists, contact support with the request details and approximate timestamp.
502 Bad Gateway
An external service that the API depends on returned an unexpected response.
{
"error": "External service returned an unexpected response."
}
Common causes:
- A downstream AI generation service is temporarily unavailable.
- Network issues between Qamera AI and its service providers.
What to do:
- Retry after a few seconds. These errors are usually transient.
503 Service Unavailable
No active content generator is available to process the request.
{
"error": "No active generator available. Please try again later."
}
Common causes:
- All generation workers are offline or undergoing maintenance.
- Temporary capacity issues during peak usage.
What to do:
- Retry after 30–60 seconds.
- Check the Qamera AI status page for ongoing incidents.
Summary Table
| Code | Meaning | Retryable |
|---|---|---|
| 200 | Success | — |
| 400 | Bad input | No (fix the request) |
| 401 | Invalid key | No (check your key) |
| 402 | Insufficient credits | No (add credits) |
| 403 | Missing scope | No (check key permissions) |
| 404 | Not found | No (check resource ID) |
| 429 | Rate limited | Yes (with backoff) |
| 500 | Server error | Yes (with delay) |
| 502 | External service error | Yes (with delay) |
| 503 | No active generator | Yes (after 30–60s) |
Job Failure Categories
The status codes above describe whether your request succeeded. A generation job is different: submitting it succeeds immediately with 200, and the work happens afterwards. A job that fails later is reported inside a successful response, not as an HTTP error.
When you poll GET /api/external/orders/:id, each job carries two fields describing its failure:
errorCategory— a fixed value from the table below. Branch your logic on this.errorHint— one sentence explaining the category and what to do. Show it to a person; do not parse it.
Both are null for jobs that succeeded, and for failures recorded before this classification existed.
errorCategory | What happened | What to do |
|---|---|---|
TRANSIENT_INFRA | A temporary infrastructure problem. | Nothing — the job is retried automatically. |
RATE_LIMIT | The generation provider rate-limited us. | Nothing — the job is retried automatically. |
PROVIDER_CAPACITY | The generation provider had no free capacity. | Nothing — the job is retried automatically. |
CONTENT_POLICY | The provider's content rules rejected the request. | Retrying the same input fails the same way. Change the prompt or the source image, then submit a new order. |
INPUT_MISSING | A required input could not be resolved — most often the source image referenced by the order. | Check the references you submitted, then create a new order. |
INPUT_NOT_READY | An input the job needs is still being prepared on our side, most often a source photo mid-upscale. | Nothing while the job waits — it runs on its own once the input is ready. If the job ends as failed, the preparation did not finish in time: submit the order again once the source image is available. |
PROVIDER_ACCOUNT | A problem with our provider account blocked the generation. | Nothing on your side. Contact support and quote the orderId. |
INTERNAL_BUG | A defect on our side. | Nothing on your side. Contact support and quote the orderId. |
TRANSIENT_INFRA, RATE_LIMIT, PROVIDER_CAPACITY and INPUT_NOT_READY are retried for you, so a job carrying them may still finish successfully — treat them as progress information rather than as a final outcome. Only act when the order stops changing and the job's status is failed. The category stays on the row after that, so read it together with status: the same INPUT_NOT_READY means "waiting" on a retry_pending job and "waited, and gave up" on a failed one. errorHint says which.
Raw provider messages are deliberately not exposed. They carry vendor names and internal system details that change without notice, so integrations that parsed them broke on every provider change. The category is the stable contract.