Implement SCA if you serve end users in the European Economic Area (EEA).
Whether SCA applies depends on each end user, not on your platform. Check each
end user, as described in step 1.
Prerequisites
Before you begin, ensure that you’ve:- Registered your application origin with Circle. Reach out to your support team
with the exact origin (scheme + host, for example
https://app.example.com). Registration is required separately for sandbox and production. - Installed the DAA web SDK.
- Obtained a
clientEntityIdfor the end user you’re enrolling. See Onboard customers for how to create one. - Run a device check for the end user and stored the
deviceIdit returned. See Collect device risk signals. Every protected operation sends thatdeviceIdinriskSignals.
The Digital Asset Accounts API base URL is
https://api-sandbox.circle.com for
sandbox and https://api.circle.com for production. Set your API key in the
Authorization header using the format Bearer YOUR_API_KEY. See
Sandbox environment and
Going to production
for environment details.Steps
Step 1. Check whether the end user requires SCA
List the end user’s passkeys withGET /v1/accounts/passkeys.
The response carries both the SCA requirement and the passkeys already enrolled:
revokedDate set to null.
Use sca.required to decide what to do before a protected operation:
If
sca is null, don’t store it. Call the endpoint as usual and handle HTTP
428 if it’s returned. Handle a 428 even when sca.required is false. For what
each value means, whether you can store it, and how voluntary SCA works, see
Which end users require SCA.
Step 2. Enroll a passkey
Enroll a passkey for each end user who requires SCA, before they run any protected operation. Run this flow once per end user, and again if they revoke their last active passkey or can’t access it on a new device.Step 2.1. Create a registration session
The frame token expires after 10 minutes. Pass it to your frontend right away.
Do not re-send the request with the same
idempotencyKey after delivering the
token. This rotates the token and invalidates the copy you already sent. Start
a fresh session with a new idempotencyKey if the token expires.Step 2.2. Run the enrollment ceremony
Initialize the SDK on your frontend and callsca.enroll with the frame token
from step 2.1.
The SDK renders the passkey prompt in a Circle-hosted iframe. Pass
attestationResponse to your backend as-is. Re-serializing it causes a
verification error.Step 2.3. Complete the registration
Send theattestationResponse from the SDK to your backend. Then forward it to
Circle to complete enrollment.
Step 3. Approve a protected operation
For every protected operation, obtain a signed challenge and include it in the API request.Step 3.1. Create a challenge
summary is a server-generated record of the operation. Don’t use it to
render a pre-confirmation to the end user, because the Circle iframe shows its
own description to the user.
The frame token expires after 5 minutes. Pass it to your frontend right away.
Re-sending with the same
idempotencyKey rotates the token and invalidates
the copy you already sent. Create a new challenge with a fresh
idempotencyKey if the token expires.operation to match the endpoint you are about to call: TRANSFER,
WITHDRAWAL, ADDRESS_BOOK_ADD, ADDRESS_BOOK_DELETE, or
WIRE_ACCOUNT_CREATE. ADDRESS_BOOK_DELETE is the one exception. That endpoint
takes no request body, so send an empty intent and put the address ID in
pathParameters:
Step 3.2. Run the approval ceremony
Pass theframeToken from the challenge response to the SDK’s approve method.
The SDK renders the passkey prompt and returns a signed assertion string.
Step 3.3. Submit the protected operation
Include thechallengeId and assertion as request headers. Use the same field
values you set in the challenge intent.
If a protected endpoint returns HTTP 428 (error code 420058), the
X-Sca-Challenge-Id or X-Sca-Assertion header was omitted from the request.
Circle requires SCA for this end user. If they have no active passkey, enroll
one (step 2) first. Then run the approval ceremony and retry with both headers
present. For other SCA errors, see the Digital Asset Accounts API
reference.