Skip to main content

Overview

AutoSend webhooks support five categories of events:
  1. Email Lifecycle Events - Track email sending and delivery
  2. Email Engagement Events - Track how recipients interact with your emails
  3. Email Subscription Events - Track unsubscribe and resubscribe actions
  4. Contact Events - Track changes to your contact database
  5. Inbound Email Events - Notify your application when emails arrive at your receiving domains
All webhook payloads follow this structure:
{
  "type": "event.type",
  "createdAt": "2025-11-12T10:30:00.000Z",
  "data": {
    "emailId": "64f1a2b3c4d5e6f7g8h9i0j1",
    "from": "[email protected]",
    "to": {
      "email": "[email protected]",
      "name": "John Doe"
    },
    "subject": "Email Subject",
    "test": false,
    "campaignId": "64f1a2b3c4d5e6f7g8h9i0j2",
    "templateId": "64f1a2b3c4d5e6f7g8h9i0j4",
    "workflowAutomationId": "64f1a2b3c4d5e6f7g8h9i0j5",
    "batchId": "64f1a2b3c4d5e6f7g8h9i0j6"
    // Additional event-specific fields
  }
}
Common Fields (for most email events):
  • emailId - Unique identifier for the email activity
  • from - Sender email address
  • to - Recipient object containing email and name
  • subject - Email subject line
  • test - Boolean indicating if this is a test email (true) or production (false)
  • campaignId - Campaign identifier (optional)
  • templateId - Template identifier (optional)
  • workflowAutomationId - Workflow automation identifier (optional)
  • batchId - Batch identifier (optional)
Note: Subscription events (email.unsubscribed, email.group_unsubscribed, email.group_resubscribed) and contact events have different structures for privacy reasons. See individual event details below.

Supported Event Types

Email Lifecycle:
  • email.sent - Email successfully sent to the recipient’s mail server
  • email.delivered - Email successfully delivered
  • email.deferred - Email delivery temporarily delayed
  • email.bounced - Email failed to deliver
Email Engagement:
  • email.opened - Recipient opened the email
  • email.clicked - Recipient clicked a link in the email
  • email.spam_reported - Recipient marked email as spam
Email Subscription:
  • email.unsubscribed - Recipient unsubscribed globally from all emails
  • email.group_unsubscribed - Recipient unsubscribed from a specific email group
  • email.group_resubscribed - Recipient resubscribed to a specific email group
Contact Management:
  • contact.created - New contact created
  • contact.updated - Contact information updated
  • contact.deleted - Contact deleted
Inbound Email:
  • email.received - An inbound email was received on one of your receiving domains

Email Lifecycle Events

email.sent

Triggered when an email is successfully sent to the recipient’s mail server.
Sample Payload:
{
  "type": "email.sent",
  "createdAt": "2025-11-12T10:00:00.000Z",
  "data": {
    "emailId": "64f1a2b3c4d5e6f7g8h9i0j1",
    "from": "[email protected]",
    "to": {
      "email": "[email protected]",
      "name": "John Doe"
    },
    "subject": "Welcome to AutoSend",
    "test": false,
    "campaignId": "64f1a2b3c4d5e6f7g8h9i0j2",
    "templateId": "64f1a2b3c4d5e6f7g8h9i0j4",
    "workflowAutomationId": "64f1a2b3c4d5e6f7g8h9i0j5",
    "batchId": "64f1a2b3c4d5e6f7g8h9i0j6"
  }
}
Data Fields:
  • emailId - Unique identifier for the email activity
  • from - Sender email address
  • to - Recipient object with email and name
  • subject - Email subject line
  • test - Boolean indicating whether this is a test email (true) or production (false)
  • campaignId - Campaign ID (optional, if sent as part of a campaign)
  • templateId - Template ID used for the email (optional)
  • workflowAutomationId - Workflow automation ID (optional, if sent from automation)
  • batchId - Batch ID (optional, if sent as part of a batch)
Use Cases:
  • Track when emails are successfully accepted by recipient server
  • Monitor email sending activity
  • Trigger follow-up workflows after email dispatch

