PENDING_AUTHORIZATION with an scaChallenge, and you
authorize it before the transfer is released. For where this sits in the wider
SCA surface, see the overview.
This applies only to customers in a region where Strong Customer Authentication
is required, in practice customers in the EU (EUR / USDC). For every other
customer, none of this appears: money-movement calls complete as usual, no
scaChallenge is returned, and the authorization endpoints are not used. If you
don’t serve EU customers you can skip this section.When you’ll encounter it
For an SCA-required customer, a money-movement call that would otherwise complete instead returns the transaction (or quote) in statusPENDING_AUTHORIZATION
with an scaChallenge object, and the transfer is not released until the
challenge is satisfied. This affects debits such as:
- Sending EUR / USDC (SEPA and intra-ledger transfers)
- Cross-currency conversions from EUR / USDC (the swap leg)
- On-chain and Lightning withdrawals
Authentication factors
ThescaChallenge.availableFactors field tells you which factors the customer
may use. scaChallenge.factor is the one in use (default SMS_OTP).
TOTP cannot satisfy a dynamically linked debit because its code cannot be bound
to the amount and payee. For a non-dynamically-linked challenge, use TOTP only
when it appears in
scaChallenge.availableFactors; that field is authoritative.
Request a specific factor per transaction with the optional top-level scaFactor
field on execute (SMS_OTP default, or PASSKEY).
Satisfying a challenge
Submit anScaAuthorization proof to POST /quotes/{quoteId}/authorize for the
quote that carries the challenge. Provide exactly one of code (for SMS_OTP)
or passkeyAssertion + origin (for PASSKEY):
PENDING_AUTHORIZATION, authorize it:
POST /quotes/{quoteId}/authorize. This is the single authorize path for both
execute (pre-funded) and realtime-funding quotes. The challenge — and the SMS
code or passkey assertion that satisfies it — only exists after the challenge is
issued, so the proof is always supplied on this follow-up call, never on the
originating request.
For a realtime-funding quote, the
202 / PENDING_AUTHORIZATION response
withholds paymentInstructions until the challenge is authorized. Authorize
first, then read paymentInstructions from the returned (advanced) quote. If you
read them off the initial pending response you’ll show the customer nothing to
fund.expiresAt is not extended. Use the quote resend endpoint:
POST /quotes/{quoteId}/authorize/resend.
In sandbox, the SMS code is always
123456.Reducing prompts for repeat payees
Trusting a beneficiary (a one-time SCA-gated whitelisting step) lets subsequent sends to that payee skip the per-transaction challenge. Use this for recurring payouts to known destinations rather than authorizing every send.Calling a customer outside SCA-regulated regions
The authorization endpoints return409 for customers outside SCA-regulated
regions (non-EU), and no scaChallenge is ever attached to their transactions.
You don’t need to branch on region. Handle scaChallenge when it’s present and
treat its absence as nothing to do.
Walkthrough by flow
The mechanics above are the same everywhere: inspect for anscaChallenge,
submit an ScaAuthorization, and repeat until the resource leaves
PENDING_AUTHORIZATION. What differs between flows is which call first returns
the challenge and which resource you authorize. Here is each one end to end.
- Send a payment (execute a quote)
- Realtime-funding quote
- Transfer-out
The common case — lock a quote, execute it, authorize the quote.
1
Lock a quote
POST /quotes returns a quote as usual. A standard (prefunded) send carries no
challenge at quote time.2
Execute the quote
POST /quotes/{quoteId}/execute returns the quote in PENDING_AUTHORIZATION
with an scaChallenge.3
Authorize the quote
POST /quotes/{quoteId}/authorize with the proof. Re-inspect the returned quote:
if it remains PENDING_AUTHORIZATION, authorize its next scaChallenge. Do not
assume a fixed number of challenges for a cross-currency or other multi-step
send.