Inbound webhooks
A tenant-scoped public route that checks the signature before anything touches real data.
Updated September 19, 2026 1 min read
A provider event can update a workflow only after its sender and destination workspace are verified. Tenant webhook routes live under src/app/api/public/[tenantSlug]/webhooks/<provider>/; use that boundary to validate the event and record a replay-safe result.
What the handler does
- Resolve the tenant from the slug. Unknown slug fails closed.
- Verify the provider signature with
timingSafeEqual. Reject the request if it does not match. - Reject replays outside a bounded time window.
- Call a canonical service (
inbound.ts,identity.ts,activities.ts, or the provider's adapter ingest function). Do not insert operational rows in the route. - Return a truthful receipt. HTTP 200 is not proof if the service returned a failure.
What the handler must not do
- Use
createPlatformServiceRoleClientfor tenant writes. UsecreateServiceRoleClient(provider.context)so every row carriestenant_id. - Log raw payloads, signatures, or tokens.
- Call a provider SDK that the existing adapter path already covers.
New providers belong as an integration adapter plus a webhook folder named for that provider. WhatsApp and HubSpot are the current examples on that generic path.