docs
IntegrateWebhooks

Setting up an endpoint

Add a webhook endpoint in the dashboard, pick the events you care about, and store the signing secret on your server.

A webhook endpoint is a URL on your server that XPay POSTs JSON events to whenever something interesting happens: a Checkout Session completes, a Refund lands, a Customer is created. You add it once in the dashboard, pick the events you want, and copy the signing secret onto your server so you can verify every payload before acting on it.

Webhook endpoints are managed only in the dashboard, not over the API. The same is true for the signing secret. Do everything below from app.xpay.app.

Open the Webhooks page

In the dashboard, open the Developers page and click the Webhooks tab. The list shows every endpoint configured for the current mode.

Test mode and live mode keep separate endpoint lists. Use the Test / Live switch at the bottom of the sidebar to flip between them. An endpoint created in test mode does not exist in live mode, and vice versa.

Create an endpoint

Click Add endpoint

Top-right of the Webhooks tab. If the list is empty, the same action is on the empty state as Create webhook endpoint.

A side panel opens with two required fields: the URL and the events.

Enter the endpoint URL

Type a fully qualified URL into Endpoint URL. The form validates the shape, not reachability. The URL must be one your server actually serves.

A few rules:

  • Include the protocol (https://...). The form rejects values that don't parse as URLs.
  • Use HTTPS in production. Plain HTTP is accepted by the form, but a reachable HTTPS URL with a valid certificate is what you want once you ship. http://localhost:... is fine in test mode while you build (see Local development for tunnels).
  • One endpoint per URL. If you need to fan out to two systems, create two endpoints with different URLs, or have one handler forward.

Pick events to listen to

Below the URL field is Select events to listen to. The picker is split into two sections:

  • A Recommended section at the top, surfacing the high-signal events most integrations subscribe to first (Checkout Session completion, refund lifecycle, customer lifecycle).
  • An Advanced collapsible below it that holds the rest, grouped by resource.

Click any group to expand it and tick individual events. Each group has an in-group Select all checkbox if you want every event in that group at once. The same resource can appear in both sections when its events span both buckets — Checkout Sessions, for example, shows checkout.session.completed under Recommended and the rest of its lifecycle under Advanced.

You must pick at least one. A common starting set:

  • checkout.session.completed for the lifecycle of the session you created.
  • refund.created and refund.failed to track reversals.
  • customer.created, customer.updated, customer.deleted to keep your customer table in sync.

Add charge.succeeded / charge.failed (under Advanced → Charges) if your data model needs to react at the charge level. Subscribe only to the events your handler actually reads — every subscription costs a delivery, a retry budget, and a signature verification on your server.

For the full list, see Event reference.

Click Add endpoint to save

XPay creates the endpoint and immediately surfaces a Webhook signing secret dialog with a whsec_* value.

Copy it now. The dashboard will not show it again. If you lose it, your only path is to delete the endpoint and create a new one.

Store it on the server that runs your handler, typically as an environment variable like XPAY_WEBHOOK_SECRET loaded once at boot. Click Done to close the dialog and return to the list.

The signing secret

Every endpoint has its own whsec_* secret. XPay signs every event delivered to that endpoint with HMAC-SHA256 using this secret, and your handler uses the same secret to confirm that an incoming event really came from XPay.

Three rules:

  • Never put the secret in client code. It belongs on the server. A leaked secret lets anyone forge events into your handler.
  • Keep test and live secrets separate. Each endpoint has its own. Don't reuse one environment variable for both.
  • Treat the secret as opaque. It's a random string with a whsec_ prefix. Don't parse it, don't truncate it.

If you suspect a secret leaked, delete the endpoint and recreate it. The dashboard does not surface a rotate-secret action today.

Test mode and live mode endpoints

Test and live are isolated environments with their own data and their own webhook endpoints. The mode switch decides which list the dashboard shows; the API key prefix (sk_test_* vs sk_live_*) decides which list events fire against.

You'll typically want at least two endpoints:

  • A test endpoint pointing at a tunnel into your dev box, or at a staging server.
  • A live endpoint pointing at the URL your production server actually serves.

Each gets its own signing secret. Build and verify against the test endpoint first, then add the live endpoint right before you flip your account into live mode.

Manage your endpoints

The actions menu on each row (the button at the right) has three options.

ActionWhat it does
Edit webhookChange the URL, change the subscribed events, or both. The signing secret stays the same, so your verification code keeps working.
Disable webhook / Enable webhookStop or resume deliveries without losing the configuration. Useful while debugging a handler.
Delete webhookPermanently removes the endpoint. The signing secret becomes invalid. Pending deliveries to that endpoint stop.

Disabled endpoints stay in the list with a Disabled badge. They receive no events and run no retries while disabled. Re-enabling resumes new deliveries; events that fired during the disabled window are not back-filled.

Where to next

On this page