Crea una chiave API, scegli un preset ed esegui il tuo primo agente dall'inizio alla fine.
Agent Flow Bind runs prebuilt agents for nine kinds of work — electrical installers (impianti), law firms (legale), finance and administration (finanza), quotes (preventivi), training new staff (formazione), manufacturing and wholesale purchasing (manifattura), condominium administration (condominio), estate agencies (immobiliare) and the phone (telefono), the sector values GET /v1/presets reports — built on five families of preset: document (invoices and receipts, delivery notes, order confirmations, job sheets to the progress bill (SAL) or the invoice, the condominium's expense split, the anti-money-laundering due diligence, drawings, registers and price lists), finance (bank reconciliation, payment reminders and debt recovery, legal deadlines, contract review, the PEC mailbox's triage), learning (the onboarding tutor that answers a new hire from your procedures), phone (answering calls and making confirmation calls) and report (the monthly summary). They run 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.
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:
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"]
}'{
"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_....
GET /v1/presets lists every preset the registry knows about, with the input it expects and the output schema it produces:
curl "https://api.agentflowbind.com/v1/presets" \
-H "Authorization: Bearer afb_live_xxxxxxxxxxxx"This guide uses document/supplier-invoice; its output schema, with those of document/delivery-note and the schema-agnostic document/custom-form, is in Presets & schemas. An agent is a workspace's own named, versioned configuration of a preset — create one with POST /v1/agents:
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"
}'{
"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.
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:
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{
"id": "b4a0c9e1-...-1f0a",
"filename": "invoice-2026-03.pdf",
"mime": "application/pdf",
"size": 184320,
"sha256": "9f2c1e...4b7a"
}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:
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"] }
}'{ "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.
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();
}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:
curl "https://api.agentflowbind.com/v1/runs/5e6a7b8c-...-9d0e" \
-H "Authorization: Bearer afb_live_xxxxxxxxxxxx"{
"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.
Once succeeded, GET /v1/runs/:id/output returns the final structured JSON (or ?format=csv when the preset supports it):
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.