Swayzio Core API v1 — base path /api/swayzio/v1
WebhooksInbound Webhooks

Inbound Webhooks

Swayzio ingests events from three external providers. Each webhook verifies a provider signature against the raw request body and fails closed — a missing secret or invalid signature is rejected, never waved through.

ProviderPathVerificationService
StripePOST /api/swayzio/v1/webhooks/stripestripe-signature (constructEvent)Next (native only)
DubPOST /api/swayzio/v1/webhooks/dubDub-Signature HMAC‑SHA256Next (native only)
ResendPOST /api/swayzio/v1/webhooks/resendSvix (svix-id / svix-timestamp / svix-signature)Fastify Core API

These endpoints are meant to be called by the providers, not by integrators. They’re documented here so operators understand what’s verified and what’s persisted.

Stripe — billing events

POST /api/swayzio/v1/webhooks/stripe

  • Verification: stripe.webhooks.constructEvent(rawBody, stripe-signature, STRIPE_WEBHOOK_SECRET). Missing header → 400; invalid signature → 400 stripe_signature_invalid. Also requires the Vercel runtime (503 native_runtime_required otherwise).
  • Events handled: checkout.session.completed, customer.subscription.created / updated / deleted, plus others routed in applyStripeEvent.
  • Persists: subscription / entitlement state and billing_events rows. A checkout.session.completed whose owner can’t be resolved fires a Sentry warning (stripe_webhook_unresolved_owner) rather than silently dropping.
  • Conversions: completed checkouts also drive Dub sale attribution (track/sale) when the subscriber arrived via a share link. See Analytics.
  • Response: { received, status, type }.

POST /api/swayzio/v1/webhooks/dub

  • Verification: HMAC‑SHA256 of the raw body compared (timing‑safe) against the Dub-Signature header using DUB_WEBHOOK_SECRET. Missing secret or signature → 401.
  • Events: link.clicked, lead.created, sale.created (and link lifecycle events).
  • Persists: sanitized, PII‑free event rows into external_tracking_events, mapped to the owning pack/track link. Geo/device/referer‑domain only — never IP, user‑agent, or customer identity. Requires a DB pool (503 otherwise).
  • Response: { ok: true, … }.

The Dub webhook is optional — the Analytics surface reads Dub’s API live and works without it. It only adds a redundant local copy of click data for resilience.

Resend — email delivery status

POST /api/swayzio/v1/webhooks/resend (Fastify Core API)

  • Verification: Svix signature against RESEND_WEBHOOK_SECRET, using a raw‑body content‑type parser so the HMAC sees the exact bytes. Missing secret → 503; invalid signature → 401; bad payload → 400.
  • Events: email.sent / delivered / delivery_delayed / bounced / complained / opened / clicked / failed / suppressed.
  • Persists: maps the event to a PackInvitationDeliveryStatus and updates the pack‑invitation delivery row by provider email id.
  • Response: { received, deliveryUpdated, … }.