---
title: "Complete an SCA login"
method: POST
path: "/sca/login/complete"
tags: ["Strong Customer Authentication"]
---

# Complete an SCA login

`POST /sca/login/complete`

Finalize an SCA login by submitting the proof for the started factor
(`code` for `SMS_OTP` / `TOTP`, or `passkeyAssertion` + `origin` for
`PASSKEY`), echoing the `challengeId` for `SMS_OTP`. Returns the
reported session status.

This endpoint is only meaningful for customers in a region where SCA is required (e.g. EU). For customers outside SCA-regulated regions, this returns `409`.

In sandbox, the SMS/TOTP code is always `123456`.

## Request body

- union — Completes an SCA login by submitting the proof for the started factor. Carries the same proof fields as an `ScaAuthorization` (`code` for `SMS_OTP` / `TOTP`, or `passkeyAssertion` + `origin` for `PASSKEY`), plus the `factor` being completed, the `endUserIpAddress` the login is being performed from, and, for `SMS_OTP`, the `challengeId` returned by the login start.
  - object
    - `factor` 'SMS_OTP' | 'TOTP' | 'PASSKEY', required — A Strong Customer Authentication factor. | Factor | Description | |--------|-------------| | `SMS_OTP` | One-time code sent by SMS to the customer's verified phone. Requires no prior enrollment. | | `TOTP` | Time-based one-time code from an authenticator app. Requires enrollment. Not valid for per-transaction challenges (cannot carry dynamic linking). | | `PASSKEY` | WebAuthn passkey assertion. Requires enrollment. |
    - `endUserIpAddress` string, required — The IP address of the end user's device completing this login, recorded against the login event by the SCA provider. Supply the customer's address, not your server's — it feeds the provider's risk assessment and any transaction-risk exemption.
    - `challengeId` string, nullable — The challenge handle returned by the login start, required for `SMS_OTP` and omitted for other factors.
    - `code` string, nullable, required — The one-time code the customer received by SMS, or read from their authenticator app. Provide for `SMS_OTP` / `TOTP`. In sandbox, the code is always `123456`.
    - `passkeyAssertion` object, nullable — Opaque WebAuthn assertion produced by the device from the login start's `passkeyOptions`. Required when completing a `PASSKEY` login.
    - `origin` string, nullable — The WebAuthn origin the `passkeyAssertion` was produced against (one of the login start's `allowedOrigins`). Required alongside `passkeyAssertion`; omit it for the `code` path.
  - object
    - `factor` 'SMS_OTP' | 'TOTP' | 'PASSKEY', required — A Strong Customer Authentication factor. | Factor | Description | |--------|-------------| | `SMS_OTP` | One-time code sent by SMS to the customer's verified phone. Requires no prior enrollment. | | `TOTP` | Time-based one-time code from an authenticator app. Requires enrollment. Not valid for per-transaction challenges (cannot carry dynamic linking). | | `PASSKEY` | WebAuthn passkey assertion. Requires enrollment. |
    - `endUserIpAddress` string, required — The IP address of the end user's device completing this login, recorded against the login event by the SCA provider. Supply the customer's address, not your server's — it feeds the provider's risk assessment and any transaction-risk exemption.
    - `challengeId` string, nullable — The challenge handle returned by the login start, required for `SMS_OTP` and omitted for other factors.
    - `code` string, nullable — The one-time code the customer received by SMS, or read from their authenticator app. Provide for `SMS_OTP` / `TOTP`. In sandbox, the code is always `123456`.
    - `passkeyAssertion` object, nullable, required — Opaque WebAuthn assertion produced by the device from the login start's `passkeyOptions`. Required when completing a `PASSKEY` login.
    - `origin` string, nullable, required — The WebAuthn origin the `passkeyAssertion` was produced against (one of the login start's `allowedOrigins`). Required alongside `passkeyAssertion`; omit it for the `code` path.

## Response `200`

SCA login completed; the session status is returned.

- ScaLoginComplete — The status of a completed SCA login session.
  - `status` string, required — The status of the login session. A successful login reports `SUCCESS`; other values indicate the login did not complete and should be surfaced to the caller.
  - `sessionExpiresAt` string, date-time, nullable — Absolute UTC timestamp after which the customer's SCA session is no longer valid and they must complete another SCA login. Money movement in SCA-regulated currencies is refused once it passes, so prompt a re-login ahead of it rather than waiting for a `SCA_SESSION_REQUIRED` failure. Present when the login established a session.

## Other responses

- `400` — Invalid or expired proof
- `401` — Unauthorized
- `404` — Customer not found
- `409` — SCA is not required for this customer.
- `423` — The customer's login is locked (or suspended) after too many failed attempts. `details.lockedUntil` says when they may retry.
- `500` — Internal service error

---

[API](https://skmtc.net/stainless-api/apis/grid-api.md) · [All operations](https://skmtc.net/stainless-api/apis/grid-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/stainless-api/grid-api/revisions/b06902b6595a/schema)
