Webhooks overview
Updated 21 September 20263 min read
On this page
Webhooks push events to your server the moment something happens, so you never have to poll. Register an HTTPS endpoint, choose the events you care about and Ledgerline sends a signed POST request for each one.
How it works
- Something changes in Ledgerline, for example a payout is paid.
- Ledgerline records an event with a unique id and a snapshot of the object.
- We deliver the event to each subscribed endpoint as a JSON
POST. - Your endpoint verifies the signature, stores the event and answers with a
2xxstatus within 10 seconds. - If it does not, we retry on a schedule.
Register an endpoint
In the dashboard, open Developers > Webhooks, or use the API:
curl https://api.ledgerline.dev/v1/webhook_endpoints \
-H "Authorization: Bearer $LEDGERLINE_API_KEY" \
-H "Idempotency-Key: 9a1c5e7b-3d20-4b8a-8f66-7e2c1d0a4b35" \
-d url="https://example.com/hooks/ledgerline" \
-d "enabled_events[]=payout.paid" \
-d "enabled_events[]=payout.failed" \
-d "enabled_events[]=payout.returned"
The response includes the signing secret, which starts with whsec_. It is shown once. Use it to verify signatures.
Endpoints must use HTTPS with a certificate from a public authority. Plans allow 5 endpoints on Starter, 25 on Growth and 100 on Scale. See Limits and quotas.
The event envelope
{
"id": "evt_01JA7E2Q9R",
"type": "payout.paid",
"api_version": "2026-09-01",
"created_at": "2026-09-21T11:20:05Z",
"livemode": true,
"data": {
"object": {
"id": "pay_01JA6D4H2K",
"status": "paid",
"amount": 1250000,
"currency": "USD"
}
}
}
api_version is the version used to render the object, which is the version your endpoint is configured for and not necessarily your account default. livemode is false for sandbox events. Payloads are at most 256 KB.
Event types
| Event | Fired when |
|---|---|
transaction.posted |
A transaction becomes posted. |
transaction.reversed |
A transaction is reversed. |
transfer.created |
An internal transfer completes. |
payout.created |
A payout is accepted. |
payout.submitted |
A payout is sent to the bank or network. |
payout.paid |
Delivery is confirmed. |
payout.failed |
A payout is rejected before delivery. |
payout.returned |
A delivered payout is sent back. |
payout.canceled |
A payout is canceled. |
counterparty.verified |
A counterparty bank account passes verification. |
kyb.status_changed |
Your business verification status changes. |
statement.ready |
A monthly statement can be downloaded. |
reconciliation.completed |
A daily reconciliation run finishes. |
reconciliation.discrepancy |
A run finds a difference that needs review. |
fx.conversion.completed |
A currency conversion is booked. |
api_key.rolled |
An API key is rolled. |
Subscribe only to what you handle. Use enabled_events[]=* to receive everything, including events added later.
Handling events well
- Respond fast, work later. Store the event, return
200and process it from a queue. A slow handler times out at 10 seconds and gets retried. - Expect duplicates. Delivery is at least once. Deduplicate on
event.id. - Do not rely on order.
payout.paidcan arrive beforepayout.submittedafter a retry. Use the object'sstatusand timestamps, or fetch the latest state from the API. - Verify first. Reject unsigned or incorrectly signed requests with
400.
Tip
Fetch the object from the API when ordering matters. The event tells you something changed; GET /v1/payouts/{id} tells you what is true now.
Testing
In the sandbox, endpoints receive events for sandbox activity. From the dashboard you can send a test event of any type to an endpoint. To rehearse a failure path, advance a sandbox payout as described in Sandbox.
Listing and replaying events
GET /v1/events lists events from the last 30 days. Replay one with POST /v1/events/{id}/redeliver. More in Webhook delivery and retries.