Developers

Send us your documents. Get the numbers back.

Point your system at one endpoint, upload a file, and dojobase reads it and runs your workflow — then calls you back with the structured result. One key, scoped to one workflow, revocable any time.

Overview

Run a workflow over HTTP and get the result back. Start a run with a POST, then either receive a completion webhook (recommended) or poll the job by id. All requests authenticate with a Bearer API key and act as a single org.

The target workflow must contain an API In node — the dedicated API entry point. Your input JSON lands there, and any files you attach are staged onto the job.

Authentication

Send the API key we sent you as a Bearer token. It is already scoped and bound to the right workflow — keep it secret and send it on every request. The scopes below are what it carries:

  • workflow:execute — start runs
  • workflow:read — poll job status (only needed if you poll instead of using the callback)

A key can be bound to one workflow (the run endpoint returns 403 for any other), so you can hand each integration its own scoped, revocable, rotatable credential.

Authorization: Bearer dojobase_live_xxxxxxxx

Submit a document

POST/v1/workflows/{workflowId}/submit

Send a document in a single HTTPS request: one multipart/form-data POST with your key and the file (up to 25 MB per file).

  • file: one or more file parts (repeat -F file=@… for multiple files).
  • callbackUrl: required. An httpsURL we POST to when we're done.
  • idempotencyKey: optional. A retry with the same value never submits twice.

The host is ingest.dojobase.com (our ingest endpoint), not the main API host.

Request
curl -X POST https://ingest.dojobase.com/v1/workflows/WORKFLOW_ID/submit \
  -H "Authorization: Bearer dojobase_live_xxxxxxxx" \
  -F file=@statement.pdf \
  -F callbackUrl=https://you.example/dojobase-hook \
  -F idempotencyKey=deal-4821
Response
202 Accepted
{
  "jobId": "b3f1...",
  "status": "queued",
  "statusUrl": "https://dojobase.com/api/public/v1/jobs/b3f1...",
  "callback": "registered"
}
Other ways to send a document

Run a workflow

POST/api/public/v1/workflows/{workflowId}/run

Body is JSON. input is passed to the entry node; callbackUrl (optional, must be https) receives the signed result when the job finishes.

Request
curl -X POST https://dojobase.com/api/public/v1/workflows/WORKFLOW_ID/run \
  -H "Authorization: Bearer dojobase_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "input": { "merchant": "Acme Co", "amount": 1200 },
    "jobName": "Acme underwriting",
    "callbackUrl": "https://you.example/dojobase-hook"
  }'
Response
202 Accepted
{
  "jobId": "b3f1...",
  "status": "queued",
  "statusUrl": "https://dojobase.com/api/public/v1/jobs/b3f1...",
  "callback": "registered"
}

Large or bulk uploads (2-step)

For very large packets or many files without the relay, upload the files first, then reference them in a JSON /run— a JSON body can't carry a file, so it's three calls:

  1. POST …/files with each file's name + contentType → get back a presigned uploadUrl, a key, and the headers to use.
  2. PUT each file's raw bytes to its uploadUrl, sending the returned headers verbatim.
  3. POST …/run with files: [{ name, key }] (plus optional input, callbackUrl, idempotencyKey).

Limits: presigned URLs expire 5 minutes after you request them; up to 20 files per upload and 25 MB per file.

POST/api/public/v1/workflows/{workflowId}/files
1. Request upload URLs
curl -X POST https://dojobase.com/api/public/v1/workflows/WORKFLOW_ID/files \
  -H "Authorization: Bearer dojobase_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "files": [
      { "name": "statement.pdf", "contentType": "application/pdf" }
    ]
  }'
Response
200 OK
{
  "uploads": [
    {
      "name": "statement.pdf",
      "key": "run-staging/WORKFLOW_ID/statement.pdf",   // pass this back in /run
      "uploadUrl": "https://s3.amazonaws.com/...signed...",
      "headers": { "Content-Type": "application/pdf" }   // send these verbatim
    }
  ]
}
2. Upload the bytes
# Step 2 — PUT the raw bytes to uploadUrl. Send EVERY header from the
# "headers" object exactly as returned (Content-Type is part of the S3
# signature; changing it breaks the upload). URLs expire in 5 minutes.
curl -X PUT "<uploadUrl>" \
  -H "Content-Type: application/pdf" \
  --data-binary @statement.pdf
3. Run with the files
curl -X POST https://dojobase.com/api/public/v1/workflows/WORKFLOW_ID/run \
  -H "Authorization: Bearer dojobase_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "files": [
      { "name": "statement.pdf", "key": "run-staging/WORKFLOW_ID/statement.pdf" }
    ],
    "callbackUrl": "https://you.example/dojobase-hook",
    "idempotencyKey": "deal-4821"
  }'

Poll a job

GET/api/public/v1/jobs/{jobId}

Optional — if you set a callbackUrlyou don't need to poll. To poll, call this until terminal is true (requires the workflow:read scope). The same shape is delivered to your callback, so you can share one handler.

Request
curl https://dojobase.com/api/public/v1/jobs/JOB_ID \
  -H "Authorization: Bearer dojobase_live_xxxxxxxx"
Response
200 OK
{
  "jobId": "b3f1...",
  "status": "done",              // queued | running | done | failed | rejected | cancelled
  "terminal": true,              // poll until this is true
  "error": null                  // a message when status = failed
}

Completion webhook

If you pass callbackUrl, dojobase POSTs the terminal result to it (with retry + backoff). It is signed so you can verify it came from us — no scope needed, it's pushed to you.

Callback request
POST https://you.example/dojobase-hook
x-dojobase-event: job.completed
x-dojobase-timestamp: 1730000000
x-dojobase-signature: sha256=<hex>

<same JSON body as GET /jobs/{id}>

Verify the signature: the secret is SHA-256(your API key), HMAC‑SHA256 over `${timestamp}.${rawBody}`.

Verify (Node.js)
import { createHash, createHmac, timingSafeEqual } from "node:crypto";

// Verify a signed dojobase callback.
//   rawBody  – the exact request body bytes (do NOT re-serialize)
//   headers  – the incoming request headers
//   apiKey   – the SAME dojobase_live_... key you sent the request with
function verify(rawBody, headers, apiKey) {
  const ts  = headers["x-dojobase-timestamp"];
  const sig = String(headers["x-dojobase-signature"] || "").replace(/^sha256=/, "");

  // Reject anything older than 5 minutes (replay protection).
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;

  // Shared secret = SHA-256(your API key) as lowercase hex. Both sides can
  // derive it; dojobase never stores your raw key.
  const secret   = createHash("sha256").update(apiKey).digest("hex");
  const expected = createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex");

  const a = Buffer.from(expected), b = Buffer.from(sig);
  return a.length === b.length && timingSafeEqual(a, b);
}

Errors

Errors come back as application/problem+json with a title, status, and detail.

401Missing or invalid/revoked API key
403Key lacks the scope, or is bound to a different workflow
404Workflow or job not found in this org
422Workflow has no API entry node, or more than one
429Rate limit exceeded (see Retry-After header)

Troubleshooting & support

  • 401 Unauthorized: the key is missing, mistyped, or revoked. Send it as Authorization: Bearer … on every request.
  • 403 Forbidden: the key isn't valid for this workflow, or it lacks the required scope.
  • Callback never arrives: make sure your callbackUrl is a public https URL that returns 2xx. We retry with backoff.
  • Signature won't verify: the secret is SHA-256(your API key), signed over `${timestamp}.${rawBody}`. Verify against the raw body bytes, before any JSON re-serialization.

Still stuck? Email dojobase support at support@dojobase.com.