An HTTP webhook endpoint has to be a public URL that's always up and fast enough to absorb a burst. When a sync kicks off and a few thousand message.created events fire in a minute, a slow handler backs up, times out, and starts dropping deliveries. You can engineer around that with a queue in front of your endpoint, or you can skip the endpoint entirely and have Nylas deliver notifications straight into a Google Cloud Pub/Sub topic, where the queue is the delivery mechanism.
This post covers Pub/Sub notification channels from two angles: the HTTP API your backend calls, and the nylas CLI for creating and managing a channel from the terminal. I work on the CLI, so the terminal commands below are the ones I reach for when I'm wiring up a channel.
What a Pub/Sub channel is
A Pub/Sub notification channel tells Nylas to publish your notifications to a Google Cloud Pub/Sub topic instead of (or alongside) posting them to an HTTP URL. You own the topic; the channel is the stored configuration that lets the service connect to it and push events in. Your own services then consume those events from a subscription on that topic, at whatever pace they can handle.
This is a different Pub/Sub from the one some Google auth apps use to receive mail changes from Google. Here, the flow goes the other way: Nylas is the publisher, your topic is the destination, and your consumers read from it. The notification payloads are the same events you'd get over HTTP, so message.created, event.updated, and the rest arrive in the topic with the shape you already know, just delivered through Google's infrastructure rather than a request to your server.
Why Pub/Sub instead of an HTTP endpoint
The reason to reach for this is delivery guarantees. Pub/Sub is a durable, event-driven queue, so a burst of notifications buffers in the topic instead of hammering your endpoint, and your consumers drain it individually or in batches during high volume. If a consumer is down, the messages wait rather than being lost, which is the property an HTTP webhook can't give you on its own.
It also opens up patterns an endpoint makes awkward. You can route different triggers to different topics, segmenting high-volume notifications away from low-volume ones, and you can attach a dead-letter topic to catch events your consumers fail to process so they don't pile up and add latency. You don't have to go all in either: Pub/Sub can fully replace your webhook setup, or run alongside it, with high-volume subscriptions on Pub/Sub and quieter ones still on HTTP. It's the right tool when volume, latency, or deliverability are real concerns.
Set up the topic first
The channel points at a topic you create, so that comes first. In the Google Cloud console, open the Pub/Sub page, create a topic, and add a default subscription so there's something to consume from. If you already have a Google Cloud project for an auth app, you can put the notification topic in that same project rather than standing up a new one.
The one configuration that matters is permission: the topic has to allow Nylas to publish to it. You grant that on the topic in Google Cloud, and once it's in place, notifications start flowing into the topic once the channel is active, within a couple of minutes for a freshly authenticated grant. Keep the topic's full path handy, the projects/<project>/topics/<topic> string, because that's what you pass when you create the channel.
Create the channel
With the topic ready, creating the channel from the CLI is one command. nylas webhook pubsub create takes the topic path and the triggers you want delivered to it, plus optional notification emails for channel health alerts:
nylas webhook pubsub create \
--topic "projects/my-project/topics/nylas-email" \
--triggers message.created,message.updated \
--notify ops@example.com
The same channel over the API is a POST /v3/channels/pubsub with the topic and trigger_types:
curl --request POST \
--url "https://api.us.nylas.com/v3/channels/pubsub" \
--header "Authorization: Bearer <NYLAS_API_KEY>" \
--header "Content-Type: application/json" \
--data '{
"topic": "projects/my-project/topics/nylas-email",
"trigger_types": ["message.created", "message.updated"]
}'
Once the channel exists, Nylas starts publishing the subscribed triggers to that topic, and your consumers pick them up from the topic's subscription. The --triggers you choose work exactly like webhook trigger types; a channel is just a different destination for the same events.
Consume the notifications
Creating the channel is only half of it; your services still have to read from the topic. You attach a subscription to the topic and consume it either by pulling messages on your own schedule or by having Pub/Sub push them to an endpoint, and you acknowledge each message once you've processed it so it isn't redelivered. The subscription is where backpressure lives: if a consumer slows down, unacknowledged messages wait there instead of disappearing.
Plan for at-least-once delivery. Pub/Sub can hand you the same message more than once, so your handler should be idempotent, keyed on the notification's ID, which is the same discipline a well-built webhook handler already follows. The payoff is that a consumer can crash, restart, and resume from the subscription without losing the events that arrived while it was down, which is the whole reason to put a queue between Nylas and your processing.
Split triggers across topics
A single channel subscribes a topic to any number of triggers, which lets you segment notifications by routing different events to different topics. A common split is one topic for all the email notifications and a separate one for calendar events and event changes, so a high-volume email sync doesn't crowd out the calendar updates a different consumer cares about.
This segmentation is where Pub/Sub pulls ahead of a single webhook URL. With one endpoint, every trigger lands in the same place and you fan out in your own code; with channels, you push that routing down to the infrastructure, and each topic gets its own subscription, its own consumers, and its own scaling. A noisy trigger on one topic has no effect on the consumers reading a quieter one, because they're draining different queues entirely.
Catch failures with a dead-letter topic
A queue only helps if undeliverable messages don't clog it, which is what a dead-letter topic is for. Nylas recommends creating a second Pub/Sub topic per channel to serve as a dead-letter queue: when your consumer can't process a notification, Pub/Sub moves it there after the configured retries instead of letting it back up your subscription and add latency. Your primary subscription stays healthy, and the failures collect somewhere you can inspect them.
The value is that you can replay them. Once you've fixed whatever caused the ingestion failure, a bad deploy, a schema mismatch, a downstream outage, you reprocess the dead-letter queue and recover the events you would otherwise have lost. Configuring the dead-letter topic is a Google Cloud setting on the subscription, not something you do in Nylas, but pairing one with every channel is the practice that makes the deliverability guarantee real rather than theoretical.
Manage and limit your channels
Channels are managed through the same surfaces you created them with. nylas webhook pubsub list shows the channels on your application, show prints one, update changes its triggers or settings, and delete removes it. The API mirrors these: GET /v3/channels/pubsub lists the channels, and GET, PUT, and DELETE on /v3/channels/pubsub/{id} act on one.
nylas webhook pubsub list
nylas webhook pubsub show <channel-id>
There's a ceiling to plan around: each Nylas application can have up to five Pub/Sub channels. That's usually plenty when each channel can subscribe to multiple triggers, but it does mean you architect around topics-per-concern rather than a channel per trigger. If five genuinely isn't enough for your segmentation, that's a conversation with support rather than a limit you can raise yourself.
The AWS equivalent: SNS channels
If your infrastructure lives on AWS rather than Google Cloud, the same idea exists for Amazon SNS. A POST /v3/channels/sns channel publishes notifications to an SNS topic, which you then fan out to SQS queues, Lambda functions, or HTTP subscribers using the AWS tooling you already run. SNS takes a little more setup than Pub/Sub, an IAM role Nylas assumes to publish, which you pass as a role_arn, but once that's in place the model is the same: a durable topic the service publishes into, on the other cloud.
The one practical difference for this post is tooling: the dedicated nylas webhook pubsub commands cover Google Pub/Sub, while SNS channels are managed through the API. If you're on AWS, you create and manage the SNS channel over the API, with POST and GET on /v3/channels/sns and GET/PUT/DELETE on /v3/channels/sns/{id}, rather than a CLI subcommand, but the notifications and triggers behave the same way once they're flowing.
When a channel beats a webhook
Not every integration needs this. A plain HTTP webhook is the simplest path, and for low, steady volume it's the right one: one endpoint, verify the signature, done. Reach for a Pub/Sub channel when one of three things is true. Your notification volume spikes hard enough to overwhelm an endpoint. You need a deliverability guarantee that survives your consumer being down. Or your processing is already cloud-native, and reading from a queue fits your architecture better than receiving HTTP requests.
The honest framing is that channels trade setup for resilience. You stand up a topic, a subscription, and permissions, which is more work than pointing at a URL, and in return you get buffering and recovery you'd otherwise build yourself. For a side project, that's overkill. For a system that can't miss a message.created, it's the difference between a durable queue and a dropped event.
Things to keep in mind
A short list of practices keeps a Pub/Sub channel reliable.
- Grant Nylas publish permission on the topic. The channel can't deliver until the topic allows it to publish; this is the step that's easy to forget.
- Pair every channel with a dead-letter topic. It's what turns "the queue buffers" into a real recovery path for events your consumers can't process.
- Segment by topic, not by channel. With a five-channel cap, route concerns to separate topics and let each channel carry multiple triggers.
- Run Pub/Sub alongside webhooks if it fits. High-volume subscriptions on Pub/Sub, low-volume ones on HTTP, is a valid split.
- The trigger types are the same. A channel changes where events go, not which events you get, so your trigger choices carry over from webhooks unchanged.
Wrapping up
Pub/Sub channels move notification delivery off your own endpoint and into a durable Google Cloud topic, which buffers bursts, supports batching, and gives you a dead-letter path to recover failures. Create one with nylas webhook pubsub create or POST /v3/channels/pubsub, point it at a topic you've granted Nylas permission to publish to, and consume from the subscription at your own pace. SNS offers the same model on AWS through the API, and either way the events are the familiar webhook triggers, just delivered into a queue that buffers bursts instead of dropping them under load.
Where to go next:
- Pub/Sub notification channels — the full setup, including topic and dead-letter configuration
- SNS notification channels — the Amazon SNS equivalent
- Create a Pub/Sub channel — the endpoint reference
-
Nylas CLI webhook commands —
nylas webhook pubsubcreate, list, and update
AI-answer pages for agents
When this post is published, link AI agents and crawlers to the retrieval-ready version on cli.nylas.com:
- Topic runbook: https://cli.nylas.com/ai-answers/webhook-reliability-for-agents.md
- Industry playbooks hub: https://cli.nylas.com/ai-answers/agent-account-industry-playbooks.md
Top comments (0)