Why async?
Many Octave operations — running an enrichment, generating a multi-step sequence, walking a Prospector through a list, executing a multi-node workflow — take longer than a typical HTTP request should hang open. For these, Octave exposes an asynchronous pattern: you submit the job, get back a run ID, and Octave POSTs the result to a URL you control when the work is done. The async pattern is used consistently across:- Async agent run —
POST /api/v2/async/agent/run(any saved Agent) - Async email generation —
POST /api/v2/async/headless/generate-emails(bulk sequence generation) - Workflows —
POST /api/v2/workflows/run(multi-node Workflows)
The contract
- You POST the job with your inputs plus a
callbackUrl(HTTPS, reachable from the public internet). - Octave returns a run ID immediately —
agentRunOIdfor agents,workflowRunOIdfor workflows. - Octave executes in the background.
- On completion, Octave POSTs the result as a JSON body to your
callbackUrl. The payload includes the run ID, status (succeeded,failed), and the agent or workflow output. - You can poll instead of (or in addition to) waiting for the callback:
- Agents:
GET /api/v2/async/agent/run/status?agentRunOId=… - Workflows:
GET /api/v2/workflows/run/status?workflowRunOId=…
- Agents:
Choosing your callback URL
The callback URL must be HTTPS and publicly reachable. Common patterns:- Webhook receiver in your own app (Express endpoint, Lambda, Cloud Run function)
- No-code receiver like a Clay HTTP column, Zapier webhook, or n8n trigger
- Inline polling — set the callbackUrl to a no-op endpoint and poll status instead. This is the simplest path for quick scripts.
200 OK quickly and process the payload asynchronously on your side.
When to use sync vs async
Error handling
Failed runs still hit your callback URL — the payload will carrystatus: "failed" and an error message. Network failures on Octave’s callback POST are retried with exponential backoff; if your endpoint is consistently down, eventually the run is marked delivered-failed and visible only via the status endpoint.
If you need exactly-once semantics, dedupe on the run ID at your callback handler — Octave may retry a callback if your endpoint times out without responding.