user.created the moment someone signs up. This guide turns that into a Courier profile and a welcome message.
What you will build
Prerequisites
- A Clerk application, and somewhere to host an HTTPS route
- A published to send
Why this needs a route in your app
Courier has an that many sources can post to directly. Clerk is not one of them, for three reasons worth knowing before you start. The field names do not line up. Courier readsevent and userId from a payload. Clerk sends type and data.id. Posted straight through, the event arrives named custom with no recipient attached.
The user does not exist yet. An inbound event only starts a journey when its userId matches an existing Courier user. On user.created there is nothing to match, so the profile has to be written first.
Courier does not verify Clerk’s signature. Courier’s inbound URL is its own credential and accepts any JSON sent to it. Verify the signature in your own endpoint before forwarding the event, because that is what stops a forged sign-up.
So the shape is Clerk to your route to Courier. Your route is where verification happens and where the profile is created.
Set it up
1
Install the packages
.env.local
2
Write the route handler
verifyWebhook checks the Svix signature Clerk sends and throws when it fails. Verify before you read anything out of the body.app/api/clerk/route.ts
id becomes the Courier user_id. One identifier across both systems means every later send addresses the user without a lookup table.A non-matching event returns 200. Clerk retries anything that is not a success, so returning an error for an event you deliberately ignore creates a retry loop.3
Point Clerk at the route
In the Clerk dashboard, under Configure → Webhooks, add an endpoint for your route’s public URL and subscribe it to
user.created.Copy the signing secret Clerk shows into CLERK_WEBHOOK_SIGNING_SECRET.Clerk needs a public HTTPS URL, so
localhost will not receive events. Use a tunnel such as ngrok while developing, and Clerk’s Testing tab to replay an event without signing up each time.Verify
1
Send a test event
Use the Testing tab in Clerk’s webhook settings to send a
user.created event. Your route should answer 200.2
Check the profile exists
Read it back with , using the Clerk user id. The email you expect should be on it.
3
Check the message went out
Open and confirm the send. A
SENT status means the provider accepted it, which is what a healthy send looks like.Adapt it for other events
The same handler shape covers the rest of Clerk’s catalog. Switch onevt.type and keep one route:
That last row is the one to reach for in a B2B app. Clerk organizations and Courier tenants model the same thing, so keeping them in step means branding and preferences follow the user automatically.