Skip to main content
POST
/
v1
/
webhooks
Outbound Webhooks
curl --request POST \
  --url https://api.sequenzy.com/v1/webhooks \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "name": "<string>",
  "url": "<string>",
  "events": [
    "<string>"
  ]
}
'
{
  "success": true,
  "webhook": {
    "id": "webhook_123",
    "name": "Production webhook",
    "url": "https://example.com/sequenzy/webhooks",
    "status": "enabled",
    "events": ["email.delivered", "email.bounced", "email.opened"],
    "consecutiveFailures": 0,
    "circuitOpenedAt": null,
    "circuitOpenUntil": null,
    "signingSecret": "whsec_...",
    "signingSecrets": [
      {
        "id": "sec_123",
        "prefix": "whsec_abcd12",
        "createdAt": "2026-05-05T12:00:00.000Z"
      }
    ]
  }
}

Documentation Index

Fetch the complete documentation index at: https://docs.sequenzy.com/llms.txt

Use this file to discover all available pages before exploring further.

Outbound Webhooks

You can configure an endpoint to receive Sequenzy email, subscriber, and sequence lifecycle events as signed JSON POST requests.

Create

name
string
required
Human-readable webhook name.
url
string
required
Absolute HTTPS endpoint URL.
events
string[]
Event types to receive. Omit this field to receive the default lifecycle events: sent, delivered, delayed, bounced, complained, email unsubscribed, and subscriber unsubscribed. Add opened, clicked, subscriber.updated, sequence.finished, and sequence.failed explicitly if you need engagement, profile sync, or sequence lifecycle events.
curl -X POST "https://api.sequenzy.com/v1/webhooks" \
  -H "Authorization: Bearer $SEQUENZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production webhook",
    "url": "https://example.com/sequenzy/webhooks",
    "events": ["email.delivered", "email.bounced", "email.opened"]
  }'

Manage

# List endpoints
curl "https://api.sequenzy.com/v1/webhooks" \
  -H "Authorization: Bearer $SEQUENZY_API_KEY"

# Update endpoint
curl -X PATCH "https://api.sequenzy.com/v1/webhooks/webhook_123" \
  -H "Authorization: Bearer $SEQUENZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "disabled"}'

# Add signing secret
curl -X POST "https://api.sequenzy.com/v1/webhooks/webhook_123/secrets" \
  -H "Authorization: Bearer $SEQUENZY_API_KEY"

# Remove signing secret
curl -X DELETE "https://api.sequenzy.com/v1/webhooks/webhook_123/secrets/sec_123" \
  -H "Authorization: Bearer $SEQUENZY_API_KEY"

# Send a test event
curl -X POST "https://api.sequenzy.com/v1/webhooks/webhook_123/test" \
  -H "Authorization: Bearer $SEQUENZY_API_KEY"

# List latest delivery attempt summary
curl "https://api.sequenzy.com/v1/webhooks/webhook_123/deliveries/del_123/attempts" \
  -H "Authorization: Bearer $SEQUENZY_API_KEY"

# Replay a delivery
curl -X POST "https://api.sequenzy.com/v1/webhooks/webhook_123/deliveries/del_123/replay" \
  -H "Authorization: Bearer $SEQUENZY_API_KEY"

Event Payload

Each webhook delivery sends a signed JSON event to your endpoint. Email events include Sequenzy IDs and, when available, your subscriber external ID:
{
  "id": "evt_123",
  "type": "email.sent",
  "object": "event",
  "metric": "sent",
  "created_at": "2026-05-05T12:00:00.000Z",
  "data": {
    "email_send_id": "send_123",
    "message_id": "ses-message-id",
    "subscriber_id": "sub_123",
    "external_id": "customer_123",
    "recipient": "user@example.com",
    "subject": "Welcome",
    "email_type": "campaign",
    "computed_lists": [
      {
        "key": "recommendedEvents",
        "items": [
          {
            "id": "evt_123",
            "title": "Auckland Theatre"
          }
        ],
        "exposures": [
          {
            "slot": 1,
            "id": "evt_123",
            "title": "Auckland Theatre"
          }
        ]
      }
    ],
    "metadata": {
      "source": "campaign"
    }
  }
}
Webhook payloads use one canonical snake_case field per value. When the recipient is linked to a subscriber with a customer-owned external ID, external_id is included. email.sent events include computed_lists when campaign personalization selected per-recipient list items for that email; items preserves the original campaign data objects. Subscriber events include the current subscriber profile. subscriber.updated fires when email, external_id, first_name, last_name, custom_attributes, or a non-unsubscribe status change occurs. Active to unsubscribed changes emit subscriber.unsubscribed; they only also emit subscriber.updated when another profile field changes in the same update. List and tag changes do not emit subscriber.updated.
{
  "id": "evt_789",
  "type": "subscriber.updated",
  "object": "event",
  "metric": "updated",
  "created_at": "2026-05-05T12:00:00.000Z",
  "data": {
    "subscriber_id": "sub_123",
    "external_id": "customer_new",
    "email": "new@example.com",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "status": "active",
    "custom_attributes": {
      "plan": "pro"
    },
    "changed_fields": ["email", "external_id", "custom_attributes"],
    "previous": {
      "email": "old@example.com",
      "external_id": "customer_old",
      "custom_attributes": {
        "plan": "starter"
      }
    }
  }
}
Sequence lifecycle events include the subscriber email, external ID when available, and the event data recorded for that sequence enrollment:
{
  "id": "evt_456",
  "type": "sequence.finished",
  "object": "event",
  "metric": "finished",
  "created_at": "2026-05-05T12:00:00.000Z",
  "data": {
    "sequence_id": "seq_welcome",
    "sequence_name": "Welcome sequence",
    "automation_id": "seq_welcome",
    "automation_name": "Welcome sequence",
    "automation_token_id": "token_123",
    "token_id": "token_123",
    "subscriber_id": "sub_123",
    "external_id": "customer_123",
    "email": "user@example.com",
    "lifecycle": "finished",
    "status": "completed",
    "current_node_id": "node_end",
    "event": {
      "id": "event_123",
      "name": "sequence_finished",
      "properties": {
        "sequence_id": "seq_welcome",
        "sequence_name": "Welcome sequence",
        "automation_id": "seq_welcome",
        "automation_name": "Welcome sequence",
        "automation_token_id": "token_123",
        "token_id": "token_123",
        "lifecycle": "finished",
        "status": "completed",
        "current_node_id": "node_end"
      }
    }
  }
}

Responses

{
  "success": true,
  "webhook": {
    "id": "webhook_123",
    "name": "Production webhook",
    "url": "https://example.com/sequenzy/webhooks",
    "status": "enabled",
    "events": ["email.delivered", "email.bounced", "email.opened"],
    "consecutiveFailures": 0,
    "circuitOpenedAt": null,
    "circuitOpenUntil": null,
    "signingSecret": "whsec_...",
    "signingSecrets": [
      {
        "id": "sec_123",
        "prefix": "whsec_abcd12",
        "createdAt": "2026-05-05T12:00:00.000Z"
      }
    ]
  }
}

Verify Requests

Webhook requests include X-Sequenzy-Timestamp and X-Sequenzy-Signature. Build the signed payload as v1:{timestamp}:{raw_request_body}, compute an HMAC-SHA256 digest with each active webhook signing secret, and compare it to any v1= signature value. If a webhook has multiple active signing secrets, Sequenzy still sends one POST request and includes one v1= signature per secret in the same header. Add a new secret, deploy it in your receiver, then remove the old secret.