GET /v1/responses/{response_id} in a loop. Attach a callback URL to the request and Valar delivers the finished result to your server as an HTTP POST. The feature works on POST /v1/responses and POST /v1/chat/completions, and is configured entirely through two metadata keys.
Parameters
Both keys live inside themetadata object on the create request.
string
The destination URL for the callback. Must be an
http or https URL. If you omit it or pass a value that can’t be used, no callback is sent and the request itself is unaffected.string
An optional shared secret. Valar sends its value as a Bearer token in the callback’s
Authorization header so your endpoint can confirm the request is genuine.Set up an endpoint
1
Expose a route that accepts POST
Your endpoint receives a JSON body and should respond as soon as it has accepted the payload. The body matches exactly what
GET /v1/responses/{response_id} returns for the same request, whether the response completed or failed.2
Verify the Authorization header
If you set
webhook_token, reject any incoming call whose header doesn’t match. Compare against Authorization: Bearer <your token> and return a 4xx for anything else.3
Submit a request that points at your endpoint
Set
background=True and add the callback URL (and token, if you use one) to metadata.What Valar sends
The callback is a single POST request.POST
Always a POST to the URL in
completion_webhook.header
application/json.header
Present only when
webhook_token was set. Carries Bearer <webhook_token>.object
The full response object, byte-for-byte identical to a
GET /v1/responses/{response_id} call - including the status field and, for failed responses, the error envelope. The response id lives here and is your key for deduplication.When a callback fires
Valar POSTs to your endpoint once a response reaches a terminal status:- Completed. The request finished normally. The body is the completed response object.
- Failed. The body is the failed response object, including the
error.codeanderror.messageyourGET /v1/responses/{response_id}would see. This includes responses Valar fails on your behalf when they get stranded short of terminal - for example, a background request that staysin_progresspast its deadline arrives withstatus: "failed"anderror.code: "timeout". Use thestatusfield to branch on success vs. failure in your handler.
Delivery semantics
- Retries. A delivery that returns a non-2xx status or hits a network error is retried up to 3 times. Return a 2xx as soon as you accept the payload to stop the retries.
- Timeout. Each attempt has a 30 second ceiling. A timeout counts as a failed attempt and triggers the next retry.
- Best-effort. Callbacks are best-effort. If every attempt fails the failure is logged but never touches the response record or the API, and the result stays available through
GET /v1/responses/{response_id}regardless of whether delivery ever succeeded.
Test it locally with ngrok
You can point a real request at a listener on your own machine.1
Run a listener that prints the body and returns 200
2
Tunnel to it
https://xxxx.ngrok-free.app forwarding URL from the output.3
Submit a request against the tunnel
4
Submit a request against the tunnel