Event Types
Inbound routing has a separate
message.routing event.
Suppression Duration
See bounces and suppression durations for expiry rules and the next steps after a failed send.Payload Structure
All webhook events use a consistent JSON structure: Events containtype, webhook_id, timestamp, and an event-specific data object. The payload webhook_id identifies the configured endpoint; the webhook-id header identifies the delivery across retries. Inbound routes use route_id instead of webhook_id. Use the payload reference for each event above.
Message Events
Transactional and campaign messages send the same message events with the same payload. The events of a campaign message also carrycampaign_id, list_id and segment_id. message.unsubscribed and message.complained are sent for campaign email only.
AhaSend reads the message when it sends a message event. When the message is deleted before then, or for a campaign message its campaign recipient or its contact, the event is not sent. An event of a campaign message is also not sent when it happens before AhaSend has logged that it received the message.
Contact Events
Contact events report changes to your contacts and to their list memberships. They are available to accounts with the marketing features. Every contact event carries thecontact and its origin. The events that can be about a list membership (contact.added_to_list, contact.removed_from_list, contact.subscribed, contact.unsubscribed and contact.complained) also carry the list and the list_contact.
- Real changes only: A write that leaves the contact and its memberships as they were sends nothing. One write sends one event for each kind of change that it makes. A spam complaint about a campaign sent to a segment is the exception: it sends
contact.complainedwhatever the contact’s state. - Unsubscribe from all lists: The contact’s
unsubscribedfield unsubscribes the contact from all lists. When it changes totrue, AhaSend sendscontact.unsubscribed, orcontact.complainedfor a spam complaint about a campaign sent to a segment. When it changes tofalse, AhaSend sendscontact.subscribed. These events are not about one list, so theirlistandlist_contactarenull. A recipient of a campaign sent to a segment who unsubscribes or reports spam unsubscribes from all lists, and the event also carriescampaign_idandsegment_id. - Domains: A webhook limited to some of your domains gets a contact event only when an email from one of those domains caused it: an unsubscribe, a complaint, or a bounce that disables the contact. A change made through the API or the dashboard, or by email validation, has no domain and goes only to webhooks for all domains.
- API key scopes: Through the API, a webhook with any contact event on needs an API key with
contacts:read. The list events also needlists:read. Without them, Create Webhook and Update Webhook answer403. Turning a contact event on for an account without the marketing features answers400. A key without these scopes can still turn the contact events off or disable the webhook.
Origin
Contact and suppression events carryorigin, which says who made the change:
recipient: the contact or recipient, through an unsubscribe link, a one-click unsubscribe, or a spam complaintapi: you, through the AhaSend APIdashboard: you, through the AhaSend dashboardsystem: AhaSend, for example after a bounce, an expired message or an email validation, or when AhaSend support makes the change
domain.dns_error have no origin.
Origin filter: Each webhook has an origins setting, the list of origins whose contact and suppression events it gets. The default is null, which means every origin. A list that holds all four origins is saved as null, so that an origin added later reaches the webhook too. An empty list is refused: to stop contact or suppression events, turn them off. Events without an origin always pass the filter. In the dashboard, the setting is Send changes made by.
Event Order
Events are not delivered in the order in which they happened, and a later event can arrive first. Order the events by theirtimestamp. For a contact or a suppression event it is the time of the change; for message.unsubscribed and message.complained, the time of the unsubscribe request or of the spam complaint report.
Changes That Send No Event
- A change of a membership’s status to
unconfirmed - Importing contacts from a CSV file
- Saving a contact search as a list
- Removing a contact field from all contacts
- Email validation results. A validation that blocks a contact changes its
status, and that sendscontact.updated. - The memberships that are deleted with their contact:
contact.deletedsays that the contact and all its memberships are gone - Deleting a list: the list’s memberships are kept
- A repeat of an existing suppression that does not change its reason
- Wiping suppressions. After a wipe, read the list again with List Suppressions.
- The removal of expired suppressions:
suppression.createdalready gave theexpires_at

