PPactDocs
Developers

Inbound webhooks — connect a provider to Pact

Every provider webhook Pact receives — the canonical URL, the events to subscribe, the signature scheme, and where the signing secret lives in Pact admin.

This page is the opposite direction from webhook subscriptions: here a third-party provider (Resend, Stripe, Twilio, Slack, and others) POSTs into Pact when something happens on their side — an email bounces, a subscription renews, an envelope is signed.

Every inbound endpoint is signature-verified. Pact rejects any request whose signature doesn't match the secret you configured, so a forged event can't poison your data. You configure each provider once in Admin → Integrations, paste the canonical URL below into the provider's dashboard, and paste the provider's signing secret back into the Configure wizard — never into a server environment variable.

Secrets live in the admin UI, encrypted per workspace

Every signing secret is stored encrypted in your tenant's credential store and resolved per request. You never set a webhook secret as a server environment variable — paste it into the provider's Configure wizard under Admin → Integrations.

Canonical URLs

Replace {tenant_id} with your workspace tenant identifier — the per-provider admin page shows the fully-substituted URL with a copy button.

ProviderInbound URLMethodSignature schemeHeaderSigning-secret field (Pact admin)
Resendhttps://api.pact.place/v1/webhooks/resendPOSTSvix HMAC-SHA256 (base64)svix-signature (+ svix-id, svix-timestamp)Resend → webhook_secret
Stripehttps://api.pact.place/v1/billing/stripe/webhookPOSTStripe HMAC-SHA256Stripe-SignatureStripe → webhook_secret
Twiliohttps://api.pact.place/v1/twilio/webhook/{tenant_id}POSTHMAC-SHA1 over URL + sorted paramsX-Twilio-SignatureTwilio → auth_token
Slackhttps://api.pact.place/v1/integrations/slack/eventsPOSTHMAC-SHA256 (v0=) + 5-min replay windowX-Slack-Signature (+ X-Slack-Request-Timestamp)Slack → signing_secret
Slack (slash commands)https://api.pact.place/v1/integrations/slack/commandsPOSTSame as Slack eventsX-Slack-SignatureSlack → signing_secret
Postmarkhttps://api.pact.place/v1/webhooks/postmark/{tenant_id}POSTHTTP Basic AuthAuthorization: BasicPostmark → basic_auth
DocuSignhttps://api.pact.place/v1/esignature/webhook/docusign/{tenant_id}POSTConnect HMAC-SHA256X-DocuSign-Signature-1DocuSign → webhook_secret
Zoomhttps://api.pact.place/v1/integrations/zoom/webhook?tenant={tenant_id}POSTHMAC-SHA256 with v0= prefixx-zm-signature (+ x-zm-request-timestamp)Zoom → webhook_secret
Google Calendarhttps://api.pact.place/v1/calendar/webhook/googlePOSTChannel token matchX-Goog-Channel-Token (+ X-Goog-Channel-ID)Minted by Pact at channel creation
Microsoft Calendarhttps://api.pact.place/v1/calendar/webhook/microsoftPOSTclientState matchclientState (in body)Minted by Pact at subscription creation

Use the per-provider admin page, not this table, for the live URL

The admin page for each provider substitutes your real tenant_id and gives you a one-click copy button. This table is the reference for what each endpoint expects — the admin page is the source of the exact string to paste.

How verification works

Each handler recomputes the signature over the raw request body (and, where the scheme requires it, the timestamp and URL) using the secret you stored, then compares it in constant time. A mismatch returns 401 and writes nothing — the event is dropped, and the rejection is recorded in the audit log. A valid event is processed exactly once; replays are de-duplicated.

  • Resend / Stripe / Postmark carry the tenant in the URL path (or resolve it from the verified payload), so the right workspace's secret is used.
  • Twilio / DocuSign embed {tenant_id} in the path.
  • Slack resolves the workspace from the verified payload, then checks the signature against that workspace's signing_secret.
  • Zoom takes the tenant as a ?tenant= query param and verifies against that tenant's webhook_secret.
  • Google / Microsoft Calendar match the channel token / clientState Pact minted when it created the notification channel — a leaked token is the only credential at risk, and it's per-channel and short-lived.

Setting one up

  1. 1

    Open the provider in Pact

    Go to Admin → Integrations and pick the provider. Each provider page (or its Configure wizard) shows the canonical inbound URL with a copy button.

  2. 2

    Register the URL with the provider

    Paste the URL into the provider's dashboard and subscribe to the events listed on the provider page. For email providers, bounces and complaints auto-suppress the address.

  3. 3

    Paste the signing secret back into Pact

    Copy the provider's signing secret (Resend/Stripe show a whsec_… value) and paste it into the Configure wizard's signing-secret field. It's encrypted at rest.

  4. 4

    Confirm events arrive

    Trigger a test event from the provider (or wait for live traffic). The provider's admin page in Pact shows incoming events in its Activity panel once verification succeeds.

What's next?