Skip to main content
Ask the user once, in the vault session link you send them, to let your app pay with their card. The user saves or picks a card in the Vault and reads what they allow, and the permission starts with that save or pick. From then on, Agentcard pays with that card without sending the user an approval link, whenever a purchase meets the conditions in Pay without an approval. Every other purchase waits for the user’s approval, as in Completing a purchase. Ask the user yourself before each purchase. Agentcard pays without asking them and never checks that your app asked.

Check what your app needs

App auto-approval works with production credentials, for any company’s app that has a client_id and a client_secret. Your app gets its platform access token with client credentials, and the examples on this page send that token as $ORG_TOKEN. Every purchase your app pays this way charges a real card. A public OAuth app has no secret, so it can’t ask for app auto-approval. Test mode can’t either: the dashboard shows the option as unavailable until you switch it to Live, and the API refuses the link under sandbox credentials. A purchase in test mode always waits for the user’s approval. Your checkout code also has to tell Agentcard which page each purchase comes from. The checkout SDK, @agent-cards/checkout, does this for you from version 0.7.0, as Send the checkout origin explains.

Set a default in the dashboard

Set a default once, and every vault session your app creates from then on asks for app auto-approval. Only an owner or admin of your company can change the default. The dashboard’s labels call the user the customer.
  1. Open the dashboard and switch it to Live.
  2. Go to Settings → Vault → Customize.
  3. Under Card enrollment, pick your app.
  4. Choose Request app auto-approval.
  5. Check “Our app will obtain customer approval before each purchase. Agentcard does not verify that approval.”
  6. Select Save enrollment default.
The default applies to new vault sessions only. Links you already sent, cards users already stored, and permissions users already granted stay as they are. A link Agentcard sends for you with Send a user their vault link never asks for app auto-approval. To ask that user, create the vault session yourself and send its url. To stop asking, choose Customer chooses and save. New links stop asking, and permissions users already granted stay on. To ask on one link, or to override your app’s default, send approval_mode when you create the vault session:
approval_mode takes partner to ask for app auto-approval, or customer to leave the choice to the user, as on any other link. Without it, the link follows your app’s default from the dashboard. Send url to the user wherever you already talk to them. expires_in sets how long the link lives, from 60 seconds to 48 hours, and defaults to 24 hours. Add user_id to send the link to a user already connected to your app: when they open it, Agentcard sends them a one-time code instead of a new account setup. Under sandbox credentials, Agentcard refuses the request and creates no link:
Create the session with your production token. To send an ordinary link instead, send approval_mode: "customer", or set your app’s default back to Customer chooses.

See what the user approves

The link opens the Vault. A new user adds a card and sets up a passkey. A returning user signs in with their passkey and picks one of their cards. On Add your card, the Vault says what the user allows:
On Select your card, the same note opens with “When you pick a card”. The Vault names your company by the display name under Settings → Vault → Customize, or by your company name when you set none. Before the permission starts, the Vault asks a user who has no master password to set one, and the user can’t skip that screen. A master password lets the user recover access to their Vault if they lose their device. An ordinary card link saves a card with a passkey alone. When the permission starts, the Vault shows “Your card is ready for Acme”. The permission has no spending limit and no end date, and it stays on after the link expires. The user’s bank can still decline a purchase. The permission works with any card the Vault saves, including a 12-digit Maestro card and an American Express card with a 4-digit security code. Each link gives your app one card. To let your app pay with a second card, send the user another link. The user can turn the permission off at any time, from that screen or from the card in their Vault, on any phone or computer that opens their Vault. From then on, your app’s purchases with that card wait for the user’s approval. Ask for permission again brings it back.

Learn when the card is ready

Receive these events at your webhook endpoint, or poll the session. A link created with user_id never fires vault.session_linked, because you already hold the id.
vault.payment_permission.updated
grant_id names the permission on that card, and allowance_id is the same for every card the user gives your app. The same event reports every later change: revoked when the user turns the permission off or your app’s connection to the user ends, and retired when the user removes the card. A delivery can repeat or arrive late, so keep the highest revision you have for each grant_id and ignore any event with a lower or equal one. The event’s page shows every field. To poll instead, read the session every poll_interval seconds until payment_permission.ready is true:
The session’s status turns linked as soon as the user signs in or sets up their passkey, before they grant the permission, so wait for ready. Later, List a user’s vaulted cards returns the same payment_permission on each card.

Get the user’s tokens

A purchase needs only your platform access token, so most apps skip this step. When your app also calls endpoints that run with the user’s own connection token, exchange the linked session once:
Store both tokens and keep them fresh with Refresh the connection. Each session exchanges once, so Agentcard refuses a second exchange:
When the user signed in to an Agentcard account that already existed, Agentcard refuses the exchange until you connect the user with a one-time code:
Connect that user with Send a code and Verify the code instead. The permission doesn’t depend on these tokens: your app’s purchases work either way.

Send the checkout origin