email.delivered

Triggered when AutoSend successfully delivers an email to the recipient’s mail server.
Sample Payload:
{
  "type": "email.delivered",
  "createdAt": "2025-11-12T10:15:00.000Z",
  "data": {
    "emailId": "64f1a2b3c4d5e6f7g8h9i0j1",
    "from": "[email protected]",
    "to": {
      "email": "[email protected]",
      "name": "John Doe"
    },
    "subject": "Welcome to AutoSend",
    "test": false,
    "campaignId": "64f1a2b3c4d5e6f7g8h9i0j2",
    "templateId": "64f1a2b3c4d5e6f7g8h9i0j4",
    "workflowAutomationId": "64f1a2b3c4d5e6f7g8h9i0j5",
    "batchId": "64f1a2b3c4d5e6f7g8h9i0j6"
  }
}
Data Fields:
  • emailId - Unique identifier for the email activity
  • from - Sender email address
  • to - Recipient object with email and name
  • subject - Email subject line
  • test - Boolean indicating whether this is a test email (true) or production (false)
  • campaignId - Campaign ID (optional, if applicable)
  • templateId - Template ID used (optional)
  • workflowAutomationId - Workflow automation ID (optional, if sent from automation)
  • batchId - Batch ID (optional, if sent as part of a batch)
Use Cases:
  • Confirm successful email delivery
  • Update delivery status in your database
  • Track delivery times and patterns

email.deferred

Triggered when email delivery is temporarily delayed by the recipient’s mail server.
Sample Payload:
{
  "type": "email.deferred",
  "createdAt": "2025-11-12T10:10:00.000Z",
  "data": {
    "emailId": "64f1a2b3c4d5e6f7g8h9i0j1",
    "from": "[email protected]",
    "to": {
      "email": "[email protected]",
      "name": "John Doe"
    },
    "subject": "Welcome to AutoSend",
    "test": false,
    "campaignId": "64f1a2b3c4d5e6f7g8h9i0j2",
    "templateId": "64f1a2b3c4d5e6f7g8h9i0j4",
    "workflowAutomationId": "64f1a2b3c4d5e6f7g8h9i0j5",
    "batchId": "64f1a2b3c4d5e6f7g8h9i0j6",
    "delayType": "InternalFailure",
    "delayReason": "Temporary connection failure",
    "expirationTime": "2025-11-12T14:10:00.000Z"
  }
}
Data Fields:
  • emailId - Unique identifier for the email activity
  • from - Sender email address
  • to - Recipient object with email and name
  • subject - Email subject line
  • test - Boolean indicating whether this is a test email (true) or production (false)
  • campaignId - Campaign ID (optional, if applicable)
  • templateId - Template ID used (optional)
  • workflowAutomationId - Workflow automation ID (optional, if sent from automation)
  • batchId - Batch ID (optional, if sent as part of a batch)
  • delayType - Type of delay, e.g., “InternalFailure”, “MailboxFull” (optional)
  • delayReason - Human-readable explanation of the delay (optional)
  • expirationTime - ISO 8601 timestamp when delivery attempts will stop (optional)
Use Cases:
  • Monitor temporary delivery issues
  • Track mail server responsiveness
  • Alert on persistent deferral patterns

email.bounced

