Skip to main content
You implement this endpoint yourself, in your backend. TapiPay calls it every time a payment changes state, so you can update the debt in your system without polling the API.
It is the only reliable source for a payment’s status. The paymentSubmitted event from the SDK means the user submitted the form, not that the payment settled. Only mark a debt as paid when this notification arrives with status: "confirmed".
This notification is not sent by the Facade API, which does not implement webhooks. It is sent by the referenced payments platform, and it is configured at the platform level during onboarding with the TapiPay team: there is no endpoint to create or change the URL. The requests come from that platform’s IPs, not from the Facade API host, and they are handed to you during onboarding.

Configuration

You define the full URL (host and path) TapiPay will send notifications to. You provide two: TapiPay does not impose a route. Any reachable path works: /api/webhooks/confirm-payment, /tapi/callback, /notifications, /payment/status.

Requirements for your endpoint

required
Reachable from the TapiPay source IPs handed to you during onboarding.
required
Return any 2xx HTTP code to acknowledge receipt. TapiPay does not read your response body, only the status code, so you can respond empty.
required
If you take longer, the request is treated as failed and enters retries. If you need heavy processing, queue it and respond first.

The payload

POST with Content-Type: application/json to the endpoint you defined.

additionalData is dynamic

additionalData forwards exactly the optional fields loaded when the debt was created, so its keys vary between clients and between services. There is no guaranteed set of fields. Check each field exists before using it: do not assume any of them will be present.

Example

The fields inside additionalData are illustrative: they show what a client might send, not a contract.

Validating the request comes from TapiPay

Your endpoint is public, so anyone can call it. TapiPay offers five mechanisms, configured during onboarding. You can enable one or combine several.
Combine at least two, for example API Key plus IP whitelist, or Bearer token plus mTLS. A single header based mechanism is vulnerable if the key leaks.

Retries and idempotency

TapiPay retries if your endpoint fails. That means you can receive the same notification more than once. Implement idempotency by operationId or you will process the same payment twice.
The right order in your handler is: validate the origin, respond 2xx quickly, and only then process.
alreadyProcessed and markProcessed must rely on persistent storage (a table with a unique operationId, or Redis), not process memory: if you restart the server between the original attempt and the retry, an in-memory mark is lost and the payment is processed again.

How to test it

TapiPay cannot reach your localhost, so you need a public URL. Two approaches, depending on what you want to verify.
To see the real payload without writing code, use a public receiver such as webhook.site and provide that URL as your staging endpoint. Every notification is logged with its headers and body.This is how you confirm what arrives in additionalData for your specific case, which is the part that cannot be documented in advance.
Staging with test data only. A public receiver exposes the payload to anyone holding the URL: never point production at it.
While you wait for TapiPay to fire a real notification, you can exercise your handler with the example payload from this page:
Call it twice with the same operationId: it is the fastest way to confirm your idempotency works before going to production.