Content Integration errors use a stable error.code value. Treat the code as the client-facing contract and the message as human-readable detail.
Error codes
| Code | Meaning | Retry |
|---|---|---|
content_invalid_api_key | Bearer token is missing, malformed, revoked, or expired. | No. Create or rotate the key. |
content_invalid_request | Request body failed validation. | No. Fix the payload. |
content_forbidden | Signed-in admin cannot manage the target organization. | No. Use an admin with access. |
content_not_found | Job, key, or webhook was not found. | No, unless the id was mistyped. |
content_conflict | Request conflicts with an existing state, or an idempotency key was reused with different request content. | Usually no. Check idempotency. |
content_rate_limit_exceeded | Key rate limit was exceeded. | Yes, after waiting. |
content_internal_error | Unexpected server error. | Yes, with backoff. |
An expansion request can also return HTTP 402 when the organization does not have enough availableCredit for all requested outputs or when payment has failed. Check GET /v1/content/credits, then add credits or resolve the billing issue before retrying. Content API expansion never falls back to Agent Platform credits.
Example error
{
"error": {
"code": "content_invalid_api_key",
"message": "Invalid or missing Content Integration API key",
"status": 401
}
}Validation errors
Requests rejected by body validation (content_invalid_request) additionally
carry error.details: one entry per invalid field with the dotted field
path, a readable message, and the failed constraints. Use it to fix a
rejected payload programmatically instead of parsing the message string.
{
"error": {
"code": "content_invalid_request",
"message": "Validation failed: sourceTitle must be a string",
"details": [
{
"field": "sourceTitle",
"message": "sourceTitle must be a string",
"constraints": ["isString", "isNotEmpty"]
}
],
"status": 422
}
}Router-level 404s under /v1/content/** (for example a typo in the path) use
the same envelope with error.code: "content_not_found".
Retry rules
- Retry
429after waiting at least 30 seconds. - Retry
500with exponential backoff. - Do not retry
400without changing the payload. - Do not retry
401without replacing the key. - Do not retry
402until the organization has enough available AI Credits and payment is active. - Do not create a second job for the same source content while the original job is still
queuedorprocessing.
Failed jobs
When a job reaches failed, fetch the result endpoint and inspect:
job.error- each
outputs[].error - requested output list
- source title
Fix the source JSON or requested outputs, then create a new job with a new idempotency key if the source content changed.
Support handoff
Send these fields to TutorFlow support:
| Field | Notes |
|---|---|
jobId | Required for expansion issues. |
keyPrefix | Safe to share. Do not send the full key. |
| Endpoint path | Example: /v1/content/integrations/expansions. |
| Timestamp | Include timezone. |
| Idempotency key | Helps find duplicate or retried requests. |
| Final response body | Include error object and status code. |
| Source JSON sample | Include only if it can be shared. |