ZyloPaydocs

Testing webhooks

Send test events, resend deliveries, read the delivery log and receive events on a development machine.

Send a test event

A test event is a ping event sent to one endpoint at once, in a single attempt. Its data.object is the endpoint itself. Use it to check reachability and your signature code.

  • Dashboard: Developers → Webhooks → Send test. It shows the HTTP status your endpoint answered.
  • API:
const delivery = await zp.webhookEndpoints.sendTest('we_2Lk9Qm4Xz7Pv1Rt8Wb3Ns6Hd');
console.log(delivery.status, delivery.last_status_code, delivery.last_error);

The response is the delivery, with your endpoint's answer. ping is sent whatever the endpoint subscribes to, and never on its own: only on request. Your handler should answer 2xx to it and ignore it. A disabled endpoint answers 409 webhook_endpoint_disabled: enable it first.

Test real events

Test mode produces real events from real actions on the testnet:

To getDo
payment_intent.created, payment_intent.canceledCreate a payment intent, then cancel it.
terminal.created, terminal.deactivatedAdd a testnet terminal in the dashboard, then deactivate it.
payment_intent.succeeded, payment.succeededTake a payment on a testnet terminal with a testnet pass.
payment_intent.payment_failedTap a pass whose spending limit is below the amount, or a frozen pass.
payment_intent.requires_actionA payment the risk policy holds for confirmation, for example above the confirmation threshold.
refund.created, refund.succeeded, payment.refundedRefund a test payment.

See the testing guide for what a sandbox payment needs.

Resend a delivery

Resend any delivery from the log (Resend in the dashboard, or POST /v1/webhook_deliveries/{id}/retry). ZyloPay sends the same event again now, as a new delivery with one attempt, freshly signed. Use it after fixing a bug in your handler.

Replay events locally

Every event is available for 30 days from GET /v1/events. Feed them to your handler in a test, or pipe one into a local request. The body must be signed, so sign it with your test secret the way ZyloPay does:

body=$(curl -s https://zylopay-api.fly.dev/api/v1/events/evt_… -H "Authorization: Bearer $ZYLOPAY_SECRET_KEY")
t=$(date +%s)
sig=$(printf '%s' "$t.$body" | openssl dgst -sha256 -hmac "$ZYLOPAY_WEBHOOK_SECRET" -r | cut -d' ' -f1)
curl -s http://localhost:4242/ -H "ZyloPay-Signature: t=$t,v1=$sig" -H "Content-Type: application/json" --data-binary "$body"

Sign test payloads in unit tests

With the Node SDK, build a valid header for any payload and secret:

import ZyloPay from '@zylopay/node';

const payload = JSON.stringify({ id: 'evt_test', object: 'event', type: 'payment.succeeded', data: { object: {} } });
const header = ZyloPay.webhooks.generateTestHeaderString({ payload, secret: 'whsec_test_secret' });
const event = ZyloPay.webhooks.constructEvent(payload, header, 'whsec_test_secret');

On a development machine

ZyloPay only delivers to public addresses. Expose your local port with a tunnel (cloudflared tunnel --url http://localhost:4242, ngrok http 4242, or similar) and register the tunnel URL on a test endpoint. Test endpoints may use http; live endpoints must use https.

Checklist before going live

  • Signature verification on the raw body, with a 5-minute tolerance.
  • Deduplication on the event ID.
  • 2xx within 10 seconds, heavy work in a queue.
  • An alert when failing_since is set on a live endpoint.
  • A scheduled catch-up from GET /v1/events.

On this page