usend Docs
Webhooks

Event types

Every webhook event and an example of its payload.

Every webhook request has the same envelope:

JSON
{
  "type": "email.delivered",
  "created_at": "2026-10-11T09:12:47.118Z",
  "data": { }
}

type is the event type and created_at is when the event was created. data depends on the event.

Email events

All email.* events except email.received describe an email you sent. Their data always has these fields:

FieldTypeDescription
email_idstringThe email's ID, as returned by POST /emails.
fromstringThe sender.
tostring[]The to recipients.
subjectstringThe subject.
created_atstringWhen the email was created.
tagsobject[]The email's tags, as { "name", "value" }.
broadcast_idstringOnly for emails sent by a broadcast.
recipientstringThe recipient the event is about, for per-recipient events (delivered, delayed, bounced, complained).

Some events add their own object, described below.

email.queued

The email was accepted and is waiting to be sent. No extra fields.

email.scheduled

The email was accepted with a scheduled_at in the future. No extra fields.

email.sent

The email was handed to the sending infrastructure. No extra fields.

JSON
{
  "type": "email.sent",
  "created_at": "2026-10-11T09:12:44.512Z",
  "data": {
    "email_id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
    "from": "Acme <[email protected]>",
    "to": ["[email protected]"],
    "subject": "Your receipt",
    "created_at": "2026-10-11T09:12:43Z",
    "tags": [{ "name": "category", "value": "receipt" }]
  }
}

email.delivered

The recipient's mail server accepted the email. Sent once per recipient. delivery.response is the server's reply.

JSON
{
  "type": "email.delivered",
  "created_at": "2026-10-11T09:12:47.118Z",
  "data": {
    "email_id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
    "from": "Acme <[email protected]>",
    "to": ["[email protected]"],
    "subject": "Your receipt",
    "created_at": "2026-10-11T09:12:43Z",
    "tags": [{ "name": "category", "value": "receipt" }],
    "recipient": "[email protected]",
    "delivery": { "response": "250 2.0.0 OK 1760173967 a1-20020a05" }
  }
}

email.delivery_delayed

Delivery failed temporarily and is being retried. delay.message explains why. delay.type is a short classification when available.

JSON
{
  "type": "email.delivery_delayed",
  "created_at": "2026-10-11T09:20:02.004Z",
  "data": {
    "email_id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
    "from": "Acme <[email protected]>",
    "to": ["[email protected]"],
    "subject": "Your receipt",
    "created_at": "2026-10-11T09:12:43Z",
    "tags": [],
    "recipient": "[email protected]",
    "delay": { "type": "MailboxFull", "message": "452 4.2.2 The email account that you tried to reach is over quota." }
  }
}

email.bounced

The recipient's server rejected the email. bounce.type is hard (permanent) or soft (temporary). Hard bounces add the address to your suppression list.

JSON
{
  "type": "email.bounced",
  "created_at": "2026-10-11T09:12:48.230Z",
  "data": {
    "email_id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
    "from": "Acme <[email protected]>",
    "to": ["[email protected]"],
    "subject": "Your receipt",
    "created_at": "2026-10-11T09:12:43Z",
    "tags": [],
    "recipient": "[email protected]",
    "bounce": {
      "type": "hard",
      "sub_type": "NoEmail",
      "message": "smtp; 550 5.1.1 The email account that you tried to reach does not exist."
    }
  }
}

email.complained

The recipient reported the email as spam. The address is added to your suppression list. complaint.feedback_type is the type reported by the mailbox provider, when it sends one (for example abuse).

JSON
{
  "type": "email.complained",
  "created_at": "2026-10-11T11:02:13.771Z",
  "data": {
    "email_id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
    "from": "Acme <[email protected]>",
    "to": ["[email protected]"],
    "subject": "Your receipt",
    "created_at": "2026-10-11T09:12:43Z",
    "tags": [],
    "recipient": "[email protected]",
    "complaint": { "feedback_type": "abuse" }
  }
}

email.opened

The email was opened. Needs open tracking. Sent for every open.

JSON
{
  "type": "email.opened",
  "created_at": "2026-10-11T09:30:05.090Z",
  "data": {
    "email_id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
    "from": "Acme <[email protected]>",
    "to": ["[email protected]"],
    "subject": "Your receipt",
    "created_at": "2026-10-11T09:12:43Z",
    "tags": [],
    "open": { "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "ip": "203.0.113.10" }
  }
}

email.clicked

A link in the email was clicked. Needs click tracking. Sent for every click.

JSON
{
  "type": "email.clicked",
  "created_at": "2026-10-11T09:31:40.552Z",
  "data": {
    "email_id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
    "from": "Acme <[email protected]>",
    "to": ["[email protected]"],
    "subject": "Your receipt",
    "created_at": "2026-10-11T09:12:43Z",
    "tags": [],
    "click": {
      "link": "https://acme.com/orders/1042",
      "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X)",
      "ip": "203.0.113.10"
    }
  }
}

email.failed

usend could not send the email, for example because every recipient is suppressed, the organization is suspended or the message was rejected before delivery. failed.reason explains why. When every recipient was suppressed, reason is suppressed and suppressed lists the addresses.

JSON
{
  "type": "email.failed",
  "created_at": "2026-10-11T09:12:44.512Z",
  "data": {
    "email_id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
    "from": "Acme <[email protected]>",
    "to": ["[email protected]"],
    "subject": "Your receipt",
    "created_at": "2026-10-11T09:12:43Z",
    "tags": [],
    "failed": { "reason": "The organization is suspended." },
    "reason": "org_suspended"
  }
}

email.canceled

A scheduled email was canceled. No extra fields.

email.received

An email arrived on one of your receiving domains. Its data is different from the other email events:

JSON
{
  "type": "email.received",
  "created_at": "2026-10-11T08:30:12.402Z",
  "data": {
    "email_id": "a39999a6-88e3-48b1-888b-beaabcde1b33",
    "from": "Ann <[email protected]>",
    "to": ["[email protected]"],
    "cc": [],
    "subject": "Question about my order",
    "text": "Hi, where is order #1042?",
    "html": "<p>Hi, where is order #1042?</p>",
    "message_id": "[email protected]",
    "created_at": "2026-10-11T08:30:12Z",
    "attachments": [
      { "id": "2a0c9ce0-3112-4728-976e-47ddcd16a318", "filename": "screenshot.png", "content_type": "image/png", "size": 182044 }
    ]
  }
}

See Receiving webhook for the fields.

contact.unsubscribed

A contact unsubscribed through a broadcast's unsubscribe link or their mail client's unsubscribe button. audience_id is the audience (segment) the contact was unsubscribed from. email_id is included when the unsubscribe came from a specific email.

JSON
{
  "type": "contact.unsubscribed",
  "created_at": "2026-10-11T12:00:31.640Z",
  "data": {
    "contact_id": "e169aa45-1ecf-4183-9955-b1499d5701d3",
    "audience_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
    "email": "[email protected]",
    "first_name": "Ann",
    "last_name": "Lee",
    "unsubscribed": true,
    "email_id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c"
  }
}

Changing a contact's unsubscribed flag through the API does not send this event.