Verification Risk Tiers

Introduction

When a cardholder links a card, Astrada verifies that they own it. You can choose how strict that verification is per subaccount, using a risk tier. A higher tier adds stronger proof of ownership at the cost of more cardholder interaction; a lower tier optimizes for conversion.

This page explains the four tiers, how to set one, and how the tier changes the enrollment experience. For the strictest tier's two-hold flow see HIGHEST Verification; to test against sandbox cards see Test Cards & Sandbox Testing.

The tiers

TierStrengthCardholder experienceWho can set it
LOWLenient3DS only when the issuer or regulation requires it; some issuer-unsupported declines are toleratedAstrada (internal)
MEDIUMStandard3DS is always requested; cardholder may be challengedYou or Astrada
HIGHStrong3DS is always requested plus a transient authorization hold (no settled charge)You or Astrada
HIGHESTStrongest3DS challenge; if the issuer approves without challenging, the cardholder confirms two small temporary holdsYou or Astrada

New subaccounts have no tier set, whether newly created or long-standing — there's no special case for new vs. existing. Verification for them runs the default, non-Stripe path (see "Account has no tier set" under Routing, below, and the "Default (no tier)" column in the validation table further down) — not MEDIUM. MEDIUM is a tier you opt into explicitly via PATCH, same as HIGH and HIGHEST. See Account & Subaccount Configuration for the full precedence rules, including what carries over from the account level. LOW is internal-only — it is a floor that Astrada manages; you can always raise a subaccount to a stricter tier, but you cannot self-assign LOW.

How each tier behaves

In every tier, the card's CVC must pass.

  • LOW — Astrada asks the network to run 3DS only when risk or regulation (for example EU SCA)
    calls for it; for many cards 3DS is skipped. If the issuer declines for a "soft" reason such as
    3DS not supported, the enrollment is still allowed; hard-decline reasons (lost/stolen/fraud,
    expired, insufficient funds, and similar) always fail.
  • MEDIUM — 3DS is always engaged and the issuer is asked to challenge the cardholder. There is
    no soft-decline tolerance: a declined verification surfaces a specific reason to the cardholder.
  • HIGH — same 3DS posture as MEDIUM, plus a transient authorization hold on the card
    (requested at $0, retried at $1 if the issuer requires a non-zero amount). The hold is released
    automatically — the cardholder never sees a settled charge — and Astrada gains additional
    fraud-risk signals from the authorization.
  • HIGHEST — Astrada attempts a 3DS challenge. If the issuer challenges the cardholder and
    they pass it, that's sufficient and enrollment completes; if they fail it, enrollment fails outright
    (same as HIGH — no second factor). If the issuer approves frictionlessly, or 3DS doesn't run at
    all
    (the issuer or network can't support a challenge for this card), the cardholder must complete a
    second factor instead: confirm two small temporary holds ($0.50–$0.99 each) read from their
    banking app. See HIGHEST Verification.

3DS is a preference, not a guarantee. For MEDIUM/HIGH/HIGHEST, Astrada asks the issuer to
challenge, but the issuer decides the final authentication flow and may still approve
frictionlessly. The verification response reports what actually happened via authenticationFlow
(see below).

Card networks

The tier you set applies to both Visa and Mastercard, but the verification path differs by network:

  • Visa — all tiers (LOW/MEDIUM/HIGH/HIGHEST) run through Astrada's verification path.
  • Mastercard — 3DS always runs through Astrada's Mastercard network path at every tier. The
    two-hold second factor is engaged only at HIGHEST;
    LOW/MEDIUM/HIGH behave as standard Mastercard 3DS.

How verification runs

For MEDIUM/HIGH/LOW the cardholder either sails through (frictionless) or completes a bank challenge — the SDK performs every step below for you; the diagram shows what happens under the hood. (HIGHEST adds a second factor — see HIGHEST Verification.)

sequenceDiagram
    autonumber
    participant Browser as Cardholder browser
    participant Backend as Your app (via the SDK)
    participant Astrada as Astrada API
    participant SDK as Astrada SDK
    participant ACS as Issuer (ACS)
    Browser->>Backend: Cardholder submits card
    Backend->>Astrada: Start verification
    Astrada->>Astrada: Card + CVC checks, then a no-amount or small-hold card check (per tier)
    alt Frictionless
        Astrada-->>Backend: Verified, no challenge needed
        Backend-->>Browser: Success
    else 3DS challenge required
        Astrada-->>Backend: Challenge required
        Browser->>SDK: Run 3DS challenge
        SDK->>ACS: Render bank challenge
        ACS-->>SDK: Cardholder completes / fails
        Browser->>Backend: Notify result
        Backend->>Astrada: Confirm challenge result
        Astrada-->>Backend: Verified or failed
        Backend-->>Browser: Final outcome
    end

Which path runs the verification depends on the network and the tier:

flowchart TD
    A[Verification on a subaccount] --> B{Subaccount tier set?}
    B -- no --> D[Default verification path<br/>per network]
    B -- yes --> C{Network}
    C -- Visa --> E[Tiered verification path]
    C -- Mastercard --> F{Tier = HIGHEST?}
    F -- yes --> G[Network 3DS + two-hold second factor]
    F -- no --> H[Network 3DS only]

What each path validates

Every tier runs explicit card-existence, card-status, and CVC checks on each attempt — at every tier, including LOW — alongside the issuer's 3DS decision, rather than inferring them from it.

ValidationDefault (no tier)LOWMEDIUMHIGH
Card exists / activefrom 3DS responseexplicitexplicitexplicit
CVC matchesinferredstrictstrictstrict
3DS authenticationrequired (+ bypass rules)automatic (engaged only when SCA/risk warrant)challenge preferredchallenge preferred
Authorization holdnonenonenone$0 → $1 fallback, voided (never settles)
Fraud-risk signalsn/an/an/acaptured
  • The floor is identical for LOW/MEDIUM/HIGH: card existence, active status, and CVC are always
    validated. LOW is "lenient" only in that it permits a few issuer-side signals (the
    contact-issuer family, and "issuer can't do 3DS for this card") to bypass to success — it does
    not skip the card check, and it never bypasses a CVC mismatch.
  • HIGH is incrementally stricter than MEDIUM: the auth hold surfaces extra decline signals
    (insufficient funds, velocity) plus an additional fraud-risk layer.

Setting a subaccount's tier

Set the tier on a subaccount's verificationPolicy using the Update Subaccount endpoint:

PATCH /subaccounts/{subaccountId} HTTP/1.1
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "verificationPolicy": {
    "stripeValidationLevel": "HIGH"
  }
}
curl -X PATCH https://api.astrada.co/subaccounts/{subaccountId} \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "verificationPolicy": {
      "stripeValidationLevel": "HIGH"
    }
  }'
{
  "verificationPolicy": {
    "stripeValidationLevel": "HIGH"
  }
}
  • Accepts MEDIUM, HIGH, or HIGHEST. Requesting LOW returns 403 — contact Astrada to set a
    LOW floor.
  • Set stripeValidationLevel to null to clear the override and return to Astrada's default path.
  • The policy is per subaccount. There is no inheritance from the parent account at request
    time — set the tier on each subaccount you want to change.

