A synchronous HTTP request must return before it times out — typically 30-90 seconds for serverless platforms. AI agents often take 10-120 seconds to complete, depending on the task, model, and input size. A direct call would time out before the agent finishes.
The solution is to separate starting the job from getting the result:
1. POST to /run — starts the job, returns immediately with a job_id
2. GET /jobs/:id — poll until status is complete or failed
3. Consume output from the completed job
Client Runcept Agent
│ │ │
│── POST /run ──▶│ │
│◀── {job_id} ───│ │
│ │── HTTP call ──▶│
│ │ │ (working...)
│── GET /jobs/id▶│ │
│◀── {queued} ───│ │
│ │ │
│── GET /jobs/id▶│ │
│◀── {running} ──│ │
│ │◀── {output} ───│
│── GET /jobs/id▶│ │
│◀── {complete} ─│ │
async function runAgent(slug, input) {
const { job_id } = await fetch('https://www.runcept.com/api/v1/run', {
method: 'POST',
headers: {
Authorization: Bearer ${process.env.RUNCEPT_API_KEY},
'Content-Type': 'application/json',
},
body: JSON.stringify({ agent: slug, input }),
}).then(r => r.json())
// Poll with exponential backoff
let delay = 2000
for (let i = 0; i < 30; i++) {
await new Promise(r => setTimeout(r, delay))
delay = Math.min(delay * 1.5, 10000) // cap at 10s
const job = await fetch(https://www.runcept.com/api/v1/jobs/${job_id}, {
headers: { Authorization: Bearer ${process.env.RUNCEPT_API_KEY} },
}).then(r => r.json())
if (job.status === 'complete') return job.output
if (job.status === 'failed') throw new Error(job.error ?? 'Agent failed')
}
throw new Error('Timed out waiting for agent')
}
|--------|---------|
queuedrunningcompletefailedCredits are only deducted on complete status. A failed job refunds automatically. Never bill your users for failed runs.