The technical reference for accounting partners and developer-minded bookkeepers —
built around three flows: Xero-style invoice sync, overdue push, and
payment.received callbacks.
Paidly expects an API key on every request, sent as either the
Authorization bearer token or the X-Paidly-Key header.
Keys are issued per-account under Settings → API and can be
scoped or rotated without taking the rest of your integration offline. Treat a
key like a password — store it in your secrets manager, never commit it, and
re-issue through the dashboard if it ever leaks.
Authorization: Bearer pdly_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx # or X-Paidly-Key: pdly_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Bulk push outstanding invoices from your accounting platform into Paidly — idempotent on (external_id). Returns the assigned Paidly IDs and the resulting collection status.
Request{
"invoices": [
{
"external_id": "xero:INV-1047",
"client_name": "Acme Build Ltd",
"client_email": "ap@acmebuild.co.uk",
"amount": 284000,
"currency": "GBP",
"due_date": "2026-08-01"
}
]
}
Response
{
"synced": 1,
"invoices": [
{
"external_id": "xero:INV-1047",
"id": "inv_01H...",
"status": "overdue"
}
]
}
Re-sending the same external_id with the same payload is a no-op —
Paidly is idempotent on the (external_id) pair so retries are safe.
To update status, POST again with the same external_id; to delete,
call DELETE /v1/invoices/:id.
payment.received callbackFired when Paidly confirms a payment against an invoice it has chased. POSTed to the URL you configured under Settings → Webhooks.
Configure the delivery URL under Settings → Webhooks. Paidly
POSTs the payload below and expects a 2xx response within 5
seconds. On a 5xx (or no response) we retry up to 5 times inside a
24-hour window with exponential back-off (1s, 2s, 4s, 8s, 16s). After 5
failed attempts, the delivery is marked dead and surfaced in the dashboard.
{
"event": "payment.received",
"invoice": {
"id": "inv_01H...",
"external_id": "xero:INV-1047",
"amount": 284000,
"currency": "GBP"
},
"paid_at": "2026-08-14T10:42:11Z",
"source": "stripe"
}
Verifying the signature. Each delivery carries a
X-Paidly-Signature header — HMAC-SHA256 of the raw body using
your webhook signing secret. Reject any request whose signature does not match
before you trust the payload.
Errors return a JSON body of the shape
{ "error": { "code": "...", "message": "..." } } plus an
X-Request-Id header. Quote the request id when contacting support.
The table below lists every code your integration should be ready to handle.
| HTTP | Error code | Meaning | Retry |
|---|---|---|---|
| 401 | unauthorized | Missing or invalid API key. The Authorization header was absent, expired, or did not match any active key on the account. | Do not retry automatically. Confirm the key under Settings → API and re-issue the request with a fresh header. |
| 403 | forbidden | The key is valid but not authorised for this resource or action (e.g. cross-account invoice ID, or the key is scoped read-only). | Do not retry. Check the key scopes in Settings → API and confirm the resource belongs to your account. |
| 404 | not_found | The referenced invoice, webhook delivery or endpoint does not exist (or has been deleted). | Do not retry without fixing the request. Treat as a permanent error and surface to the operator. |
| 409 | conflict | The same idempotency key was reused with a different payload, or an invoice is in a state that blocks the requested transition (e.g. trying to mark a paid invoice as overdue again). | Do not retry without resolving the conflict. Compare the original request body or advance the invoice state from the dashboard. |
| 422 | unprocessable_entity | Request body parsed cleanly but failed field-level validation — missing required field, malformed date, currency not supported, or amount below the minimum. | Do not retry. Fix the offending field (the error body names it) and resubmit. |
| 429 | rate_limited | You exceeded the per-key request budget. The response includes a Retry-After header (seconds) indicating when to come back. | Safe to retry. Honour the Retry-After header, then back off exponentially if you keep hitting the limit. |
| 500 | server_error | Unexpected error on Paidly's side. Safe to assume the request did not land and try again. | Safe to retry with exponential back-off (1s, 2s, 4s, 8s, 16s). After 5 attempts inside a 24h window, escalate to support with the X-Request-Id from the response headers. |
| 503 | service_unavailable | Maintenance window or downstream dependency outage. Same retry posture as 500. | Safe to retry with exponential back-off. If the window exceeds 15 minutes, treat as a sustained outage and queue the requests locally. |
Get your overdue invoices in front of AI in under two minutes.
Free to try. No card required.