Payment webhooks
Payment webhooks are sent to your webhook URI registered in Console when a payment enters a new state.
Below are the webhook types that you can receive as a payment moves through its lifecycle.
Configure the URI where you receive webhooks in Console.
All our webhooks include these headers:
Field | Type | Description |
---|---|---|
X-TL-Webhook-Timestamp | ISO-8601 Timestamp | Time that the webhook was sent to you. This will be in the following format: 2020-05-18T10:17:47Z. |
TL-Signature | string | JSON web signature with a detached payload in the form {HEADER}..{SIGNATURE} All incoming webhook requests must have verified signatures, or you risk accepting fraudulent payment status events. |
Webhook bodies are encoded in JSON format with the following fields:
Field | Type | Description |
---|---|---|
type | string | Event type |
event_id | string | A UUID for the event |
event_version | string | Version of the event type |
Webhooks may include additional fields. See the specific event webhook for more information.
payment_authorized
This webhook is optional, and is disabled by default. It is particularly useful in geographies where banks can take a long time to notify that payments have been executed. Contact us if you would like this webhook to be enabled.
The following table includes the fields that appear in the payment_authorized
notification:
Field | Type | Optional | Description |
---|---|---|---|
type | string | No | Type of the event ("payment_authorized" ) |
event_id | string | No | A UUID for the event |
event_version | string | No | The version of the event schema |
payment_id | string | No | The unique ID for the payment |
metadata | object | Yes | A set of key-value pairs of custom data that was provided when the payment was created |
authorized_at | datetime | No | An RFC-3339 timestamp of when the payment was authorized |
payment_source | object | Yes | Information about the source account of the payment, if available from the remitter's bank. The account identifiers available will be those provided by the bank. |
{
"type": "payment_authorized",
"event_version": 1,
"event_id": "c1e475a8-f838-4a35-95df-51465d66a61d",
"payment_id": "ecad2b93-efe9-4f25-b82d-920248a9c1ad",
"payment_method": {
"type": "bank_transfer",
"provider_id": "mock-payments-gb-redirect",
"scheme_id": "faster_payments_service"
},
"payment_source": {
"account_identifiers": [
{
"type": "sort_code_account_number",
"sort_code": "040668",
"account_number": "00000871"
}
],
"account_holder_name": "JOHN SANDBRIDGE"
},
"authorized_at": "2023-06-27T09:54:55.777Z"
}
payment_executed
The following table includes the fields that appear in the payment_executed
notification:
Field | Type | Optional | Description |
---|---|---|---|
type | string | No | Type of the event ("payment_executed" ) |
event_id | string | No | A UUID for the event |
event_version | string | No | The version of the event schema |
payment_id | string | No | The unique ID for the payment |
metadata | object | Yes | A set of key-value pairs of custom data that was provided when the payment was created |
payment_method | object | No | Method of the payment. type can be "mandate" or "bank_transfer" .Mandates contain mandate_id and bank transfers contain provider_id and scheme_id , if available. |
executed_at | datetime | No | An RFC-3339 timestamp of when the payment was executed |
payment_source | object | Yes | Information about the source account of the payment, if available from the remitter's bank. The account identifiers available will be those provided by the bank. Note that the account_holder_name can differ from the one returned in the payment_settled webhook. |
{
"type": "payment_executed",
"event_version": 1,
"event_id": "b8d4dda0-ff2c-4d77-a6da-4615e4bad941",
"payment_id": "60c0a60ed8d7-4e5b-ac79-401b1d8a8633",
"executed_at": "2021-12-25T15:00:00.000Z",
"payment_method": {
"type": "bank_transfer",
"provider_id": "mock-payments-gb-redirect",
"scheme_id": "faster_payments_service"
},
"payment_source": {
"account_identifiers": [
{
"type": "sort_code_account_number",
"sort_code": "040668",
"account_number": "00000871"
}
],
"account_holder_name": "JOHN SANDBRIDGE"
}
}
{
"type": "payment_executed",
"event_version": 1,
"event_id": "b8d4dda0-ff2c-4d77-a6da-4615e4bad941",
"payment_id": "60c0a60ed8d7-4e5b-ac79-401b1d8a8633",
"executed_at": "2021-12-25T15:00:00.000Z",
"payment_method": {
"type": "bank_transfer",
"provider_id": "mock-payments-de-redirect",
"scheme_id": "sepa_credit_transfer"
},
"settlement_risk":
{
"category": "low_risk"
}
}
}
payment_source
informationPayments in the
authorized
,executed
, andfailed
states, including payments not made into a TrueLayer merchant account, from CMA9 banks exceptob-boi
include apayment_source
object.The
payment_source
object includes the name of the account holder and any account identifiers provided by the bank. Note that thepayment_source
object does not include theid
field, which refers specifically to a user who pays into a merchant account.
payment_failed
The following table includes the fields that appear in the payment_failed
notification:
Field | Type | Optional | Description |
---|---|---|---|
type | string | No | Type of the event ("payment_failed" ) |
event_id | string | No | A UUID for the event |
event_version | string | No | The version of the event schema |
payment_id | string | No | The unique ID for the payment |
metadata | object | Yes | A set of key-value pairs of custom data that was provided when the payment was created |
payment_method | object | No | Method of the payment. type can be "mandate" or "bank_transfer" .Mandates contain mandate_id and bank transfers contain provider_id and scheme_id , if available. |
failed_at | datetime | No | An RFC-3339 timestamp of when the payment failed |
failure_stage | string | No | An enum identifying where the payment failed in its lifecycle. Can be one of "authorization_required" , "authorizing" , "authorized" |
failure_reason | string | No | The reason the payment failed. Read more about failure reasons. |
payment_source | object | Yes | Information about the source account of the payment, if available from the remitter's bank. The account identifiers available will be those provided by the bank. This field is optional. |
{
"type": "payment_failed",
"event_version": 1,
"event_id": "b8d4dda0-ff2c-4d77-a6da-4615e4bad941",
"payment_id": "60c0a60ed8d7-4e5b-ac79-401b1d8a8633",
"failed_at": "2021-12-25T15:00:00.000Z",
"failure_stage": "authorizing",
"failure_reason": "provider_rejected",
"payment_method": {
"type": "mandate",
"mandate_id": "d65f3521-fa55-44fc-9a75-ba43456de7f2",
},
"payment_source": {
"account_holder_name": "HOLDER NAME",
"account_identifiers": [
{
"type": "sort_code_account_number",
"sort_code": "111111",
"account_number": "00000111"
}
]
}
}
payment_settled
The following table includes the fields that appear in the payment_settled
notification. Note that this webhook is only available when using closed-loop payments.
Field | Type | Optional | Description |
---|---|---|---|
type | string | No | Type of the event ("payment_settled" ) |
event_id | string | No | A UUID for the event |
event_version | string | No | The version of the event schema |
payment_id | string | No | The unique ID for the payment |
metadata | object | Yes | A set of key-value pairs of custom data that was provided when the payment was created |
payment_method | object | No | Method of the payment. type can be "mandate" or "bank_transfer" . Mandates contain mandate_id and bank transfers contain provider_id and scheme_id , if available. |
settled_at | datetime | No | An RFC-3339 timestamp of when the payment was settled |
payment_source | object | No | Source of the payment for which the event is being sent. This object contains a id for the settled payment's source, which can be used in closed-loop payouts. Read more about payment sources.Note that the account_holder_name can differ from the one returned in the payment_executed webhook . |
user_id | string | No | The user id for this payment, which can be used in closed-loop payouts. This is the same value received in the create payment response. |
{
"type": "payment_settled",
"event_version": 1,
"event_id": "b8d4dda0-ff2c-4d77-a6da-4615e4bad941",
"payment_id": "60c0a60ed8d7-4e5b-ac79-401b1d8a8633",
"payment_method": {
"type": "bank_transfer",
"provider_id": "mock-payments-de-redirect",
"scheme_id": "sepa_credit_transfer"
},
"settled_at": "2021-12-25T15:00:00.000Z",
"payment_source": {
"account_identifiers": [
{
"type": "iban",
"iban": "DE79370400440532013000"
}
],
"id": "1f111d3c-9427-43be-1111-1111219d111c",
"account_holder_name": "HOLDER NAME"
},
"user_id": "ec01ece1-1dbe-48f1-82b2-bce8cfa44d08"
}
payment_creditable
Sent when the payment is ready to be credited to the user, and you can grant services to your user.
By default, you receive this webhook when a payment settles. Alternatively, you can set up one or more alternative timings for each country, based on your risk appetite.
The following table includes the fields that appear in the payment_creditable
notification.
Learn more about the different possible behaviours of this webhook and how to configure them.
Field | Type | Optional | Description |
---|---|---|---|
type | string | No | Type of the event ("payment_creditable" ) |
event_id | string | No | A UUID for the event |
event_version | string | No | The version of the event schema |
payment_id | string | No | The unique ID for the payment |
metadata | object | Yes | A set of key-value pairs of custom data that was provided when the payment was created |
creditable_at | datetime | No | An RFC-3339 timestamp of when TrueLayer determined that the payment was ready to be credited |
{
"type": "payment_creditable",
"event_version": 1,
"event_id": "b8d4dda0-ff2c-4d77-a6da-4615e4bad941",
"payment_id": "60c0a60ed8d7-4e5b-ac79-401b1d8a8633",
"creditable_at": "2023-06-13T15:00:00.000Z"
}
payment_settlement_stalled
Sent when the payment doesn't reach settled
status after a specific amount of time has passed since the payment reached executed
status. You specify the amount of time when you contact us to enable this webhook.
This webhook is optional, and is disabled by default. Contact us if you would like this webhook to be enabled.
The following table includes the fields that appear in the payment_settlement_stalled
notification.
Field | Type | Optional | Description |
---|---|---|---|
type | string | No | Type of the event ("payment_settlement_stalled" ) |
event_id | string | No | A UUID for the event |
event_version | string | No | The version of the event schema |
payment_id | string | No | The unique ID for the payment |
metadata | object | Yes | A set of key-value pairs of custom data that was provided when the payment was created |
settlement_stalled_at | datetime | No | An RFC-3339 timestamp of when TrueLayer determined that the payment's settlement was stalled based on the client's chosen delay or the default one |
{
"type": "payment_settlement_stalled",
"event_id": "b8d4dda0-ff2c-4d77-a6da-4615e4bad941",
"event_version": 1,
"payment_id": "60c0a60ed8d7-4e5b-ac79-401b1d8a8633",
"settlement_stalled_at": "2023-06-13T15:00:00.000Z"
}
external_payment_received
You'll get the external_payment_received
notification when a payment, made using a payment method not offered by TrueLayer, to a merchant account has settled in that merchant account. The following table includes the fields that appear in the notification body:
Field | Type | Optional | Description |
---|---|---|---|
type | string | No | Type of the event ("external_payment_received" ) |
event_id | string | No | A UUID for the event |
event_version | string | No | The version of the event schema |
transaction_id | string | No | The unique ID for the transaction |
currency | string | No | The currency of the payment |
amount_in_minor | string | No | The amount of the payment |
settled_at | datetime | No | An RFC-3339 timestamp of when the payment was settled |
merchant_account_id | string | No | The unique ID for the Merchant Account |
remitter.account_holder_name | string | No | The remitter information of the payment |
remitter.account_identifiers | array | No | The remitter account identifiers of the payment. We support the following identifiers: sort_code_account_number , iban , bban , nrb |
remitter.reference | string | No | The reference for the payment you received from an external source. |
{
"type": "external_payment_received",
"event_version": 1,
"event_id": "b8d4dda0-ff2c-4d77-a6da-4615e4bad941",
"transaction_id": "7806739d-1944-44d9-a1b8-5d2cd079676b",
"currency": "GBP",
"amount_in_minor": 1,
"settled_at": "2021-12-25T15:00:00.000Z",
"merchant_account_id": "200552da-13da-43c5-a9ba-04ee1502ac57",
"remitter": {
"account_holder_name": "Example remitter name",
"account_identifiers": [{
"type": "sort_code_account_number",
"sort_code": "12-34-56",
"account_number": "12345678"
},
{
"type": "iban",
"iban": "GB29NWBK60161331926819"
}],
"reference":"Example payment reference"
}
}
external_payment_received webhook behaviour
There are two different behaviours for the external_payment_received
webhook. The behaviour depends on whether you have enabled automatic refunds for payments from external sources or not.
A external payment in the context of this webhook usally refers to the following three scenarios:
- When an existing user pays into your merchant account again using saved SCAN/IBAN details.
For example, through a Send again button in their banking app. - When you fund your merchant account from a corporate bank account through your SCAN/IBAN details.
- When a new and unknown user pays into your account using your merchant account's SCAN/IBAN details.
Out of the above scenarios, you likely only want to keep funds from an existing user or your corporate bank account, not an unknown user. Automatic refunds solve this problem, but you can also implement various measures to mitigate the risk of payments from external sources.
Note that any payments that return the
external_payment_received
webhook have a Type of External Deposit in the Console payments view.
Behaviour with automatic refunds enabled
If automatic refunds are enabled, you usually receive no external_payment_received
webhook when you receive an external payment. The reason for this is that the payment is automatically received and then refunded, so the webhook isn't surfaced.
You do however see two payments in the Console payments view:
- An External Deposit.
- An Open-Loop Payout, which is sent 1 hour after the initial External Deposit.
However, in some cases, the payout to refund a payment is blocked or rejected by the remitter bank (for example, if the account was closed). In this case you receive the external_payment_received
webhook, and another External Deposit displays in Console. You can search in Console for external deposits with the search bar, or by filtering by payment type.
Default behaviour without automatic refunds enabled
By default, without automatic refunds enabled, you receive the external_payment_received
webhook for each payment from an external source. Each of these payments have a Type of External Deposit in the Console payments view.
If you're receiving external_payment_received
payments, there are a number of approaches you can take to handle these:
- Enable automatic refunds for your integration.
- Create an allowlist of bank details you want to accept payments from.
- Flag external deposits for manual review.
- Develop your own logic to automatically return external payments as an open-loop payout, by either using the information in the
external_payment_received
webhook, or that you receive from the/transactions
endpoint.
Updated 2 months ago