Test your receiver
- Configure a final public HTTPS URL that accepts POST directly, without a
redirect. For local development, use a public HTTPS tunnel;
localhost, private IPs and internal DNS destinations are blocked in both modes. - Subscribe to the event for your sandbox payment or payout flow and securely save the raw signing secret returned during setup.
- Run the flow using Test Mode credentials. Sandbox events make real HTTP requests to your configured endpoint, so use a receiver that cannot trigger production fulfillment during testing.
- Verify the signature over the raw body, then durably record the event before acknowledging it with a 2xx response.
- Make your handler idempotent using
X-HostPay-Delivery-IdorIdempotency-Key. The same delivery ID is reused on retries. Do not deduplicate solely on a transaction ID: different state-change events can refer to the same transaction.
Inspect delivery status
The dashboard’s Webhooks → Delivery Log shows the latest 50 delivery records for the selected application, not a separate row for every HTTP attempt. Refresh to update the snapshot. Select an event row for processing time, next retry, last error, response code, latency and payload.pending: waiting for the worker.processing: claimed by a worker.processing_started_atcan be null on legacy records; clients must accept a nullable timestamp.failed/ Retry pending: an attempt failed; checknext_attempt_at.delivered/ Success: the endpoint returned 2xx. This does not prove that your application’s downstream processing finished.dead/ Stopped: no more automatic retries. This can follow attempt exhaustion or a missing/inactive subscription.
Diagnose failures
- Signing failed: no HTTP request was sent for that attempt. Check the active subscription secret and ask the operator to verify encryption configuration. Do not disable signature verification. Rotate only when necessary and update your receiver with the new raw secret.
- URL blocked: use a public destination, remove URL credentials/fragments, and use HTTPS for live events. A mixed public/private DNS answer is rejected.
- Redirect blocked: configure the final URL, including its required trailing slash. A 301, 302, 307 or 308 response is not followed.
- Connection failed: check DNS, endpoint availability and TLS. A timeout may happen after your receiver accepted a request; always handle duplicates.
- Pending with zero attempts: ask the operator to check worker logs and the read-only schema preflight. For API release 0.12.0 and later, also confirm Celery Beat is scheduling the 30-second delivery sweep. This is not proof that your receiver rejected it.