Loading...
Loading...
Enable AI agents to request payment credentials from Link wallets for secure purchases without exposing real card details
npx skill4agent add aradotso/devtools-skills stripe-link-cliSkill by ara.so — Devtools Skills collection.
npm i -g @stripe/link-clinpxnpx @stripe/link-clinpx skills add stripe/link-clitoon--format [json|yaml|md|jsonl].mcp.json{
"mcpServers": {
"link": {
"command": "npx",
"args": ["@stripe/link-cli", "--mcp"]
}
}
}# Login with custom client name for identification
link-cli auth login --client-name "Claude Code"
# Check authentication status
link-cli auth status
# Logout
link-cli auth logout# Store credentials in specific file
link-cli auth login --auth /path/to/auth.json
# Use credentials from specific file (all commands)
link-cli payment-methods list --auth /path/to/auth.jsonLINK_AUTH_FILEexport LINK_AUTH_FILE=/path/to/auth.json
link-cli payment-methods list# List all saved payment methods
link-cli payment-methods list
# JSON output
link-cli payment-methods list --format jsonidpayment_method_id# List saved shipping addresses
link-cli shipping-address list
# JSON output
link-cli shipping-address list --format jsonlink-cli spend-request create \
--payment-method-id csmrpd_xxx \
--merchant-name "Stripe Press" \
--merchant-url "https://press.stripe.com" \
--context "Purchasing 'Working in Public' from press.stripe.com. The user initiated this purchase through the shopping assistant to learn about open source sustainability." \
--amount 3500 \
--line-item "name:Working in Public,unit_amount:3500,quantity:1" \
--total "type:total,display_text:Total,amount:3500" \
--request-approval--payment-method-idpayment-methods list--merchant-name--merchant-url--context--amount--currencyusd--credential-typevirtual_cardshared_payment_token--shipping-address-idshipping-address list--request-approvalcontextamountcurrency--line-itemkey:value--line-item "name:Running Shoes,unit_amount:12000,quantity:1,description:Trail runners,sku:SKU-123" \
--line-item "name:Socks,unit_amount:1500,quantity:2"namequantityunit_amountdescriptionskuurlimage_urlproduct_url--total--total "type:subtotal,display_text:Subtotal,amount:12000" \
--total "type:shipping,display_text:Shipping,amount:500" \
--total "type:tax,display_text:Tax,amount:950" \
--total "type:total,display_text:Total,amount:13450"typesubtotaltaxtotalitems_base_amountitems_discountdiscountfulfillmentshippingfeegift_wraptipstore_creditdisplay_textamountlink-cli spend-request create \
--test \
--payment-method-id pm_test_card \
--merchant-name "Test Merchant" \
--merchant-url "https://example.com" \
--context "Testing payment flow with test credentials. This is a development test to verify the integration before using real payment methods." \
--amount 1000 \
--line-item "name:Test Item,unit_amount:1000,quantity:1" \
--total "type:total,display_text:Total,amount:1000"# Basic retrieval (card masked)
link-cli spend-request retrieve lsrq_001
# Include unmasked card details
link-cli spend-request retrieve lsrq_001 --include card
# Write card to secure file (stdout shows redacted data only)
link-cli spend-request retrieve lsrq_001 \
--include card \
--output-file /tmp/link-card.json \
--format json--output-file0600--forcecard_output_filecard// Poll until terminal status (approved, denied, expired, canceled)
link-cli spend-request retrieve lsrq_001 \
--interval 2 \
--max-attempts 300code: "POLLING_TIMEOUT"# Update before approval
link-cli spend-request update lsrq_001 \
--merchant-url https://press.stripe.com/working-in-public \
--amount 4000# Request approval separately (alternative to --request-approval flag)
link-cli spend-request request-approval lsrq_001# Cancel from any non-terminal state
link-cli spend-request cancel lsrq_001link-cli spend-request retrieve lsrq_001 --include card --output-file /tmp/card.json --format jsonnumbercvcexp_monthexp_yearbilling_addressvalid_untilimport { readFileSync } from 'fs';
// Read card from secure file
const cardData = JSON.parse(readFileSync('/tmp/card.json', 'utf8'));
const card = cardData.card;
// Use card details in checkout automation
await fillCheckoutForm({
cardNumber: card.number,
cvc: card.cvc,
expMonth: card.exp_month,
expYear: card.exp_year,
billingAddress: card.billing_address
});credential_type: shared_payment_token# Create SPT spend request
link-cli spend-request create \
--payment-method-id csmrpd_xxx \
--merchant-name "Climate Stripe" \
--merchant-url "https://climate.stripe.dev" \
--context "Contributing to climate initiatives through climate.stripe.dev. The user wants to offset carbon emissions from their recent travel." \
--amount 100 \
--credential-type "shared_payment_token" \
--line-item "name:Carbon Offset,unit_amount:100,quantity:1" \
--total "type:total,display_text:Total,amount:100" \
--request-approval
# After approval, pay using MPP
link-cli mpp pay https://climate.stripe.dev/api/contribute \
--spend-request-id lsrq_001 \
--method POST \
--data '{"amount":100}' \
--header "Content-Type: application/json"WWW-Authenticatelink-cli mpp decode \
--challenge 'Payment id="ch_001", realm="merchant.example", method="stripe", intent="charge", request="..."'network_id# Get schema for create command
link-cli spend-request create --schema
# List all commands in LLM-friendly format
link-cli --llms-fullimport { execSync } from 'child_process';
// 1. Get payment methods
const pmResult = execSync('link-cli payment-methods list --format json', { encoding: 'utf8' });
const paymentMethods = JSON.parse(pmResult);
const pmId = paymentMethods[0].id;
// 2. Create spend request
const createCmd = `link-cli spend-request create \
--payment-method-id ${pmId} \
--merchant-name "Acme Store" \
--merchant-url "https://acme.example" \
--context "Purchasing office supplies from acme.example. The user requested pens and notebooks for the team meeting next week." \
--amount 2500 \
--line-item "name:Blue Pens,unit_amount:1000,quantity:1" \
--line-item "name:Notebook,unit_amount:1500,quantity:1" \
--total "type:total,display_text:Total,amount:2500" \
--request-approval \
--format json`;
const createResult = JSON.parse(execSync(createCmd, { encoding: 'utf8' }));
const spendRequestId = createResult.id;
// 3. Poll for approval
const pollCmd = `link-cli spend-request retrieve ${spendRequestId} \
--interval 2 \
--max-attempts 300 \
--include card \
--output-file /tmp/card-${spendRequestId}.json \
--format json`;
const approvedResult = JSON.parse(execSync(pollCmd, { encoding: 'utf8' }));
// 4. Read card from secure file
const cardFile = `/tmp/card-${spendRequestId}.json`;
const cardData = JSON.parse(readFileSync(cardFile, 'utf8'));
// 5. Use card in checkout
await completeCheckout(cardData.card);import { execSync } from 'child_process';
// 1. Decode MPP challenge to get network_id
const challenge = response.headers['www-authenticate'];
const decodeResult = execSync(
`link-cli mpp decode --challenge '${challenge}' --format json`,
{ encoding: 'utf8' }
);
const { network_id } = JSON.parse(decodeResult);
// 2. Create SPT spend request
const createCmd = `link-cli spend-request create \
--payment-method-id ${pmId} \
--merchant-name "Climate Stripe" \
--merchant-url "https://climate.stripe.dev" \
--context "Contributing to climate offset program through climate.stripe.dev. The user wants to neutralize carbon emissions from their last flight." \
--amount 100 \
--credential-type "shared_payment_token" \
--line-item "name:Carbon Offset,unit_amount:100,quantity:1" \
--total "type:total,display_text:Total,amount:100" \
--request-approval \
--format json`;
const createResult = JSON.parse(execSync(createCmd, { encoding: 'utf8' }));
const spendRequestId = createResult.id;
// 3. Poll for approval
execSync(`link-cli spend-request retrieve ${spendRequestId} --interval 2 --max-attempts 300`);
// 4. Pay using MPP
const payCmd = `link-cli mpp pay https://climate.stripe.dev/api/contribute \
--spend-request-id ${spendRequestId} \
--method POST \
--data '{"amount":100}' \
--header "Content-Type: application/json" \
--format json`;
const payResult = JSON.parse(execSync(payCmd, { encoding: 'utf8' }));// User 1 session
process.env.LINK_AUTH_FILE = '/secure/user1-auth.json';
execSync('link-cli auth login --client-name "User1 Agent"');
// User 2 session
process.env.LINK_AUTH_FILE = '/secure/user2-auth.json';
execSync('link-cli auth login --client-name "User2 Agent"');
// Use different sessions
function getPaymentMethodsForUser(userId: string) {
const authFile = `/secure/${userId}-auth.json`;
return execSync(`link-cli payment-methods list --auth ${authFile} --format json`, {
encoding: 'utf8'
});
}| Variable | Description |
|---|---|
| Override auth credential file path (flag |
| Override API base URL |
| Override auth base URL |
| Route requests through HTTP proxy (requires |
| Set to |
link-cli auth statusauthenticated: false# Logout and login again
link-cli auth logout
link-cli auth login --client-name "My Agent"link-cli spend-request create \
--payment-method-id csmrpd_xxx \
--merchant-name "Updated Merchant" \
--merchant-url "https://merchant.example" \
--context "Revised purchase with updated details per user feedback. The user now wants the blue model instead of red, which has a different price point." \
--amount 4000 \
--line-item "name:Blue Model,unit_amount:4000,quantity:1" \
--total "type:total,display_text:Total,amount:4000" \
--request-approvalcontext must be at least 100 characters--context "Purchasing premium subscription to ExampleService for the team. This will give us access to advanced features including API access, priority support, and increased usage limits that we need for the upcoming project launch."amount must not exceed 50000code: "POLLING_TIMEOUT"--max-attempts# Poll for up to 15 minutes (2s interval × 450 attempts)
link-cli spend-request retrieve lsrq_001 \
--interval 2 \
--max-attempts 450# Cancel old request
link-cli spend-request cancel lsrq_001
# Create new request
link-cli spend-request create \
--payment-method-id csmrpd_xxx \
--credential-type "shared_payment_token" \
# ... rest of flags--output-file--forcelink-cli spend-request retrieve lsrq_001 \
--include card \
--output-file /tmp/card.json \
--force# Run interactive demo (test mode)
link-cli demo
# Only virtual card flow
link-cli demo --only-card
# Only MPP/SPT flow
link-cli demo --only-spt# Complete setup flow
link-cli onboard