Delivery vs start SLA
Delivery is controlled by client_wait — independently of the start SLA processing_lane. See Start SLA.
Pipeline slug
Job paths use handler___command with three underscores. OCR: POST /job/add/paperoffice_aiocr___generate. IDP: POST /job/add/workflow. No dot and no po-* in the path.
Dot notation (handler.command) returns HTTP 400 (JOB_CONFIG_INVALID).
IDP POST /job/add/workflow accepts only multipart file or pofid — no JSON URL arrays.
Default — hold the connection
POST /job/add/{pipeline} → hold the connection until ~295s → 200 result OR HTTP 202 + job_id + poll_url
After the hold window the job keeps running. Poll GET /job/get/{job_id} every 5–10 seconds or use poll_url from the response.
Queued, running and completed API jobs: Account → API → Job queue (/paperoffice-account/api-queue).
Immediate job_id
client_wait=false OR async_only=true
1. POST /job/add/{pipeline} → job_id immediately (~100ms)
2. GET /job/get/{job_id} → poll every 5–10 s until job_status = "completed"
3. GET /job/download/{token} → only when job_result contains a download URL
HTTP 202 — the job continues
HTTP 202 is a success path, not an error. The job stays active. Poll job_id and poll_url until job_status is completed. The result is in job_result.
On connection hold the finished result is in result. When polling it is in job_result. Clients must read the stable code field, not the localised message text.
Response format
All responses are JSON and include processing_time.
Success:
{
"status": "success",
"job_id": "abc123",
"result": { "text": "…" },
"processing_time": "45.12ms"
}
Polling / HTTP 202:
{
"status": "success",
"job_id": "abc123",
"poll_url": "/job/get/abc123",
"client_wait": false,
"max_wait_seconds": 60,
"message": "Job queued — poll for result",
"processing_time": "45.12ms"
}
Error:
{
"status": "error",
"code": "INSUFFICIENT_CREDITS",
"message": "Not enough credits for this job",
"processing_time": "12.04ms"
}
Error codes
| HTTP | Code | Meaning | What to do |
|---|---|---|---|
| 400 | INVALID_REQUEST | Missing / invalid parameters | Check the request body |
| 400 | JOB_CONFIG_INVALID | Invalid pipeline slug | Use handler___command, not dot notation |
| 401 | AUTH_REQUIRED | No Bearer token | Set Authorization: Bearer YOUR_TOKEN |
| 401 | INVALID_TOKEN | Token invalid | Check prefix (po_sk_, po_ut_, po_gt_, po_pk_) |
| 401 | BEARERTOKEN_EXPIRED | Token expired | Request a new token |
| 402 | INSUFFICIENT_CREDITS | Not enough credits | Top up or choose a lower lane |
| 402 | BUDGET_EXHAUSTED | Publishable-key budget reached | Create a new po_pk_ or raise the cap |
| 403 | FORBIDDEN | Action not allowed | Check scope, origin or licence |
| 403 | TIER_RESTRICTED | Product API without token (VISITOR) | Set a Bearer token — this is not HTTP 401 |
| 403 | JOB_REQUIRES_PAID_TIER | Free tier not allowed | Use a paid plan |
| 404 | NOT_FOUND | Not found | Check the URL path |
| 429 | RATE_LIMIT_EXCEEDED | Too many requests | Honour Retry-After |
| 429 | QUEUE_LIMIT_REACHED | Queue full | Retry later |
| 500 | INTERNAL_ERROR | Server error | Retry after a short pause |
| 503 | SERVICE_UNAVAILABLE | Service unreachable | Retry with backoff |