Skip to content
Get started

Getting started

#Overview

Agent Flow Bind runs prebuilt agents — document extraction today, phone and finance families later — through three interchangeable "doors": the console (a human clicking through a UI), the API documented here, or a published app an end user fills in directly. All three ultimately call the same /v1 API; this guide walks through calling it directly.

Every request and response on /v1 is JSON. All timestamps are ISO 8601 UTC, and every resource id is a UUID.

#1. Get an API key

API keys are workspace-scoped and carry one or more scopes (runs:write, agents:read, ...). The very first key for a new workspace is created from the console (Settings → API keys), which authenticates with your session cookie instead of a key you don't have yet. Once you have one key, you can mint more from the API itself:

bash
curl -X POST "https://api.agentflowbind.com/v1/api-keys" \
  -H "Authorization: Bearer afb_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CI pipeline",
    "scopes": ["runs:read", "runs:write", "files:write", "agents:read"]
  }'
json
{
  "id": "8f1e2b0a-...-c9d3",
  "name": "CI pipeline",
  "scopes": ["runs:read", "runs:write", "files:write", "agents:read"],
  "key": "afb_live_51f3a9...",
  "createdAt": "2026-03-14T09:12:00.000Z"
}

The plaintext key is only ever returned once, at creation — store it in a secret manager, not in source control. Every other request in this guide sends it as Authorization: Bearer afb_live_....

#2. Pick a preset and create an agent

GET /v1/presets lists every preset the registry knows about, with the input it expects and the output schema it produces:

bash
curl "https://api.agentflowbind.com/v1/presets" \
  -H "Authorization: Bearer afb_live_xxxxxxxxxxxx"

The document family ships three presets today: document/supplier-invoice, document/delivery-note, and the schema-agnostic document/custom-form (see Presets & schemas). An agent is a workspace's own named, versioned configuration of a preset — create one with POST /v1/agents:

bash
curl -X POST "https://api.agentflowbind.com/v1/agents" \
  -H "Authorization: Bearer afb_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "presetId": "document/supplier-invoice",
    "name": "AP invoice extractor"
  }'
json
{
  "id": "3c1a9e40-...-77bd",
  "family": "document",
  "presetId": "document/supplier-invoice",
  "name": "AP invoice extractor",
  "currentVersion": 1,
  "config": { "presetId": "document/supplier-invoice" }
}

Keep the returned id — it's the agentId every run below references.

#3. Upload a document

POST /v1/files accepts a raw body (with Content-Type + X-Filename) or a multipart/form-data body. Uploads are capped at 25 MB and allow application/pdf, image/png, image/jpeg, text/csv, and text/plain:

bash
curl -X POST "https://api.agentflowbind.com/v1/files" \
  -H "Authorization: Bearer afb_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/pdf" \
  -H "X-Filename: invoice-2026-03.pdf" \
  --data-binary @invoice-2026-03.pdf
json
{
  "id": "b4a0c9e1-...-1f0a",
  "filename": "invoice-2026-03.pdf",
  "mime": "application/pdf",
  "size": 184320,
  "sha256": "9f2c1e...4b7a"
}

#4. Create a run

POST /v1/runs queues an agent execution: it estimates the cost, reserves credits (a 402 billing.insufficient_credits here means the workspace balance is too low), inserts the run in queued status, and enqueues it for apps/worker to pick up. Reference the uploaded file by id under input.fileIds:

bash
curl -X POST "https://api.agentflowbind.com/v1/runs" \
  -H "Authorization: Bearer afb_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 2fbb0e7a-6b8a-4b0e-8e2a-6d6b6a2b7a10" \
  -d '{
    "agentId": "3c1a9e40-...-77bd",
    "input": { "fileIds": ["b4a0c9e1-...-1f0a"] }
  }'
json
{ "id": "5e6a7b8c-...-9d0e", "status": "queued", "estimateCredits": 42 }

The Idempotency-Key header is optional but recommended for anything that retries on a network error — see Errors & rate limits. See Runs lifecycle & statuses for the full state machine a run moves through after this.

typescript
async function createRun(agentId: string, fileId: string): Promise<{ id: string }> {
  const res = await fetch("https://api.agentflowbind.com/v1/runs", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.AFB_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({ agentId, input: { fileIds: [fileId] } }),
  });
  if (!res.ok) throw new Error(`createRun failed: ${res.status} ${await res.text()}`);
  return res.json();
}

#5. Wait for it to finish

Poll GET /v1/runs/:id until status is terminal (succeeded, failed, or cancelled) — or open GET /v1/runs/:id/events for a live text/event-stream instead of polling:

bash
curl "https://api.agentflowbind.com/v1/runs/5e6a7b8c-...-9d0e" \
  -H "Authorization: Bearer afb_live_xxxxxxxxxxxx"
json
{
  "id": "5e6a7b8c-...-9d0e",
  "status": "succeeded",
  "costCredits": 38,
  "output": { "supplier": { "name": "Acme GmbH" }, "total": 1249.5, "...": "..." },
  "humanRequest": null
}

A status of needs_input, needs_approval, or needs_review instead means the run is paused waiting on a person — see Human-in-the-loop.

#6. Read the output

Once succeeded, GET /v1/runs/:id/output returns the final structured JSON (or ?format=csv when the preset supports it):

bash
curl "https://api.agentflowbind.com/v1/runs/5e6a7b8c-...-9d0e/output" \
  -H "Authorization: Bearer afb_live_xxxxxxxxxxxx"

That's the whole loop. From here: subscribe a webhook instead of polling, wire up human-in-the-loop answers, or reach for the TypeScript SDK (preview) to skip writing this HTTP plumbing by hand.