# Test your endpoint

> Send test events, replay deliveries and develop on your own computer.

Source: https://app.getoatmilk.com/docs/webhooks/testing

You don't have to wait for an invoice to be paid to know your endpoint works.

## Send a test event

In **Developers › Webhooks**, open an endpoint and choose **Send a test event**. Or ask the API, optionally with a catalog event to get a realistic sample:

```bash
curl https://app.getoatmilk.com/api/v1/accounting/webhooks.test \
  -H "Authorization: Bearer $OATMILK_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "endpointId": "5d4c3b2a-1f0e-4d9c-8b7a-6e5f4d3c2b1a",
  "eventType": "invoice.paid"
}'
```

Test deliveries are signed like real ones and appear in the delivery log, but they never count towards turning an endpoint off.

## Watch the delivery log

Every delivery, with its payload, your server's status code, how long it took and a short excerpt of its answer, is in the delivery log in Developers › Webhooks and in `webhooks.deliveries.list`. Delivery rates and response times over time are in **Developers › Usage** and `webhooks.deliveries.stats`. Retry a failed delivery from there, or with `webhooks.deliveries.retry`, once your server is fixed.

```bash
curl -G https://app.getoatmilk.com/api/v1/accounting/webhooks.deliveries.list \
  -H "Authorization: Bearer $OATMILK_API_KEY" \
  --data-urlencode 'status=failed' \
  --data-urlencode 'limit=20'
```

## Develop on your own computer

While you develop, an endpoint can point at `http://localhost`. To receive real deliveries from staging, expose your local server with a tunnel such as `ngrok` or `cloudflared` and add its `https://` address as an endpoint.

To test your signature check without Oatmilk at all, sign a sample with your own secret in the [signature playground](https://app.getoatmilk.com/docs/webhooks/signatures.md#try-it-here) and send it with the `curl` command it gives you. The timestamp is current, so your tolerance check passes.

## A checklist before going live

- The endpoint answers `2xx` within a few seconds, before slow work.
- It verifies `Oatmilk-Signature` against the raw body and refuses anything older than 300 seconds.
- It stores each event `id` and skips duplicates.
- It reads the record from the API when the order of events matters.
- It answers `200` to event types it doesn't recognise.
- The signing secret is stored like a password, and rotating it is a documented step.
