Errors

Perchat Media uses conventional HTTP response codes and returns structured error objects in the response envelope.

Error format

{
  "data": null,
  "error": {
    "code": "validationError",
    "message": "S3 presigned URL jobs are not available yet; use s3_direct with a storage connection instead",
    "details": [ { "path": "input.sourceType", "issue": "notAvailable" } ]
  },
  "metadata": { "requestId": "req_01HX...", "responseTime": 4, "timestamp": "...", "version": "v1" }
}

Job create validation returns validationError with details[] pointing at the input field — use path and issue to fix the payload. Common issues: missing connectionId, bucket not on the connection, or unsupported sourceKey extension.

CodeHTTPWhen
validationError422Request body or params failed validation.
unauthorized401Missing, malformed, or invalid API key.
forbidden403Wrong key type, missing permission, or resource not in scope.
quotaExceeded403Monthly workspace credit cap reached for transcription, indexing, or semantic search (message names the service, e.g. ai_search credit limit). See Plans & limits.
notFound404Resource doesn't exist or isn't visible.
conflict409Operation not allowed in current state, or stale revision on segment PATCH (another save won).
internalError500Unhandled server exception.
serviceUnavailable503Dependency outage (including catalog / vector search for POST /v1/catalog/search).

Stale transcript revision (409)

Segment PATCH endpoints return 409 conflict when revision in the body does not match the stored transcript (another save, glossary apply, or revert ran first). Re-GET the transcript and retry with the new revision. Prefer batch PATCH …/segments when saving many segments at once — see Transcripts → Edit multiple segments.

{
  "data": null,
  "error": {
    "code": "conflict",
    "message": "transcript txt_01HX2K9V3JEK4WYZN6F0XQ2W8M was modified (expected revision 0); refresh and retry",
    "details": [{ "path": "revision", "issue": "stale" }]
  },
  "metadata": { "requestId": "req_01HX...", "responseTime": 3, "timestamp": "...", "version": "v1" }
}

Job failures (async)

When a job finishes with status: failed, the envelope is still 200 on GET /v1/jobs/{jobId}. Read data.error on the Job object (code + message), not the top-level envelope error field. For lastError, progress[].error, retries, and attemptHistory[], see Jobs → Job failures & retries.

Common data.error.code values: duration_exceeded, transcript_too_large, processing_failed. Full table in Plans & limits.