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 — Visa/Stripe and Mastercard/TNS share one ledger — so it can't be sidestepped by retrying on a different scheme. It protects issuers (and your account standing) from card-enumeration and brute-force abuse.
This is not the HIGHEST lockoutThis page covers the cross-network attempt lockout for the
LOW/MEDIUM/HIGHtiers. TheHIGHESTtier 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:
PATCH /subaccounts/{subaccountId}
Authorization: Bearer <token with subaccounts:write>
{
"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 rolling 60-minute window block the card for 60 minutes, then it auto-clears.
- 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.
flowchart LR A[Active] -->|5 hard fails in 60 min| B[Temporary lock<br/>60 min] B -->|auto-expires| A B -->|POST /card-verifications/unlock| A A -->|15 cumulative hard fails| C[Permanent lock] C -->|POST /card-verifications/unlock| A
Error codes
When a locked card attempts verification, the request returns 400 with a verification.*
errorCode:
errorCode | category | retryable | HTTP | Cardholder sees (SDK) |
|---|---|---|---|---|
verification.attempts_locked | verification-locked | no | 400 | "Verification temporarily blocked" |
verification.attempts_locked_permanent | verification-locked | no | 400 | "Verification blocked" |
- The temporary code carries
metadata.lockedUntil(ISO-8601) — the moment the lock auto-clears. - The permanent code has no
lockedUntil.
See Error States & Remediation for the full error catalog.
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:
POST /card-verifications/unlock
Authorization: Bearer <token with subaccounts:write>
{
"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.
Token scopeUnlocking requires
subaccounts:write— the same scope used to manage a subaccount's policy — notcard-verifications:write(which creates verifications). A token withoutsubaccounts:writeis 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 clears only the cross-network attempt lockout — the
HIGHESTper-card lockout is separate.
Two different lockoutsThe attempt lockout (this page) is cross-network, opt-in via
failedAttemptLockout, and you clear it withPOST /card-verifications/unlock(subaccounts:write). The HIGHEST lockout (HIGHEST Verification) is the two-hold amount-confirm lockout (stripe.amount_confirm_locked), specific to theHIGHESTtier, and clears only by contacting Astrada.

