curl --request POST \
--url https://api.next.orenda.finance/v1/customers/{customerId}/batch-payments/submit \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"action": "initiate",
"batchId": "3f1c8f9e-1d2b-4a3c-9e5f-6a7b8c9d0e1f",
"payments": [
{
"payer": {
"account": {
"type": "uk",
"sortCode": "010203",
"accountNumber": "12345678"
}
},
"payee": {
"name": "Ada Lovelace",
"account": {
"type": "uk",
"sortCode": "040506",
"accountNumber": "87654321"
}
},
"reference": "Invoice 1024",
"amount": "150.00"
}
]
}
'{
"success": true,
"totalAmount": "350.00",
"currency": "GBP",
"scaChallenge": {
"hash": "9f86d0...",
"nonce": "b1946ac9",
"timestamp": "2026-06-05T10:00:00Z"
}
}Submit a batch
Authorise and send the batch with SCA.
curl --request POST \
--url https://api.next.orenda.finance/v1/customers/{customerId}/batch-payments/submit \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"action": "initiate",
"batchId": "3f1c8f9e-1d2b-4a3c-9e5f-6a7b8c9d0e1f",
"payments": [
{
"payer": {
"account": {
"type": "uk",
"sortCode": "010203",
"accountNumber": "12345678"
}
},
"payee": {
"name": "Ada Lovelace",
"account": {
"type": "uk",
"sortCode": "040506",
"accountNumber": "87654321"
}
},
"reference": "Invoice 1024",
"amount": "150.00"
}
]
}
'{
"success": true,
"totalAmount": "350.00",
"currency": "GBP",
"scaChallenge": {
"hash": "9f86d0...",
"nonce": "b1946ac9",
"timestamp": "2026-06-05T10:00:00Z"
}
}action: "submit" to POST /v1/customers/{customerId}/batch-payments/submit
with the scaChallenge from initiate and a confirmation
object. There are three ways to authenticate (see the submit examples below):
- Passkey — first send
action: "passkey-challenge"to the same endpoint to get apasskeySessionandfido2options, run the passkey on the device, then submit withconfirmation: { "method": "passkey", "passkeySession": …, "assertion": … }. - 2FA code — submit with
confirmation: { "method": "totp", "totp": …, "accessToken": … }.accessTokenis theaccess_tokenfrom sign-in — not theid_tokenyou send as theAuthorizationbearer. - PIN (program capability) — submit with
confirmation: { "method": "pin", "pin": … }.
batchId. Then track the batch.
Paying a draft
batchId is required on this route. It comes from
verify, so this endpoint can only pay a batch that went through
verification — omitting it is a 400, not a new batch.
The draft is checked for expiry and for belonging to you, and it can only be paid once —
a second submit of the same draft is rejected rather than paying twice. One that has expired,
was already submitted, or belongs to someone else is rejected before any money moves.
POST /v1/customers/{customerId}/batch-payments) keeps the
previous contract: batchId is optional there, and omitting it creates a new batch. Existing
integrations are unaffected.initiate, passkey-challenge and submit — the three steps that
authorise a payment. action is required; "verify" is rejected with 403 and belongs to
verify.Send the same items you sent to initiate. The scaChallenge is bound to the payee
account and amount of every row, in order, so any change between the two calls invalidates it.403 until yours is
enabled. Until then, send action: "submit" to
POST /v1/customers/{customerId}/batch-payments — the request and response bodies are
identical. See the overview.Multi-customer and back office
Paying from the accounts of many customers in one batch? Use the path-less form,POST /v1/batch-payments/submit, which resolves each item’s payer account against you.
It is back-office only and rejects any account you are not responsible for.
Passkey step-up is always your passkey
The challenge is issued against the acting caller — the signed-in user’s own email and identity — never the customer being paid. An operator paying on behalf of a customer authenticates with their own passkey, and the assertion is bound to that identity, so a session minted for one user cannot authorise another user’s batch. The ceremony itself is identical on every route: sameaction: "passkey-challenge", same
passkeySession + fido2options response, same confirmation shape on submit. Only the
tenant the credential is looked up in differs:
| Caller | Passkey resolved against |
|---|---|
| Customer (front end) | your own program, honouring the sandbox flag |
| Back office | the shared back-office pool, production only |
programId is the program they’re acting on,
taken from the query string — their Cognito user and FIDO credentials live in the back-office
pool, not in that program. One consequence worth knowing: a back-office passkey ceremony
always resolves to production, even when the batch itself is a sandbox batch.
Send the Origin header on the challenge request. It is carried into the WebAuthn ceremony,
and a mismatch fails verification.
Retry safely
Pass anidempotencyKey (a UUID) in the request body and reuse the same key on every
retry, so a lost response can’t send the whole batch twice. See
Idempotency for the full retry contract.
Idempotency-Key header.idempotencyKey alone — it is not
scoped to the customer the way the single-resource creates are, and it does not make
submit replayable.Two submissions that share a key land on the same batchId and re-run the submission
rather than returning the first result: the funds are reserved again and the payments can
be sent a second time. Parameters aren’t compared either, so a reused key with a
different list of payments is not rejected.If a submit response is lost, do not resend. Track the
batch with the batchId to find out whether it landed — or, if
you never received one, list the customer’s
batches.idempotencyKey is optional today but will be required in a future release. Start
sending it now.Authorizations
The caller's id_token from authentication — the ID token, not the access_token. The program and environment come from the token.
Path Parameters
The customer id.
Body
Required — initiate, passkey-challenge or submit. verify is rejected with 403; it belongs to the /batch-payments/verify route.
initiate, passkey-challenge, submit The payment items. Required for initiate and submit, and must be identical between them or SCA verification fails.
Show child attributes
Show child attributes
The strong-customer-authentication challenge from initiate. Pass it back on submit.
Show child attributes
Show child attributes
Step-up confirmation (for submit). Set method to passkey, totp, or pin and include that method's fields. pin is a program capability — see Program capabilities.
- Passkey
- 2FA code
- PIN
Show child attributes
Show child attributes
Optional UUID. Reuse the same key to make submit safe to retry — batch and item IDs are then derived deterministically, so a retry cannot double-pay.
Required. The draft returned by verify. This route only pays a batch that was verified first, so initiate and submit both need it. It is checked for expiry and ownership and cannot be paid twice.
Response
Result for the requested step — initiate → totalAmount/currency/scaChallenge; passkey-challenge → passkeySession/fido2options; submit → batchId/status/counts.
The response is of type object.