Triggered when an email bounces (fails to deliver).
Sample Payload:
{
  "type": "email.bounced",
  "createdAt": "2025-11-12T10:20:00.000Z",
  "data": {
    "emailId": "64f1a2b3c4d5e6f7g8h9i0j1",
    "from": "[email protected]",
    "to": {
      "email": "[email protected]",
      "name": "Invalid User"
    },
    "subject": "Welcome to AutoSend",
    "test": false,
    "campaignId": "64f1a2b3c4d5e6f7g8h9i0j2",
    "templateId": "64f1a2b3c4d5e6f7g8h9i0j4",
    "workflowAutomationId": "64f1a2b3c4d5e6f7g8h9i0j5",
    "batchId": "64f1a2b3c4d5e6f7g8h9i0j6",
    "bounceType": "Permanent",
    "bounceSubType": "General",
    "reason": "550 5.1.1 The email account that you tried to reach does not exist"
  }
}
Data Fields:
  • emailId - Unique identifier for the email activity
  • from - Sender email address
  • to - Recipient object with email and name
  • subject - Email subject line
  • test - Boolean indicating whether this is a test email (true) or production (false)
  • campaignId - Campaign ID (optional, if applicable)
  • templateId - Template ID used (optional)
  • workflowAutomationId - Workflow automation ID (optional, if sent from automation)
  • batchId - Batch ID (optional, if sent as part of a batch)
  • bounceType - Bounce classification: “Permanent” or “Transient” (optional)
  • bounceSubType - Detailed bounce category, e.g., “General”, “NoEmail”, “Suppressed” (optional)
  • reason - Human-readable bounce reason from the mail server (optional)
Bounce Types:
  • Permanent: Hard bounce - invalid email address, domain doesn’t exist
  • Transient: Soft bounce - mailbox full, server temporarily unavailable
Use Cases:
  • Remove hard bounced emails from your list
  • Retry soft bounces later
  • Monitor bounce rates for sender reputation

Email Engagement Events

email.opened

Triggered when a recipient opens an email.
Sample Payload:
{
  "type": "email.opened",
  "createdAt": "2025-11-12T10:30:00.000Z",
  "data": {
    "emailId": "64f1a2b3c4d5e6f7g8h9i0j1",
    "from": "[email protected]",
    "to": {
      "email": "[email protected]",
      "name": "John Doe"
    },
    "subject": "Welcome to AutoSend",
    "test": false,
    "campaignId": "64f1a2b3c4d5e6f7g8h9i0j2",
    "templateId": "64f1a2b3c4d5e6f7g8h9i0j4",
    "workflowAutomationId": "64f1a2b3c4d5e6f7g8h9i0j5",
    "batchId": "64f1a2b3c4d5e6f7g8h9i0j6"
  }
}
Data Fields:
  • emailId - Unique identifier for the email activity
  • from - Sender email address
  • to - Recipient object with email and name
  • subject - Email subject line
  • test - Boolean indicating whether this is a test email (true) or production (false)
  • campaignId - Campaign ID (optional, if applicable)
  • templateId - Template ID used (optional)
  • workflowAutomationId - Workflow automation ID (optional, if sent from automation)
  • batchId - Batch ID (optional, if sent as part of a batch)
Privacy Note: This event does NOT include ipAddress, userAgent, device, or location information for privacy protection.Use Cases:
  • Track email engagement rates
  • Identify best send times
  • Segment engaged vs unengaged contacts

email.clicked

Triggered when a recipient clicks a link in an email.
Sample Payload:
{
  "type": "email.clicked",
  "createdAt": "2025-11-12T10:35:00.000Z",
  "data": {
    "emailId": "64f1a2b3c4d5e6f7g8h9i0j1",
    "from": "[email protected]",
    "to": {
      "email": "[email protected]",
      "name": "John Doe"
    },
    "subject": "Welcome to AutoSend",
    "test": false,
    "clickedUrl": "https://example.com/product",
    "campaignId": "64f1a2b3c4d5e6f7g8h9i0j2",
    "templateId": "64f1a2b3c4d5e6f7g8h9i0j4",
    "workflowAutomationId": "64f1a2b3c4d5e6f7g8h9i0j5",
    "batchId": "64f1a2b3c4d5e6f7g8h9i0j6"
  }
}
Data Fields:
  • emailId - Unique identifier for the email activity
  • from - Sender email address
  • to - Recipient object with email and name
  • subject - Email subject line
  • test - Boolean indicating whether this is a test email (true) or production (false)
  • clickedUrl - The URL that was clicked (optional)
  • campaignId - Campaign ID (optional, if applicable)
  • templateId - Template ID used (optional)
  • workflowAutomationId - Workflow automation ID (optional, if sent from automation)
  • batchId - Batch ID (optional, if sent as part of a batch)
