Skip to main content
When you create a request through POST /v1/responses, POST /v1/chat/completions, or POST /v1/messages, you can provide a completion webhook in request metadata. When processing finishes, Sail will POST the full response payload to your URL so you can process it without polling.

Enabling a completion webhook

Include a completion_webhook URL in the metadata object of your create request. The URL must be http or https.
If metadata.completion_webhook is omitted or invalid, no webhook request is sent. The create call and the response itself are unchanged; webhooks are optional and best-effort. For Chat Completions and Anthropic Messages, pass the same metadata keys (completion_webhook, webhook_token) on the request body.

Webhook payload

Sail sends a POST request to your URL with:
  • Content-Type: application/json
  • Body: The same general JSON object returned by GET /v1/responses/{response_id}. Webhook payloads can omit metadata.supercached_input_tokens and metadata.supercache_write_input_tokens.
A Responses API completion webhook can carry status: "completed" or status: "incomplete". An incomplete payload is a successful webhook delivery, not a webhook error. Its body preserves usage, incomplete_details, and any partial output. Process that payload once and do not keep polling the response for another status.

Securing webhooks with a token

To verify that incoming requests are from Sail, set webhook_token in the metadata. Sail will send the value of webhook_token as a Bearer token in the Authorization header of the webhook POST.
Your server can check Authorization: Bearer your-secret-token and reject requests that don’t match.

Delivery behavior

  • Duplicates: Sail may occasionally deliver the same webhook more than once. Log the response id from the webhook body and ignore events you have already processed.
  • Retries: Sail retries failed deliveries (a non-2xx status or a network error) in rounds. A round makes up to 3 attempts back to back within a 30-second budget, and failed rounds are repeated with increasing delays of up to a few minutes, for at most 20 rounds. A persistently failing endpoint can receive up to 60 requests for one response. Respond with a 2xx status as soon as you have accepted the payload so that Sail stops retrying.
  • Best-effort: Webhook failures are logged but do not affect the response or the API. The response remains available via GET /v1/responses/{response_id} even if the webhook never succeeds.

Full example

Here’s a full, end-to-end example using ngrok: 1. Start a local webhook listener that prints the payload and returns 200:
2. In a second terminal, expose it with ngrok:
Copy the https://xxxx.ngrok-free.app forwarding URL from the output. 3. In a third terminal, create a response with the webhook:
When the response completes, Sail POSTs the full payload to your listener.