Verification Attempt Lockout
Introduction
The verification attempt lockout is an opt-in, account-scoped safeguard that throttles a card after repeated hard verification failures. It applies across every network.
This is not the HIGHEST lockout
This page covers the cross-network attempt lockout for the LOW/MEDIUM/HIGH tiers. The
HIGHEST tier has its own, separate per-card lockout (the two-hold amount-confirm). See HIGHEST Verification. The two never cross-feed.
Enabling it
The lockout is off by default. Turn it on per subaccount with the failedAttemptLockout flag on verificationPolicy, using the Update Subaccount endpoint:
HTTPcURLRequest body
PATCH /subaccounts/{subaccountId} HTTP/1.1
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"verificationPolicy": {
"failedAttemptLockout": true
}
}
curl -X PATCH https://api.astrada.co/subaccounts/{subaccountId} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"verificationPolicy": {
"failedAttemptLockout": true
}
}'
{
"verificationPolicy": {
"failedAttemptLockout": true
}
}
- Failures are always recorded. The flag only controls enforcement. So you can flip it on and it is immediately protective, with no warm-up window.
- The policy is per subaccount; set it on each subaccount you want protected. Set
failedAttemptLockouttofalse(ornull) to turn it off.
How it works
The lockout is keyed to the card, account-scoped, and counts countable hard failures across all networks. There are two tiers:
- Temporary lock: 5 hard failures inside a 60-minute window block the card for 60 minutes, then it auto-clears. The window is fixed, not rolling: it starts at the first failure and resets only once a failure arrives 60+ minutes after that start. It doesn't continuously slide with each new failure.
- Permanent lock: 15 cumulative hard failures (over any span of time) block the card with no auto-expiry; it stays locked until you clear it.
What counts: hard declines (insufficient funds, stolen / lost / restricted card, contact-issuer), incorrect CVC, and 3DS authentication rejected by the issuer.
What doesn't: transient errors ("try again later"), cardholder-abandoned or canceled attempts, and the HIGHEST second-factor steps.
Error codes
When a locked card attempts verification, the request returns 400 with a verification.* errorCode: verification.attempts_locked (temporary; carries metadata.lockedUntil) or verification.attempts_locked_permanent (no lockedUntil). Full table (category, retryable, the cardholder-facing screen for each) in Error States & Remediation. That page is the canonical error catalog; this one owns the mechanism.
What the cardholder sees
The SDK renders both lockout screens for you. There's no UI to build. Each lock tier shows its own screen so the cardholder knows whether to wait or to get help.
Temporary lock: verification.attempts_locked |
Permanent lock: verification.attempts_locked_permanent |
|---|---|
- Temporary: "Verification temporarily blocked." Tells the cardholder to wait and try again later; the lock auto-clears at
metadata.lockedUntil. - Permanent: "Verification blocked." Directs the cardholder to contact their spend-management provider (you); clear it with
POST /card-verifications/unlockbelow.
Unlocking a card
Clear a card's lockout (temporary or permanent) with the Unlock Card Verification endpoint:
HTTPcURLRequest body
POST /card-verifications/unlock HTTP/1.1
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"cardId": "00cdba2d-01f0-46bb-b34a-c76d9699e991"
}
curl -X POST https://api.astrada.co/card-verifications/unlock \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"cardId": "00cdba2d-01f0-46bb-b34a-c76d9699e991"
}'
{
"cardId": "00cdba2d-01f0-46bb-b34a-c76d9699e991"
}
Returns 200 with { "unlocked": true } (plus vaultCardFingerprint when a lock was actually cleared). It is idempotent: unlocking a card with no active lock succeeds and clears nothing.
Unlocking requires subaccounts:write (the same scope used to manage a subaccount's policy), not card-verifications:write (which creates verifications). A token without subaccounts:write is rejected with 403.
- The endpoint clears both the temporary and the permanent lock. (The temporary lock also clears on its own once the 60-minute window passes.)
- It doesn't touch the HIGHEST lockout. See the note at the top of this page.