Skip to main content
Webhooks allow your application to receive real-time notifications when events occur in your Paygentic account. When enabled, we’ll send HTTP POST requests to your configured endpoints whenever relevant events happen, such as customer creation, subscription changes, and more.

Quickstart guide

Get up and running with webhooks in just a few minutes:
1

Enable webhooks

Navigate to the Developer > Webhooks section in your Paygentic dashboard and turn on Enable Webhooks. You can also enable webhooks through the API.
2

Configure your endpoint

Once enabled, select Open Webhook Portal under “Manage Webhook Endpoints” to open the webhook management portal, where you can:
  • Add your webhook endpoint URL (e.g., https://your-domain.com/webhooks/paygentic)
  • Select which event types to subscribe to
  • View the endpoint’s signing secret. Each endpoint has its own secret
3

Test your endpoint

Use tools like Hookdeck or ngrok to test webhooks during development without deploying to production.
4

Verify and process events

Setting up webhooks

Enabling webhooks

  1. Access the dashboard: Log in to your Paygentic account and navigate to Developer > Webhooks
  2. Enable webhooks: Turn on the Enable Webhooks switch
  3. Access management portal: Under “Manage Webhook Endpoints”, select Open Webhook Portal

Configuring endpoints

In the webhook management portal, you can:
  • Add endpoints: Specify the URL where you want to receive webhook events
  • Select event types: Select which events you want to subscribe to
  • View logs: Monitor webhook deliveries and debug any issues
  • Retrieve signing secrets: Each endpoint has its own signing secret for verification
Remember to keep your webhook signing secret secure and never commit it to version control. Store it in environment variables or a secure secrets management system.

Best practices

  • Use HTTPS endpoints only (HTTP is not supported for security reasons)
  • Implement webhook processing asynchronously to respond quickly
  • Handle duplicate events: dedupe on svix-id, and on the resource ID for events that matter (see Idempotency)
  • Disable CSRF protection for your webhook endpoint
  • Respond with a 2xx status code within 15 seconds

Managing webhooks through the API

Use the API to check whether delivery is on, to pause and resume it, and to get a portal link without a dashboard login. Endpoint URLs, event subscriptions, and signing secrets live in the webhook management portal — the API doesn’t change them. Your API key has the permissions of the user it belongs to. Enabling, updating, and disabling webhooks need write access to webhooks; reading the configuration and getting a portal link need read access. The user who creates a merchant account has both.
API Reference: See Get, Enable, Update, Disable, and Get Portal Access for complete request and response schemas.

Reading the configuration

The response has the same shape as the enable response, and enabled tells you whether delivery is on. If webhooks were never enabled, the response is 404 Not Found.

Pausing and resuming delivery

Set enabled to false to pause delivery, and to true to resume it. It’s the only field, and it’s required.
Returns 200 OK with the configuration. DELETE /v0/webhooks has the same effect as PATCH with { "enabled": false } and returns 204 No Content. Neither call deletes anything — your endpoints, their event subscriptions, and their signing secrets stay in the portal.
Paygentic doesn’t keep events while delivery is paused. Events that occur while enabled is false are never sent, even after you resume.
Response:
The link opens the webhook management portal for your account without a login, and it expires one hour after it’s issued, at expiresAt. Request a new link each time you need one. Delivery must be enabled, or the response is 404 Not Found.
Treat the link as a secret. Until it expires, anyone who holds it can add endpoints and read their signing secrets.

Security and verification

Webhook security is critical to ensure that the events you receive are legitimate and have not been tampered with. Paygentic signs all webhooks with HMAC-SHA256.

Required headers

Every webhook request includes three important headers:
  • svix-id: Unique identifier for the webhook message (use for idempotency)
  • svix-timestamp: Unix timestamp when the webhook was sent
  • svix-signature: Base64 encoded signature(s) for verification

Signature verification

Always verify webhook signatures in production. This prevents attackers from sending fake events to your endpoint.
Use Svix’s verification library for easy and secure webhook verification:

Verification examples

Replay attack protection

The timestamp in the svix-timestamp header protects against replay attacks. The Svix library automatically rejects webhooks with timestamps more than 5 minutes old (past or future). Ensure your server’s clock is synchronized using NTP.

Handling webhooks

Response requirements

  • Status code: Return a 2xx status code (200-299) to indicate successful receipt
  • Timeout: Respond within 15 seconds or the delivery will be considered failed
  • Body: The response body is ignored - a simple “OK” or empty response is fine

Processing best practices

Idempotency

Your endpoint can receive the same event more than once. A retry of one message keeps its svix-id, so dedupe on svix-id first:
Some events can also arrive as separate messages with different svix-id values, for example invoice.issued.v0. For events that change state in your system, also dedupe on the resource ID in data, such as invoiceId or subscriptionId.

Delivery guarantees

Webhooks tell you that something changed — they aren’t a complete record. Paygentic doesn’t retry an event that it fails to hand to the delivery service, and it doesn’t send events that occur while delivery is paused. When your system needs exact state, such as whether an invoice is paid, read the resource from the API.

CSRF protection

Disable CSRF protection for webhook endpoints. Webhooks are verified using signatures, not CSRF tokens.

Retry policy and failure handling

Automatic retry schedule

If your endpoint does not respond successfully, the delivery is retried with exponential backoff:

Failure scenarios

A webhook delivery is considered failed if:
  • Your endpoint returns a non-2xx status code
  • Your endpoint does not respond within 15 seconds
  • The endpoint is unreachable (connection error)
  • Your endpoint returns a 3xx redirect (not followed)

Endpoint disabling

If an endpoint fails continuously for 5 days, it is automatically disabled. Paygentic does not send a webhook event when this happens, so check the delivery logs in the webhook management portal. You can re-enable the endpoint from the portal.

Manual recovery

You can manually retry failed webhooks through the webhook management portal:
  • Individual retry: Retry a specific failed message
  • Bulk recovery: Replay all failed messages from a specific date
  • View logs: Inspect delivery attempts and error messages

Event types reference

Paygentic currently supports the following webhook event types:
Triggered when a new customer is successfully created.
Triggered when customer creation fails.
error.code is the name of the error type, for example ValidationError. Use error.message for display, and do not rely on a fixed list of codes.
Triggered when a customer is deleted.
Triggered when a new subscription is created.
Triggered when a subscription becomes active and ready for use.This event fires when a subscription transitions to the active state, which happens:
  • Immediately upon creation for subscriptions without upfront costs
  • After successful payment of upfront costs for subscriptions that require them
  • Immediately, before payment, for a bank-transfer subscription set to activate immediately. The payload then has activatedWithoutPayment: true
Key distinction: While subscription.created.v0 fires when a subscription is first created (which may be in pending_payment state), subscription.activated.v0 fires when the subscription is ready for use. Use this event to provision access or activate features for customers.
Best practice: Listen to subscription.activated.v0 rather than subscription.created.v0 to provision access. If you must have payment first and activatedWithoutPayment is true, wait for the invoice.paid.v0 event of the subscription’s first invoice.
Triggered when a subscription is terminated. Its entitlements are canceled at the same time.
endingAt is when the subscription ends. reason is optional free text, so do not branch on its value.
Triggered when you migrate a subscription to another plan version with POST /v0/subscriptions/{id}/versionMigration. updates holds the new version. updates.versionPolicy is always pinned, and updates.effectiveAt can be null. A floating subscription that moves to a new default version at its next billing period does not send this event.
Triggered when a payment is successfully completed.
Triggered when a payment attempt fails. Includes error details from the payment processor.
This event applies only to Payment Links. Paygentic doesn’t send it when a subscription charge fails. See When an automatic charge fails.
error.code and error.message carry the same failure reason: authentication_required, card_declined, insufficient_funds, expired_card, stolen_card, lost_card, card_velocity_exceeded, do_not_honor, fraud_suspected, processing_error, incorrect_details, not_supported, account_update_required, or unknown.
Triggered when a payment session expires before the customer completes it.
Triggered when a subscription invoice is issued, including a zero-amount invoice. customerId can be null.
Paygentic delivers this event at least once, so you can receive more than one invoice.issued.v0 for the same invoice. Use invoiceId to ignore duplicates.
Triggered when an invoice transitions to PAID — covers subscription renewals, grant purchases (the grantId is included in the payload), out-of-band payments, and zero-amount invoices.
grantId is set when the invoice pays for a grant purchase, for example one made with POST /v1/entitlements/{id}/grants/purchase. Otherwise it is omitted. paymentIntentId is the payment provider’s reference for the payment, for example a Stripe PaymentIntent ID. It is omitted for out-of-band and zero-amount invoices.
grandTotal is the authoritative amount paid. subtotal and totalTax are each rounded to 2 decimal places independently, so re-adding them can land a cent off grandTotal — use grandTotal directly rather than re-summing the parts.
This event is delivered at least once. On rare retries you may receive the same invoice.paid.v0 more than once for a given invoice — dedupe on invoiceId before acting on it.
Triggered when a usage source is successfully activated and connected.
Triggered when a usage source fails to activate due to configuration or authentication issues.
Triggered when a usage source is disconnected or deactivated.
Triggered when a source event enters pending state and requires manual processing.
Triggered when a source event is successfully processed into usage events.
Triggered when a source event fails to process due to errors.
Triggered when a source event is manually rejected by a user.

Common event fields

All webhook events include these standard fields:

Code examples

Complete webhook handler

Here’s a production-ready webhook handler example:

Testing webhooks locally

For local development, use a tunneling service to expose your local server:
Then add this URL as your webhook endpoint in the webhook management portal for testing.

Additional resources

Need help?

If you encounter any issues with webhooks:
  1. Check the delivery logs in the webhook management portal for error messages
  2. Verify your endpoint is returning a 2xx status code
  3. Ensure you’re using the correct signing secret
  4. Confirm your server’s clock is synchronized (for timestamp validation)
  5. Contact support if you need additional assistance