Privacy Note: This event does NOT include ipAddress, userAgent, or device information for privacy protection.Use Cases:
  • Track which links are most popular
  • Identify highly engaged contacts
  • Trigger follow-up campaigns based on clicked links

email.spam_reported

Triggered when a recipient marks an email as spam or files a complaint.
Sample Payload:
{
  "type": "email.spam_reported",
  "createdAt": "2025-11-12T10:45:00.000Z",
  "data": {
    "emailId": "64f1a2b3c4d5e6f7g8h9i0j1",
    "from": "[email protected]",
    "to": {
      "email": "[email protected]",
      "name": "John Doe"
    },
    "subject": "Welcome to AutoSend",
    "test": false,
    "campaignId": "64f1a2b3c4d5e6f7g8h9i0j2",
    "templateId": "64f1a2b3c4d5e6f7g8h9i0j4",
    "workflowAutomationId": "64f1a2b3c4d5e6f7g8h9i0j5",
    "batchId": "64f1a2b3c4d5e6f7g8h9i0j6",
    "complaintType": "abuse"
  }
}
Data Fields:
  • emailId - Unique identifier for the email activity
  • from - Sender email address
  • to - Recipient object with email and name
  • subject - Email subject line
  • test - Boolean indicating whether this is a test email (true) or production (false)
  • campaignId - Campaign ID (optional, if applicable)
  • templateId - Template ID used (optional)
  • workflowAutomationId - Workflow automation ID (optional, if sent from automation)
  • batchId - Batch ID (optional, if sent as part of a batch)
  • complaintType - Type of complaint: “abuse”, “fraud”, “virus”, “other” (optional)
Use Cases:
  • Automatically suppress emails that file complaints
  • Monitor spam complaint rates
  • Improve email content and targeting to reduce complaints
  • Protect sender reputation

Email Subscription Events

email.unsubscribed

Triggered when a recipient globally unsubscribes from all emails.
Sample Payload:
{
  "type": "email.unsubscribed",
  "createdAt": "2025-11-12T10:40:00.000Z",
  "data": {
    "emailId": "64f1a2b3c4d5e6f7g8h9i0j1",
    "test": false,
    "campaignId": "64f1a2b3c4d5e6f7g8h9i0j2",
    "templateId": "64f1a2b3c4d5e6f7g8h9i0j4",
    "workflowAutomationId": "64f1a2b3c4d5e6f7g8h9i0j5",
    "batchId": "64f1a2b3c4d5e6f7g8h9i0j6"
  }
}
Data Fields:
  • emailId - Unique identifier for the email activity (optional - only present if triggered from an email)
  • test - Boolean indicating whether this is a test email (true) or production (false)
  • campaignId - Campaign ID (optional - only present if triggered from a campaign email)
  • templateId - Template ID (optional - only present if triggered from an email)
  • workflowAutomationId - Workflow automation ID (optional - only present if triggered from automation email)
  • batchId - Batch ID (optional - only present if triggered from batch email)
Important Notes:
  • This event does NOT include from, to, or subject fields for privacy protection
  • Fields like emailId, campaignId, templateId, workflowAutomationId, and batchId are optional and only present when the unsubscribe is triggered from an email context
Use Cases:
  • Automatically remove contacts from all mailing lists
  • Update contact preferences in your CRM
  • Track global unsubscribe reasons for analytics
  • Ensure compliance with email regulations

email.group_unsubscribed

