Collect Payment
Given a user’s online banking credentials, the Collect Payment Service allows to let users initiate pre-defined payments.
Do not use this service to initiate user-defined payments. |
Issue a service ticket 
Use CollectPayment
as a service identifier when issuing tickets.
The service expects the following ticket data:
Restrictions on remittance and creditor name:
-
Some banks require a minimum remittance of a few characters.
-
Long texts may be truncated, typically with a limit of 140 characters for remittance and 70 for the creditor name.
-
Providers accept different character sets for the creditor name and remittance. The safe baseline is:
abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 /-?:().,' + Space
Other characters may be accepted, rejected, stripped or replaced.
The service officially only supports payments in EUR to creditor accounts within the eurozone. Payments with other currencies and receivers (within the Single Euro Payments Area) should generally work, though. Use them at your own risk, but feel free to report any issues. Also do not hesitate to contact us to discuss specific requirements. |
Issue a service ticket:
-
Python
-
Java
-
Node.js
-
Rust
-
PHP
ticket_id = str(uuid.uuid4())
ticket = issue_ticket(
ticket_id,
"CollectPayment",
{
"amount": {
"amount": "100",
"currency": "EUR",
},
"creditorAccount": {
"iban": COMPANY_IBAN,
},
"creditorName": COMPANY_NAME,
"remittance": f"Sign-up fee {PRODUCT_NAME} {customer_id}",
},
)
String ticketId = UUID.randomUUID().toString();
String ticket = issueTicket(
ticketId,
"CollectPayment",
Map.of(
"amount", Map.of(
"amount", "100",
"currency", "EUR"
),
"creditorAccount", Map.of(
"iban", COMPANY_IBAN
),
"creditorName", COMPANY_NAME,
"remittance", "Sign-up fee " + PRODUCT_NAME + " " + customer_id
)
);
let ticketId = uuidv4()
let ticket = issueTicket(
ticketId,
'CollectPayment',
{
amount: { amount: '100', currency: 'EUR' },
creditorAccount: { iban: COMPANY_IBAN },
creditorName: COMPANY_NAME,
remittance: `Sign-up fee ${PRODUCT_NAME} ${customerId}`
}
)
let ticket_id = Uuid::new_v4().to_string();
let ticket = issue_ticket(
&ticket_id,
"CollectPayment",
json!({
"amount": {
"amount": "100",
"currency": "EUR",
},
"creditorAccount": {
"iban": COMPANY_IBAN,
},
"creditorName": COMPANY_NAME,
"remittance":
format!("Sign-up fee {PRODUCT_NAME} {customer_id}")
}),
)?;
$ticketId = uniqid();
$ticket = issueTicket(
$ticketId,
"CollectPayment",
json_encode([
'amount' => [
'amount': '100',
'currency': 'EUR',
],
'creditorAccount' => [
'iban' => $COMPANY_IBAN,
],
'creditorName' => $COMPANY_NAME,
'remittance' => 'Sign-up fee '.$PRODUCT_NAME.' '.$customerId,
])
);
Instant by default
By default, instant payments are requested if possible, with a fallback to non-instant payments.
In case you need more fine-grained control, e.g. to inform the user or ask for confirmation, you can specify the instant
property in the ticket data.
With instant
set to true
, the service will try to request an instant payment and return an UnsupportedProduct
error if that fails.
With instant
set to false
, it will request a non-instant payment if possible.
Note that full control is not always possible, as some providers do not offer separate interfaces and/or apply implicit fallbacks.
Call the service 
The client accepts the following arguments:
-
An optional debtor account.
This could be provided by the user, known from a previous transaction, or gathered from the accounts service.
If no debtor account is provided, a selection dialog may be returned, depending on the bank. This dialog indicates the
Accounts
context and provides options for each possible IBAN. If the list contains only a single element, its main purpose is to inform the client of the IBAN (e.g., for future use), and the response can be automated. For building a richer user selection dialog, we recommend using the accounts service beforehand (please contact us if this service is not included in your plan).
Refer to your client library for details and documentation.
Call the service:
-
JavaScript
-
Kotlin
-
Rust
-
Swift
await client.collectPayment({
credentials,
ticket,
account: { (1)
iban: "NL58YAXI1234567890",
currency: "EUR"
}
})
1 | Optional debtor account |
client.collectPayment(
credentials,
ticket = ticket,
account = AccountReference( (1)
AccountIdentifier.Iban("NL58YAXI1234567890"),
currency = "EUR",
),
)
1 | Optional debtor account |
client.collect_payment(
credentials,
None,
ticket,
Some(AccountReference { (1)
id: AccountIdentifier::Iban("NL58YAXI1234567890".to_string()),
currency: Some("EUR".to_string()),
}),
).await?;
1 | Optional debtor account |
try await client.collectPayment(
credentials: credentials,
session: nil,
ticket: ticket,
account: AccountReference( (1)
id: .iban("NL58YAXI1234567890"),
currency: "EUR"
)
)
1 | Optional debtor account |
Result 
A successful response from the service confirms that the user’s bank has initiated the payment using the properties specified in the ticket you previously issued in your backend. This means that the user has authorized the payment and has neither canceled nor rejected it. Finally, you forward the result to your backend system to reconcile its data with the ticket after verifying its authenticity.
The service currently does not provide a transaction status, but we plan to add this in the future. Feel free to contact us to discuss any specific requirements. |
Example result:
-
Result JWT
-
Decoded JWT header
-
Decoded JWT payload
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6ImFwaS1rZXktMjE0YWQ 2MDEtZmFlNS00NWY4LTllNDItYTFiNTdkNTA0MTRjIn0.eyJkYXRhIjp7ImRhdG EiOm51bGwsInRpY2tldElkIjoiMTljM2NiZjEtYWNhZS00YTdlLWEwZTctNzk5Y mJiZWYzOWViIiwidGltZXN0YW1wIjoiMjAyNS0wNi0wMVQxMToxMTozMC40MjA4 MDg5MTZaIn0sImV4cCI6MjU0MDgwODAwMH0.-UigvbxCp9LJjueo3Oha1QMzdEY 6iYFQGsLwD2JD2Uk
{
"typ": "JWT",
"alg": "HS256",
"kid": "api-key-214ad601-fae5-45f8-9e42-a1b57d50414c"
}
{
"data": {
"data": null, (1)
"ticketId": "19c3cbf1-acae-4a7e-a0e7-799bbbef39eb",
"timestamp": "2025-06-01T11:11:30.420808916Z"
},
"exp": 2540808000
}
1 | Note that a successful Collect Payment doesn’t contain any data. The fact that a Result was returned means that the payment was successful. |
Recovery
If your frontend is unable to retrieve (or forward) the final response, you can use the ticket ID to request the last status from the service. The service retains the status for about 15 minutes and exposes it via an HTTP endpoint:
Method: POST
Path: /collect-payment/status/{ticketId}
curl -X POST \
https://api.yaxi.tech/collect-payment/status/0708c88b-382a-4aef-9677-8201c6b1817c