Developers
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.
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.
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 runsworkflow: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_xxxxxxxxSend 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.
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-4821202 Accepted
{
"jobId": "b3f1...",
"status": "queued",
"statusUrl": "https://dojobase.com/api/public/v1/jobs/b3f1...",
"callback": "registered"
}Body is JSON. input is passed to the entry node; callbackUrl (optional, must be https) receives the signed result when the job finishes.
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"
}'202 Accepted
{
"jobId": "b3f1...",
"status": "queued",
"statusUrl": "https://dojobase.com/api/public/v1/jobs/b3f1...",
"callback": "registered"
}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:
POST …/files with each file's name + contentType → get back a presigned uploadUrl, a key, and the headers to use.PUT each file's raw bytes to its uploadUrl, sending the returned headers verbatim.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.
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" }
]
}'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
}
]
}# 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.pdfcurl -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"
}'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.
curl https://dojobase.com/api/public/v1/jobs/JOB_ID \
-H "Authorization: Bearer dojobase_live_xxxxxxxx"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
}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.
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}`.
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 come back as application/problem+json with a title, status, and detail.
| 401 | Missing or invalid/revoked API key |
| 403 | Key lacks the scope, or is bound to a different workflow |
| 404 | Workflow or job not found in this org |
| 422 | Workflow has no API entry node, or more than one |
| 429 | Rate limit exceeded (see Retry-After header) |
Authorization: Bearer … on every request.callbackUrl is a public https URL that returns 2xx. We retry with backoff.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.