Skip to main content
For the complete webhook guide — setup, signature verification, event catalog, payload schemas, and best practices — see the central Webhooks documentation.

Quick Reference

import { verifyWebhook } from '@solvapay/server'

const event = verifyWebhook({
  body: rawBodyString,
  signature: request.headers.get('sv-signature')!,
  secret: process.env.SOLVAPAY_WEBHOOK_SECRET!,
})

switch (event.type) {
  case 'payment.succeeded':
    // fulfil the order
    break
  case 'purchase.created':
    // grant access
    break
  case 'purchase.cancelled':
    // revoke access
    break
}

Edge Runtimes

import { verifyWebhook } from '@solvapay/server/edge'

const event = await verifyWebhook({
  body: rawBodyString,
  signature: svSignatureHeader,
  secret: process.env.SOLVAPAY_WEBHOOK_SECRET!,
})

Fetch runtimes (Deno, Cloudflare Workers, Supabase Edge)

For web-standards fetch runtimes, @solvapay/server/fetch provides a solvapayWebhook factory that handles the full lifecycle (read body, verify signature, parse, respond):
// supabase/functions/solvapay-webhook/index.ts
import { solvapayWebhook } from '@solvapay/server/fetch'

Deno.serve(solvapayWebhook({
  onEvent: async event => {
    // Handle events here
  },
}))
The factory reads SOLVAPAY_WEBHOOK_SECRET from the environment automatically. Use verifyWebhook from @solvapay/server/edge if you need manual control over the request lifecycle. See the Supabase Edge Functions guide for the complete setup.

Event Types

SolvaPay emits 46 event types across these domains. event.type is fully typed as WebhookEventType, so your editor autocompletes every name and narrows event.data.object in a switch.
DomainExamples
Customercustomer.created, customer.updated, customer.deleted
Purchase & subscriptionpurchase.created, purchase.activated, purchase.renewed, purchase.past_due, purchase.cancellation_scheduled, purchase.cancelled, purchase.plan_changed, purchase.refunded
Payments, refunds & disputespayment.succeeded, payment.failed, payment.refunded, payment.refund_pending, payment.canceled, payment.disputed, payment.dispute_closed
Payoutspayout.paid, payout.failed
Checkoutcheckout_session.created, checkout_session.completed, checkout_session.expired
Creditscustomer.credit.topped_up, customer.credit.debited, customer.credit.low_balance, customer.credit.exhausted, customer.credit.granted, customer.credit.adjusted
Usage & meteringusage.charged, usage.recorded, usage.reset
Catalogproduct.created/updated/archived, plan.created/updated/archived
See the central Webhooks documentation for the full table and per-event payload schemas.

Subscribing to specific events

Endpoints receive all events by default. To receive only a subset, set enabledEvents when creating/updating the endpoint (empty = all), or choose Selected events in the Console. See Choosing which events to receive.

Side effects on Customer and Transaction records

Two SolvaPay-internal webhook handlers update derived data you may rely on:
  • Card mirror on payment_intent.succeeded. When a payment succeeds, SolvaPay mirrors the card brand, last4, expMonth, and expYear onto the Customer record. GET /v1/sdk/payment-method?customerRef=… reads from this mirror, so the SDK’s usePaymentMethod hook and CurrentPlanCard never round-trip to Stripe. The mirror is updated whenever a new successful payment lands, so the “payment method on file” always reflects the last working card.
  • Refund FX normalization. For refunds against transactions with a non-unity exchange rate (e.g. EUR → USD), the refund record now stores both the original-currency amount and the USD equivalent computed from the source transaction’s stored exchangeRate. This keeps credit balances and revenue reports consistent after cross-currency refunds.
Both behaviors are idempotent and safe to replay. See Webhooks documentation for full payload schemas and integration examples.