# Webhooks in the sandbox

Signed test events, delivery log and replay.


Webhook endpoints are **mode-scoped**: an endpoint created with a test key only ever receives test events, and never sees live traffic.

## Create a test endpoint

```bash
curl https://api.southbill.com/v1/webhook_endpoints \
  -H "Authorization: Bearer sk_test_…" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://your-app.example.com/webhooks","enabled_events":["*"]}'
```

The response contains the signing secret (`whsec_…`) — store it, it is shown once.

## Verify the signature

Identical to live: the signature header carries a timestamp and an HMAC-SHA256 of `timestamp.payload`. See **Webhooks → Verify signatures**.

## Events you will see in test

`checkout.session.completed`, `payment_intent.succeeded`, `payment_intent.payment_failed`, `checkout.session.refunded`, `charge.dispute.created`, `invoice.paid`, `invoice.partially_paid`, `invoice.payment_succeeded`, `invoice.installment.paid`, `invoice.installment.due`, `invoice.installment.overdue`, `subscription.created`, `subscription.updated`, `subscription.canceled`.

Payout events exist in live only.

## Delivery log & replay

```bash
curl "https://api.southbill.com/v1/webhook_endpoints/{id}/deliveries" \
  -H "Authorization: Bearer sk_test_…"
```

Failed deliveries are retried automatically with exponential backoff, exactly as in live.

## No public URL yet?

Point the endpoint at any HTTPS request bin, or tunnel your local server (for example `ngrok http 3000`) and use the public HTTPS URL.

