WebhooksTesting webhooks

Testing webhooks

Local development with a tunnel

Your laptop isn’t reachable from api.soxara.com. Use a tunnel to expose your local server.

ngrok

# install: brew install ngrok
ngrok http 3000
# → forwards https://abc-123.ngrok.app → http://localhost:3000

Cloudflare Tunnel (free, no sign-in needed for quick try)

brew install cloudflared
cloudflared tunnel --url http://localhost:3000

Take the public URL and register it as your test webhook endpoint, using an sxm_test_ key:

curl -X POST https://api.soxara.com/v1/api/webhook-endpoints \
  -H "Authorization: Bearer $SOXARA_TEST_KEY" \
  -d '{
    "url": "https://abc-123.ngrok.app/webhooks/soxara",
    "events": ["payment.completed", "payment.failed"]
  }'

Now any test payment that settles fires a webhook to your laptop.

Redelivering a failed delivery

Soxara keeps a per-endpoint delivery log (Developers → Webhooks → an endpoint → Deliveries in the dashboard). A delivery that ended failed or dead_letter (after exhausting the 7-attempt retry schedule — see Overview) can be forced back to pending for one more try — “Redeliver” next to that row.

Useful for:

  • Retrying a real delivery your handler dropped because it was down at the time
  • Confirming a fix to your handler against an event it previously failed on

This redelivers the same event — same Soxara-Delivery id — so your handler must dedupe on it, the same as any retry.

There’s no bulk “replay all events since a date” tool today — this is per-delivery, from the endpoint’s own log.

Triggering specific events in test mode

Use an sxm_test_ key throughout. The reliable way to fire a payment event on demand is simulate — it runs a test payment link through the exact same fan-out as production, so you get a real webhook without real money:

curl -X POST $SOXARA_BASE/v1/api/payment-links/{id}/simulate \
  -H "Authorization: Bearer $SOXARA_TEST_KEY" \
  -d '{"method": "card", "outcome": "completed"}'
To triggerDo this
payment.completedsimulate with "outcome": "completed"
payment.failedsimulate with "outcome": "failed"
payroll_run.completed / .partial / .failedCreate a test-key payroll run and approve it — a test mandate/run resolves immediately rather than waiting on a real disbursement
catalog.publishedPublish a catalog version against your test merchant
inventory.low_stockRecord an inventory movement that takes an item’s quantity at or below its low_stock_threshold

Inspecting webhook payloads without a server

If you just want to see what Soxara sends without writing a handler yet:

  • webhook.site gives you a free unique URL that captures whatever you POST to it. Register that as a test endpoint, fire some test events, inspect the JSON.
  • Beeceptor is similar.

Don’t use either for live mode — they don’t verify signatures.

Signature verification in tests

Test deliveries are signed the same way live deliveries are. Don’t disable signature verification in your test environment. That’s how you find verification bugs before they bite you in production.

Use your test endpoint’s signing secret (different from your live secret) when verifying test deliveries. Store both in your environment:

SOXARA_TEST_WEBHOOK_SECRET=KciRV7ED9...   # the secret from your test endpoint's registration
SOXARA_LIVE_WEBHOOK_SECRET=Ab3xQp1Ln...   # the secret from your live endpoint's registration

There’s no fixed prefix on the secret (it’s 43 random base64url characters) — it’s whatever came back in the secret field when you registered the endpoint.

In your handler, pick the right secret based on which endpoint received the request (or based on data.payment.environment — "test" or "live" — in the payload, after a one-time parse-then-verify dance — but the URL-based pick is simpler).