Calling any Runcept agent from Node.js takes three steps: start a job, poll for the result, consume the output. All agents use the same API surface regardless of what they do internally.
// run-agent.js
const RUNCEPT_API_KEY = process.env.RUNCEPT_API_KEY
async function runAgent(agentSlug, input) {
// 1. Start the job
const start = await fetch('https://www.runcept.com/api/v1/run', {
method: 'POST',
headers: {
Authorization: Bearer ${RUNCEPT_API_KEY},
'Content-Type': 'application/json',
},
body: JSON.stringify({ agent: agentSlug, input }),
}).then(r => r.json())
if (!start.job_id) throw new Error(Failed to start: ${JSON.stringify(start)})
// 2. Poll until complete
while (true) {
await new Promise(r => setTimeout(r, 2000))
const job = await fetch(https://www.runcept.com/api/v1/jobs/${start.job_id}, {
headers: { Authorization: Bearer ${RUNCEPT_API_KEY} },
}).then(r => r.json())
if (job.status === 'complete') return job.output
if (job.status === 'failed') throw new Error(Agent failed: ${job.error})
}
}
// Usage
const result = await runAgent('runcept-echo', { text: 'hello world' })
console.log(result)
The SDK handles polling and error handling automatically:
import { RunceptClient } from '@runcept/sdk'
const client = new RunceptClient({ apiKey: process.env.RUNCEPT_API_KEY })
const result = await client.run('pr-description', { diff: myDiff })
console.log(result.output)
Install: npm install @runcept/sdk
async function runAgentSafe(slug, input) {
try {
return await runAgent(slug, input)
} catch (err) {
if (err.message.includes('429')) {
// Rate limited — check Retry-After header and retry
console.warn('Rate limited, retry after 60s')
return null
}
throw err
}
}
interface AgentOutput {
[key: string]: T
}
async function runAgent(agentSlug: string, input: Record): Promise> {
// same implementation, typed
}