PaySaxas XS2A
PSD2 access to account — Berlin Group NextGenPSD2 v1.3.15

← All documentation

Strong customer authentication (redirect)

PaySaxas offers the redirect approach only. The embedded and decoupled approaches are not implemented and will not be — the customer authenticates on our surface, and you never see, relay or store their credentials.

The flow

sequenceDiagram
    participant T as Your service
    participant P as PaySaxas XS2A
    participant C as Customer (PSU)
    participant A as PaySaxas auth surface

    T->>P: POST /v1/consents (or /v1/payments/...)
    P-->>T: 201 + consentId/paymentId + _links.scaRedirect
    T->>C: send them to scaRedirect
    C->>A: authenticates (password + SMS OTP)
    A->>C: shows exactly what is being granted
    C->>A: approves or declines
    A->>C: redirect to your TPP-Redirect-URI?state=...
    C->>T: returns with state
    T->>P: GET .../status
    P-->>T: valid | rejected | RCVD → ACSP ...

What the customer sees

For a consent: your name, the data types requested, the accounts (only those they hold), and the validity period.

For a payment: the amount and the payee, bound into the authentication itself — see dynamic linking below.

Dynamic linking (payments)

A payment ceremony is cryptographically bound to this amount and this payee. The binding is computed from the persisted payment, so an authorisation cannot be replayed against different money. If the payment changes after the ceremony was created, the authorisation fails — by design.

The state parameter

Unusually, we generate state, not you. Most OAuth-shaped flows have the client mint it; here the authorisation resource is ours, so the value is created when the authorisation is created and handed to you twice — appended to the scaRedirect link, and appended again to your redirect URI when the customer returns.

   
Source Generated by PaySaxas when the authorisation is created
Format UUID v4 — 36 characters, lowercase hex with hyphens, [0-9a-f-]
Lifetime The authorisation’s own: 15 minutes, or until it is finalised, declined or expires
Reuse Never. A new authorisation always carries a new value
Where you get it The scaRedirect href, as ?state=…
Where it comes back Your TPP-Redirect-URI, as ?state=…

What to do with it. Store it against the pending authorisation on your side — keyed by consentId or paymentId — and when the customer returns, compare the value on the incoming request with the one you stored. If they differ, or you hold no pending authorisation for it, discard the callback.

That comparison is the whole point: without it, anyone who can reach your redirect URI can claim a customer just approved something. It is not proof that the approval succeeded — always confirm with GET .../status — but it ties the return to a flow you actually started.

Treat it as opaque. The format above is what we emit today; do not parse it, derive anything from it, or assume it stays a UUID.

Redirect URIs

Timing

An authorisation lives for 15 minutes. After that the customer sees an expiry message and you must start again — the link is not renewable, since a stale approval prompt is exactly what a social-engineering attack wants.

Polling scaStatus

GET /v1/consents/{consentId}/authorisations/{authorisationId}
GET /v1/payments/{product}/{paymentId}/authorisations/{authorisationId}

Values: received, started, psuAuthenticated, finalised, failed.

Where authorisationId comes from

Take it from the creation response. POST /v1/consents and POST /v1/payments/{product} both return authorisationId as a top-level field, next to consentId / paymentId:

{
  "consentId": "…",
  "consentStatus": "received",
  "authorisationId": "AUTH-…",
  "_links": { "scaRedirect": { "href": "…" }, "scaStatus": { "href": "…" } }
}

If you no longer hold it, list the sub-resources:

GET /v1/consents/{consentId}/authorisations
GET /v1/payments/{product}/{paymentId}/authorisations
→ { "authorisationIds": ["AUTH-…"] }

Do not parse the id out of the scaStatus href. It appears there, but URL shape is not part of this contract and may change without a breaking-change notice; the field and the list above are the supported routes. Either follow _links.scaStatus as an opaque href, or use the id — not a substring of one.

Only the implicit authorisation start is offered — POST /v1/consents already returns scaRedirect, so there is no separate authorisation resource to create. The templated sub-resource exists for polling only.

When SCA is not repeated

Under RTS Art. 10a (as amended by (EU) 2022/2360), account data stays readable for 180 days after the customer’s authentication, without a fresh ceremony. The four-per-day unattended cap still applies throughout.

Payments always require a ceremony. We do not offer TRA, low-value or trusted-beneficiary exemptions on this channel.