Every published agent answers on three routes. Pick the one that fits the work, and retry an unanswered request safely.
Choose a route
All three run the same agent and share keys, user and learner_group.
/runs |
/jobs |
/chat/completions |
|
|---|---|---|---|
| You send | input, optional conversation_id |
The same, plus Idempotency-Key |
model (the slug) and messages |
| You get | The result, or a stream | 202 and a job to poll |
choices[0].message.content |
| Time | 60 s, or the agent's 10–120 | 5 minutes or more | As /runs |
| In the dashboard | API · runs | API · background job | API · chat completions |
Start with /runs when someone is waiting; "stream": true streams the reply. Use /jobs for long research, image generation, or a host that cuts requests short. For OpenAI-compatible SDKs, set the base URL to https://api.viablelab.org/v1/agents/{slug}; agents with Ask user steps need /runs.
Run a background job
curl https://api.viablelab.org/v1/agents/YOUR_AGENT_SLUG/jobs \
-H "Authorization: Bearer $VIABLE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: my-app-turn-8f2c-0004" \
-d '{"input": "Draft a reading list on photosynthesis.", "user": "my-app:student-0001"}'
# Then poll its status_url with the same key:
curl https://api.viablelab.org/v1/agents/YOUR_AGENT_SLUG/jobs/agtj_... \
-H "Authorization: Bearer $VIABLE_API_KEY"
The 202 has an id (agtj_…), a status_url and a Retry-After header. Wait that long between polls.
queuedorrunning: poll again.completed:resultis the body/runsreturns.failed:errorhas thecode. To try again, submit a new job with a new key. A job not started within 15 minutes fails withagent_job_expired, and one that stopped before its run began withagent_job_interrupted: nothing ran, so send the turn again.recovery_required: the run had started, and completion is uncertain: it may have drawn an image or called a web address. Check Run history; don't submit the turn again.
Keep one job per conversation at a time.
Retry safely
Send an Idempotency-Key with every turn: 8–128 letters, digits, dots, underscores, colons or hyphens. Save the route, body and key on your server. If no answer arrives, resend the same body to the same route with the same key.
- The run completed: you get the same result.
- Still going: 409
agent_request_pending. Retry later with the same key. - The body differs: 409
idempotency_conflict. - It started, then failed (such as
provider_timeout): the key keeps that error. Retry with a new key. - Rejected before it started (validation, 401, 403, 404, 413, rate or spending limits): nothing was recorded. Reuse the key once fixed.
Warning
Never change the key to get past a pending or uncertain turn: that can run it twice. Never switch a pending turn between
/runsand/jobs.
Limits and errors
- Size: 12 MiB per request,
contextup to 128 KiB, up to 400messages. - Rate: a key's per-minute limit covers all your users: thirty learners in one class share it.
- 429: wait for
Retry-After. For token, cost or credit limits, don't retry in a loop.
Branch on error.code, and never show an error as the agent's reply. The API reference lists every code.
- Learners and traces: keep each turn's run ID and trace.
- Keys, credit and costs: set a key's limits and see who pays.