Send checkout_origin, the origin of the top-level checkout page such as https://shop.example.com, with every checkout authorization. Without it, the purchase waits for the user: Agentcard pays without asking only when it knows which page the purchase comes from. The checkout SDK sends it for you from version 0.7.0. When the merchant’s card request pauses, the SDK reads the origin of the top-level page, never the payment processor’s frame. An older version never sends it, so none of its purchases go through without the user. Install the current release:
When your own code pauses the card request instead of the SDK, add checkout_origin to each checkout authorization you create:
Write checkout_origin as the exact origin: https://, the host in lower case, and nothing after the host except a port other than 443. A path, a trailing slash, an uppercase letter or :443 makes the value invalid, and Agentcard refuses the checkout authorization:
A checkout authorization created without checkout_origin still goes through, but the purchase waits for the user, and the authorization says why:

Pay without an approval

Create the checkout authorization with your platform access token, as in Completing a purchase, and pass the stored user_id in the user field. The checkout SDK makes this call for you. Agentcard pays without asking the user when every one of these is true:
  • The purchase runs under production credentials.
  • The checkout authorization carries checkout_origin.
  • The purchase is in US dollars, and Agentcard knows the amount. Pass amount and currency with a purchase that turns the card into a token, because that request carries no amount. A one-step Stripe payment qualifies without them, because Agentcard reads the amount from Stripe.
  • Exactly one of the user’s cards carries an active permission for your app, or the checkout authorization names the card with card_id, which the SDK takes as cardId.
  • The checkout sends the card in a step the table below marks as paid without asking.
The other token processors in List recognized processors work like the first row: Agentcard completes their card request in place of the user’s device. When the purchase qualifies, Agentcard pays with the card the user gave your app and asks nobody. The authorization carries execution_mode: "autopilot", the grant_id of the permission that paid, an autopilot_status, and no approvalUrl. Read it until it finishes:
Replay response into the merchant request your browser paused, as after an approval. The SDK does this for you. On approved, your webhook endpoint also receives checkout_authorization.approved with execution_mode: "autopilot" and the same grant_id. A purchase that turned the card into a token finishes with charged_kind: "none". The merchant charges that token from its own server afterwards, so Agentcard never sees the charge, and you report what the merchant did. A one-step Stripe payment finishes with charged_kind: "captured", or "authorized" when the merchant captures later, and Agentcard reads the payment back from Stripe into settlement, as after any approval. A user can also turn on auto-approval rules of their own in the Vault, with limits they set. Those rules pay only for apps the user never gave a permission. Once the user gives your app one, only your app’s permission pays for its purchases.

Handle a purchase that waits

Any other purchase waits for the user. The authorization stays awaiting_approval with execution_mode: "user_approval" and an approvalUrl to send the user, as without app auto-approval. With the SDK, onApprovalUrl fires only for these purchases.

Follow an unfinished payment

autopilot_status follows Agentcard’s attempt to pay. Agentcard sends checkout_authorization.approved when the attempt succeeds and checkout_authorization.declined when the processor declines the card, so read the authorization to learn every other result. Branch on execution_mode as well as status: an authorization can read awaiting_approval while Agentcard is still paying, and only user_approval carries an approvalUrl. When the user’s bank asks for 3D Secure, the payment stops at action_required, and the user never sees the bank’s request: Agentcard can’t answer it for them, and the Vault doesn’t show it. The payment stays open until Stripe reports it finished or canceled, and the authorization stays awaiting_approval until then. The current SDK raises PaymentOutcomeUnknownError with the reason autopilot_action_required.

Report what the merchant did

When an auto-approved purchase finishes with charged_kind: "none", report what the merchant charged. Send the report with the platform access token of the app that created the purchase:
Agentcard answers 201 with the entry, and every later read of the authorization carries outcome with the net amount you reported. Send declined instead when the merchant’s charge failed, with an optional reason. Report each refund after the charge, one call per refund:
Name every refund with the id the merchant’s payment processor gave it, in processor_reference. When the processor gave you none, send your own id for that refund in partner_reference, the same id on every retry. A report sent again answers 200 with replayed: true and adds nothing, so a retry is safe. Agentcard records your report as you sent it and does not verify it. Report a checkout outcome lists every rule and error.

Ask for permission again

A permission that reads revoked comes back from a new link. Create a vault session with approval_mode: "partner" and send it to the user. When they pick the same card on Select your card, the Vault opens the Restore Acme permission screen, and one tap on the card turns the permission back on. The permission keeps its grant_id, its revision goes up, and vault.payment_permission.updated reports active again. A permission that reads retired doesn’t come back, because the user removed the card. Send a new link so the user adds a card, and your app gets a new permission for it.

Give your agent rules

  • Get the user’s approval before each purchase. Agentcard pays without asking them and never checks that your app asked.
  • Send the checkout page’s own origin as checkout_origin, never the payment processor’s frame, such as https://js.stripe.com. Agentcard names the merchant from it.
  • Pass amount and currency on every purchase. A request that only turns the card into a token carries no amount, and without one the purchase waits for the user.
  • Pass card_id once the user has given your app more than one card. Without it, every purchase waits for the user.
  • Never start a second purchase for an order whose first purchase reads outcome_unknown or action_required. The first payment is still open, and Agentcard doesn’t know yet whether it will charge the card.
  • Report every charge, decline and refund of a purchase that ends with charged_kind: "none", and give each refund its own reference, so a retry never counts twice.