Triggered when a recipient unsubscribes from a specific email group or suppression group (but not all emails).
Sample Payload:
{
  "type": "email.group_unsubscribed",
  "createdAt": "2025-11-12T10:42:00.000Z",
  "data": {
    "emailId": "64f1a2b3c4d5e6f7g8h9i0j1",
    "test": false,
    "unsubscribeGroupId": "newsletter-marketing",
    "campaignId": "64f1a2b3c4d5e6f7g8h9i0j2",
    "templateId": "64f1a2b3c4d5e6f7g8h9i0j4",
    "workflowAutomationId": "64f1a2b3c4d5e6f7g8h9i0j5",
    "batchId": "64f1a2b3c4d5e6f7g8h9i0j6"
  }
}
Data Fields:
  • emailId - Unique identifier for the email activity (optional - only present if triggered from an email)
  • test - Boolean indicating whether this is a test email (true) or production (false)
  • unsubscribeGroupId - The specific group ID they unsubscribed from (optional)
  • campaignId - Campaign ID (optional - only present if triggered from a campaign email)
  • templateId - Template ID (optional - only present if triggered from an email)
  • workflowAutomationId - Workflow automation ID (optional - only present if triggered from automation email)
  • batchId - Batch ID (optional - only present if triggered from batch email)
Important Notes:
  • This event does NOT include from, to, or subject fields for privacy protection
  • Fields like emailId, campaignId, templateId, workflowAutomationId, and batchId are optional and only present when the unsubscribe is triggered from an email context
Use Cases:
  • Remove contacts from specific mailing lists or segments
  • Allow granular subscription management
  • Track which email categories users opt out of
  • Maintain subscriber preferences across different email types

email.group_resubscribed

Triggered when a recipient resubscribes to a specific email group they previously unsubscribed from.
Sample Payload:
{
  "type": "email.group_resubscribed",
  "createdAt": "2025-11-12T11:00:00.000Z",
  "data": {
    "emailId": "64f1a2b3c4d5e6f7g8h9i0j1",
    "test": false,
    "unsubscribeGroupId": "newsletter-marketing",
    "campaignId": "64f1a2b3c4d5e6f7g8h9i0j2"
  }
}
Data Fields:
  • emailId - Unique identifier for the email activity (optional)
  • test - Boolean indicating whether this is a test email (true) or production (false)
  • unsubscribeGroupId - The specific group ID they resubscribed to (optional)
  • campaignId - Campaign ID (optional)
Important Notes:
  • This event does NOT include from, to, or subject fields for privacy protection
Use Cases:
  • Re-add contacts to specific mailing lists
  • Track re-engagement patterns
  • Update subscription preferences in your CRM
  • Resume sending specific types of emails to the contact

Contact Events

contact.created

Triggered when a new contact is created in your AutoSend project.
Sample Payload:
{
  "type": "contact.created",
  "createdAt": "2025-11-12T09:00:00.000Z",
  "data": {
    "contactId": "64f1a2b3c4d5e6f7g8h9i0j3",
    "email": "[email protected]",
    "name": "John Doe"
  }
}
Data Fields:
  • contactId - Unique identifier for the contact (optional)
  • email - Contact’s email address (optional)
  • name - Contact’s name (optional)
Note: Additional custom fields may be included based on your contact schema.Use Cases:
  • Sync new contacts to your CRM
  • Trigger welcome email sequences
  • Update analytics dashboards
  • Initialize contact tracking in external systems

contact.updated

Triggered when an existing contact’s information is updated.
Sample Payload:
{
  "type": "contact.updated",
  "createdAt": "2025-11-12T09:30:00.000Z",
  "data": {
    "contactId": "64f1a2b3c4d5e6f7g8h9i0j3",
    "email": "[email protected]",
    "name": "Jonathan Doe",
    "changedFields": ["name"]
  }
}
Data Fields:
  • contactId - Unique identifier for the contact (optional)
  • email - Contact’s email address (optional)
  • name - Contact’s name (optional)
  • changedFields - List of field names that were changed (optional)
Note: Additional custom fields may be included based on your contact schema.Use Cases:
  • Keep contact data synchronized across systems
  • Track contact lifecycle changes
  • Trigger workflows based on specific field changes
  • Update contact profiles in external databases

contact.deleted

Triggered when a contact is deleted from your AutoSend project.
Sample Payload:
{
  "type": "contact.deleted",
  "createdAt": "2025-11-12T09:45:00.000Z",
  "data": {
    "contactId": "64f1a2b3c4d5e6f7g8h9i0j3",
    "email": "[email protected]"
  }
}
Data Fields:
  • contactId - Unique identifier for the deleted contact (optional)
  • email - Contact’s email address for reference (optional)
