Docs
Firmly Agentic Commerce
Set theme to dark (⇧+D)

Agentic Pay

Firmly acts as a Network Token Router for agentic commerce. Destinations integrate once with Firmly’s APIs and the Firmly iFrame — Firmly routes tokenization, cardholder authentication, and payment instructions to the appropriate card network. Adding a new network is a Firmly-side change with no destination code impact.

​​ Two Ways to Pay

Enrollment happens once per cardholder. After a card is enrolled and verified, the destination stores the resulting virtual_card_id and reuses it for every future payment — no PAN re-entry and no repeat verification. That single enrolled card powers both payment models below; the difference is only who approves the payment at transaction time.

Human in the loop The cardholder is present and approves each payment in real time — a FIDO/passkey assertion (or OTP) at the intent step proves presence. Best for interactive checkout where the buyer confirms the purchase.
Autonomous agent No human is present at transaction time. The agent transacts within a mandate the cardholder pre-authorized — bounded by a maximum amount, an expiration time, and the purchase intent. Best for delegated or recurring agent-driven purchases.

​​ The mandate: a cardholder’s delegated authority

Every payment intent carries a mandate — the cardholder’s authorization describing what the agent may charge. In the human-in-the-loop model the cardholder also approves it live; in the autonomous model the mandate is the guardrail that lets the agent act without a human present:

Limit Mandate field What it bounds
Maximum amount amount (+ currency_code) The order-completion capture amount must not exceed this. Firmly rejects a higher capture before the network is called.
Expiration ttl_seconds How long the authorization stays valid. Once it lapses, a fresh intent is required.
Purchase intent / scope merchant_name, merchant_category_code, quantity, consumer_prompt What the agent is authorized to buy, from whom, and the prompt the cardholder approved.

​​ How It Works

Agentic Pay breaks the payment flow into three phases: Enrollment, Intent, and Order Completion.

​​ Phase 1: Card Enrollment

The destination sends the cardholder’s PAN. Firmly inspects the BIN, routes to the correct network, and returns abstract verification challenges. The destination drives the cardholder through the challenges without needing to know which network is involved.

After enrollment, the destination receives a virtual_card_id and masked card details (last4, expiry, brand). The flow_token carries all state between steps — no server-side session storage is needed.

Destinations should persist virtual_card_id, card_art, and masked for returning buyers. A stored card can start a new payment via /select-card without re-entering card details — it returns the same shape as /enroll, so the intent and order chain is reused unchanged.

​​ Phase 2: Payment Intent

When it’s time to pay, the destination creates a payment intent carrying the mandate (amount, expiry, merchant scope — see The mandate). The mandate is the cardholder’s authorization for the agent to act on their behalf. In the human-in-the-loop model a FIDO assertion in the cardholder’s browser proves presence; in the autonomous model the agent transacts within the previously authorized mandate limits.

​​ Phase 3: Order Completion

The destination sends the flow_token and intent_id to place the order. Firmly retrieves network token credentials and completes the payment.

​​ Key Concepts

​​ Flow Token

The flow_token is an encrypted token that carries the entire enrollment and payment state. It is:

  • Stateless — no server-side session; all state lives in the token
  • Refreshed on every API call — each response returns a new flow_token that must be used for the next call
  • Tamper-proof — encrypted and integrity-checked; any modification invalidates it
  • Scoped — contains destination ID, network, enrollment status, and expiry
  • Short-lived — expires 30 minutes after issue. An expired or out-of-sequence token returns BadRequest (flow_token expired / Invalid flow_token format) — restart the flow from /enroll or /select-card.

​​ BIN Routing

Firmly automatically detects the card network from the PAN’s BIN (Bank Identification Number):

Network BIN Range Status
Visa 4xxx Supported
Mastercard 5xxx, 222100–272099 Supported
Discover 6011, 65xx, 644000–649999 Supported — no cardholder verification step (see below)
Amex 34xx, 37xx Planned

If a network is not supported or not enabled for the destination, the API returns PaymentMethodNotAvailable. Networks are enabled per destination — confirm with Firmly which networks your API token can transact on.

Discover has no cardholder-verification ceremony. /enroll returns an empty verification_methods array and the card is immediately enrolled, and /intent returns the intent_id directly instead of a challenge — there is no /intent/challenge call. Mastercard can also skip the intent challenge when the cardholder authenticated moments earlier at enrollment (see Create Intent).

​​ Verification Methods

The API returns verification_methods — an abstract challenge contract. Destinations see only the challenge type; network-specific details are encapsulated by Firmly:

Type Description
embed_iframe_handshake Iframe that captures a secure_token via postMessage
otp One-time passcode sent via SMS or email
embed_iframe FIDO2 registration or assertion via network-hosted iframe

New networks can plug in without destinations changing code — Firmly maps each network’s auth flow into one of the abstract challenge types.

​​ Card Art

Every network returns card_art metadata for rendering the card visually, but the exact fields differ by network. Firmly proxies the image through a signed URL so destinations can render card images without CORS issues.

Field Visa Mastercard Discover
network ✅ ✅ ✅
url ✅ ✅ ✅
background_color ✅ — ✅
foreground_color ✅ — ✅
descriptor (issuer name) — ✅ —

{
"card_art": {
"network": "mastercard",
"url": "https://api.firmly.work/api/v1/wallets/agentic-pay/card-art/<token>",
"descriptor": "Test Bank 2"
}
}

The example above is a Mastercard card, so it carries descriptor and no color fields. A Visa or Discover card_art carries background_color and foreground_color instead of descriptor.

The url is HMAC-signed — no authentication header is needed. Drop it directly into ![](...).

​​ Masked Card

Alongside card art, enrollment returns masked — display-only funding-card details for rendering a saved-card chip (e.g. “Test Bank 2 •••• 4595 · DEBIT”). It is a sibling of card_art (different source). Like card_art, its fields are network-dependent: Mastercard returns the full set (last4, exp_month, exp_year, brand, card_type, issuer_name); Visa returns last4, exp_month, exp_year, brand only (no card_type/issuer_name); Discover returns last4 and brand only.


{
"masked": {
"last4": "4595",
"exp_month": "12",
"exp_year": "2030",
"brand": "mastercard",
"card_type": "DEBIT",
"issuer_name": "Test Bank 2"
}
}

​​ Card Metadata Availability

Capture card_art and masked at enrollment. They are returned only on /enroll, never on /select-card — persist them with the virtual_card_id and reuse them on every later payment and in the order UI.

Source card_art masked Notes
/enroll (new card) ✅ returned ✅ returned Persist both for reuse
/select-card (saved card) null null Reuse the values persisted at enroll
Order payment_summary ✅ when enrolled this session ✅ when enrolled this session Carried through from /enroll → Vault → order; absent on the select-card path

​​ Order Completion Auth

The enrollment and intent endpoints use App Authentication (the destination API token). Order completion (/wallet-complete-order) is authenticated with a device session token, which can be obtained either way:

  • Browser-session JWT — for browser-present checkout (human-in-the-loop).
  • Server-to-server auth — for backend or autonomous-agent contexts where no browser is involved.

​​ Next Steps