Transfer

Given a user’s online banking credentials, the Transfer Service allows to let users initiate arbitrary credit transfers.

Do not use this service to initiate pre-defined payments. The Collect Payment service is made for that purpose.
sequenceDiagram actor User participant YAXI participant Your Backend participant Bank User->>+Your Backend: Ticket request Your Backend-->>User: Ticket with ID rect rgb(243, 243, 243) note right of User: Encrypted and verified channel User->>+YAXI: Ticket YAXI->>+YAXI: Verify authenticity YAXI-->>-User: Bank login form User->>+YAXI: Send login credentials end YAXI->>+Bank: Initiate transfer opt Strong Customer Authentication Bank-->>-User: Request authorization User->>+Bank: Authorize end Bank-->>-YAXI: OK YAXI-->>-User: OK

Issue a service ticket backend

Use Transfer as a service identifier when issuing tickets. The service does not accept any ticket data.

Issue a service ticket:

  • Python

  • Java

  • Node.js

  • Rust

  • PHP

ticket_id = str(uuid.uuid4())
ticket = issue_ticket(ticket_id, "Transfer", None)
String ticketId = UUID.randomUUID().toString();
String ticket = issueTicket(ticketId, "Transfer", null);
let ticketId = uuidv4()
let ticket = issueTicket(ticketId, 'Transfer', null)
let ticket_id = Uuid::new_v4().to_string();
let ticket = issue_ticket(&ticket_id, "Transfer", ())?;
$ticketId = uniqid();
$ticket = issueTicket($ticketId, 'Transfer', null);

Call the service frontend

  • The payment product

  • An optional debtor account.

    Providing a debtor account in the request may reduce the number of confirmation steps the user must complete. For this reason, you should include a debtor account whenever it is available to you, whether retrieved from the accounts service, stored from a previous transaction, or collected from the user in an earlier step.

    If you don’t provide a debtor account, 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 one element, its primary purpose is to inform the client of the IBAN (for example, for future use), and you can handle the response automatically. 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).

  • An optional debtor name.

  • An optional execution data.

    Providing an execution date (and time) will schedule a transfer, if supported. If no execution date is provided, the transfer gets submitted for immediate execution.

  • A list of transfer details.

    The list typically contains a single entry for single transfers. Multiple entries lead to the submission of a bulk payment, if supported.

Refer to your client library for details and documentation.

Call the service:

  • JavaScript

  • Kotlin

  • Rust

  • Swift

  • C++

await client.transfer({
  credentials,
  ticket,
  product: PaymentProduct.DefaultSepaCreditTransfer,
  debtorAccount: { (1)
    iban: "NL58YAXI1234567890",
    currency: "EUR"
  },
  debtorName: "Debtor", (2)
  details: [
    {
      amount: {
          amount: "100.00",
          currency: "EUR"
      },
      creditorAccount: {
          iban: "NL58YAXI1234567890"
      },
      creditorName: "John Doe",
    },
  ],
})
1 Optional debtor account
2 Optional debtor name
client.transfer(
    credentials,
    ticket = ticket,
    product = PaymentProduct.DEFAULT_SEPA_CREDIT_TRANSFER,
    debtorAccount = AccountReference( (1)
        AccountIdentifier.Iban("NL58YAXI1234567890"),
        currency = "EUR",
    ),
    debtorName = "Debtor", (2)
    details = listOf(
        TransferDetails(
            amount = Amount(BigDecimal("100.00"), "EUR"),
            creditorAccount = AccountIdentifier.Iban("NL58YAXI1234567890"),
            creditorName = "John Doe",
        ),
    ),
)
1 Optional debtor account
2 Optional debtor name
client.transfer(
    credentials,
    ticket,
    PaymentProduct::DefaultSepaCreditTransfer,
    Some(AccountReference { (1)
        id: AccountIdentifier::Iban("NL58YAXI1234567890".to_string()),
        currency: Some("EUR".to_string()),
    }),
    Some("Debtor".to_string()), (2)
    None, (3)
    [TransferDetails::new(
        Amount::new(100, "EUR"),
        AccountIdentifier::Iban("NL58YAXI1234567890".to_string()),
        "John Doe",
    )],
).send().await?;
1 Optional debtor account
2 Optional debtor name
3 No execution date for immediate execution
try await client.transfer(
    credentials: credentials,
    session: nil,
    ticket: ticket,
    product: .defaultSepaCreditTransfer,
    details: [TransferDetails(
        amount: Amount(
            currency: "EUR",
            amount: Decimal(string: "100.00")!
        ),
        creditorAccount: .iban("NL58YAXI1234567890"),
        creditorName: "John Doe"
    )],
    debtorAccount: AccountReference( (1)
        id: .iban("NL58YAXI1234567890"),
        currency: "EUR"
    ),
    debtorName: "Debtor" (2)
)
1 Optional debtor account
2 Optional debtor name
client.transfer(
    credentials,
    ticket,
    yaxi::PaymentProduct::DefaultSepaCreditTransfer,
    {{
        .amount = "100.00",
        .currency = "EUR",
        .creditorIban = "NL58YAXI1234567890",
        .creditorName = "John Doe",
    }},
    yaxi::AccountReference{ (1)
        .iban = "NL58YAXI1234567890",
        .currency = "EUR",
    },
    "Debtor" (2)
);
1 Optional debtor account
2 Optional debtor name

Result frontend backend

A successful response from the service confirms that the user’s bank has received the payment initiation 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.

The resulting JWT contains the following data, if requested in the ticket:

Example result:

  • Result JWT

  • Decoded JWT header

  • Decoded JWT payload

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6ImFwaS1rZXktMjE0YWQ
2MDEtZmFlNS00NWY4LTllNDItYTFiNTdkNTA0MTRjIn0.eyJkYXRhIjp7ImRhdG
EiOnt9LCJ0aWNrZXRJZCI6IjE5YzNjYmYxLWFjYWUtNGE3ZS1hMGU3LTc5OWJiY
mVmMzllYiIsInRpbWVzdGFtcCI6IjIwMjUtMDYtMDFUMTE6MTE6MzAuNDIwODA4
OTE2WiJ9LCJleHAiOjI1NDA4MDgwMDB9.yBf2tn-aFptMbvp-ZV-8faLtC8i785
uVpcTFMfpsHzQ
{
  "typ": "JWT",
  "alg": "HS256",
  "kid": "api-key-214ad601-fae5-45f8-9e42-a1b57d50414c"
}
{
  "data": {
    "data": {}, (1)
    "ticketId": "19c3cbf1-acae-4a7e-a0e7-799bbbef39eb",
    "timestamp": "2025-06-01T11:11:30.420808916Z"
  },
  "exp": 2540808000
}
1 Note that no data is returned here. The fact that a Result was returned means that the payment initiation was successful.