Use Cases:
  • Remove contacts from external systems
  • Update contact counts and analytics
  • Maintain data consistency across platforms
  • Ensure GDPR/privacy compliance in external systems

Inbound Email Events

For a conceptual overview of receiving emails on AutoSend, see the Inbound Email API.

email.received

Triggered when an inbound email is received on one of your project’s receiving domains. Use inboundEmailId from the payload to fetch the full structured message via the Get Message endpoint.
Sample Payload:
{
  "type": "email.received",
  "createdAt": "2026-06-24T10:30:00.000Z",
  "data": {
    "inboundEmailId": "64f1a2b3c4d5e6f7g8h9i0j1",
    "from": {
      "email": "[email protected]",
      "name": "Jane Customer"
    },
    "to": [
      {
        "email": "[email protected]",
        "name": null
      }
    ],
    "cc": [],
    "subject": "Question about my order",
    "attachments": [
      {
        "attachmentId": "64f1a2b3c4d5e6f7g8h9i0k1",
        "attachmentIndex": 0,
        "filename": "receipt.pdf",
        "contentType": "application/pdf",
        "size": 20480
      }
    ],
    "spamVerdict": "PASS",
    "virusVerdict": "PASS",
    "receivedAt": "2026-06-24T10:30:00.000Z",
    "threadId": "64f1a2b3c4d5e6f7g8h9i0j2",
    "inReplyToEmailActivityId": "64f1a2b3c4d5e6f7g8h9i0j3",
    "inReplyToInboundEmailId": null
  }
}
Data Fields:
  • inboundEmailId - The database ID of the inbound message (this is the id field in the Get Message API response — use it as the {id} path parameter)
  • from - Sender object with email and name
  • to - Array of recipient objects with email and name
  • cc - Array of CC recipient objects with email and name (empty array if none)
  • subject - Email subject line
  • attachments - Array of attachment metadata objects (empty array if none). Each entry includes attachmentId, attachmentIndex, filename, contentType, and size
  • spamVerdict - SES spam check verdict (e.g. PASS, FAIL)
  • virusVerdict - SES virus check verdict (e.g. PASS, FAIL)
  • receivedAt - ISO 8601 timestamp when the message was received
  • threadId - Thread identifier for grouping related messages (optional - only present when a thread was matched)
  • inReplyToEmailActivityId - ID of the outbound email this message is a reply to, if matched (optional)
  • inReplyToInboundEmailId - ID of a previously received inbound message this is a reply to, if matched (optional)
Note: This payload contains metadata only. To access the full message body, headers, attachments, and verdicts, call the Get Message endpoint with the messageId.Use Cases:
  • Route incoming support emails to a ticketing system
  • Auto-reply to customer questions
  • Parse and store inbound replies alongside outbound conversations
  • Trigger workflows when a specific address receives mail

Event Handling Examples

app.post("/webhooks/autosend", async (req, res) => {
  const { type, data } = req.body;

  switch (type) {
    case "email.sent":
      await handleEmailSent(data);
      break;

    case "email.delivered":
      await handleEmailDelivered(data);
      break;

    case "email.deferred":
      await handleEmailDeferred(data);
      break;

    case "email.opened":
      await handleEmailOpened(data);
      break;

    case "email.clicked":
      await handleEmailClicked(data);
      break;

    case "email.bounced":
      await handleEmailBounced(data);
      break;

    case "email.spam_reported":
      await handleSpamReport(data);
      break;

    case "email.unsubscribed":
      await handleGlobalUnsubscribe(data);
      break;

    case "email.group_unsubscribed":
      await handleGroupUnsubscribe(data);
      break;

    case "email.group_resubscribed":
      await handleGroupResubscribe(data);
      break;

    case "contact.created":
      await handleContactCreated(data);
      break;

    case "contact.updated":
      await handleContactUpdated(data);
      break;

    case "contact.deleted":
      await handleContactDeleted(data);
      break;

    default:
      console.log(`Unhandled event: ${type}`);
  }

  res.status(200).json({ received: true });

});

