Payouts
At any time you can pay out funds from you Virtual Account to an external account.
Initiating Payout
You can initiate Payout in two ways:
- from Merchant Portal, Balances section
- using Volume API
Initiating Payout in Merchant Portal
In order to make a Payout, please go to Balances section and press Make Payout next to the account you want to make payment from.
Once you've made the payment and it has been finished, you'll see change in balance reflected in the same Balances page.
Initiating Payout using Volume API
Path
{{api-host}}/api/merchants/{{merchant-id}}/applications/{{application-id}}/payouts
Headers
Header | Value |
---|---|
x-app-name | application name |
x-application-id | application-id |
x-application-secret | application-secret |
Content-Type | application/vnd.volume.v0.7+json |
Accept | application/vnd.volume.v0.7+json |
Request Body
{
"payInAccountId": 10,
"amount": 50
}
Response Body
{
"payoutPaymentId": "50cb26b8-1a2d-4455-ba2a-f1c229779500",
"createdAtUtc": "2024-11-07T07:55:26.026",
"status": "IN_PROGRESS",
"payoutRequestDetails": {
"amount": 0.3,
"currency": "GBP",
"reference": "241107073325914PYB",
"destination": {
"type": "SCAN",
"name": "John Smith",
"accountNumber": "12345678",
"sortCode": "123456",
"iban": null
}
}
}
Failure Response
Error codes:
Error Code | Meaning |
---|---|
4xx | client errors including bad request, authentication/authorisation, configuration or payment status problems |
5xx | server errors |
Body:
{
"statusCode": 500,
"statusName": "INTERNAL_SERVER_ERROR",
"errorMessage": "Virtual Account Provider API Error -> ClientError code=INSUFFICIENT_BALANCE, message=Source does not have enough balance",
"traceId": "32671492024036f8",
"source": "MODULR"
}
Example Curl
curl --location 'https://api.sandbox.volumepay.io/api/merchants/{merchant-id}/applications/{application-id}/payouts' \
--header 'x-application-id: application-id' \
--header 'x-application-secret: aplication-secret' \
--header 'Content-Type: application/json' \
--data '{
"payInAccountId": 1,
"amount": 50
}'
With following values replaced by specific to your configuration:
- merchant-id
- application-id
- applicaiton-secret
Payout status
Payout status is delivered to you by Payout Webhooks.
Payout status has following values:
Status | Description |
---|---|
IN_PROGRESS | payment is in progress |
PROCESSED | payment is was processed (does not mean delivered) |
CANCELLED | payment was cancelled |
FAILED | payment failed |
HELD | payment is held and may require contact with volume for it's further processing |
RETURNED | payment was delivered to destination account and returned |
Payout status delivered by Webhooks
Once you've configured Payout Webhook URL in Merchant Portal, in Settings->Webhooks And Callbacks section, you will be provided with a Webhook for any status change. It is important to note that Webhooks are delivered in the same way regardless of where you have initiated Payout payment : in Merchant Portal or from the API.
Delivery guarantee
Each webhook is delivered until your endpoint answers with 200 OK.
Body
Webhook calls will be delivered as PUT REST call with following payload
{
"eventTimeUtc" : "2024-11-07T07:55:27.004128Z",
"applicationId" : "62b36790-f8cd-4764-8e19-2e19ada49cb1",
"payoutId" : "50cb26b8-1a2d-4455-ba2a-f1c229779500",
"payoutAmount" : 0.30,
"payoutCurrency" : "GBP",
"payoutReference" : "241107073325914PYB",
"payoutStatus" : "IN_PROGRESS",
"payoutStatusDescription" : "",
"payoutWebhookDeliveryAttempt" : 0,
"destination" : {
"type" : "SCAN",
"name" : "John Smith",
"accountNumber" : "12345678",
"sortCode" : "123456"
}
}
Important headers
Expect this call with following headers:
Header | Value |
---|---|
Content-Type | application/json |
Accept | application/json |
Authorization | signature of the request calculated as described here |
Security
You can verify webhook integrity by checking it's signature passed via Authorization header. Mechanism is identical to signature verification if regular payment webhooks. You can find description here
How to get pay-in accounts list
In order to initiate Payout you need to use following payload, that requires payInAccountId.
{
"payInAccountId": 10,
"amount": 50
}
What payInAccountId is.
You can have several bank accounts configured in your Merchant Application. For example you can have one external bank account and one Virtual Account, or two Virtual Accounts. The point is that you can have one or more account in Merchant Application. In order for CreatePayout to know from which account you want to make the payment, you need to provide an id of such account, and this is payInAccountId.
How can I get one.
There is an endpoint GetPayInAccounts that privides you with such information.
Path
{{api-host}}/api/merchants/{{merchant-id}}/applications/{{application-id}}/payin-accounts?onlyVirtualAccounts=true
Parameter | Value | Description |
---|---|---|
onlyVirtualAccounts | boolean | return only virtual accounts |
Headers
Header | Value |
---|---|
x-app-name | application name |
x-application-id | application-id |
x-application-secret | application-secret |
Accept | application/vnd.volume.v0.7+json |
Authentication/Authorization
Endpoint is authenticated and authorized via application-id and applicaiton-secret values passed using x-application-id and x-application-secret headers mentioned above.
Response Body
[
{
"id": 1,
"selector": "d71bae89-d70c-47f4-8be5-0a98ee70c6d9",
"forCurrency": "GBP",
"defaultForCurrency": null,
"accountHolderName": "Volume",
"accountIdentification1": {
"type": "ACCOUNT_NUMBER",
"number": "03330123"
},
"accountIdentification2": {
"type": "SORT_CODE",
"number": "000000"
},
"payeeAddress": {
"streetName": null,
"buildingNumber": null,
"postCode": null,
"townName": null,
"country": "GB",
"department": null,
"subDepartment": null,
"addressType": null
},
"isVirtualAccount": true,
"virtualAccountInformation": {
"balance": 269.00,
"availableBalance": 269.00,
}
}
]