Payment webhooks
Tenant API payment webhooks notify your service when payments are settled, scheduled, failed, or when an eligible invoice is declined. Configure one or more webhook definitions with the API, then verify and process each delivery at your endpoint.
Configure a webhook
Section titled “Configure a webhook”Create a definition with POST /v2/webhooks/payments. A definition contains
an HTTPS destination URL and filters for the invoices and payment events you
want to receive:
{ "url": "https://example.com/kivra/webhooks", "cid_filter": "client-key", "tkey_filter": "tenant-key", "types": [ "bank", "autogiro" ], "events": [ "scheduled", "settled", "failed" ]}You can create multiple definitions, but duplicate definitions result in
duplicate deliveries. The cid_filter identifies the OAuth client that sent
the invoice and the tkey_filter identifies the sender tenant. The client may
be acting as a partner for that tenant. The cid_filter must be a specific
client key in this API; a wildcard requires arrangement with Kivra.
tkey_filter can use * to match all applicable tenants, but both filters
cannot be wildcards at the same time.
Use types to filter instant, bank, or autogiro payments. Use events
to filter scheduled, settled, failed, or declined events. The
available combinations are:
| Payment type | Events |
|---|---|
instant |
settled, failed |
bank |
settled, scheduled, failed |
autogiro |
settled, scheduled, failed |
| Invoice | declined |
The invoice_declined event applies only to invoice.renewal and
invoice.donation content. Regular invoice content cannot be declined in
Kivra.
List definitions with GET /v2/webhooks/payments, update one with
PATCH /v2/webhooks/payments/{id}, or remove one with
DELETE /v2/webhooks/payments/{id}. The destination URL must use HTTPS and
must not resolve to a reserved domain or reserved IPv4 range.
Test your endpoint
Section titled “Test your endpoint”Call POST /v2/webhooks/payments/{id}/test to schedule a test delivery.
The test has the same payload shape and signature format as a real delivery,
but its data is static and should not be treated as a real payment.
Your endpoint must respond with a 2xx status within one second of the
connection being established. A successful webhook delivery is acknowledged
with 200 OK.
Verify the signature
Section titled “Verify the signature”Kivra Payments follows Standard Webhooks. Every delivery includes these headers:
| Header | Description |
|---|---|
webhook-id |
Unique identifier for the delivery |
webhook-timestamp |
Unix timestamp when the delivery was sent |
webhook-signature |
One or more signatures used to verify the payload |
The signature header contains signatures such as
v1,<signature1> v1a,<signature2>. Build the signed message by joining the
delivery ID, timestamp, and raw request body with periods:
webhook-id.webhook-timestamp.raw-request-bodyUse the shared secret and HMAC-SHA256 to verify the signature. Always verify the unmodified request body and reject requests with an unacceptable timestamp. Standard Webhooks provides verification libraries for several languages.
Process the payload
Section titled “Process the payload”The JSON payload contains id, timestamp, type, and data. The type is
one of:
| Type | Data |
|---|---|
payment_callback |
Payment details, including content_key, payment_type, payment_event, event_time, amount, and currency |
invoice_declined |
Declined invoice details, including content_key, due_date, remittance_type, remittance_string, event_time, and content_type |
payment_callback_retry |
Deprecated retry type; use the original event type and identify the delivery as a retry |
Optional payment data includes due and payment dates, destination account details, remittance information, payment option details, and Swish references. Payment amounts are strings, and payment times use ISO 8601 date-time values.
Handle retries
Section titled “Handle retries”Kivra retries a delivery when your endpoint returns a non-200 response. The schedule is:
| Attempt | Delay | Time since start |
|---|---|---|
| 1 | Immediately | 00:00:00 |
| 2 | 5 seconds | 00:00:05 |
| 3 | 5 minutes | 00:05:05 |
| 4 | 30 minutes | 00:35:05 |
| 5 | 2 hours | 02:35:05 |
| 6 | 5 hours | 07:35:05 |
| 7 | 10 hours | 17:35:05 |
| 8 | 14 hours | 31:35:05 |
| 9 | 20 hours | 51:35:05 |
| 10 | 24 hours | 75:35:05 |
After the tenth unsuccessful attempt, Kivra cancels the delivery. Store the webhook ID and make processing idempotent so retries do not apply the same payment event twice.
See the Tenant API reference for the complete request, response, and schema definitions.