Payments
Virtual Accounts feature is available as a Private Beta version. Please contact your Customer Success Manager if you would like to access it.
Introduction
The following payment types are supported on your virtual account:
Type | Description |
---|---|
PAY_IN | Funds received into your account |
PAY_OUT | Funds sent from your account to an external bank account |
REFUND | Refund a payment back to the original payer |
TRANSFER | Funds transferred between 2 of your accounts |
RETURN_IN | The return of a pay out due to it being rejected by the beneficiary bank |
RETURN_OUT | The return of a pay in due to it being recalled by the sending bank |
Pay In & Pay Out
Pay In
Funds that are received into your virtual account from an external source are known as a Pay In.
A Pay In can represent:
- A payment you have collected from your customers through Yapily Payments
- A payment you have collected from your customers through any payment method that utilises the supported payment schemes (e.g. a bank transfer over FPS to a GBP account)
- Payments that you have requested your PSP to settle into your virtual account
- Funds you have deposited to your account through any payment method that utilises the supported payment schemes
By collecting payments that you instruct through Yapily Payments into your virtual account, you are guaranteed to receive a settlement notification once the funds have arrived.
Create a Pay In
Initiate the payment, specifying your virtual account inside the payee
object.
In the accountIdentifications
block, specify the type
as VIRTUAL_ACCOUNT_ID
, and the identification
as your virtual account ID.
You can retrieve your account ID by getting your account information.
To ensure that the payments you initiate can be linked to the Pay Ins on your account, the reference
must be unique for each payment. We also recommend it is a maximum of 18 characters.
Example Request:
{
"userUuid": "30a556b4-b5f7-4dc9-a226-3f562a6ecfe3",
"institutionId": "mock-sandbox",
"paymentRequest": {
"type": "DOMESTIC_PAYMENT",
"paymentIdempotencyId": "1d54cf71bfe44b1b8e67247aed455d96",
"reference": "REFERENCE",
"contextType": "OTHER",
"amount": {
"amount": "1.00",
"currency": "GBP"
},
"payee": {
"accountIdentifications": [
{
"type": "VIRTUAL_ACCOUNT_ID",
"identification": "{{account-id}}"
}
]
}
}
}
A COMPLETED
payment status indicates that the payer bank has initiated the payment and it has been successfully processed. When the funds settle, this results in a Pay In to your virtual account
Subscribe to virtualAccount.payIn.status
notifications to be notified of changes in the payment status.
Reconciling Yapily Payments to Pay Ins
When a Pay In is received on your account, we confirm whether it relates to a previously initiated Yapily Payment.
If so, the Pay In status notification will contain an additional field, paymentInitiationId
, with the corresponding Yapily Payment ID.
Access source account details
The source account or sender's account details can be found in the source
object in the following responses:
Pay Out
You can make a payment from your virtual account to any account that is connected via the supported payment schemes.
This payment can be for any purpose, for example:
- Final settlement to your business account
- Settlement to one of your clients (e.g. a merchant)
- A customer withdrawal or pay out from your app
Create a Pay Out
1. Set up a beneficiary
To send money to an account, it must be set up as a beneficiary.
If the beneficiary already exists, you can verify its details using the Get Beneficiary endpoint.
If the beneficiary doesn't exist, it must be created using the Create Beneficiary endpoint.
2. Execute the request
Once the beneficiary exists, you can instruct a payment to it using the Create Pay Out endpoint.
You need to include the paymentScheme
in the request. The paymentScheme
must be supported by the beneficiary as specified when creating the beneficiary.
A unique value must be supplied in the idempotency-key
header. If 2 requests are submitted with the same value, the second request will not be processed.
Example request:
curl -L -X POST 'https://api.yapily.com/virtual-accounts/payments/pay-outs' \
-H 'Content-Type: application/json' \
-H 'client-id: <virtual_account_client_id>' \
-H 'idempotency-key: <idempotency_key>' \
-u 'APPLICATION_KEY:APPLICATION_SECRET' \
-d '{
"accountId": "<account-id>",
"amount": {
"amount": 10,
"currency": "GBP"
},
"reference": "REFERENCE",
"beneficiaryId": "<beneficiary-id>",
"paymentScheme": "FASTER_PAYMENTS"
}'
If created successfully, you will be provided with an id
for the Pay Out and it will have a status of INITIATED
.
Example response:
{
"meta": {
"tracingId": "0c62dfa1678442f2955707515ff67f49"
},
"data": {
"id": "6172f457-a667-40cc-be97-cd9f0e42b6af",
"createdDate": "2022-05-16T20:55:02.692Z",
"paymentDate": "2022-05-16",
"type": "PAY_OUT",
"paymentScheme": "FASTER_PAYMENTS",
"amount": {
"amount": -1,
"currency": "GBP"
},
"reference": "REFERENCE",
"status": "INITIATED",
"source": {
"type": "ACCOUNT",
"accountId": "a1JUMS93c1JQTnBSOHdzdmtITFBaQT09"
},
"destination": {
"type": "BENEFICIARY",
"beneficiaryId": "45c4f822-e12c-4800-8227-d7eb6ac2b0b7"
}
}
}
The payment is then executed.
Subscribe to virtualAccount.payOut.status
notifications to be notified of changes in the payment status.
Alternatively, you can check the current status of the payment by retrieving the payment details.
Returns
Pay Out Return
A return may be sent by the beneficiary bank when they initially accept a payment request but, subsequently, cannot credit the funds to the beneficiary. Reasons for this occurring may include compliance checks at the beneficiary bank or an invalid beneficiary account status.
This return of funds is seen as a separate credit payment of type RETURN_IN
. This is linked to the original (pay out) payment through the originalPaymentId
Because the payment request was initially accepted by the beneficiary bank, it is likely that the Pay Out is of COMPLETED
status at the time the return is made. Typically, returns will occur within the normal settlement period of the payment scheme.
Subscribe to Pay Out return notifications to be notified when one of your Pay Outs is returned.
Pay In Return
In the event of a payer/sender wishing to recall a payment they have sent you, we will contact you in order to agree the correct action to take. If the recall is actioned, then a RETURN_OUT
payment will be made. This is linked to the original (pay in) payment through the originalPaymentId
Retrieve payments
Get a list of payments
You can retrieve a list of payments made into and out of your virtual account using the Get Payments endpoint. You can provide query parameters to filter the list as required.
Example request:
curl -L -X GET 'https://api.yapily.com/virtual-accounts/payments' \
-H 'client-id: <virtual_account_client_id>' \
-u 'APPLICATION_KEY:APPLICATION_SECRET'
Example response:
{
"meta": {
"tracingId": "4c29beddb2f7431aa59946b3f00df711"
},
"links": {
"next": "https://api.yapily.com/virtual-accounts/payment?type=TRANSFER&cursor=cGFnZT0xJnNpemU9MTAwMA==",
"self": "https://api.yapily.com/virtual-accounts/payment?type=TRANSFER&cursor=cGFnZT0wJnNpemU9MTAwMA==",
"first": "https://api.yapily.com/virtual-accounts/payment?type=TRANSFER&cursor=cGFnZT0wJnNpemU9MTAwMA=="
},
"data": [
{
"id": "cb5c0f24-d70f-4614-9641-4f54e4035d5f",
"createdDate": "2022-06-10T12:47:01.55Z",
"type": "TRANSFER",
"amount": {
"amount": -1.0,
"currency": "GBP"
},
"reference": "ref-1",
"status": "COMPLETED",
"source": {
"type": "ACCOUNT",
"accountId": "ea1232ff-3fe7-4d51-abbe-5fb8d308fd15"
},
"destination": {
"type": "ACCOUNT",
"accountId": "00961c0d-5bb9-40d7-9cbe-6a47876556d0"
}
},
{
"id": "6f340fc7-60cb-43a1-aca6-c78919fe6126",
"createdDate": "2022-06-13T08:24:49.861Z",
"type": "TRANSFER",
"amount": {
"amount": -0.01,
"currency": "GBP"
},
"reference": "REF 123456",
"status": "COMPLETED",
"source": {
"type": "ACCOUNT",
"accountId": "ea1232ff-3fe7-4d51-abbe-5fb8d308fd15"
},
"destination": {
"type": "ACCOUNT",
"accountId": "00961c0d-5bb9-40d7-9cbe-6a47876556d0"
}
}
]
}
Get payment details
You can retrieve information and the status of a specific payment using the Get Payment endpoint. You must provide the id
of the payment you want to retrieve in the path.
Example request:
curl -L -X GET 'https://api.yapily.com/virtual-accounts/payments/{payment-id}' \
-H 'client-id: <virtual_account_client_id>' \
-u 'APPLICATION_KEY:APPLICATION_SECRET'
Example response:
{
"meta": {
"tracingId": "497a9d43c043411eb266539101324703"
},
"data": {
"id": "2f2cdeb8-4438-43db-955e-59ecac68a3bb",
"createdDate": "2022-05-23T15:24:48.873Z",
"paymentDate": "2022-05-23",
"type": "PAY_OUT",
"paymentScheme": "FASTER_PAYMENTS",
"amount": {
"amount": -1.0,
"currency": "GBP"
},
"reference": "Payment from John",
"status": "COMPLETED",
"source": {
"type": "ACCOUNT",
"accountId": "5dd9a19f-c89a-4c93-a65e-617e3c4f83ef"
},
"destination": {
"type": "BENEFICIARY",
"beneficiaryId": "d919d0f8-7ec6-44a2-ae50-024f7d516f4e"
}
}
}
Payment status
The steps in the payment lifecycle are:
Status | Description |
---|---|
INITIATED | Payment validated and accepted for processing. |
PROCESSING | Payment processing. |
SCHEDULED | Payment validated and scheduled for execution on the requested future date. |
COMPLETED | Payment successfully processed. Funds will have been credited to or debited from your account, dependent on the payment type. For a Pay Out, the instruction has been released to the payment scheme and settlement at the beneficiary is expected according to the estimated settlement periods. |
FAILED | Payment failed. |
Subscribe to virtualAccount.payIn.status
and virtualAccount.payOut.status
notifications to be notified of changes in payment status.
Supported payment schemes
Table of the supported payment schemes for Pay In and Pay Out
Currency | Payment Scheme | Beneficiary Countries | Payment Limit | Cut-off | Estimated Settlement Time |
---|---|---|---|---|---|
GBP | Faster Payments | GB | GBP 1,000,000 | - | Instant 24/7/365 |
GBP | CHAPS | GB | - | 5:30 PM GMT for same day Next business day after cut-off |
1 - 2 hours (business days only) |
GBP | SWIFT | All except sanctioned countries | - | 3:00 PM GMT for same day | 2-5 working days depending on the destination country |
GBP | SWIFT Express | All except sanctioned countries | - | 2:00 PM GMT | 1 working day |
EUR | SEPA | All SEPA Countries | - | 2:00 PM GMT for same day. Next business day after cut-off. |
2 - 3 hours (business days only) |
EUR | SEPA Instant | All SEPA Countries | EUR 100,000 | - | Instant 24/7/365 |
EUR | SWIFT | All except sanctioned countries | - | 3:00 PM GMT for same day | 2-5 working days depending on the destination country |
EUR | SWIFT Express | All except sanctioned countries | - | 2:00 PM GMT | 1 working day |
USD | IAT | US | - | 6:00 PM GMT | Next working day |
USD | WIRE | US | - | 6:00 PM GMT | Next working day |
CAD | SWIFT | All except sanctioned countries | - | 3:00 PM GMT for same day | 2-5 working days depending on the destination country |
CZK | SWIFT | All except sanctioned countries | - | 3:00 PM GMT for same day | 2-5 working days depending on the destination country |
HUF | SWIFT | All except sanctioned countries | - | 3:00 PM GMT for same day | 2-5 working days depending on the destination country |
HUF | SWIFT Express | All except sanctioned countries | - | 12:30 PM GMT | 1 working day |
RON | SWIFT | All except sanctioned countries | - | 3:00 PM GMT for same day | 2-5 working days depending on the destination country |
HRK | SWIFT | All except sanctioned countries | - | 3:00 PM GMT for same day | 2-5 working days depending on the destination country |
info
If a payment is instructed via SEPA_INSTANT
, but the destination bank does not support this, the payment will instead be sent via SEPA_CREDIT
.
Payment data validation
Payment reference
The validation of a payment reference
depends on the target paymentScheme
:
Payment Scheme(s) | Min Length | Max Length | Allowed Characters | Other |
---|---|---|---|---|
FASTER_PAYMENTS | 1 | 18 | Alpha (a-z, A-Z) Numeric (0-9) (space) , (comma) . (fullstop) - (hyphen) |
|
SEPA_INSTANT SEPA_CREDIT |
2 | 140 | Alpha (a-z, A-Z) Numeric (0-9) + (plus) - (hyphen) / (forward slash) ? (question mark) . (fullstop) : (colon) , (comma) ( (open bracket) ) (close bracket) (space) |
Cannot consist of a single repeated character e.g. aaa |
Refunds
note
Only Yapily Open Banking Payments can be refunded.
Refunds can only be issued back to the source or original payer.
You can refund a payment made to your virtual account back to the source or original payer.
Refunds are sent through SEPA Instant (EUR) or Faster Payments (GBP).
You can optionally make a partial refund, or specify the execution date.
Create a refund
Make a request to the create refund endpoint, specifying the ID of the original Yapily Payment as the paymentInitiationId
.
note
The payment must have settled in the virtual account to request a refund.
Example request:
curl -L -X POST 'https://api.yapily.com/virtual-accounts/refunds' \
-H 'Content-Type: application/json' \
-H 'client-id: <virtual_account_client_id>' \
-H 'idempotency-id: <idempotency_key>'\
-u 'APPLICATION_KEY:APPLICATION_SECRET' \
-d '{
"originalPayment": {
"paymentInitiationId": "<ORIGINAL_PAYMENT_ID>"
},
"reason": "REQUESTED_BY_CUSTOMER",
"reference": "Refund 123",
"refundTo": "SOURCE",
"beneficiaryType": "INDIVIDUAL"
}'
Create a partial refund
By default the refund amount is equal to the amount of the original payment.
To create a partial refund include the amount
object in the request body:
...
"amount": {
"amount": 10,
"currency": "GBP"
}
...
Create a future refund
By default the paymentDate
is the same date you make the request.
To execute the refund in the future, include the paymentDate
field in the request body specifying the date you want the refund to occur:
...
"paymentDate": "2025-08-28"
...
Example response:
{
"data":{
"id":"46d3349e-6733-459d-a6da-71850a7e8076",
"originalPayment": {
"paymentInitiationId": "<ORIGINAL_PAYMENT_ID>"
},
"status": "INITIATED",
"amount":{
"amount": 10,
"currency": "GBP"
},
"reason": "REQUESTED_BY_CUSTOMER",
"paymentDate": "2022-08-28",
"reference": "Refund 123",
"beneficiaryType": "INDIVIDUAL",
"createdDateTime": "2022-04-31T15:00:57.345Z",
"updatedDateTime": "2022-05-31T14:00:57.751Z"
}
}
The response includes fields retrieved from the original Yapily Payment even when they're not specified in the refund request. For example, amount
and paymentDate
.
Once the request is created and validated, in the background, a beneficiary is created and a Pay Out made to execute the request.
To understand when the refund is COMPLETED
or FAILED
we recommend subscribing to virtualAccount.refund.status
event notifications which will alert you to the changes in the refund status.
Retrieve refunds
Get a list of refunds
You can retrieve a list of refunds made using the Get Refunds endpoint. You can provide query parameters to filter the list as required.
You can use the paymentInitiationId
query parameter to retrieve a list of all the refunds requested for a specific payment to calculate the total value of refunds to date and the total amount left available to refund.
Example request:
curl -L -X GET 'https://api.yapily.com/virtual-accounts/refunds' \
-H 'client-id: <virtual_account_client_id>' \
-u 'APPLICATION_KEY:APPLICATION_SECRET'
Example response:
{
"meta": {
"tracingId": "96169af01d394ad39658f17d53b49a5d"
},
"links": {
"next": "https://api.yapily.com/virtual-accounts/refunds?cursor=cGF5bWVudEluaXRpYXRpb25JZD1QRENfMjliZDg1MjgtOWI2Zi00YjZlLWE5NjMtOTM4Mjk0NGRjODMwJnN0YXR1cz1GQUlMRUQmY3JlYXRlZERhdGVUaW1lRnJvbT0yMDIzLTAxLTEzVDE2OjQxOjUxLjEzNjA4NVomY3JlYXRlZERhdGVUaW1lVG89MjAyMy0wMi0xMFQxODo0Mjo1MS4xMzYwODVaJnBvaW50ZXI9MjAyMy0wMS0xM1QxNjo0MTo1MS4xMzYwODU="
},
"data": [
{
"id": "46d3349e-6733-459d-a6da-71850a7e8076",
"originalPayment": {
"paymentInitiationId": "19d2fbfb-f30c-44eb-b3b5-978560d2b712"
},
"status": "INITIATED",
"amount": {
"amount": 100,
"currency": "GBP"
},
"reason": "REQUESTED_BY_CUSTOMER",
"paymentDate": "2022-11-11",
"reference": "Ref Order 123",
"refundTo": "SOURCE",
"refundToOriginalPayer": true,
"beneficiaryType": "INDIVIDUAL",
"createdDateTime": "2022-11-11T15:00:57.345Z",
"updatedDateTime": "2022-11-11T14:00:57.751Z"
},
{
"id": "b0a6242c-d634-4a5a-bdcc-410c4355e9f8",
"originalPayment": {
"paymentInitiationId": "4cb0060a-4aef-4f94-811b-f9356692ca37"
},
"status": "COMPLETED",
"amount": {
"amount": 20.59,
"currency": "GBP"
},
"reason": "REQUESTED_BY_CUSTOMER",
"paymentDate": "2022-11-08",
"reference": "Ref Order 099",
"refundTo": "SOURCE",
"refundToOriginalPayer": true,
"beneficiaryType": "INDIVIDUAL",
"createdDateTime": "2022-11-08T11:00:57.345Z",
"updatedDateTime": "2022-11-08T11:22:59.751Z"
}
]
}
Get refund details
You can retrieve information and the status of a specific refund using the get refund endpoint. You must provide the id
of the refund you want to retrieve in the path.
Example request:
curl -L -X GET 'https://api.yapily.com/virtual-accounts/refunds/{refundId}' \
-H 'client-id: <virtual_account_client_id>' \
-u 'APPLICATION_KEY:APPLICATION_SECRET'
Example response:
{
"data":{
"id":"46d3349e-6733-459d-a6da-71850a7e8076",
"originalPayment": {
"paymentInitiationId": "<ORIGINAL_PAYMENT_ID>"
},
"status": "COMPLETED",
"amount":{
"amount": 10,
"currency": "GBP"
},
"reason": "REQUESTED_BY_CUSTOMER",
"paymentDate": "2022-08-28",
"reference": "Refund 123",
"beneficiaryType": "INDIVIDUAL",
"createdDateTime": "2022-04-31T15:00:57.345Z",
"updatedDateTime": "2022-05-31T14:00:57.751Z"
}
}
Refund status
Refunds have the same status values as other types of payment as described below:
Status | Description |
---|---|
INITIATED | Refund validated and accepted for processing. |
PROCESSING | Refund processing. |
SCHEDULED | Refund validated and scheduled for execution on the requested future date. |
COMPLETED | Refund successfully processed and funds debited from your account. The payment instruction has been released to the payment scheme and settlement at the beneficiary is expected according to the estimated settlement periods. |
FAILED | Refund failed. |
Subscribe to virtualAccount.refund.status
notifications to be notified of changes in the refund status.
Validation
The following validation rules apply to refund requests:
Error | Description |
---|---|
REFUND_AMOUNT_MUST_BE_POSITIVE |
Refund amount has to be positive |
PAYMENT_NOT_SETTLED |
Original payment must have settled before requesting a refund |
PAYMENT_INVALID_EXECUTION_DATE |
Payment date must be today or in the future |
REFUND_AMOUNT_EXCEEDS_AMOUNT_LEFT_TO_REFUND |
Total refund amount cannot exceed the original payment amount |
PAYMENT_INVALID_CURRENCY |
Refund currency must match account currency |
PAYMENT_INSUFFICIENT_FUNDS |
Virtual account must have sufficient funds to cover the refund amount |
Transfer funds
You can move funds between your virtual accounts when they have the same currency.
Create a transfer
Make a request to the create transfer endpoint, supplying a unique value in the idempotency-key
header.
If 2 requests are submitted with the same value, the second request will not be processed.
Example request:
curl -L -X POST 'https://api.yapily.com/virtual-accounts/payments/transfers' \
-H 'Content-Type: application/json' \
-H 'client-id: <virtual_account_client_id>' \
-H 'idempotency-id: <idempotency_key>'\
-u 'APPLICATION_KEY:APPLICATION_SECRET' \
-d '{
"source": {
"accountId": "04006d46-776d-4f9a-ae11-a4c9ab0aee3c"
},
"destination": {
"accountId": "78f1fbe0-f831-4f92-a4d0-5b0747103f9d"
},
"amount": {
"amount": 1,
"currency": "GBP"
},
"reference": "Transfer - 1"
}'
Example response:
{
"meta": {
"tracingId": "ae00b32635894d83a21bc24c5bbd4d41"
},
"data": {
"id": "604038fb-1205-4594-8893-0b83540e7174",
"createdDate": "2022-05-23T14:43:39.579Z",
"type": "TRANSFER",
"amount": {
"amount": -1,
"currency": "GBP"
},
"reference": "REF 123456",
"status": "INITIATED",
"source": {
"type": "ACCOUNT",
"accountId": "VnJhVy9NclFEbmdQREZCUWVIYWlRZz09"
},
"destination": {
"type": "ACCOUNT",
"accountId": "dk96dzJpUW9KOGlYMDRhVG14Q2NhUT09"
}
}
}