async function handleEmailOpened(data) {
  const { emailId, to } = data;

  await db.emails.update({
    where: { id: emailId },
    data: {
      opened: true,
      openedAt: new Date(),
      opens: { increment: 1 },
    },
  });

  await db.contacts.update({
    where: { email: to.email },
    data: {
      lastEngagement: new Date(),
      engagementScore: { increment: 1 },
    },
  });
}

async function handleEmailClicked(data) {
  const { emailId, to, clickedUrl } = data;

  await db.clicks.create({
    data: {
      emailId,
      recipientEmail: to.email,
      url: clickedUrl,
      clickedAt: new Date(),
    },
  });

  await db.contacts.update({
    where: { email: to.email },
    data: {
      lastEngagement: new Date(),
      engagementScore: { increment: 5 },
    },
  });
}
async function handleEmailBounced(data) {
  const { to, bounceType, reason } = data;

  if (bounceType === 'Permanent') {
    // Remove from active mailing lists
    await db.contacts.update({
      where: { email: to.email },
      data: {
        status: 'bounced',
        bouncedAt: new Date(),
        bounceReason: reason,
      },
    });

    // Suppress future emails
    await db.suppressions.create({
      data: {
        email: to.email,
        type: 'bounce',
        reason: reason,
      },
    });

    // Alert team
    await sendAlert(`Hard bounce for ${to.email}: ${reason}`);
  }
}

async function handleSpamReport(data) {
  const { to } = data;
  const email = to.email;

  // Immediately suppress the email
  await db.suppressions.create({
    data: {
      email,
      type: 'complaint',
      reportedAt: new Date(),
    },
  });

  // Update contact status
  await db.contacts.update({
    where: { email },
    data: {
      status: 'complained',
      complainedAt: new Date(),
    },
  });

  // Alert team for reputation monitoring
  await sendAlert(`Spam complaint from ${email}`);
}
async function handleGlobalUnsubscribe(data) {
  const { emailId, campaignId } = data;

  // Update email activity record
  await db.emails.update({
    where: { id: emailId },
    data: {
      unsubscribed: true,
      unsubscribedAt: new Date(),
    },
  });

  console.log(
    `Global unsubscribe from email ${emailId}, campaign ${campaignId}`
  );
}

async function handleGroupUnsubscribe(data) {
  const { emailId, unsubscribeGroupId, campaignId } = data;

  // Update email activity record
  await db.emails.update({
    where: { id: emailId },
    data: {
      groupUnsubscribed: true,
      unsubscribeGroupId,
      unsubscribedAt: new Date(),
    },
  });

  console.log(
    `Group unsubscribe from email ${emailId}, group ${unsubscribeGroupId}`
  );
}

async function handleGroupResubscribe(data) {
  const { emailId, unsubscribeGroupId } = data;

  // Update subscription record
  await db.emails.update({
    where: { id: emailId },
    data: {
      resubscribed: true,
      resubscribeGroupId: unsubscribeGroupId,
      resubscribedAt: new Date(),
    },
  });

  console.log(
    `Group resubscribe for email ${emailId}, group ${unsubscribeGroupId}`
  );
}
async function handleContactCreated(data) {
  const { contactId, email, name } = data;

  // Sync to CRM
  await crm.contacts.create({
    externalId: contactId,
    email,
    name,
    createdAt: new Date(),
  });
}

async function handleContactUpdated(data) {
  const { contactId, email, name, changedFields } = data;

  // Sync to CRM
  await crm.contacts.update({
    externalId: contactId,
    email,
    name,
    changedFields,
    updatedAt: new Date(),
  });
}

async function handleContactDeleted(data) {
  const { contactId, email } = data;

  // Remove from CRM
  await crm.contacts.delete({
    externalId: contactId,
  });

  console.log(`Contact ${email} removed from CRM`);
}

Get Available Events via API

