Search the docs
Find a page, a section, or an endpoint.
Event types
Every event the product emits, generated from the code that emits them.
There are 36 event types you can subscribe to. An endpoint
with no event_types gets all of them; naming them is how your endpoint is called
for the three you act on rather than for every one of these.
Every event carries ids and never a body — fetch the message when you want it. The envelope's shape, the signature and the retry schedule are on Webhooks.
What fires
| Fires when | |
|---|---|
message.received | Mail arrived at one of your addresses and is in the inbox. |
message.sent | We accepted a message from you and handed it to the network. |
message.delivered | The receiving server accepted it. This can be minutes after it was sent. |
message.bounced | The receiving server refused it permanently. The address is wrong or gone. |
message.rejected | We refused to send it — a send rule, a quota, or an address that may not send. |
message.complained | Somebody you mailed pressed their provider’s spam button. This costs reputation. |
message.read | A Pidgeon address you wrote to read it through the API for the first time — its agent has it. Once per recipient, and only from an address that has turned read receipts on. |
message.handed_off | A Pidgeon address you wrote to handed the conversation to a person. Once per recipient. |
message.spam | Mail arriving for you was classified as spam and filed there. |
message.held | Pidgeon Firewall held mail arriving for you for a person, instead of `message.received`. Ids, the verdict and the kinds of signal, never content: a key cannot read it until a person releases it. |
message.released | A person released a message Pidgeon Firewall held. Your software can read it now, as if it had just arrived. |
message.invitation | Mail arrived carrying a calendar part — an invitation, a reply to one you sent, or a cancellation. `method` says which. |
message.archived | A message was taken out of the inbox, by a person or by your software. |
message.deleted | A message was moved to Trash. Deleting for good does not fire an event. |
| Conversations | Fires when |
|---|---|
thread.created | A conversation began — whether a message arrived at your address or your own send opened one. Every later message updates it rather than making another. |
thread.updated | A message joined the conversation, or its labels, status or assignee changed. |
thread.assigned | Somebody took the conversation, or was given it. |
thread.unassigned | The conversation went back to nobody. |
| Approvals | Fires when |
|---|---|
draft.approval_requested | A send was held for a person to approve, and is a draft until they do. `reason` is `first_contact` (someone the address has never written to or heard from) or `risky_thread` (a message in the conversation tried to give the agent instructions). |
draft.approved | A person approved a held send, and it went out. `draft_id` is now the sent message’s id. |
draft.rejected | A person turned down a held send. It stays a draft, unsent. |
draft.expired | Nobody decided on a held send within 24 hours, so it expired unsent. |
| Calendar | Fires when |
|---|---|
calendar.event.created | A meeting appeared on an inbox’s calendar — put there through the API, or by an invitation that arrived as mail. `source` says which. |
calendar.event.updated | A meeting changed: its time, its title, its attendees, or its status. A cancellation is an update, because the meeting is still on the calendar and still says it was called off. |
calendar.event.deleted | A meeting was taken off the calendar, or one date of a repeating one was. Cancelling is not this — see above. |
calendar.event.starting | A meeting on an inbox’s calendar has started. **This is the only event here that fires from a clock** rather than from somebody doing something, so it arrives within about a minute of the time rather than immediately. |
calendar.event.ending | A meeting has finished. The other half of the pair above. |
calendar.event.responded | Somebody answered an invitation this inbox sent — they replied by mail and the event’s attendee list now says so. |
| Addresses and domains | Fires when |
|---|---|
identity.created | An address was created, by a person or through the API. |
identity.updated | An address’s name, capabilities or send policy changed. |
identity.suspended | An address stopped accepting and sending mail. Its mail is kept. |
identity.transferred | An inbox moved to another workspace, with its mail. |
domain.verified | A domain’s DNS checks passed and it can carry mail. Subscribe instead of polling. |
domain.dns_changed | We changed records in a domain’s DNS, or undid a change: what, by whom, and the value we replaced. |
| Account | Fires when |
|---|---|
referral.rewarded | A company that signed up through your referral link is up and running, and you earned a month of Pro. |
card_log.matched | A new entry in the card log claims a name or domain one of your monitors watches, look-alikes included: `term`, `address`, `reason`, and `index` in the log. |
Two you cannot subscribe to
These are written to the event log and never delivered. The reason is a loop:
an endpoint subscribed to everything would be sent webhook.failed, the
attempt to send it could fail, and that failure would emit another one. The
log is where you watch your webhooks; a webhook is not.
| Log only | Fires when |
|---|---|
webhook.delivered | Your endpoint answered 2xx. Written to the log; never delivered — it would loop. |
webhook.failed | Your endpoint did not answer, or answered an error. Also log-only. |
A type you do not recognise
The log is immutable, so a message written last year keeps the type it was
written with even after we stop emitting it. message.failed is the one that
has happened — it was split into message.rejected and message.complained,
which are the two different things it was being used for.
Match on the types you handle and ignore the rest. An integration that switches exhaustively over this list breaks the day we add to it, which we will.