GET /v1/task/{task_id} until it finishes, or you can hand WideRouter an
https URL and let it come to you. The second path is the callback, and it is
a property of the task API itself, not of any one model: the same field, the
same payload and the same rules apply to a Nano Banana image and a Grok Imagine
video.
Polling needs your API key on every request. A callback needs none. The
receiver is a URL you host; WideRouter calls it, so there is no credential to
load, forward or get wrong. If your poller ever answers
401, or you have
thousands of tasks in flight, this is the page for you.One field on submit
Addcallback_url next to model and input. Nothing else about the request
changes, and the submit response is the same task id you would get otherwise.
400 invalid_callback_url; a bad secret is 400 invalid_params with param
set to callback_secret:
What WideRouter sends you
OnePOST per task, Content-Type: application/json, when the task reaches a
terminal state. Three headers let you route and authenticate before you parse
the body:
The body is the task object, byte for byte what
GET /v1/task/{task_id}
returns at that moment. One parser serves both the callback and the polling
path.
- task.completed
- task.failed
task.failed is also
your signal that the charge has been reversed. Output files are named after the
task id, which makes them easy to file without renaming.
Delivery rules
Two consequences worth designing around:
- Be idempotent. A retry after a slow
200means the same task can arrive twice. Key your handler onid. - Keep a polling fallback for stragglers. Store the task id at submit time. If a callback has not arrived a few minutes after the model’s usual latency, read the task once. A callback is a latency optimization, not a delivery guarantee.
Verifying the signature
Send acallback_secret on submit and every callback for that task carries
X-Wide-Signature. It proves two things: the request came from WideRouter, and
the body was not altered on the way. It is not encryption — the body only ever
holds public URLs.
t is the Unix time the callback was sent. v1 is
hex(HMAC-SHA256(callback_secret, "<t>.<raw body>")): the timestamp, a dot,
then the request body exactly as received.
1
Take the raw body
The digest is over bytes. Parsing the JSON and serializing it again changes
the bytes, so read the body before any framework touches it.
2
Recompute and compare in constant time
Rebuild the HMAC with the same secret and compare with a constant-time
function, never with
==.3
Reject stale timestamps
Drop anything whose
t is more than 300 seconds away from your clock in
either direction. That is what stops a captured callback from being replayed
later. Measured skew in testing was about 3 seconds.callback_secret there is no signature header, and the unguessable
path in callback_url is the only thing between you and a forged “completed”.
Either way, re-read GET /v1/task/{task_id} with your API key before you
download or bill on a task: the signature proves who sent the callback, the
read proves what the task is now.
A receiver in three languages
Each handler does the same five things: verify the signature over the raw body, check the event header, acknowledge with200 immediately, hand the task
id to a queue, and let a worker re-read the task and download the outputs.
The verify function is the one from the previous section. The download is deliberately outside the
request handler because outputs can be several megabytes and you have ten
seconds to answer.
Trying it without a server
Any request-inspection service that gives you a publichttps URL works as a
throwaway receiver: submit a task with that URL as callback_url and watch the
task object land in the inspector. When you are ready to receive on your own
machine, an https tunnel to your local port does the same job. Remember that
the URL must be reachable from the internet; a LAN address is rejected at
submit time.
Download promptly
Output URLs stop working 24 hours after the task completes, and the callback is the earliest moment you know they exist. A receiver that downloads on arrival never has to think about expiry; one that only stores the URL and reads it later will eventually store links to nothing.Next steps
Async task API
The envelope, the polling loop, task states and the error table.
Quickstart
Submit, poll and download in about five minutes.