Developer

Webhook payload reference

Configure Apex webhooks, verify signatures, and handle the event payloads Apex delivers today.

Apex webhooks notify your system after selected experiment, Guardian, screenshot, and publication events. Webhooks are shop-scoped. Each endpoint has a URL, subscribed event list, active flag, and generated signing secret.

Create an endpoint

Create webhooks with the public API:

http
POST /api/v1/webhooks
Authorization: Bearer apx_your_key_here
Content-Type: application/json
 
{
  "url": "https://example.com/apex/webhooks",
  "events": ["experiment.started", "experiment.completed"]
}

The URL must be HTTPS. The create response includes the generated secret once. List, read, and update responses do not include it.

Event names

These are the event names accepted by the public webhook create/update schema:

EventWhen Apex enqueues it
experiment.startedAn experiment starts from the dashboard launch flow or scheduled launch worker.
experiment.completedA public API request completes an experiment.
experiment.significantAuto-stop pauses an experiment because a significant winner was found.
experiment.guardian_triggeredGuardian detects a warning and alerts without pausing.
experiment.guardian_pausedGuardian pauses an experiment for a configured safety finding.
variation.winningAuto-stop identifies the winning variation for the primary goal.
screenshots.completedA screenshot job finishes and stores screenshot results.
project.publishedRuntime publication records a shop revision when publication webhooks are enabled.

Delivery envelope

Every outbound delivery body is JSON. Apex serializes the stored event payload, then adds delivery metadata:

json
{
  "event": "experiment.started",
  "experiment_id": "11111111-1111-4111-8111-111111111111",
  "experiment_name": "PDP trust badge",
  "delivery_id": "22222222-2222-4222-8222-222222222222",
  "timestamp": "2026-07-08T12:00:00.000Z"
}

Headers:

HeaderValue
Content-Typeapplication/json
X-Drip-Signaturesha256= followed by the hex HMAC SHA-256 of the exact request body using the webhook secret.
X-Drip-EventEvent name, for example experiment.started.
X-Apex-Delivery-IdDelivery row ID. Use this for idempotency.
User-AgentDrip-Webhooks/1.0

Verify signatures

Verify the raw body bytes before parsing or transforming the payload:

ts
import crypto from "node:crypto";
 
export function verifyApexWebhook(rawBody: string, signatureHeader: string, secret: string) {
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
 
  const received = Buffer.from(signatureHeader);
  const expectedBytes = Buffer.from(expected);
  return received.length === expectedBytes.length
    && crypto.timingSafeEqual(received, expectedBytes);
}

Payload shapes

Common metadata is always added by the dispatcher:

FieldTypeNotes
eventstringEvent name.
delivery_idstringUnique Apex delivery ID.
timestampISO datetime stringDelivery serialization time.

Event-specific fields:

EventFields
experiment.startedexperiment_id, experiment_name
experiment.completedexperiment_id, experiment_name
experiment.significantexperiment_id, experiment_name, goal_id, winning_variation_id
variation.winningexperiment_id, experiment_name, variation_id, goal_id
experiment.guardian_triggeredexperiment_id, experiment_name, kind, action, variation_id, goal_id, details
experiment.guardian_pausedexperiment_id, experiment_name, reason, variation_id, goal_id
screenshots.completedjob_id, experiment_id, results
project.publishedproject_id, revision, environment_key, status, published_at

goal_id can be null where the triggering condition does not apply to a specific goal. details and results are JSON objects whose internal shape depends on the Guardian finding or screenshot job output.

Retries and failure behavior

Apex queues matching active webhooks and processes pending deliveries asynchronously. A delivery is claimed as processing, sent with a 10 second timeout, and marked delivered only when the receiver returns a 2xx status.

Failed fetches and non-2xx responses are retried up to five attempts with exponential backoff. Retry delay starts at 15 seconds and is capped at 30 minutes. Processing deliveries older than 10 minutes are treated as stale and can be claimed again.

After the final failed attempt, the delivery is marked dead. The parent webhook's consecutive failure counter is incremented. After three consecutive dead deliveries, Apex disables the webhook and sets disabled_at.

Inspect deliveries

Use the delivery log endpoint to debug recent attempts:

http
GET /api/v1/webhooks/22222222-2222-4222-8222-222222222222/deliveries?status=dead&limit=20
Authorization: Bearer apx_your_key_here

Valid status filters are queued, processing, delivered, failed, and dead. limit defaults to 50 and is clamped from 1 to 100.