Webhook'lar
Add an endpoint under Developers → Webhooks and pick the events it should receive. Every delivery is an HTTPS POST with a JSON body, signed with the endpoint's secret. Use the dashboard's "Send test event" button to try your receiver before going live.
Where an endpoint may point
The address has to be one the open internet can reach. An endpoint on localhost, on a private network, or on one of the addresses a cloud provider answers its own metadata on is refused when you save it, and again before each delivery, because it is this platform's server that would be making the request rather than yours. Redirects are not followed for the same reason.
Developing locally? Put a tunnel in front of your machine and give us the tunnel's address, or use the delivery log to replay a delivery once your receiver is reachable.
Live and test mode
An endpoint belongs to the mode you were in when you added it, and stays in it. A payment taken in test mode is only ever announced to test endpoints, and a live payment only to live ones, so trying something out can never create a real order. Switch the dashboard to the other mode to see and add that mode's endpoints.
Every payload also carries a mode of live or test, so your receiver can tell real money from a rehearsal without looking anything up.
Event types
-
charge.createdA charge was opened and its rate locked. -
charge.payment_detectedA transfer was seen on-chain and is gathering confirmations. -
charge.paidThe payment is confirmed. Fulfil the order. -
charge.underpaidA confirmed payment fell short of your tolerance. -
charge.late_paymentFunds arrived after the charge expired or was canceled. -
charge.refundedYou recorded that funds were sent back to the customer. -
charge.expiredThe rate lock ran out before the customer paid. -
charge.canceledThe charge was canceled from the dashboard or the API. -
invoice.createdAn invoice was issued. -
invoice.sentThe invoice, or a reminder of it, was emailed to the customer. -
invoice.viewedThe customer opened the invoice for the first time. -
invoice.paidOne of the invoice's charges was paid, which settles it. -
invoice.voidedThe invoice was withdrawn and can no longer be paid.
Charge events carry the charge under data.charge; invoice events carry the invoice under data.invoice (code, number, status, amount, currency, customer, hosted_url, charges). A paid invoice produces both charge.paid and invoice.paid: fulfil on one of them, not both.
Each payload carries an event_id. The same events are kept in the timeline of the charge or invoice and can be read back with GET /v1/events (filter with ?type=, ?charge= and ?invoice=) or GET /v1/events/{id}, which is handy for catching up after your endpoint was down.
Payload and headers
POST /your/endpoint
Content-Type: application/json
User-Agent: VeliraPay-Webhooks/1.0
X-VeliraPay-Event: charge.paid
X-VeliraPay-Delivery: 9d2e0b8a-…-5f3a
X-VeliraPay-Signature: t=1758067200,v1=4f1c…ab09
{
"id": "9d2e0b8a-…-5f3a",
"event_id": "9d2e0b89-…-77c1",
"event": "charge.paid",
"mode": "live",
"created_at": "2026-09-17T00:05:12.000000Z",
"data": {
"charge": {
"code": "2t4bcuqkpkoy",
"status": "paid",
"fiat_amount": "150.00",
"fiat_currency": "USD",
"asset": "BTC",
"asset_amount": "0.002500000000000000",
"received_amount": "0.002500000000000000",
"customer_email": "[email protected]",
"description": "Invoice #1042",
"metadata": {"order_id": "1042"},
"payment_link": null,
"paid_at": "2026-09-17T00:05:10.000000Z",
…
}
}
}
Next
- Verifying signatures → Prove a delivery came from us before you act on it.
- Retries and failures → What happens when your receiver is slow, broken or offline.