API context for agents

The whole CloudRaker API contract on one page — written to be fetched as Markdown by a coding agent.

View as Markdown

Point a coding agent at https://docs.cloudraker.com/developers/agents.md and it has everything it needs to write a working integration: auth, the request and error envelopes, all six verbs, the run lifecycle, the schema dialect, and the limits.

$curl -s https://docs.cloudraker.com/developers/agents.md

Every page on this site has the same .md twin, and https://docs.cloudraker.com/llms.txt indexes them all. This page is the one to start from.

Base URL and auth

Base URL: https://api.cloudraker.com. Every request carries an organization API key as a bearer token:

Authorization: Bearer $CLOUDRAKER_API_KEY
Content-Type: application/json

One key belongs to one organization; the key is the tenant, so no tenant, account, or workspace id is ever passed. Keys are created in the app under Admin → API keys and shown once. Staging (https://api.staging.raker.one) and development (https://api.dev.raker.one) are separate environments with separate keys.

The six verbs

Each is a single POST that creates a run, is synchronous by default, and accepts ?wait= (0–120 seconds, 60 default). Minimal bodies:

1// POST /v1/extract — document -> JSON matching your schema, with citations
2{ "file": { "url": "https://example.com/invoice.pdf" },
3 "schema": { "type": "object", "properties": { "total": { "type": ["number", "null"] } } } }
4
5// POST /v1/extract — no schema: infer one, then extract with it (exploration only)
6{ "file": { "url": "https://example.com/invoice.pdf" }, "hints": "It's an invoice; capture the header fields" }
7
8// POST /v1/extract/batch — one saved action over many files; always 202
9{ "action": "invoice-header", "files": [{ "url": "" }, { "url": "" }] }
10
11// POST /v1/parse — document -> markdown + structured JSON, no schema
12{ "file": { "url": "https://example.com/contract.pdf" } }
13
14// POST /v1/redact — destructive PII removal; returns a NEW file
15{ "file": { "id": "<fileId>" }, "categories": ["ssn", "ein"], "mode": "targeted" }
16
17// POST /v1/fill — fill a form PDF from source documents
18{ "template": { "id": "<templateId>" }, "files": [{ "id": "<fileId>" }], "review": "none", "output": "flattened" }
19
20// POST /v1/sign — e-signature envelope; always 202, status needs_input
21{ "file": { "id": "<fileId>" }, "signers": [{ "name": "Jane Doe", "email": "[email protected]" }] }
22
23// POST /v1/pipeline — several capabilities over one file set, in parallel (not chained)
24{ "files": [{ "url": "" }],
25 "steps": [{ "extract": { "schema": { "type": "object", "properties": {} } } }, { "redact": { "categories": ["ssn"] } }] }

Shared optional fields on every verb: metadata (your own key/values, ≤10 KB, echoed back and filterable), webhook ({url} or {id}), ttl (seconds, default 86400, max 604800), and the idempotency-key request header.

extract, redact, fill, and sign also accept action: "<id or slug>" instead of inline config; inline fields win over the saved ones. Save one with POST /v1/actions {capability, name, config}; discover configurable shapes with GET /v1/actions/catalog.

File references

Anywhere a file is taken, the value is one of two shapes — never a multipart upload:

1{ "url": "https://…", "name": "invoice.pdf", "processing": "auto" } // fetched server-side
2{ "id": "a04d6597-4e34-4a99-94ea-964c289a4c68" } // already registered or produced

processing: auto (default), ocr, simple, transcribe, transcribe_diarize. Single-file verbs take file; multi-file verbs take files[] (up to 100). Sending both is a 400.

Register a persistent file with POST /v1/files — either {url, name?} (the source must serve a Content-Length) or {name, mimeType}, which returns an uploadUrl valid 15 minutes that you PUT the bytes to with the identical Content-Type. Poll GET /v1/files/:id until status: "ready". Files a run creates inline expire with the run; files you register do not.

Runs

GET /v1/runs list (filters below)
GET /v1/runs/:id status + result; accepts ?wait=
POST /v1/runs/:id/cancel stop in-flight work
DELETE /v1/runs/:id purge now (204, idempotent)
POST /v1/runs/:id/keep persist into a space; clears the TTL
GET /v1/runs/:id/output/:name 302 to a signed download URL

Id prefixes: exr_ extract, par_ parse, rdr_ redact, flr_ fill, sgr_ sign, plr_ pipeline. Treat ids as opaque strings.

Statuses: queued, processing, processed, failed, cancelled, expired, needs_input. output exists only at processed. needs_input means a human is required — a fill review (tasks[]) or an open signature envelope (envelopeUrl).

A synchronous call that doesn’t finish within ?wait= returns 202 with the run handle, never a timeout error — poll statusUrl or use a webhook. Sign runs are exempt from the TTL purge while the envelope is open; every other run and its inline files are purged at expiresAt.

GET /v1/runs takes object, status (the six values above minus queued), limit (1–50, default 20), cursor, and up to three metadata.<key>=<value> pairs. It returns {object:"list", data:[…handles…], has_more, cursor} and is eventually consistentGET /v1/runs/:id is authoritative.

Extract output

1{
2 "object": "extract_run", "id": "exr_…", "status": "processed",
3 "config": { "schema": { /* the schema actually applied — inline, saved, or inferred */ } },
4 "output": {
5 "value": { "total": 1889.45 }, // alias of documents[0].value
6 "citations": { // field path -> evidence
7 "total": [{ "fileId": "", "page": 0, "bbox": { "x": 0.1, "y": 0.2, "width": 0.1, "height": 0.02 },
8 "text": "CAD 1,889.45", "confidence": 5 }]
9 },
10 "documents": [{ "fileId": "", "name": "invoice.pdf", "status": "done", "value": {}, "citations": {} }]
11 }
12}

page is 0-based; bbox is normalized 01 with a top-left origin; confidence is 05. A field the document doesn’t contain comes back null, which is why every property should be declared nullable.

Extraction schema dialect

Plain JSON Schema with four constraints, checked before the run starts (400 invalid_schema, with the offending path):

  1. The root must be {"type": "object"}.
  2. Nesting may not exceed 5 levels.
  3. No $defs, $ref, oneOf, anyOf, allOf, const, or pattern — these are the only rejected keywords, and only in keyword positions (a property named pattern is fine). Constrain values with enum; describe formats in description.
  4. The serialized schema must stay under 64 KB.

Making every primitive nullable — {"type": ["string", "null"]} — is recommended, never enforced: a non-nullable field pressures the extractor into inventing a value instead of returning null. It is the single highest-impact change to extraction quality.

Add a description per property; it is the strongest accuracy lever. unit controls cardinality: per_document (default), across_documents, rows_per_document.

Errors

Every /v1 failure is the same envelope, with x-request-id also on the response headers:

1{ "code": "invalid_request", "message": "file: provide exactly one of `file` or `files`",
2 "retryable": false, "requestId": "req_…", "docUrl": "https://docs.cloudraker.com/developers/errors#invalid_request" }

Branch on code, never on message. Common codes: unauthorized, invalid_token (401); invalid_request, invalid_schema, action_unknown, file_ineligible, run_too_large, schema_too_large (400); not_found (404); file_not_ready, output_not_ready, already_kept, pipeline_running (409); run_expired (410); file_fetch_failed, webhook_endpoint_not_found, webhook_endpoint_disabled (422); rate_limited (429); internal_error, file_unreadable, file_upload_failed (5xx). Retry only where retryable is true.

Rate limits

At least 67 requests per minute per organization, shared across every /v1 endpoint — a guaranteed floor enforced per edge location, so a distributed caller may sustain more. Over it: 429, code: "rate_limited", Retry-After: 60. Nothing is started and nothing is billed. Respect Retry-After, then back off exponentially with jitter. One batch call and one long-poll each cost a single request, which is why both beat looping.

Webhooks

Send webhook: {"url": "https://…"} on any verb, or register an endpoint with POST /v1/webhooks and reference it as webhook: {"id": …}. Deliveries are signed JWTs verified against GET /v1/webhooks/jwks.json (public, unauthenticated, never rate limited). Run metadata is not included in deliveries — re-fetch the run by id.

Rules that save you a debugging session

  • Nothing a /v1 run touches appears in the CloudRaker app until you POST /v1/runs/:id/keep. That is deliberate — ephemeral by default.
  • Schema inference (hints, no schema) picks its own field names and can differ between runs. Use it once to discover the shape, then pin config.schema or save it as an action.
  • hints with a schema or an action is a 400; use instructions instead.
  • POST /v1/extract/batch has a strict body — schema and hints are rejected, not ignored — and always returns 202.
  • Pipeline steps run in parallel over the same files. A step never consumes another step’s output.
  • A produced file is registered a moment after processed; until then output.file.url and /output/:name return 409 output_not_ready (retryable, never 404). Wait a moment and ask again.
  • Reuse fileIds instead of re-sending URLs: the document is neither re-fetched nor re-parsed.

Full reference

  • OpenAPI: https://docs.cloudraker.com/openapi.json — the full gateway spec, including POST /v1/extract/batch and GET /v1/runs. It is re-exported whenever the surface changes; where it and this page ever disagree, this page is right.
  • Markdown index for agents: https://docs.cloudraker.com/llms.txt
  • MCP server: https://mcp.cloudraker.com — see MCP server
  • Human-readable start: Agent quickstart, Quickstart