Handling interrupts

Possible interrupts are either dialogs that you have to display to your users or redirects, i.e., links to web pages to which you have to send users to.

Check interrupts:

  • JavaScript

  • Kotlin

  • Java

  • Rust

  • Swift

  • C++

  • Lua

switch (response.constructor) {
  case Result: ...; break
  case Dialog: ...; break
  case Redirect: ...; break
  case RedirectHandle: ...; break
}
when (response) {
    is Response.Dialog -> { /* ... */ }
    is Response.Redirect -> { /* ... */ }
    is Response.RedirectHandle -> { /* ... */ }
    is Response.Result -> { /* ... */ }
}
if (response instanceof Response.Dialog<AccountsResult> dialog) {
    // ...
} else if (response instanceof Response.Redirect<AccountsResult> redirect) {
    // ...
} else if (response instanceof Response.RedirectHandle<AccountsResult> handle) {
    // ...
} else if (response instanceof Response.Result<AccountsResult> result) {
    // ...
}
match response {
    OBResponse::Result(result, session, connection_data) => ...
    OBResponse::Dialog(dialog) => ...
    OBResponse::Redirect(redirect) => ...
    OBResponse::RedirectHandle(handle) => ...
}
switch response {
case .result(let result, let session, let connectionData):
    ...
case .dialog(let contex, let message, let image, let input):
    ...
case .redirect(let url, let context):
    ...
case .redirectHandle(let handle, let context):
    ...
}
template<typename... Ts> struct overloaded : Ts... {
    using Ts::operator()...;
};
template<typename... Ts> overloaded(Ts...) -> overloaded<Ts...>;

std::visit(overloaded {
    [](const yaxi::ServiceResult& result) {
        ...
    },
    [](const yaxi::Dialog& dialog) {
        ...
    },
    [](const yaxi::Redirect& redirect) {
        ...
    },
    [](const yaxi::RedirectHandle& handle) {
        ...
    },
}, response);
if response:isInstanceOf(Dialog) then
  ...
elseif response:isInstanceOf(Redirect) then
  ...
elseif response:isInstanceOf(RedirectHandle) then
  ...
elseif response:isInstanceOf(Result) then
  ...
end

Handle dialogs

Dialogs consist of an optional message and an optional image to display to the user as well as some input definition. Possible input types are:

Confirmation

The user needs to confirm the dialog. This is typically used when waiting for a decoupled authentication, e.g., confirmation in the bank’s app.

Selection

The user needs to choose from a list of options and confirm the choice.

Field

A text input field in which the user has to enter some value.

Example 1. Confirmation dialog with message

Please confirm the transaction in your authenticator app.

Example 2. Selection dialog without message

Example 3. Input dialog with message and image

Please use your TAN reader and enter the generated TAN.

The input details contain a context to continue with the process. Each service that might return interrupts also provides two ways for that, depending on the input type, e.g., for the accounts service:

Confirm dialog without input for the accounts service:

  • JavaScript

  • Kotlin

  • Java

  • Rust

  • Swift

  • C++

  • Lua

response = await client.confirmAccounts({ ticket, context })
response = client.confirmAccounts(ticket, context)
response = client.confirmAccounts(ticket, context).join();
let response = client.confirm_accounts(ticket, context).await?;
let response = try await client
    .confirmAccounts(ticket: ticket, context: context)
response = std::get<0>(client.confirmAccounts(ticket, context));
response = client:confirmAccounts({
  ticket = ticket,
  context = context,
})

Respond to any other dialog for the accounts service:

  • JavaScript

  • Kotlin

  • Java

  • Rust

  • Swift

  • C++

  • Lua

response = await client.respondAccounts({ ticket, context, response })
response = client.respondAccounts(ticket, context, userResponse)
response = client.respondAccounts(ticket, context, userResponse).join();
let response = client.respond_accounts({ticket, context, response}).await?;
let response = try await client.respondAccounts(
    ticket: ticket,
    context: context,
    response: response
)
response = std::get<0>(client.respondAccounts(ticket, context, response));
local response = client:respondAccounts({
  ticket = accountsTicket,
  context = context,
  response = response,
})

The passed response is either the user’s choice from the list of options/actions or the user’s input. The result is, again, either another interrupt or the desired data.

This is an example for the Accounts service. See your client SDK for the respective methods for other services.

Handle redirects

In case of a redirect, the user gets sent to a given URL. Desktop or mobile applications could either open it in a browser or inside an element like a WebView. Eventually, the user gets redirected to a URI that you provide. You may use it to redirect the user back to a web application or to jump back into the context of a desktop or mobile application.

The easiest and most efficient way to obtain a redirect URL is to provide your redirect URI before calling any service:

Set redirect URI:

  • JavaScript

  • Kotlin

  • Java

  • Rust

  • Swift

  • C++

  • Lua

await client.setRedirectUri('myapp://redirect?context=signup')
client.setRedirectUri("myapp://redirect?context=signup")
client.setRedirectUri("myapp://redirect?context=signup");
client.set_redirect_uri("myapp://redirect?context=signup")?;
client.setRedirectUri(redirectUri: "myapp://redirect?context=signup")
client.setRedirectUri("myapp://redirect?context=signup");
client:setRedirectUri("myapp://redirect?context=signup")

