Release candidate

This is v2.2-rc2 — a release candidate for the v2.2 standards, published for review and not yet ratified. It MUST NOT be used as the basis for a production implementation. For the current standards, switch to v2.1 using the version selector. See the v2.1 → v2.2-rc2 changelog for every change in this version.

LFI · Banking · Service Initiation · Multi-Authorization

Multi-Authorization 2 min read

The Open Finance standards support payment journeys that require more than one authorizer. This guide explains how TPPs and LFIs must coordinate multi-authorization for payment consents and how the consent lifecycle is reflected in API calls and responses.

01 Prerequisites

What you need before initiating a multi-authorization payment

Before initiating a multi-authorization payment, ensure the following are in place:

  • Registered Application — The application must be created within the Trust Framework and assigned the BSIP role as defined in Roles.
  • An active payment consent — A payment consent must have been created through the relevant Service Initiation API Guide. Multi-authorization applies after the first authorizer has completed their step.
  • Understanding of the Consent Journey — You should understand consent status transitions, including AwaitingAuthorization, Authorized, and Rejected.
02 Sequence Flow

API sequence flow

Sequence diagramMulti-AuthorizationClick to expand
03 PAR Request

Indicating multi-authorization support

Step 1 — Setting IsSingleAuthorization and AuthorizationExpirationDateTime in the PAR Request

When submitting the Pushed Authorization Request (PAR), the TPP MUST set IsSingleAuthorization inside authorization_details[].consent:

  • true — only a single authorizer is supported for the payment.
  • false — multiple authorizers are supported (multi-authorization enabled).

The TPP MAY also set AuthorizationExpirationDateTime inside authorization_details[].consent. This field is the deadline by which the consent MUST reach Status=Authorized — that is, by which all required authorizers must have acted. If the deadline passes while the consent is still AwaitingAuthorization, the consent is set to Rejected.

The field applies to both authorization modes, and the API Hub validates it identically in each. It is also the only field that bounds the authorization window — ExpirationDateTime bounds the life of the consent, not the time available to authorize it.

  • AuthorizationExpirationDateTime MUST NOT be in the past, and MUST NOT be after ExpirationDateTime.
  • When IsSingleAuthorization is false, the TPP SHOULD set it. Without it, a consent can sit part-authorized for as long as ExpirationDateTime allows.
  • When IsSingleAuthorization is true, the TPP MAY set it to cap how long the single authorizer has to complete the authorization journey. Earlier guidance on this page said TPPs SHOULD NOT set it in this case; the standard places no such restriction.
Tip

These fields are carried in the Rich Authorization Request (authorization_details[].consent.IsSingleAuthorization, authorization_details[].consent.AuthorizationExpirationDateTime). See the Authorization Endpoints OpenAPI for the full schema reference.

04 LFI Behaviour

LFI behavior

Step 2 — Account selection based on authorization type

Before showing eligible accounts during the consent journey, the LFI checks IsSingleAuthorization from the PAR request:

  • If true: allow selection only from accounts that require a single authorizer. If none exist, decline the consent, cancel the journey, and redirect the user to the TPP with an appropriate error.
  • If false: allow selection from accounts that require either single or multiple authorizers.

Step 3 — Managing the authorization flow

After the first user authorizes, the LFI must:

  • Inform OFH of required authorizers by PATCHing the consent to include Meta.MultipleAuthorizers.
  • Keep consent status as AwaitingAuthorization — do not set Status=Authorized yet.
  • Redirect back to the TPP via /doConfirm once the PATCH is accepted.

Example PATCH consents/{consentId} body after first authorizer (still awaiting others):

PATCH consents/{consentId}json
{
  "psuIdentifiers": {
    "userId": "52738e3b-eacf-4a7c-a73b-da01caa45c3f"
  },
  "accountIds": [
    "100004000000000000000001",
    "100004000000000000000003",
    "100004000000000000000004"
  ],
  "consentBody": {
    "Meta": {
      "MultipleAuthorizers": {
        "TotalRequired": 2,
        "Authorizations": [
          {
            "AuthorizerId": "ab7eb4fb-2446-4058-bbc4-114fe6d3f44a",
            "AuthorizerType": "admin-group",
            "AuthorizationStatus": "Pending"
          },
          {
            "AuthorizerId": "e5afc3c6-5064-4a9a-baab-5fd39c4cf1eb",
            "AuthorizerType": "admin-group",
            "AuthorizationStatus": "Pending"
          }
        ]
      }
    }
  },
  "authorizationChannel": "App"
}

The TPP receives the redirect/callback, exchanges the authorization code at /token, and receives an access token plus the consent object still marked AwaitingAuthorization, including the Meta.MultipleAuthorizers structure above.

05 Tracking

Tracking additional authorizations

Step 4 — Updating consent status after each authorization

The LFI must PATCH the consent after each additional authorization to reflect progress:

  • If any required authorizer rejects → set Status=Rejected.
  • When all required authorizers approve → set Status=Authorized.

Example: one authorizer approved, another still pending

one approved, one pendingjson
{
  "consentBody": {
    "Meta": {
      "MultipleAuthorizers": {
        "TotalRequired": 2,
        "Authorizations": [
          {
            "AuthorizerId": "ab7eb4fb-2446-4058-bbc4-114fe6d3f44a",
            "AuthorizerType": "admin-group",
            "AuthorizationDate": "2025-06-19T06:28:17Z",
            "AuthorizationStatus": "Approved"
          },
          {
            "AuthorizerId": "e5afc3c6-5064-4a9a-baab-5fd39c4cf1eb",
            "AuthorizerType": "admin-group",
            "AuthorizationStatus": "Pending"
          }
        ]
      }
    }
  },
  "authorizationChannel": "App"
}

Example: final approval — consent becomes Authorized

final approvaljson
{
  "consentBody": {
    "Data": {
      "Status": "Authorized"
    },
    "Meta": {
      "MultipleAuthorizers": {
        "TotalRequired": 2,
        "Authorizations": [
          {
            "AuthorizerId": "ab7eb4fb-2446-4058-bbc4-114fe6d3f44a",
            "AuthorizerType": "admin-group",
            "AuthorizationDate": "2025-06-19T06:28:17Z",
            "AuthorizationStatus": "Approved"
          },
          {
            "AuthorizerId": "e5afc3c6-5064-4a9a-baab-5fd39c4cf1eb",
            "AuthorizerType": "admin-group",
            "AuthorizationDate": "2025-06-19T08:10:02Z",
            "AuthorizationStatus": "Approved"
          }
        ]
      }
    }
  },
  "authorizationChannel": "App"
}

Example: a required authorizer rejects — consent becomes Rejected

authorizer rejectsjson
{
  "consentBody": {
    "Data": {
      "Status": "Rejected"
    },
    "Meta": {
      "MultipleAuthorizers": {
        "TotalRequired": 2,
        "Authorizations": [
          {
            "AuthorizerId": "ab7eb4fb-2446-4058-bbc4-114fe6d3f44a",
            "AuthorizerType": "admin-group",
            "AuthorizationDate": "2025-06-19T06:28:17Z",
            "AuthorizationStatus": "Approved"
          },
          {
            "AuthorizerId": "e5afc3c6-5064-4a9a-baab-5fd39c4cf1eb",
            "AuthorizerType": "admin-group",
            "AuthorizationStatus": "Rejected"
          }
        ]
      }
    }
  },
  "authorizationChannel": "App"
}