Webhooks

Event webhooks

Get a signed HTTPS request when a run starts, needs attention or finishes. Event types, payload, signing, retries and when an endpoint is switched off.

Outqube sends an HTTPS request to your endpoint when a run changes state. Messages are signed with Standard Webhooks, so any library for that spec can verify them. Organisation admins manage endpoints in Settings, Event webhooks, or with a manage key through the API. An app has up to 10 endpoints.

This page is about event webhooks, which Outqube sends to you. Settings, Webhooks is the other way round: a URL you call to start a suite from your pipeline.

Events

Pick the event types an endpoint receives, or all of them. Each type has its own reference page with the full payload.

TypeWhen
run.queuedA run is created.
run.startedThe first test starts.
run.needs_attentionA test waits for a person to answer. Runs started from the API, CLI, GitHub or a schedule never wait, so they do not send this.
run.completedEvery test ended. Has an outcome: passed, failed or error.
run.cancelledEvery test ended and at least one was stopped.
pingA test event you send from settings or with POST /webhooks/{webhookId}/test.

The message

POST /outqube/events HTTP/1.1
content-type: application/json
user-agent: Outqube-Webhooks/1
webhook-id: 7b1c2f0e-6d2a-4c58-9f0b-3a1d5e8c9a41
webhook-timestamp: 1793361601
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3FJ9qMeKJmcZU=
{
  "type": "run.completed",
  "timestamp": "2026-10-30T12:00:01.123Z",
  "data": {
    "run": {
      "id": "3e0d6f52-0b5e-4c0e-9d57-1f6a8c2b7a10",
      "app_id": "9a1c4d7e-2f3b-4a68-8c15-5b0e7d9f1a23",
      "status": "completed",
      "outcome": "failed",
      "source": "github",
      "commit_sha": "4f1c2a9",
      "branch": "feature/login",
      "pr_number": 42,
      "repo": "acme/web",
      "counts": { "total": 12, "passed": 10, "failed": 2, "error": 0 },
      "url": "https://app.outqube.com/acme/runs?execution=3e0d6f52-0b5e-4c0e-9d57-1f6a8c2b7a10",
      "api_url": "https://app.outqube.com/api/v1/runs/3e0d6f52-0b5e-4c0e-9d57-1f6a8c2b7a10"
    }
  }
}

The payload is thin on purpose: no steps, reasoning, screenshots or logs. Fetch those from api_url with an API key. counts.total counts test runs, so a test on two devices counts twice. run.needs_attention also has data.test_run with the test run's id, test_id and status.

Signing

The signed text is {webhook-id}.{webhook-timestamp}.{raw body}. Verify the raw bytes you received, not JSON you parsed and wrote out again. The secret starts with whsec_ and is shown in settings. Libraries reject a timestamp more than five minutes off. Receive and verify webhooks has code in TypeScript and Python, with and without a library.

Answer any 2xx within 10 seconds. Redirects are not followed and count as a failure.

Retries

A failed attempt (no 2xx, a timeout or a connection error) is retried after about 5 seconds, 30 seconds, 2 minutes, 10 minutes, 30 minutes, 1 hour, 3 hours and 6 hours, with up to 20% jitter either way. That is up to nine attempts over about ten hours. The webhook-id is the same on every attempt and equals the event id.

While an endpoint is switched off, new messages for it are dropped, so turning it back on does not send a burst of old events.

Order and duplicates

  • Delivery is at least once. The same event can arrive twice, so ignore an id you have already handled.
  • Delivery is not ordered. A retried older event can arrive after a newer one. Use the payload timestamp and status, and fetch the run from api_url when the order matters.

When an endpoint is switched off

After 5 messages in a row use up all their retries, Outqube switches the endpoint off, shows a banner in settings and writes a row to the audit log. Fix the receiver, then turn it on again. Any success resets the count, and test events never count.

Delivery log

Settings keep every message for 30 days: each attempt with its time, status, latency, error and the first 1 KB of your response. Resend queues a finished message again with the same webhook-id, and Send test event sends a ping.

Rotate the secret

Rotating creates a new secret. For 24 hours each message carries two signatures, separated by a space, so a receiver holding either secret can verify it. Update your receiver within that window. The secret is returned only when you create an endpoint or rotate its secret.

Allow-list Outqube's addresses

Outqube sends from fixed IP addresses. The current list is in Settings, Event webhooks. Allow those addresses in your firewall.

Endpoint URLs must be https:// on port 443 with a public host name: no credentials, and no private, loopback, link-local or cloud metadata addresses. The host is checked when you save and again at every send.

Manage endpoints with the API

With a manage key: GET and POST /webhooks, GET, PATCH and DELETE /webhooks/{webhookId}, POST /webhooks/{webhookId}/rotate-secret and POST /webhooks/{webhookId}/test.

Next steps

On this page