curl --request POST \
--url https://api.next.orenda.finance/v1/customers/{customerId}/batch-payments/verify \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"action": "verify",
"payments": [
{
"payer": {
"account": {
"type": "uk",
"sortCode": "010203",
"accountNumber": "12345678"
}
},
"payee": {
"name": "Ada Lovelace",
"account": {
"type": "uk",
"sortCode": "040506",
"accountNumber": "87654321"
},
"accountType": "CONSUMER"
},
"reference": "Invoice 1024",
"amount": "150.00"
},
{
"payer": {
"account": {
"type": "iban",
"iban": "DE89370400440532013000"
}
},
"payee": {
"name": "Grace Hopper",
"account": {
"type": "iban",
"iban": "FR7630006000011234567890189",
"bic": "AGRIFRPP"
}
},
"reference": "Invoice 1025",
"amount": "200.00"
}
]
}
'{
"success": true,
"data": {
"requestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"status": "PENDING",
"batchId": "3f1c8f9e-1d2b-4a3c-9e5f-6a7b8c9d0e1f",
"expiresAt": "2026-08-17T09:00:00.000Z"
}
}{
"success": false,
"code": "VALIDATION_ERROR",
"message": "Validation failed: payments: Required"
}{
"message": "Unauthorized"
}{
"success": false,
"code": "FORBIDDEN",
"message": "Forbidden"
}{
"success": false,
"code": "RESOURCE_NOT_FOUND",
"message": "Batch not found"
}{
"success": false,
"code": "FUNDING_FAILED",
"message": "Insufficient available balance"
}{
"success": false,
"code": "SCA_REQUIRED",
"message": "Strong Customer Authentication required"
}{
"success": false,
"code": "INTERNAL_SERVER_ERROR",
"message": "Internal Server Error"
}Verify a batch (single customer)
Step 1. Submits the items for validation against your program’s rules and a name check on the payee (Confirmation of Payee in the UK, Verification of Payee in the EU). Returns a requestId, a batchId, and expiresAt. Validation runs in the background; poll Get verify status with the requestId. Nothing is charged or reserved, so verify as often as the user edits.
This route serves only verify. The action field is optional and defaults to "verify"; initiate, passkey-challenge, and submit are rejected with 403 and belong to the submit route. It’s gated separately from paying a batch, so preparation can be granted without the ability to move money.
Items. Each item is one payment. UK programs send accountNumber and sortCode; EU programs send iban and bic. A reference (6 to 64 characters) and amount are required. Add scheduledDate (YYYY/MM/DD) to send an item on a future date.
Drafts. Verifying creates a draft and returns its batchId and expiresAt. The draft records that these items are prepared and awaiting submission, which is what lets one person prepare a batch and another pay it. Send the same batchId back to re-verify after edits and the draft is updated in place, keeping its original creation time. A draft expires after 7 days, or at the end of its earliest scheduledDate, whichever comes first. After that it can’t be submitted; verify the items again for a new draft.
Sending a file. Post a CSV or an ISO 20022 pain.001 file as file: { content, format } instead of payments (one or the other, not both) and we parse it. format is optional; omitted, it’s detected from the content. Each row becomes an item and is validated the same way, so a bad row comes back in invalidPayments rather than being dropped. Only verify takes a file, and only on the split verify routes.
pain.001 is accepted in any version from .03 to .09. Namespace prefixes, BIC and BICFI, and all three ReqdExctnDt forms (bare, Dt, DtTm) are handled. UK sort codes are read from CdtrAgt/FinInstnId/ClrSysMmbId/MmbId only when ClrSysId/Cd is GBDSC, or when no scheme is named and the payee has no IBAN, so a German DEBLZ Bankleitzahl isn’t mistaken for one. The reference comes from RmtInf/Ustrd (joined if it repeats), falling back to RmtInf/Strd/CdtrRefInf/Ref. A past ReqdExctnDt is kept, not corrected, so the draft’s expiresAt is already elapsed and submit fails on expiry. InstdAmt/@Ccy is ignored; payments settle in the payer account’s currency. camt.053 is a statement, not a payment file, and is rejected.
CSV is the published batch template. The header row is found by looking for the Payee Name column, so a title row above it is fine, and quoted fields are honoured. Amount must be dot-decimal (1234.56); a decimal comma in an unquoted cell splits the row. Dates must be YYYY-MM-DD or YYYY/MM/DD (single-digit month or day is padded); anything else comes back as an invalid row rather than being guessed at.
Anything the parser couldn’t use (an unrecognised Payee AccountType, an EndToEndId outside 2 to 35 characters, a row whose column count differs from the header) is reported in a warnings array. The payments are still queued; the field is absent when there’s nothing to report.
initiatorId is ignored here; the path customerId is authoritative. Use POST /v1/batch-payments/verify to target customers by initiatorId.
Rollout. The split verify and submit routes are enabled per program and return 403 until yours is. Until then, send the same action to the single endpoint POST /v1/customers/{customerId}/batch-payments; the request and response bodies are identical, except that the single endpoint doesn’t accept a file.
curl --request POST \
--url https://api.next.orenda.finance/v1/customers/{customerId}/batch-payments/verify \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"action": "verify",
"payments": [
{
"payer": {
"account": {
"type": "uk",
"sortCode": "010203",
"accountNumber": "12345678"
}
},
"payee": {
"name": "Ada Lovelace",
"account": {
"type": "uk",
"sortCode": "040506",
"accountNumber": "87654321"
},
"accountType": "CONSUMER"
},
"reference": "Invoice 1024",
"amount": "150.00"
},
{
"payer": {
"account": {
"type": "iban",
"iban": "DE89370400440532013000"
}
},
"payee": {
"name": "Grace Hopper",
"account": {
"type": "iban",
"iban": "FR7630006000011234567890189",
"bic": "AGRIFRPP"
}
},
"reference": "Invoice 1025",
"amount": "200.00"
}
]
}
'{
"success": true,
"data": {
"requestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"status": "PENDING",
"batchId": "3f1c8f9e-1d2b-4a3c-9e5f-6a7b8c9d0e1f",
"expiresAt": "2026-08-17T09:00:00.000Z"
}
}{
"success": false,
"code": "VALIDATION_ERROR",
"message": "Validation failed: payments: Required"
}{
"message": "Unauthorized"
}{
"success": false,
"code": "FORBIDDEN",
"message": "Forbidden"
}{
"success": false,
"code": "RESOURCE_NOT_FOUND",
"message": "Batch not found"
}{
"success": false,
"code": "FUNDING_FAILED",
"message": "Insufficient available balance"
}{
"success": false,
"code": "SCA_REQUIRED",
"message": "Strong Customer Authentication required"
}{
"success": false,
"code": "INTERNAL_SERVER_ERROR",
"message": "Internal Server Error"
}Authorizations
The caller's access_token from authentication. Management API callers send the id_token. The program and environment come from the token.
Path Parameters
The customer id.
Query Parameters
Required on the Management API, where the token carries no program: omitting it returns 400. Customer API callers resolve the program from their token and should omit it; a value sent there is ignored.
Body
- Option 1
- Option 2
Send either payments or file: exactly one. A request carrying both is refused rather than resolved by precedence.
The payment items to validate. Required unless a file is sent instead.
Show child attributes
Show child attributes
Optional: this route serves only verify, so a missing value defaults to it. Any other value is rejected with 403.
verify A CSV or pain.001 file to parse into payments instead of sending payments. Exactly one of payments / file is required; sending both is rejected.
Show child attributes
Show child attributes
Optional. The draft being re-verified after edits: the draft is updated in place and keeps its original creation time. Omit to create a new draft.
Legacy step-up credential. Superseded by confirmation.
Legacy TOTP step-up code. Superseded by confirmation.
Legacy passkey session id. Superseded by confirmation.
Legacy passkey assertion. Superseded by confirmation.