Retrieve payment credentials with spend requests
Let your agent retrieve one-time-use payment credentials that customers approve in Link.
A Link spend request lets your agent retrieve a one-time-use payment credential to buy anywhere online. Your agent creates a spend request, the customer approves it, and Link returns the credential. Your agent then completes the purchase with that credential.
Spend requests support several payment options, including one-time-use virtual cards and shared payment tokens. A one-time-use virtual card works at any seller that accepts cards online. A shared payment token works only at sellers that accept shared payment tokens.
Link CLI gives you one integration across payment rails. Your agent requests a credential without integrating each rail directly.
Before you begin
Before you begin, make sure that:
- You’ve set up OAuth , including the payment _ methods. agentic scope.
- You’ve installed Link CLI and keep it up to date: npm install -g @stripe/link-cli . Update it regularly to get the latest commands and skills.
How spend requests work
- Your agent creates a spend request with the purchase amount, merchant, context, and payment credential type.
- Link returns an approval _ url to present to the customer.
- The customer approves the request on the Link website or in the Link mobile app. Customers don’t need to install the mobile app to approve.
- Your agent polls the spend request until it sees that the request is approved.
- Link returns a one-time-use payment credential your agent uses to complete the purchase.
Create a spend request
To create a spend request, use the spend-request create command:
Create spend request
link-cli spend-request create \
--amount 3500 \
--context "Purchasing 'Working in Public' from press.stripe.com. The customer initiated this purchase through the shopping assistant." \
--merchant-name "Stripe Press" \
--merchant-url "https://press.stripe.com" \
--line-item "name:Working in Public,unit_amount:3500,quantity:1" \
--total "type:total,display_text:Total,amount:3500"
Response
Present the approval_url to the customer and ask them to approve the purchase.
By default, spend-request create returns a card credential—a one-time-use virtual card. Set --credential-type to choose the type that matches how your agent pays:
| Credential type | When to use it |
|---|---|
Virtual card ( card, default) | Buying on the open web, at any merchant that accepts cards. |
Shared payment token ( shared_payment_token) | Paying sellers that accept shared payment tokens, including machine-payment merchants. |
Parameters
The spend-request create command accepts the following parameters:
| Parameter | Required | Description |
|---|---|---|
--amount | Yes | Purchase amount in the smallest currency unit (for example, 3500 for 35.00 USD). |
--context | Yes | Description of what’s being purchased and why. Must be at least 100 characters. This appears to the customer in the approval prompt. |
--merchant-name | Conditional | The merchant where the purchase occurs. Required for card requests. Omit for shared_payment_token requests. |
--merchant-url | Conditional | The URL of the product or merchant page. Required for card requests. Omit for shared_payment_token requests. |
--network-id | Conditional | Required for shared_payment_token requests. Retrieve it from the seller’s profile_id when you use UCP, or with mpp decode when you pay machine-payment merchants. |
--payment-method-id | No | The payment method to charge. Defaults to the customer’s default payment method, or the first eligible one when no default is set. |
--credential-type | No | Type of payment credential to return: card (default) or shared_payment_token. |
--currency | No | Three-letter ISO currency code. Defaults to usd. |
--line-item | No | A line item to display on the approval screen. Repeatable. |
--total | No | A total to display on the approval screen. Repeatable. |
--metadata | No | Arbitrary string data in key:value format. Repeatable. Maximum 50 keys, keys up to 40 characters, values up to 500 characters. |
--test | No | Creates a test mode spend request that returns test credentials without a real charge. Defaults to false. |
Line items and totals
The --line-item and --total parameters take repeatable key:value pairs. They control what the customer sees on the approval screen, so include them when the purchase has more than one component.
The keys for the --line-item parameter, where name is required:
- name
- quantity
- unit _ amount
- description
- sku
- url
- image _ url
- product _ url
The keys for the --total parameter, where all three are required:
- type , one of subtotal , tax , total , items _ base _ amount , items _ discount , discount , fulfillment , shipping , fee , gift _ wrap , tip , or store _ credit
- display _ text
- amount
For example, to create a spend request for a purchase with multiple items, run:
Itemized request
link-cli spend-request create \
--amount 12000 \
--context "Purchasing trail running shoes from example.com. The customer selected these after comparing three options with the shopping assistant." \
--merchant-name "Example Store" \
--merchant-url "https://example.com/running-shoes" \
--line-item "name:Running Shoes,unit_amount:12000,quantity:1,description:Trail runners" \
--total "type:subtotal,display_text:Subtotal,amount:12000" \
--total "type:total,display_text:Total,amount:12000"
Poll for approval
After presenting the approval URL, poll the spend request until it reaches a terminal status:
Poll spend request
link-cli spend-request retrieve lsrq_abc123 --interval 2 --max-attempts 300
The --interval flag sets the polling interval in seconds, and --max-attempts sets how many polls to make before giving up. Polling exits successfully only after the request reaches a terminal status: approved, denied, expired, or canceled.
The customer has 10 minutes from the approval request to respond, after which the status becomes expired. Size --interval and --max-attempts to cover that window. See Limits.
Handle interruptions while polling
Two outcomes stop polling before a terminal status:
- A status of
requires_action: The customer needs to do something before the request can proceed. Present next _ action. display _ message and next _ action. action _ url to the customer, then resume polling. See Next actions for how to branch on each action type. - An exhausted timeout : If --timeout elapses or --max-attempts runs out while the request is still non-terminal, the command exits non-zero with code: "the related setting _ the related setting" .
Don't treat a polling timeout as a completed purchase
A the related setting exit means the request is still pending, not that it failed or succeeded. Retrieve the spend request again to determine its actual status before you retry or tell the customer anything.
Retrieve card payment credentials
Retrieving a spend request excludes card details by default, to keep the cardholder’s PII out of any response shown to the customer. Pass --include card to return them:
Retrieve with card details
link-cli spend-request retrieve lsrq_abc123 --include card --format json
To keep the full card out of your agent’s transcript and logs, write it to a file with --output-file. Standard output then carries only redacted fields:
Write credentials to a file
Card numbers printed to standard output can persist in agent transcripts, model context, and log aggregation. Use --output-file in any hosted agent. Link CLI creates the file with 0600 permissions, and fails rather than overwriting an existing file unless you pass --force.
When you set --output-file, the JSON output replaces the card object with redacted fields and adds a card_output_file path pointing at the file. The approved spend request contains the credential:
Approved response
{
"id": "lsrq_abc123",
"status": "approved",
"card": {
"brand": "visa",
"number": "4242424242424242",
"cvc": "100",
"exp_month": 6,
"exp_year": 2029,
"billing_address": {
"name": "Jenny Rosen",
"postal_code": "94015",
"country": "US"
},
"valid_until": "2026-06-13T03:40:10Z"
}
}
The card is one-time-use. By default, it expires 12 hours after you create the spend request, at the time shown in valid_until.
Complete the purchase
Use the card details from the approved spend request to complete checkout on the merchant’s site. Your agent can fill in the card number, CVC, expiration date, and billing address at checkout.
Limits
These limits apply per agent integration. To raise them for your integration, contact your Stripe sales representative.
| Limit | Value |
|---|---|
| Per request | 500 USD |
| Daily | 500 USD |
| Monthly, over 30 days | 20,000 USD |
| Concurrent active requests | 30, counting created and approved |
| Concurrent approved requests | 10 |
| Creation rate | 50 per hour, and 200 over 60 days |
| Approval window | 10 minutes from the approval request |
| Credential validity | 12 hours from spend request creation |
Spend request statuses
A spend request moves through one of nine statuses. Handle each one explicitly, because polling returns whatever the current status is.
| Status | Meaning | Action |
|---|---|---|
created | The request exists and approval will be requested. | Continue polling until the status changes to pending_approval. |
pending_approval | Waiting for the customer to approve or deny. | Continue polling. |
requires_action | The customer needs to complete an action before the request can proceed. | Present next_action.display_message and action_url to the customer, then follow Next actions. |
approved | The customer approved the request. Payment credentials are available. | Complete the purchase. |
denied | The customer denied the request. | Tell the customer, and don’t retry without creating a new request. |
expired | The customer didn’t respond within the approval window. | Create a new spend request if the customer still wants to proceed. |
canceled | The request was canceled before completion. | Create a new spend request if the customer still wants to proceed. |
succeeded | The payment completed. | No further action. |
failed | The payment failed and the request is terminal. | Read status_details.failed.code for the failure reason before retrying. |
Next actions
When a spend request has a status of requires_action, read status_details.requires_action.next_action. It contains:
| Field | Description |
|---|---|
type | The kind of action the customer needs to complete. |
resolution | How your agent proceeds after the customer acts. |
display_message | A customer-facing string you can present directly to the customer. |
action_url | A Stripe-hosted URL to send the customer to, when one applies. |
expires_at | When action_url expires, as an ISO 8601 string. null when there’s no expiry. |
Branch on type and resolution rather than on failure_code alone, because the same failure_code maps to different action types depending on context.
| Action type | Resolution | What to do |
|---|---|---|
ssn_verification | create_new_spend_request_after_completion | Send the customer to action_url to verify their identity, then create a new spend request. |
identity_verification | create_new_spend_request_after_completion | Send the customer to action_url for additional identity verification, then create a new spend request. |
contact_support | create_new_spend_request_after_completion | Identity verification attempts are exhausted. Send the customer to Link support. |
select_payment_method | create_new_spend_request | The payment method was declined. Ask the customer to choose another, then create a new spend request. |
add_payment_method | create_new_spend_request_after_completion | No eligible payment method is on file. Send the customer to action_url to add one, then create a new spend request. |
update_payment_method | create_new_spend_request | The card needs attention, such as an expiry, address, or security code problem. Send the customer to action_url, then create a new spend request. |
re_authorize | create_new_spend_request | The charge exceeded the approved amount. Create a new spend request for the correct amount. |
three_d_secure | auto_resume | Send the customer to action_url to complete the challenge, then keep polling. The request resumes on its own. |
three_d_secure_retry | create_new_spend_request | The challenge wasn’t completed. Create a new spend request. |
Only auto_resume keeps the existing spend request alive. Every other resolution means the request is terminal, so create a new one after the customer acts.
Raise the amount on an approved request
Agents don’t always know the final price when they request approval. A checkout might require card details before it shows the final total, including tax or shipping. Rather than requesting a buffer amount upfront, you can raise the amount on a spend request the customer already approved.
Raising the amount requires the customer to approve again. On approval, Link triggers an incremental authorization so the card can be charged for the higher amount.
Before you call update, check that:
- The request supports incremental authorization. Read incremental _ auth _ enabled on the spend-request retrieve response.
- The customer already approved the request.
- You haven’t successfully used the card yet. A virtual card can’t be used more than once.
Pass the new total, not the difference:
Raise the amount
link-cli spend-request update lsrq_abc123 --amount 7500
Then ask the customer to approve again and poll for their decision:
Request approval and poll
link-cli spend-request request-approval lsrq_abc123
link-cli spend-request retrieve lsrq_abc123 --interval 2 --max-attempts 300
Incremental authorizations aren’t guaranteed. A safe default is to try the increase and fall back to canceling and recreating the request on any error. In every failure case, the spend request stays usable at its original amount—a failed increase never invalidates credentials you already hold.
| What happened | How it surfaces | What to do |
|---|---|---|
| The increase succeeded | status: approved with the higher amount | Use the card you already retrieved. |
| The issuer declined the increase | A payment-declined error | Proceed at the original amount, or cancel and recreate. |
| The increase exceeds the customer’s limits | A limits error with a specific code | Branch on the code. The request is unchanged and still usable. |
| The card was already used | A conflict error | Poll retrieve. Create a new request if you still need to spend more. |
| The card doesn’t support incremental authorization | A not_supported error | Cancel and recreate. |
Amount is the only field you can change this way. The card details stay the same throughout.
Manage a spend request
Retrieve a spend request to see the details of the transaction, including refunds and payment success events:
Retrieve a request
link-cli spend-request retrieve lsrq_abc123
List all spend requests for the authorized customer:
List requests
link-cli spend-request list
Cancel a request from the created, pending_approval, or approved state:
Cancel a request
link-cli spend-request cancel lsrq_abc123
Test your integration
Pass --test to create a test mode spend request. Link CLI returns test credentials, such as card number 4000009990001984, and doesn’t charge the underlying payment method:
Test mode spend request
link-cli spend-request create \
--test \
--amount 3500 \
--context "Purchasing 'Working in Public' from press.stripe.com. The customer initiated this purchase through the shopping assistant." \
--merchant-name "Stripe Press" \
--merchant-url "https://press.stripe.com"
To walk through both credential types interactively, run link-cli demo, which always uses test mode.
