Verified payments
Add account-ownership verification and an approval gate to an Open Banking payment
Beta
Verified payments are currently in beta. Request/response shapes might be subject to change. Please reach out to your Volt contact before integrating.
Overview
A verified payment is a standard Open Banking payment with an Account Ownership Verification step placed in front of settlement. Before the payment is sent to the bank, the payer authenticates at their bank — confirming they have access to the account they are paying from — and Volt matches their name against the account holder name on the bank record. Volt sends you the account holder data and the name-match result, and the payment pauses for your approval decision — only once you approve does Volt initiate the transfer.
It runs as a single payment on the Global API and works with any integration channel — , , or the . Adding the X-Volt-Verified-Payment: true header to your existing POST /payments call is the only change required — the request body and the rest of your integration stay exactly the same. The verification and approval gate are surfaced through the usual paymentInitiationFlow, and you do not manage a separate account-access request; Volt handles the verification internally.
Availability
Verified payments are available for Open Banking (EU, UK) payments at institutions that support account verification. Talk to your Volt account manager to have verified payments enabled for your application.
How it works
A verified payment moves through two distinct ADDITIONAL_AUTHORIZATION_REQUIRED checkpoints:
- Account authorisation — the payer authorises at their bank, and Volt uses that authorisation to verify account ownership and read the account holder name.
- Approval gate — once verification and the name match complete, Volt sends you the account holder data and the name-match result, and the payment waits for your approve/refuse decision.
Steps
Authenticate with Volt
In order to use Volt's API you need to be authenticated. Use this to handle authentication with Volt's API.
Create the verified payment
Call POST /payments with your usual X-Volt-Initiation-Channel (here api) and add the X-Volt-Verified-Payment: true header. Everything else is the standard Open Banking payment body.
curl --request POST \
--url https://gateway.volt.io/payments \
--header 'authorization: Bearer <your access token>' \
--header 'content-type: application/json' \
--header 'idempotency-key: <your idempotency key>' \
--header 'x-volt-api-version: 1' \
--header 'x-volt-initiation-channel: api' \
--header 'x-volt-verified-payment: true' \
--data '{
"currency": "EUR",
"amount": 1000,
"paymentReference": "ABCDE12345F6GH78X9",
"internalReference": "your-internal-reference",
"payer": {
"email": "johndoe@example.com",
"firstName": "John",
"lastName": "Doe",
"reference": "JDOE-101"
},
"device": {
"ip": "192.168.0.1",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0",
"fingerprint": "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"
},
"paymentSystem": "OPEN_BANKING_EU",
"openBankingEU": {
"type": "SERVICES",
"institutionId": "<institution id>",
"accountIdentifiers": {
"iban": "DE75512108001245126199"
}
},
"communication": {
"return": {
"urls": {
"unified": { "url": "https://mywebsite.com/payment" }
}
},
"notifications": {
"url": "https://mywebsite.com/webhooks"
}
},
"termsAndConditionsAccepted": true
}'The payer name powers the match
Volt matches payer.firstName and payer.lastName against the account
holder name returned by the bank, so supply them as accurately as you can.
Volt sends you the match result so you can decide whether to approve the
payment (see step 5).
The payment is created and immediately enters account-ownership verification, returning ADDITIONAL_AUTHORIZATION_REQUIRED. The paymentInitiationFlow guides the payer through bank authorisation — for most banks, a redirect:
{
"id": "fbd0a297-9c96-48c9-a85e-ef5d3d986e96",
"status": "ADDITIONAL_AUTHORIZATION_REQUIRED",
"paymentInitiationFlow": {
"status": "PROCESSING",
"details": {
"reason": "AWAITING_USER_REDIRECT",
"redirect": {
"url": "https://vo.lt/short",
"directUrl": "https://myBank.com/authorisation?code=xyz"
}
}
}
// ...
}→
Payer authorises at their bank
The payer completes authentication and authorisation within the selected bank interface. This first authorisation is what lets Volt verify the account. The payment stays at ADDITIONAL_AUTHORIZATION_REQUIRED until it completes.
→
Select the account, if prompted
If the verified account holder has more than one account, the payment pauses at status ACCOUNT_SELECTION and the paymentInitiationFlow returns an ACCOUNT_ID input. Its allowedValues list the candidate accounts, and its propertyPath tells you where to put your choice. Submit the chosen account with PATCH /payments/{id}, the same way you resolve any required input. With a single account, this step is skipped automatically.
Volt matches the name, calculates the score and notifies you
Once the payer has authorised, Volt confirms the payer has access to the account and matches the payer name you supplied against the account holder name. Volt then sends the match score and the account holder data to your notification URL so you can decide whether to proceed. The notification contains a paymentInitiationFlow object, which now asks for your approval decision:
You can configure payment notifications in the Fuzebox or pass it directly in the POST /payments request.
{
"id": "fbd0a297-9c96-48c9-a85e-ef5d3d986e96",
"status": "ADDITIONAL_AUTHORIZATION_REQUIRED",
"score": 0.89,
"accountData": {
"accounts": [
{
"owner": "JANE DOE",
"balances": [
{
"type": "AVAILABLE",
"amount": {
"value": 20,
"currency": "EUR"
}
}
],
"identifiers": {
"iban": "DE69500105176334166465"
}
}
]
},
"paymentInitiationFlow": {
"status": "WAITING_FOR_INPUT",
"requiredInput": [
{
"name": "CUSTOMER_APPROVAL",
"propertyPath": "customer.approval.status",
"allowedValues": [
{
"name": "APPROVE",
"value": "APPROVED",
"description": null
},
{
"name": "REFUSE",
"value": "REFUSED",
"description": null
}
]
}
]
}
}Account holder data is delivered once
The account holder data (accountData) is included only in this
notification — it is not returned by GET /payments/{id}. Persist it from
the webhook if you need it for your approval logic or your records.
The notification carries:
score— name-match score as a floating-point value (for example,0.89); a higher value indicates a closer match between the payer name you supplied and the account holder name.accountData.accounts[].owner— account holder name returned by the bank.accountData.accounts[].balances— account balances, when available.accountData.accounts[].identifiers— account identifiers, such asiban.paymentInitiationFlow— asks for your approval decision through theCUSTOMER_APPROVALrequired input.
When account holder data is unavailable
If Volt can't retrieve the account holder data, the accountData fields
are omitted and score is 0.0. The approval gate still opens, so it
remains your decision whether to approve or refuse the payment.
While you're weighing the approval decision, the payer is still on your checkout — if you're polling GET /payments/{id} on their behalf (for example, in a hosted checkout screen), the paymentInitiationFlow reports a different, purely informational shape:
{
"id": "fbd0a297-9c96-48c9-a85e-ef5d3d986e96",
"status": "ADDITIONAL_AUTHORIZATION_REQUIRED",
"paymentInitiationFlow": {
"status": "PROCESSING",
"details": {
"reason": "AWAITING_CUSTOMER_APPROVAL"
}
}
// ...
}Two shapes, two audiences
The WAITING_FOR_INPUT/CUSTOMER_APPROVAL shape from the notification
above is addressed to you — it's what you get back if you call
GET/PATCH /payments/{id} directly. PROCESSING/AWAITING_CUSTOMER_APPROVAL
is addressed to the payer — it's what a payer-facing checkout polling
the same endpoint sees while your decision is still pending.
Submit your approval decision
Resolve the CUSTOMER_APPROVAL input by sending the decision to PATCH /payments/{id}. The value must be either APPROVED or REFUSED.
curl --request PATCH \
--url https://gateway.volt.io/payments/fbd0a297-9c96-48c9-a85e-ef5d3d986e96 \
--header 'authorization: Bearer <your access token>' \
--header 'content-type: application/json' \
--data '{
"customer": {
"approval": {
"status": "APPROVED"
}
}
}'→
APPROVED→ the payment advances toAPPROVED_BY_RISKand Volt initiates the transfer.REFUSED→ the payment ends atREFUSED_BY_RISKand is not sent to the bank.
The approval gate stays open for 30 seconds. If no decision is
submitted within that window, the payment is automatically refused
(REFUSED_BY_RISK), so resolve the input promptly.
Payer authorises the payment
After approval, Volt initiates the payment, and the payer completes the process within the selected bank interface to authorise the transfer — using whichever authorisation flow the bank supports.
→
Receive the result
Poll the GET /payments/{id} endpoint until the payment reaches a final state, or rely on the payment notification (webhook) Volt sends when the status changes. On success, the payment reaches COMPLETED.
You can configure payment notifications in the Fuzebox or pass it directly in the POST /payments request.
Payment statuses
A verified payment uses the standard Volt payment statuses. The sequence specific to this flow is below; see the for the full reference.
| Status | Meaning in the verified flow | Notification |
|---|---|---|
| NEW_PAYMENT | Payment created; account-ownership verification is starting. | No |
| ADDITIONAL_AUTHORIZATION_REQUIRED | Either the payer must authorise at their bank (verification), or — after verification — the payment is awaiting your approval decision. | No |
| ACCOUNT_SELECTION | The account holder has more than one account; one is being selected. | No |
| APPROVED_BY_RISK | You approved the payment; Volt is initiating the transfer. | No |
| REFUSED_BY_RISK | You refused the payment, or the approval gate timed out. The payment is not sent to the bank. | Yes |
| BANK_REDIRECT | The payer is being redirected to the bank to authorise the transfer. | Yes |
| COMPLETED | The payment was instructed and accepted by the payer's bank. | Yes |
| FAILED | The verification authorisation could not be completed. | Yes |
| CANCELLED_BY_USER | The payer declined the authorisation at their bank. | Yes |
| ABANDONED_BY_USER | The payer abandoned the payment. | Yes |
Next steps
How is this guide?
Last updated on