Developers

Visual workflows, callable from your code.

Build the workflow on the canvas, then start it from your systems with one request. Send JSON or files, and get typed results back by waiting, polling or a signed webhook.

Start a run

One request in. Typed JSON out.

Every published workflow has a run endpoint. Add ?wait=30 to get the result in the same response, or poll the run later. Test runs from the builder never count against your plan.

start-run.sh
# Start a run with a photo and wait up to 30s
curl -X POST "https://api.runocr.com/v1/workflows/42/runs?wait=30" \
  -H "Authorization: Bearer rk_…" \
  -F "file=@package.jpg" \
  -F "dock=Rotterdam-3"

# 201 Created
{
  "id": 812,
  "status": "succeeded",
  "output": {
    "label":  { "tracking_number": "1Z999AA10123456784", "weight_kg": 12.9, "confidence": 0.99 },
    "weight": { "same": true, "diff_pct": 3.2 }
  }
}
Building blocks

Everything you need to integrate.

Account API keys

Create, roll or revoke a key in Settings. Keys are stored hashed and shown once.

Files and JSON

Send multipart files (images, PDF, video) with form fields, or plain JSON input.

Wait or poll

Wait up to 60 seconds for the result, or poll the run by id at your own pace.

Inbound webhooks

Each workflow has a secret URL. Send image_url and RunOCR fetches the image.

Signed outbound calls

Trigger webhook steps sign the body with HMAC-SHA256 in X-RunOCR-Signature.

Typed outputs

Each step's fields are defined in the builder, so the JSON shape is predictable.

Run statuses

queued, running, waiting (human review), succeeded, failed or canceled.

Records API

Push reference data into collections. New records can start workflows too.

Webhooks

Verify every call we send you.

Set a signing secret on a Trigger webhook step and check the signature before you trust the payload.

POST/v1/workflows/{id}/runs
GET/v1/runs/{id}
GET/v1/workflows
POST/v1/files
POST/v1/collections/{name}/records
POST/hooks/{token}
verify-signature.js
// Node.js: check X-RunOCR-Signature on the raw body
import crypto from "node:crypto";

function verify(rawBody, header, secret) {
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(header), Buffer.from(expected));
}
Full documentation

Ship your first integration this afternoon.

Build the workflow visually, publish it and call it from your code.

No card needed · 3 workflows and 100 runs free · Cancel anytime