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.

Virtual Account Pay In flow

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:

Copy
Copied
{
    "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

Virtual Account Pay Out flow

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:

Copy
Copied
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:

Copy
Copied
{
   "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:

Copy
Copied
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:

Copy
Copied
{
   "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:

Copy
Copied
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:

Copy
Copied
{
   "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.

Virtual Account Refund flow

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:

Copy
Copied
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:

Copy
Copied
...
"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:

Copy
Copied
...
"paymentDate": "2025-08-28"
...

Example response:

Copy
Copied
{
   "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:

Copy
Copied
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:

Copy
Copied
{
  "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:

Copy
Copied
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:

Copy
Copied
{
   "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:

Copy
Copied
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:

Copy
Copied
{
   "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"
       }
   }
}