Troubleshooting
Start with the delivery history under Online Payments in the portal. It shows the response code your endpoint returned for the ten most recent attempts. This usually identifies the problem on its own.
By response code
Section titled “By response code”| What you see | Cause | Fix |
|---|---|---|
401 or 403 | Signature check failing, or the endpoint rejecting us | Verify against the raw body, confirm the secret matches the one in the portal, and accept any matching v1= value during a rotation |
404 | URL no longer exists | Update the endpoint in the portal. We do not follow redirects |
3xx | Endpoint redirects | Register the final URL. A redirect counts as a failure |
400 and other 4xx | Your handler rejected the payload | Treated as permanent and not retried. Check the code before returning 4xx |
5xx | Your handler errored | Retried on the schedule |
| Timeout | Handler took longer than 5 seconds | Queue the event and return 2xx first |
| TLS error | Handshake failed | Serve a valid certificate over TLS 1.2 or 1.3. Older versions are refused |
| Connection error | Host unreachable | The endpoint must resolve to a public address on port 443 |
Nothing arrives at all
Section titled “Nothing arrives at all”Work through these in order:
-
Webhooks are disabled. The toggle in Online Payments gates all delivery. Deliveries made while disabled are recorded as
SKIPPEDand are not retried later. -
Your framework is rejecting the POST before your handler runs. Rails, Django and Laravel apply CSRF protection to every POST by default, which rejects webhooks with a
403your handler never sees. Exempt the webhook route:app/controllers/webhooks_controller.rb class WebhooksController < ApplicationControllerprotect_from_forgery except: :paydotendwebhooks/views.py from django.views.decorators.csrf import csrf_exempt@csrf_exemptdef paydot_webhook(request): ...bootstrap/app.php ->withMiddleware(function (Middleware $middleware) {$middleware->validateCsrfTokens(except: ['paydot/webhook',]);}) -
The payment never reached a final status. Only
EXECUTED,SETTLED,FAILEDandCANCELLEDdispatch. A payment sitting inPENDINGproduces no event. -
Your endpoint is unreachable from the public internet. Private, loopback and reserved addresses are rejected before any request is sent.
Use Send test event to tell “our delivery is broken” apart from “no event has happened yet”. It exercises the same signing and delivery path as a real payment.
Signature mismatches
Section titled “Signature mismatches”Almost always one of these:
- The body was re-encoded. Parsing JSON and re-serializing it changes whitespace and key order. Sign the raw bytes.
- A rotation is in progress. Several
v1=values arrive. Accept the request if any one matches. - Clock drift. If you reject stale timestamps, an unsynchronized server clock rejects valid events.