With a pre-set redirect URI services will provide redirect objects with the URL to send the user to and the context required to continue with the service.

If no redirect URI was set, the context will get returned along a handle that can be used to register a redirect URI and receive the redirect URL to use:

Register redirect URI:

  • JavaScript

  • Kotlin

  • Java

  • Rust

  • Swift

  • C++

  • Lua

let redirectUrl = await client.registerRedirectUri({
  ticket,
  handle,
  redirectUri: 'myapp://redirect?context=signup'
})
val redirectUrl = client.registerRedirectUri(
    ticket,
    handle,
    "myapp://redirect?context=signup",
)
String redirectUrl = client.registerRedirectUri(
    ticket,
    handle,
    "myapp://redirect?context=signup"
).join();
let redirect_url = client.register_redirect_uri(
    ticket,
    handle,
    "myapp://redirect?context=signup",
).await?;
let redirectUrl = try await client.registerRedirect(
    ticket: ticket,
    handle: handle,
    redirectUri: "myapp://redirect?context=signup"
)
auto redirectUrl = std::get<0>(client.registerRedirectUri(
    ticket,
    handle,
    "myapp://redirect?context=signup"
));
local redirectUrl = client:registerRedirectUri({
  ticket = accountsTicket,
  handle = handle,
  redirectUri = "myapp://redirect?context=signup",
})

When the redirect should be done, e.g., the URL that you provided got called or the user manually confirmed that he finished the process, you can continue with the redirect’s context as you would for a confirmation dialog:

Confirm redirect for the accounts service:

  • JavaScript

  • Kotlin

  • Java

  • Rust

  • Swift

  • C++

  • Lua

response = await client.confirmAccounts({
  ticket,
  context: redirect.context
})
val response = client.confirmAccounts(
    ticket,
    context = redirect.context,
)
Response<AccountsResult> response =
    client.confirmAccounts(ticket, redirect.getContext()).join();
let response = client
    .confirm_accounts(ticket, redirect.context)
    .await?;
let response = try await client
    .confirmAccounts(ticket: ticket, context: redirectContext)
auto response = std::get<0>(
    client.confirmAccounts(ticket, redirectContext)
);
response = client:confirmAccounts({
  ticket = ticket,
  context = redirect.context,
})
This is an example for the Accounts service. See your client SDK for the respective methods for other services.

Polling

Confirmation dialogs are often used for decoupled steps where the user takes some action directly with the bank. The user confirms the completion with the dialog. As it is a bit clumsy and inconvenient to ask the user for explicit confirmation, you may poll the status. A confirmation that may be polled indicates a polling delay. When you confirm the dialog while the decoupled step is not completed, you get back a new confirmation dialog that you can continue with.

Make sure to poll only those confirmation dialogs that indicate a polling delay and to respect the value as a minimum before doing so.
Make sure to stop polling at some point, as there are no guarantees that it will start failing if the step did not get completed.
Confirmation dialogs may also be meant purely for polling, e.g., when waiting for a final status of an instant payment. In such cases, an explicit user confirmation does not really make sense.

Polling is also possible for redirects for the case that you did not receive the signal, e.g. because the user or the system did not follow a deeplink into your app. When you confirm the redirect while it is not completed, you get back a confirmation dialog as well, indicating a redirect context and a polling delay. You can safely continue polling by confirming those dialogs.

Make sure to stop polling at some point, as there are no guarantees that it will start failing if the redirect did not get completed.

Test cases

Demo connections are available for development, one per credentials model combination. They exist only in the integration environment and are not reachable in production.

Credentials model Connection ID IBAN

User ID

connection-96386142-60e5-4ca9-abcf-944efce5bc1e

DE09000000000000000001

Full

connection-2618f4b3-8a97-4aa4-9cda-3601c05982ec

DE79000000000000000002

None

connection-a2c5b6e8-4646-4905-9853-ada53bf4a2b3

DE52000000000000000003

User ID or None

connection-08aff288-9f19-45ab-bfb7-02395522fd29

DE25000000000000000004

Full or None

connection-c16b7d8f-0a68-4ad0-a113-313984316c9e

DE95000000000000000005

Each IBAN is discoverable through the bank search and resolves to the corresponding demo connection.

The user identifier determines the test case; the demo accepts any password when one is required.

User identifier Response

result

Immediate service result

confirmation

SCA confirmation dialog

selection

Account selection dialog

input

photoTAN-like dialog

redirect or empty

Redirect

pollN

SCA confirmation dialog, pollable for N seconds (1-999)

random

All interrupt types, in random order

Any other user identifier returns an InvalidCredentials error.

Confirming a redirect or confirmation dialog or responding to a selection or input dialog with any value leads to a service result. In case of random, it leads to the next step. When all types have been completed, it leads to a service result. In case of pollN, confirming leads to the same dialog until N seconds have elapsed, then to a service result.