Agentic Pay
Agentic Pay is Firmly’s Network Token Router — an API that enables card enrollment and network token payment authorization. Destinations integrate one abstract API; Firmly handles the network-specific mechanics behind the scenes.
Supported Networks
The network is automatically detected from the card’s BIN (Bank Identification Number — the leading digits of the card number) — destinations never specify which network to use.
Authentication
All Agentic Pay endpoints accept your API token either in the x-firmly-authorization header (raw token, no prefix) or as a standard Authorization: Bearer <token> header. This is an app-level token, not a browser session token. The Headless SDK sends the same token as Authorization: Bearer — its apiToken config value is that token.
| Header | Type | Required | Description |
|---|---|---|---|
x-firmly-authorization |
string | Yes | API token for authentication |
Flow Token
Every Agentic Pay response includes a flow_token — a JWE-encrypted (JSON Web Encryption) state token that carries the enrollment or payment context forward. Each subsequent call requires the flow_token from the previous response. This eliminates the need for server-side session storage and ensures stateless, tamper-proof request chaining.
Two Entry Points, One Payment Chain
There are two ways to start a payment. Choose one based on whether the buyer is entering a new card or reusing a saved one — both paths return the same shape and then converge on the identical intent → order chain below.
/enroll with the cardholder’s PAN (Primary Account Number — the full card number). Firmly enrolls the card and returns verification challenges (OTP — one-time password, and FIDO2 — the FIDO Alliance passkey/WebAuthn standard). Persist virtual_card_id, card_art, and masked for returning buyers.
/select-card with a stored virtual_card_id — no PAN re-entry. Returns the same shape as /enroll, so the rest of the flow is identical.
Once you have a flow_token from either path, the remainder of the chain is shared:
Payment Intent
POST /intent with the transaction amount. A FIDO2 assertion proves cardholder presence.
Order Completion
Send the flow_token and intent_id to the wallet-complete-order endpoint. Firmly retrieves network token credentials and places the order.
Available Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /enroll |
Enroll a card and receive verification methods |
| POST | /select-card |
Start a payment from a previously-enrolled card (no PAN) |
| POST | /enroll/trigger |
Trigger a verification challenge (OTP, iframe) for enrollment |
| POST | /enroll/verify |
Submit the verification response to complete enrollment |
| POST | /intent |
Create a payment intent for an enrolled card |
| POST | /intent/challenge |
Complete a payment-level FIDO challenge for the intent |
| GET | /card-art/:token |
Retrieve the card art image for an enrolled card |
| GET | /iframe-callback |
Iframe postMessage bridge for browser-based verification flows |
| POST | /cards/delete |
Revoke an enrolled card on the network |
Endpoint Reference
Enrollment
Payment
intent_id directly when no challenge is needed
Intent Challenge
Submit the FIDO assertion result and receive the intent_id for order placement
Browser Helpers
Typical Flow
Start Session
New card: POST /enroll with card details (PAN, expiry, consumer info). Receive flow_token, virtual_card_id, verification_methods, card_art, and masked. Persist virtual_card_id, card_art, and masked for returning buyers.
Saved card: POST /select-card with the stored virtual_card_id and network — no PAN needed. Returns the same shape as /enroll (card_art and masked are null — use persisted values).
Verify Cardholder (New Card)
POST /enroll/trigger with the chosen method_id, then POST /enroll/verify with the cardholder’s response (OTP or FIDO2). May require multiple verify calls. Discover returns an empty verification_methods array from /enroll — the card is enrolled immediately and both calls are skipped. Saved cards skip enrollment verification, but a Visa saved card still returns an embed_iframe_handshake from /select-card whose secure_token must be captured and passed to /intent; Mastercard saved cards proceed straight to /intent.
Create Payment Intent
POST /intent with the flow_token and transaction mandate. Receive either a FIDO2 assertion challenge, or — for Discover, and for Mastercard when a fresh enrollment authentication can be reused — the intent_id directly.
Complete Intent (when a challenge was returned)
POST /intent/challenge with the FIDO2 result. Receive intent_id. Skip this step if /intent already returned intent_id.
Place Order
POST /api/v2/payment/domains/{domain}/wallet-complete-order with flow_token, intent_id, and billing_info. (This is the payment/vault surface at cc.firmly.work, outside the Agentic Pay base URL.)