You can programmatically fetch the list of available events:
curl -X GET https://api.autosend.com/v1/webhooks/events/available \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-project-id: YOUR_PROJECT_ID"
const fetch = require('node-fetch');

const API_KEY = process.env.AUTOSEND_API_KEY;
const PROJECT_ID = process.env.AUTOSEND_PROJECT_ID;

async function getAvailableEvents() {
  const response = await fetch(
    'https://api.autosend.com/v1/webhooks/events/available',
    {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${API_KEY}`,
        'x-project-id': PROJECT_ID,
      },
    }
  );

  const data = await response.json();
  console.log(data);
  return data;
}

getAvailableEvents();
import requests
import os

API_KEY = os.environ.get('AUTOSEND_API_KEY')
PROJECT_ID = os.environ.get('AUTOSEND_PROJECT_ID')

def get_available_events():
    url = 'https://api.autosend.com/v1/webhooks/events/available'
    headers = {
        'Authorization': f'Bearer {API_KEY}',
        'x-project-id': PROJECT_ID
    }

    response = requests.get(url, headers=headers)
    data = response.json()
    print(data)
    return data

get_available_events()
<?php

$apiKey = getenv('AUTOSEND_API_KEY');
$projectId = getenv('AUTOSEND_PROJECT_ID');

$ch = curl_init('https://api.autosend.com/v1/webhooks/events/available');

curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer ' . $apiKey,
    'x-project-id: ' . $projectId
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$data = json_decode($response, true);
curl_close($ch);

print_r($data);
?>
package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
)

func main() {
    apiKey := os.Getenv("AUTOSEND_API_KEY")
    projectId := os.Getenv("AUTOSEND_PROJECT_ID")

    req, _ := http.NewRequest("GET", "https://api.autosend.com/v1/webhooks/events/available", nil)
    req.Header.Set("Authorization", "Bearer "+apiKey)
    req.Header.Set("x-project-id", projectId)

    client := &http.Client{}
    resp, _ := client.Do(req)
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
require 'net/http'
require 'json'
require 'uri'

api_key = ENV['AUTOSEND_API_KEY']
project_id = ENV['AUTOSEND_PROJECT_ID']

uri = URI('https://api.autosend.com/v1/webhooks/events/available')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request['Authorization'] = "Bearer #{api_key}"
request['x-project-id'] = project_id

response = http.request(request)
data = JSON.parse(response.body)
puts data
Response:
{
  "success": true,
  "data": {
    "events": [
      "email.sent",
      "email.delivered",
      "email.deferred",
      "email.opened",
      "email.clicked",
      "email.bounced",
      "email.spam_reported",
      "email.unsubscribed",
      "email.group_unsubscribed",
      "email.group_resubscribed",
      "contact.created",
      "contact.updated",
      "contact.deleted",
      "email.received"
    ]
  }
}

https://mintcdn.com/autosend-13920f5c/nx_wYfWx3qeZwg1C/icons/introduction.svg?fit=max&auto=format&n=nx_wYfWx3qeZwg1C&q=85&s=9b4ef691e39d4517b800d381b32a89db

Introduction

Getting started with webhooks
https://mintcdn.com/autosend-13920f5c/nx_wYfWx3qeZwg1C/icons/retries-refresh.svg?fit=max&auto=format&n=nx_wYfWx3qeZwg1C&q=85&s=6c8bfc5edaa01d3624986eebbb4cbb09

Retries and Replays

Automatic retry logic and best practices
https://mintcdn.com/autosend-13920f5c/nx_wYfWx3qeZwg1C/icons/verify-requests.svg?fit=max&auto=format&n=nx_wYfWx3qeZwg1C&q=85&s=dec233ef8a7a82b41b8ab4d6540904ec

Verify Webhook Requests

Security and signature verification
https://mintcdn.com/autosend-13920f5c/nx_wYfWx3qeZwg1C/icons/webhook.svg?fit=max&auto=format&n=nx_wYfWx3qeZwg1C&q=85&s=14ad6675c71731ac04f786559a813ee1

Webhooks

Manage your webhooks from the AutoSend sidebar