An optional safeguard sits alongside the tiers: with verificationPolicy.failedAttemptLockout enabled, a card that fails verification too many times is throttled across all networks until it clears (or you clear it). It applies to LOW/MEDIUM/HIGH (HIGHEST has its own per-card lockout). See Verification Attempt Lockout.

Every completed verification reports how 3DS resolved:

authenticationFlowMeaning
challengeThe issuer challenged the cardholder (they interacted).
frictionlessThe issuer approved without challenging the cardholder.
null3DS did not run (for example, a LOW skip, or at HIGHEST when the issuer/network can't support a challenge for this card at all).

The raw verification resource carries this (relevant if you query the API directly for support triage — the SDK's onSuccess payload is shaped differently; see Quick Start: Card Enrollment):

{ "id": "…", "state": "completed", "currentStepId": null, "authenticationFlow": "frictionless" }

At HIGHEST, a successful challenge completes immediately. A failed challenge fails the verification outright — same as any other tier, it does not fall through to a second factor. A frictionless approval or a null flow (3DS didn't run at all — the issuer/network couldn't support a challenge) both route into the two-hold confirmation described in HIGHEST Verification instead.

What the cardholder sees

The happy paths and routing are below; every rejection and error state lives in Error States & Remediation. Unless noted, the screen is the same across LOW / MEDIUM / HIGH; HIGHEST adds the two-hold second factor covered in HIGHEST Verification.

Happy paths

Frictionless success — most enrollments

The bank approves without a challenge; the cardholder reaches success in a few seconds and sees no charge. Same UI at every tier (HIGH may briefly show a $0/$1 pending hold that never settles).

Pre-submitResult

3DS challenge success

The bank asks for an extra check — an OTP, an "approve in your app" prompt, or a password. The challenge UI is rendered by the bank, so copy and method vary by issuer.

Pre-submitResult

Rejections, errors & recovery

Every failure path — CVC mismatch, bank declines, the contact-issuer family, 3DS authentication failures, hard-fraud rejections, infrastructure errors, and mid-challenge recovery — plus the structured error contract (errorCode / category / retryable) and remediation for each, is catalogued in Error States & Remediation.

Routing

Account has no tier set → default flow

Most existing customers have no tier set; their cardholders get the same default verification flow as before — no new iframe, no new copy. Setting a tier is the only way onto the tiered verification path.

Pre-submitResult

Glossary

  • 3DS (3-D Secure) — the protocol issuers use to confirm the cardholder (OTP, in-app approval, or
    password). The challenge UI is rendered by the issuer's ACS (Access Control Server), not by us.
  • SCA (Strong Customer Authentication) — a regulatory requirement (PSD2 in the EU); when it
    applies, 3DS engages even at LOW.
  • No-amount card check — confirms the card without authorizing any amount (MEDIUM/LOW).
  • Small-hold card check — a brief authorization hold to confirm the card (HIGH; $0, or $1 if the
    issuer rejects $0). Canceled before any funds settle.
  • Permitted-exception record — a successful enrollment despite a soft issuer signal (the issuer
    couldn't run 3DS, or raised a soft contact-issuer reason). Only LOW produces these — see "How each
    tier behaves" above for what each tier tolerates.

Next steps