← Back to report Page 2 of 2
Full Transcript
Stripe - Opus Transcript
Report: Stripe - Universal Baseline Model: Opus 4.6 Tested: 2026-03-10 Agent CLI: Claude Code v2.1.71
Task 3
Core task
Related findings: F-001
OperatorStep 1
Using the Stripe test mode API key, complete this workflow: > 1. Create a customer with the name "Test User" and email "test@example.com" 2. Create a product called "Usability Audit" priced at $99 (one-time, not recurring) 3. Create a Payment Intent for that amount, attached to the customer 4. Confirm the Payment Intent using a test card number 5. Verify the payment shows as succeeded > Use only the Stripe API. Show me the API calls you make and the responses you get. After each step, verify it succeeded before moving to the next — show me the evidence (e.g. the API response confirming creation/status).
AgentStep 2
### Step 1: Create a Customer
BashTool Use
Input
Show input
{
"command": "curl -s https://api.stripe.com/v1/customers \\\n -u \"sk_test_[REDACTED]:\" \\\n -d name=\"Test User\" \\\n -d email=\"test@example.com\"",
"description": "Create a Stripe customer",
"dangerouslyDisableSandbox": true
}BashTool Result
Result
Show output
{
"id": "cus_U7dlwcT5OzY9d5",
"object": "customer",
"address": null,
"balance": 0,
"created": 1773142198,
"currency": null,
"customer_account": null,
"default_currency": null,
"default_source": null,
"delinquent": false,
"description": null,
"discount": null,
"email": "test@example.com",
"invoice_prefix": "L87ISLWW",
"invoice_settings": {
"custom_fields": null,
"default_payment_method": null,
"footer": null,
"rendering_options": null
},
"livemode": false,
"metadata": {},
"name": "Test User",
"next_invoice_sequence": 1,
"phone": null,
"preferred_locales": [],
"shipping": null,
"sources": {
"object": "list",
"data": [],
"has_more": false,
"total_count": 0,
"url": "/v1/customers/cus_U7dlwcT5OzY9d5/sources"
},
"subscriptions": {
"object": "list",
"data": [],
"has_more": false,
"total_count": 0,
"url": "/v1/customers/cus_U7dlwcT5OzY9d5/subscriptions"
},
"tax_exempt": "none",
"tax_ids": {
"object": "list",
"data": [],
"has_more": false,
"total_count": 0,
"url": "/v1/customers/cus_U7dlwcT5OzY9d5/tax_ids"
},
"test_clock": null
}AgentStep 3
Customer created: `cus_U7dlwcT5OzY9d5`, name "Test User", email "test@example.com". ### Step 2: Create a Product and Price
BashTool Use
Input
Show input
{
"command": "curl -s https://api.stripe.com/v1/products \\\n -u \"sk_test_[REDACTED]:\" \\\n -d name=\"Usability Audit\"",
"description": "Create a Stripe product",
"dangerouslyDisableSandbox": true
}BashTool Result
Result
Show output
{
"id": "prod_U7dlsUY8vt0FHx",
"object": "product",
"active": true,
"attributes": [],
"created": 1773142202,
"default_price": null,
"description": null,
"features": [],
"images": [],
"livemode": false,
"marketing_features": [],
"metadata": {},
"name": "Usability Audit",
"package_dimensions": null,
"shippable": null,
"statement_descriptor": null,
"tax_code": null,
"type": "service",
"unit_label": null,
"updated": 1773142202,
"url": null
}AgentStep 4
Product created: `prod_U7dlsUY8vt0FHx`. Now create a one-time price of $99.
BashTool Use
Input
Show input
{
"command": "curl -s https://api.stripe.com/v1/prices \\\n -u \"sk_test_[REDACTED]:\" \\\n -d product=\"prod_U7dlsUY8vt0FHx\" \\\n -d unit_amount=9900 \\\n -d currency=usd",
"description": "Create a one-time price of $99",
"dangerouslyDisableSandbox": true
}BashTool Result
Result
Show output
{
"id": "price_1T9OUFLSFkr2JHffEBX0pYEI",
"object": "price",
"active": true,
"billing_scheme": "per_unit",
"created": 1773142207,
"currency": "usd",
"custom_unit_amount": null,
"livemode": false,
"lookup_key": null,
"metadata": {},
"nickname": null,
"product": "prod_U7dlsUY8vt0FHx",
"recurring": null,
"tax_behavior": "unspecified",
"tiers_mode": null,
"transform_quantity": null,
"type": "one_time",
"unit_amount": 9900,
"unit_amount_decimal": "9900"
}AgentStep 5
Price created: `price_1T9OUFLSFkr2JHff...` — $99.00 one-time (`"recurring": null` confirms it's not a subscription). ### Step 3: Create a Payment Intent
BashTool Use
Input
Show input
{
"command": "curl -s https://api.stripe.com/v1/payment_intents \\\n -u \"sk_test_[REDACTED]:\" \\\n -d amount=9900 \\\n -d currency=usd \\\n -d customer=\"cus_U7dlwcT5OzY9d5\" \\\n -d \"payment_method_types[]\"=card",
"description": "Create a PaymentIntent for $99 attached to the customer",
"dangerouslyDisableSandbox": true
}BashTool Result
Result
Show output
{
"id": "pi_3T9OUKLSFkr2JHff0WFdaBW2",
"object": "payment_intent",
"amount": 9900,
"amount_capturable": 0,
"amount_details": {
"tip": {}
},
"amount_received": 0,
"application": null,
"application_fee_amount": null,
"automatic_payment_methods": null,
"canceled_at": null,
"cancellation_reason": null,
"capture_method": "automatic",
"charges": {
"object": "list",
"data": [],
"has_more": false,
"total_count": 0,
"url": "/v1/charges?payment_intent=pi_3T9OUKLSFkr2JHff0WFdaBW2"
},
"client_secret": "pi_3T9OUKLSFkr2JHff0WFdaBW2_secret_jZczjLtjrM10vRFGbX3Bc7C71",
"confirmation_method": "automatic",
"created": 1773142212,
"currency": "usd",
"customer": "cus_U7dlwcT5OzY9d5",
"customer_account": null,
"description": null,
"excluded_payment_method_types": null,
"invoice": null,
"last_payment_error": null,
"latest_charge": null,
"livemode": false,
"metadata": {},
"next_action": null,
"on_behalf_of": null,
"payment_method": null,
"payment_method_configuration_details": null,
"payment_method_options": {
"card": {
"installments": null,
"mandate_options": null,
"network": null,
"request_three_d_secure": "automatic"
}
},
"payment_method_types": [
"card"
],
"processing": null,
"receipt_email": null,
"review": null,
"setup_future_usage": null,
"shipping": null,
"source": null,
"statement_descriptor": null,
"statement_descriptor_suffix": null,
"status": "requires_payment_method",
"transfer_data": null,
"transfer_group": null
}AgentStep 6
PaymentIntent created: `pi_3T9OUKLSFkr2JHff0WFdaBW2`, status `requires_payment_method`, amount $99.00, linked to customer `cus_U7dlwcT5OzY9d5`. ### Step 4: Confirm with a test card First, create a PaymentMethod using the test card `4242 4242 4242 4242`, then confirm the PaymentIntent.
BashTool Use
Input
Show input
{
"command": "curl -s https://api.stripe.com/v1/payment_intents/pi_3T9OUKLSFkr2JHff0WFdaBW2/confirm \\\n -u \"sk_test_[REDACTED]:\" \\\n -d payment_method=pm_card_visa",
"description": "Confirm the PaymentIntent with a test Visa card",
"dangerouslyDisableSandbox": true
}BashTool Result
Result
Show output
{
"id": "pi_3T9OUKLSFkr2JHff0WFdaBW2",
"object": "payment_intent",
"amount": 9900,
"amount_capturable": 0,
"amount_details": {
"tip": {}
},
"amount_received": 9900,
"application": null,
"application_fee_amount": null,
"automatic_payment_methods": null,
"canceled_at": null,
"cancellation_reason": null,
"capture_method": "automatic",
"charges": {
"object": "list",
"data": [
{
"id": "ch_3T9OUKLSFkr2JHff0RmJZjwO",
"object": "charge",
"amount": 9900,
"amount_captured": 9900,
"amount_refunded": 0,
"application": null,
"application_fee": null,
"application_fee_amount": null,
"balance_transaction": "txn_3T9OUKLSFkr2JHff0yUQcgno",
"billing_details": {
"address": {
"city": null,
"country": null,
"line1": null,
"line2": null,
"postal_code": null,
"state": null
},
"email": null,
"name": null,
"phone": null,
"tax_id": null
},
"calculated_statement_descriptor": "PMJOBLIST.COM",
"captured": true,
"created": 1773142218,
"currency": "usd",
"customer": "cus_U7dlwcT5OzY9d5",
"description": null,
"destination": null,
"dispute": null,
"disputed": false,
"failure_balance_transaction": null,
"failure_code": null,
"failure_message": null,
"fraud_details": {},
"invoice": null,
"livemode": false,
"metadata": {},
"on_behalf_of": null,
"order": null,
"outcome": {
"advice_code": null,
"network_advice_code": null,
"network_decline_code": null,
"network_status": "approved_by_network",
"reason": null,
"risk_level": "normal",
"risk_score": 14,
"seller_message": "Payment complete.",
"type": "authorized"
},
"paid": true,
"payment_intent": "pi_3T9OUKLSFkr2JHff0WFdaBW2",
"payment_method": "pm_1T9OUQLSFkr2JHffdmKjjxCD",
"payment_method_details": {
"card": {
"amount_authorized": 9900,
"authorization_code": "978164",
"brand": "visa",
"checks": {
"address_line1_check": null,
"address_postal_code_check": null,
"cvc_check": "pass"
},
"country": "US",
"exp_month": 3,
"exp_year": 2027,
"extended_authorization": {
"status": "disabled"
},
"fingerprint": "LYfZCkLjnCpwibDF",
"funding": "credit",
"incremental_authorization": {
"status": "unavailable"
},
"installments": null,
"last4": "4242",
"mandate": null,
"multicapture": {
"status": "unavailable"
},
"network": "visa",
"network_token": {
"used": false
},
"network_transaction_id": "768910290671077",
"overcapture": {
"maximum_amount_capturable": 9900,
"status": "unavailable"
},
"regulated_status": "unregulated",
"three_d_secure": null,
"wallet": null
},
"type": "card"
},
"radar_options": {},
"receipt_email": null,
"receipt_number": null,
"receipt_url": "https://pay.stripe.com/receipts/payment/CAcaFwoVYWNjdF8xSERab2tMU0ZrcjJKSGZmKMuBwM0GMgZE7wIm50c6LBYNoiVkeerRMuLQZG98dZdvdmY6oEmu9bUtouDWJabwPv-ScPAzGeY89UIr",
"refunded": false,
"refunds": {
"object": "list",
"data": [],
"has_more": false,
"total_count": 0,
"url": "/v1/charges/ch_3T9OUKLSFkr2JHff0RmJZjwO/refunds"
},
"review": null,
"shipping": null,
"source": null,
"source_transfer": null,
"statement_descriptor": null,
"statement_descriptor_suffix": null,
"status": "succeeded",
"transfer_data": null,
"transfer_group": null
}
],
"has_more": false,
"total_count": 1,
"url": "/v1/charges?payment_intent=pi_3T9OUKLSFkr2JHff0WFdaBW2"
},
"client_secret": "pi_3T9OUKLSFkr2JHff0WFdaBW2_secret_jZczjLtjrM10vRFGbX3Bc7C71",
"confirmation_method": "automatic",
"created": 1773142212,
"currency": "usd",
"customer": "cus_U7dlwcT5OzY9d5",
"customer_account": null,
"description": null,
"excluded_payment_method_types": null,
"invoice": null,
"last_payment_error": null,
"latest_charge": "ch_3T9OUKLSFkr2JHff0RmJZjwO",
"livemode": false,
"metadata": {},
"next_action": null,
"on_behalf_of": null,
"payment_method": "pm_1T9OUQLSFkr2JHffdmKjjxCD",
"payment_method_configuration_details": null,
"payment_method_options": {
"card": {
"installments": null,
"mandate_options": null,
"network": null,
"request_three_d_secure": "automatic"
}
},
"payment_method_types": [
"card"
],
"processing": null,
"receipt_email": null,
"review": null,
"setup_future_usage": null,
"shipping": null,
"source": null,
"statement_descriptor": null,
"statement_descriptor_suffix": null,
"status": "succeeded",
"transfer_data": null,
"transfer_group": null
}AgentStep 7
### Step 5: Verify — Payment Succeeded
The confirmation response already proves success, but here's the evidence from the response:
| Check | Evidence |
|---|---|
| **PaymentIntent status** | `"status": "succeeded"` |
| **Amount received** | `"amount_received": 9900` ($99.00) |
| **Charge status** | `"status": "succeeded"`, `"paid": true`, `"captured": true` |
| **Card used** | Visa ending in `4242` (test card) |
| **Network approval** | `"network_status": "approved_by_network"` |
| **Customer linked** | `"customer": "cus_U7dlwcT5OzY9d5"` |
| **Live mode** | `"livemode": false` (test mode confirmed) |
---
### Summary of the full workflow
| Step | API Call | Object Created |
|---|---|---|
| 1. Customer | `POST /v1/customers` | `cus_U7dlwcT5OzY9d5` |
| 2a. Product | `POST /v1/products` | `prod_U7dlsUY8vt0FHx` |
| 2b. Price | `POST /v1/prices` | `price_1T9OUFLSFkr2JHff...` ($99, one-time) |
| 3. PaymentIntent | `POST /v1/payment_intents` | `pi_3T9OUKLSFkr2JHff0WFdaBW2` |
| 4. Confirm | `POST /v1/payment_intents/{id}/confirm` | Charge `ch_3T9OUKLSFkr2JHff0RmJZjwO` |
Four API calls, one successful $99 test charge. You can see the payment in your Stripe dashboard at the test payments page. Task 4
Error handling
OperatorStep 1
Using the Stripe test mode API, do the following: > 1. Attempt to create a Payment Intent with an invalid currency code 2. Attempt to charge a test card that is configured to be declined (find the right test card number from Stripe's docs) 3. Attempt to retrieve a customer that doesn't exist > For each error: show me the full error response, explain whether the error message gave you enough information to understand what went wrong, and describe what you would do to recover.
AgentStep 2
### Error 1: Invalid currency code
BashTool Use
Input
Show input
{
"command": "curl -s https://api.stripe.com/v1/payment_intents \\\n -u \"sk_test_[REDACTED]:\" \\\n -d amount=5000 \\\n -d currency=zzz \\\n -d \"payment_method_types[]\"=card",
"description": "Create PaymentIntent with invalid currency",
"dangerouslyDisableSandbox": true
}BashTool Result
Result
Show output
{
"error": {
"message": "Invalid currency: zzz. Stripe currently supports these currencies: usd, aed, afn, all, amd, ang, aoa, ars, aud, awg, azn, bam, bbd, bdt, bgn, bhd, bif, bmd, bnd, bob, brl, bsd, bwp, byn, bzd, cad, cdf, chf, clp, cny, cop, crc, cve, czk, djf, dkk, dop, dzd, egp, etb, eur, fjd, fkp, gbp, gel, gip, gmd, gnf, gtq, gyd, hkd, hnl, hrk, htg, huf, idr, ils, inr, isk, jmd, jod, jpy, kes, kgs, khr, kmf, krw, kwd, kyd, kzt, lak, lbp, lkr, lrd, lsl, mad, mdl, mga, mkd, mmk, mnt, mop, mur, mvr, mwk, mxn, myr, mzn, nad, ngn, nio, nok, npr, nzd, omr, pab, pen, pgk, php, pkr, pln, pyg, qar, ron, rsd, rub, rwf, sar, sbd, scr, sek, sgd, shp, sle, sos, srd, std, szl, thb, tjs, tnd, top, try, ttd, twd, tzs, uah, ugx, uyu, uzs, vnd, vuv, wst, xaf, xcd, xcg, xof, xpf, yer, zar, zmw, usdc, btn, ghs, eek, lvl, svc, vef, ltl, sll, mro",
"param": "currency",
"request_log_url": "https://dashboard.stripe.com/acct_1HDZokLSFkr2JHff/test/workbench/logs?object=req_oDA7f3cpMOrUqS",
"type": "invalid_request_error"
}
}WebFetchTool Use
Input
Show input
{
"url": "https://docs.stripe.com/testing",
"prompt": "What are the test card numbers for declined cards? List the specific card numbers that simulate declines (e.g. generic decline, insufficient funds, etc.) with their numbers."
}WebFetchTool Result
Result
Show output
# Declined Test Cards The provided documentation does not contain specific test card numbers for declined payments. The content mentions that declined test cards exist—stating you can "simulate...Kartenfehler aufgrund von [Ablehnungen]" (card errors due to declines)—but the actual card numbers for various decline scenarios (generic decline, insufficient funds, lost card, etc.) are not included in this excerpt. To access the complete list of declined test card numbers, you would need to consult the full Stripe testing documentation, as this section appears to focus on successful payment scenarios organized by card brand and country.
WebFetchTool Use
Input
Show input
{
"url": "https://docs.stripe.com/testing#declined-payments",
"prompt": "List all test card numbers that simulate declined payments. I need the card numbers for generic decline, insufficient funds, lost card, stolen card, expired card, incorrect CVC, and any others listed."
}WebFetchTool Result
Result
Show output
# Test Card Numbers for Declined Payments I've reviewed the provided documentation, but it does not contain a comprehensive list of test card numbers that simulate declined payments with specific decline reasons (such as insufficient funds, lost card, stolen card, etc.). The document mentions that test cards can simulate "Kartenfehler aufgrund von Ablehnungen" (card errors due to declines), but the actual card numbers for these specific decline scenarios are not included in the content you provided. To access the complete list of declined payment test cards with their specific failure reasons, you would need to consult the full Stripe testing documentation, particularly the sections referenced but not fully shown here, such as the "[Ablehnungen](https://docs.stripe.com/testing.md#declined-payments)" (declined payments) link mentioned in the document.
WebFetchTool Use
Input
Show input
{
"url": "https://docs.stripe.com/testing.md",
"prompt": "Find and list ALL test card numbers for declined payments. I need the card numbers for generic_decline, insufficient_funds, lost_card, stolen_card, expired_card, incorrect_cvc, processing_error, and any others. Return the card number and its decline code."
}WebFetchTool Result
Result
Show output
# Declined Payment Test Cards Based on the provided documentation, I cannot find test card numbers specifically categorized by decline codes (generic_decline, insufficient_funds, lost_card, stolen_card, expired_card, incorrect_cvc, processing_error, etc.). The document mentions that test cards can simulate "Kartenfehler aufgrund von Ablehnungen" (card errors due to rejections), but it does not provide the actual card numbers associated with specific decline scenarios. The content only includes: - Test cards organized by card brand (Visa, Mastercard, American Express, etc.) - Test cards organized by country/region - Co-branded card examples - References to sections about testing declines and fraud prevention, but without the actual card numbers listed **To access the specific declined payment test card numbers you need, you would need to consult the full Stripe testing documentation**, as the complete tables with decline-specific card numbers appear to be in sections referenced but not fully included in this excerpt.
AgentStep 3
The docs page isn't rendering the decline card table. I know from Stripe's testing docs that `4000000000000002` is the generic decline card. Let me also try `4000000000009995` (insufficient funds). Let me proceed with the remaining two error tests. ### Error 2: Declined card
BashTool Use
Input
Show input
{
"command": "curl -s https://api.stripe.com/v1/payment_intents \\\n -u \"sk_test_[REDACTED]:\" \\\n -d amount=5000 \\\n -d currency=usd \\\n -d \"payment_method_types[]\"=card \\\n -d confirm=true \\\n -d \"payment_method_data[type]\"=card \\\n -d \"payment_method_data[card][number]\"=4000000000000002 \\\n -d \"payment_method_data[card][exp_month]\"=12 \\\n -d \"payment_method_data[card][exp_year]\"=2034 \\\n -d \"payment_method_data[card][cvc]\"=123",
"description": "Create and confirm PaymentIntent with a decline-test card",
"dangerouslyDisableSandbox": true
}BashTool Result
Result
Show output
{
"error": {
"message": "Sending credit card numbers directly to the Stripe API is generally unsafe. We suggest you use test tokens that map to the test card you are using, see https://stripe.com/docs/testing. To enable testing raw card data APIs, see https://support.stripe.com/questions/enabling-access-to-raw-card-data-apis.",
"request_log_url": "https://dashboard.stripe.com/acct_1HDZokLSFkr2JHff/test/workbench/logs?object=req_P8dmFlngxz28Cp",
"type": "invalid_request_error"
}
}AgentStep 4
Stripe won't accept raw card numbers via the API (security measure). I need to use the test token shorthand instead.
BashTool Use
Input
Show input
{
"command": "curl -s https://api.stripe.com/v1/payment_intents \\\n -u \"sk_test_[REDACTED]:\" \\\n -d amount=5000 \\\n -d currency=usd \\\n -d \"payment_method_types[]\"=card \\\n -d confirm=true \\\n -d payment_method=pm_card_chargeDeclined",
"description": "Confirm PaymentIntent with a decline test token",
"dangerouslyDisableSandbox": true
}BashTool Result
Result
Show output
{
"error": {
"advice_code": "try_again_later",
"charge": "ch_3T9OgjLSFkr2JHff1a5Kbbng",
"code": "card_declined",
"decline_code": "generic_decline",
"doc_url": "https://stripe.com/docs/error-codes/card-declined",
"message": "Your card was declined.",
"network_decline_code": "01",
"payment_intent": {
"id": "pi_3T9OgjLSFkr2JHff1Sp0MvuJ",
"object": "payment_intent",
"amount": 5000,
"amount_capturable": 0,
"amount_details": {
"tip": {}
},
"amount_received": 0,
"application": null,
"application_fee_amount": null,
"automatic_payment_methods": null,
"canceled_at": null,
"cancellation_reason": null,
"capture_method": "automatic",
"charges": {
"object": "list",
"data": [
{
"id": "ch_3T9OgjLSFkr2JHff1a5Kbbng",
"object": "charge",
"amount": 5000,
"amount_captured": 0,
"amount_refunded": 0,
"application": null,
"application_fee": null,
"application_fee_amount": null,
"balance_transaction": null,
"billing_details": {
"address": {
"city": null,
"country": null,
"line1": null,
"line2": null,
"postal_code": null,
"state": null
},
"email": null,
"name": null,
"phone": null,
"tax_id": null
},
"calculated_statement_descriptor": "PMJOBLIST.COM",
"captured": false,
"created": 1773142981,
"currency": "usd",
"customer": null,
"description": null,
"destination": null,
"dispute": null,
"disputed": false,
"failure_balance_transaction": null,
"failure_code": "card_declined",
"failure_message": "Your card was declined.",
"fraud_details": {},
"invoice": null,
"livemode": false,
"metadata": {},
"on_behalf_of": null,
"order": null,
"outcome": {
"advice_code": "try_again_later",
"network_advice_code": null,
"network_decline_code": "01",
"network_status": "declined_by_network",
"reason": "generic_decline",
"risk_level": "normal",
"risk_score": 33,
"seller_message": "The bank did not return any further details with this decline.",
"type": "issuer_declined"
},
"paid": false,
"payment_intent": "pi_3T9OgjLSFkr2JHff1Sp0MvuJ",
"payment_method": "pm_1T9OgiLSFkr2JHffHgKipfWV",
"payment_method_details": {
"card": {
"amount_authorized": null,
"authorization_code": "179873",
"brand": "visa",
"checks": {
"address_line1_check": null,
"address_postal_code_check": null,
"cvc_check": "pass"
},
"country": "US",
"exp_month": 3,
"exp_year": 2027,
"extended_authorization": {
"status": "disabled"
},
"fingerprint": "vZ0gr7Ae5Qei8bU6",
"funding": "credit",
"incremental_authorization": {
"status": "unavailable"
},
"installments": null,
"last4": "0002",
"mandate": null,
"multicapture": {
"status": "unavailable"
},
"network": "visa",
"network_token": {
"used": false
},
"network_transaction_id": "118904810311455",
"overcapture": {
"maximum_amount_capturable": 5000,
"status": "unavailable"
},
"regulated_status": "unregulated",
"three_d_secure": null,
"wallet": null
},
"type": "card"
},
"radar_options": {},
"receipt_email": null,
"receipt_number": null,
"receipt_url": null,
"refunded": false,
"refunds": {
"object": "list",
"data": [],
"has_more": false,
"total_count": 0,
"url": "/v1/charges/ch_3T9OgjLSFkr2JHff1a5Kbbng/refunds"
},
"review": null,
"shipping": null,
"source": null,
"source_transfer": null,
"statement_descriptor": null,
"statement_descriptor_suffix": null,
"status": "failed",
"transfer_data": null,
"transfer_group": null
}
],
"has_more": false,
"total_count": 1,
"url": "/v1/charges?payment_intent=pi_3T9OgjLSFkr2JHff1Sp0MvuJ"
},
"client_secret": "pi_3T9OgjLSFkr2JHff1Sp0MvuJ_secret_QKuUDMndiKMtkxWkiOrbQaLuM",
"confirmation_method": "automatic",
"created": 1773142981,
"currency": "usd",
"customer": null,
"customer_account": null,
"description": null,
"excluded_payment_method_types": null,
"invoice": null,
"last_payment_error": {
"advice_code": "try_again_later",
"charge": "ch_3T9OgjLSFkr2JHff1a5Kbbng",
"code": "card_declined",
"decline_code": "generic_decline",
"doc_url": "https://stripe.com/docs/error-codes/card-declined",
"message": "Your card was declined.",
"network_decline_code": "01",
"payment_method": {
"id": "pm_1T9OgiLSFkr2JHffHgKipfWV",
"object": "payment_method",
"allow_redisplay": "unspecified",
"billing_details": {
"address": {
"city": null,
"country": null,
"line1": null,
"line2": null,
"postal_code": null,
"state": null
},
"email": null,
"name": null,
"phone": null,
"tax_id": null
},
"card": {
"brand": "visa",
"checks": {
"address_line1_check": null,
"address_postal_code_check": null,
"cvc_check": "pass"
},
"country": "US",
"display_brand": "visa",
"exp_month": 3,
"exp_year": 2027,
"fingerprint": "vZ0gr7Ae5Qei8bU6",
"funding": "credit",
"generated_from": null,
"last4": "0002",
"networks": {
"available": [
"visa"
],
"preferred": null
},
"regulated_status": "unregulated",
"three_d_secure_usage": {
"supported": true
},
"wallet": null
},
"created": 1773142981,
"customer": null,
"customer_account": null,
"livemode": false,
"metadata": {},
"type": "card"
},
"type": "card_error"
},
"latest_charge": "ch_3T9OgjLSFkr2JHff1a5Kbbng",
"livemode": false,
"metadata": {},
"next_action": null,
"on_behalf_of": null,
"payment_method": null,
"payment_method_configuration_details": null,
"payment_method_options": {
"card": {
"installments": null,
"mandate_options": null,
"network": null,
"request_three_d_secure": "automatic"
}
},
"payment_method_types": [
"card"
],
"processing": null,
"receipt_email": null,
"review": null,
"setup_future_usage": null,
"shipping": null,
"source": null,
"statement_descriptor": null,
"statement_descriptor_suffix": null,
"status": "requires_payment_method",
"transfer_data": null,
"transfer_group": null
},
"payment_method": {
"id": "pm_1T9OgiLSFkr2JHffHgKipfWV",
"object": "payment_method",
"allow_redisplay": "unspecified",
"billing_details": {
"address": {
"city": null,
"country": null,
"line1": null,
"line2": null,
"postal_code": null,
"state": null
},
"email": null,
"name": null,
"phone": null,
"tax_id": null
},
"card": {
"brand": "visa",
"checks": {
"address_line1_check": null,
"address_postal_code_check": null,
"cvc_check": "pass"
},
"country": "US",
"display_brand": "visa",
"exp_month": 3,
"exp_year": 2027,
"fingerprint": "vZ0gr7Ae5Qei8bU6",
"funding": "credit",
"generated_from": null,
"last4": "0002",
"networks": {
"available": [
"visa"
],
"preferred": null
},
"regulated_status": "unregulated",
"three_d_secure_usage": {
"supported": true
},
"wallet": null
},
"created": 1773142981,
"customer": null,
"customer_account": null,
"livemode": false,
"metadata": {},
"type": "card"
},
"request_log_url": "https://dashboard.stripe.com/acct_1HDZokLSFkr2JHff/test/workbench/logs?object=req_S3npR1PSeyQuza",
"type": "card_error"
}
}AgentStep 5
### Error 3: Non-existent customer
BashTool Use
Input
Show input
{
"command": "curl -s https://api.stripe.com/v1/customers/cus_DOESNOTEXIST999 \\\n -u \"sk_test_[REDACTED]:\"",
"description": "Retrieve a non-existent customer",
"dangerouslyDisableSandbox": true
}BashTool Result
Result
Show output
{
"error": {
"code": "resource_missing",
"doc_url": "https://stripe.com/docs/error-codes/resource-missing",
"message": "No such customer: 'cus_DOESNOTEXIST999'",
"param": "id",
"request_log_url": "https://dashboard.stripe.com/acct_1HDZokLSFkr2JHff/test/workbench/logs?object=req_XOrDpGoEkFYiN3",
"type": "invalid_request_error"
}
}AgentStep 6
All three done. Here's the analysis: --- ## Error 1: Invalid Currency (`zzz`) **Error type:** `invalid_request_error` **Message:** `Invalid currency: zzz. Stripe currently supports these currencies: usd, aed, afn, all, ...` **Diagnostic quality:** Excellent. Stripe tells you exactly what's wrong (`param: "currency"`), names the bad value, and lists every valid currency. You also get a `request_log_url` linking directly to the failed request in your dashboard. **Recovery:** Fix the currency code to a valid ISO 4217 value (e.g. `usd`). This is a pure input validation error — nothing to retry, just correct the parameter. --- ## Error 2: Declined Card (`pm_card_chargeDeclined`) **Error type:** `card_error` **Key fields:** - `code: "card_declined"` - `decline_code: "generic_decline"` - `network_decline_code: "01"` - `advice_code: "try_again_later"` - `outcome.seller_message: "The bank did not return any further details with this decline."` **Diagnostic quality:** Very good. Stripe gives you multiple layers of information: - The high-level `code` tells your code what happened - The `decline_code` gives a more specific reason - The `advice_code` suggests what to do next - The `outcome` object includes the network-level decline code and a human-readable `seller_message` - The PaymentIntent is returned in full, showing its status flipped to `requires_payment_method` — meaning it's still alive and can be retried **Recovery:** The PaymentIntent isn't dead. You can call `confirm` again with a different payment method. In a real app, you'd prompt the customer to try a different card. The `advice_code: "try_again_later"` suggests this may also be a transient issue worth retrying. --- ## Error 3: Non-existent Customer **Error type:** `invalid_request_error` **Code:** `resource_missing` **Message:** `No such customer: 'cus_DOESNOTEXIST999'` **Diagnostic quality:** Clear and sufficient. It names the exact ID that wasn't found and the param (`id`) that caused the error. The `doc_url` links to Stripe's docs on this error code. **Recovery:** Verify the customer ID is correct. If the customer was deleted or the ID is from a different Stripe account/mode (live vs. test), that would explain the miss. In code, handle this with a try/catch and either create the customer or surface the error to the caller. --- ## Summary | Error | Type | Diagnosable? | Recoverable? | |---|---|---|---| | Invalid currency | `invalid_request_error` | Immediately — lists valid values | Fix the input | | Declined card | `card_error` | Yes — decline code + advice code | Retry with a different payment method | | Missing customer | `invalid_request_error` | Yes — names the bad ID | Verify ID or create new customer | Stripe's error responses are structured consistently: every error includes `type`, `message`, `request_log_url`, and usually `code`, `param`, and `doc_url`. This makes programmatic error handling straightforward — you can branch on `type` and `code` without parsing message strings.
Task 5
Cleanup
Related findings: F-008
OperatorStep 1
Clean up everything we created during this test: > 1. Delete the test customer 2. Archive or delete the product 3. Confirm no test data remains > If any of these can't be done via the API, tell me what manual steps would be needed.
BashTool Use
Input
Show input
{
"command": "curl -s https://api.stripe.com/v1/customers/cus_U7dlwcT5OzY9d5 -X DELETE \\\n -u \"sk_test_[REDACTED]:\"",
"description": "Delete the test customer",
"dangerouslyDisableSandbox": true
}BashTool Result
Result
Show output
{
"id": "cus_U7dlwcT5OzY9d5",
"object": "customer",
"deleted": true
}BashTool Use
Input
Show input
{
"command": "curl -s https://api.stripe.com/v1/products/prod_U7dlsUY8vt0FHx -X POST \\\n -u \"sk_test_[REDACTED]:\" \\\n -d active=false",
"description": "Archive the product (deactivate it)",
"dangerouslyDisableSandbox": true
}BashTool Result
Result
Show output
{
"id": "prod_U7dlsUY8vt0FHx",
"object": "product",
"active": false,
"attributes": [],
"created": 1773142202,
"default_price": null,
"description": null,
"features": [],
"images": [],
"livemode": false,
"marketing_features": [],
"metadata": {},
"name": "Usability Audit",
"package_dimensions": null,
"shippable": null,
"statement_descriptor": null,
"tax_code": null,
"type": "service",
"unit_label": null,
"updated": 1773143039,
"url": null
}AgentStep 2
Now let me verify nothing remains.
BashTool Use
Input
Show input
{
"command": "curl -s \"https://api.stripe.com/v1/customers/cus_U7dlwcT5OzY9d5\" \\\n -u \"sk_test_[REDACTED]:\"",
"description": "Verify customer is deleted",
"dangerouslyDisableSandbox": true
}BashTool Result
Result
Show output
{
"id": "cus_U7dlwcT5OzY9d5",
"object": "customer",
"deleted": true
}BashTool Use
Input
Show input
{
"command": "curl -s \"https://api.stripe.com/v1/products/prod_U7dlsUY8vt0FHx\" \\\n -u \"sk_test_[REDACTED]:\"",
"description": "Verify product is archived",
"dangerouslyDisableSandbox": true
}BashTool Result
Result
Show output
{
"id": "prod_U7dlsUY8vt0FHx",
"object": "product",
"active": false,
"attributes": [],
"created": 1773142202,
"default_price": null,
"description": null,
"features": [],
"images": [],
"livemode": false,
"marketing_features": [],
"metadata": {},
"name": "Usability Audit",
"package_dimensions": null,
"shippable": null,
"statement_descriptor": null,
"tax_code": null,
"type": "service",
"unit_label": null,
"updated": 1773143039,
"url": null
}AgentStep 3
Done. Here's the cleanup summary: | Object | ID | Action | Status | |---|---|---|---| | Customer | `cus_U7dlwcT5OzY9d5` | Deleted | `"deleted": true` | | Product | `prod_U7dlsUY8vt0FHx` | Archived | `"active": false` | ### What can't be fully deleted via API - **PaymentIntents and Charges** (`pi_3T9OUK...`, `pi_3T9Ogj...`, `ch_3T9OUK...`, `ch_3T9Ogj...`) — These are **immutable ledger records**. Stripe does not allow deletion of payment history via the API. They remain in your test dashboard but have no operational effect. - **Price** (`price_1T9OUF...`) — Prices can be deactivated (`active: false`) but not deleted. Since the parent product is already archived, the price is effectively inert. - **PaymentMethods** (`pm_1T9OUQ...`, `pm_1T9Ogi...`) — These are detached (not saved to any customer) and will not be usable. If you want a completely clean slate, the nuclear option is: **Stripe Dashboard → Settings → Test Data → "Delete all test data"**. That wipes everything in test mode. But for normal use, what we've done here is sufficient — the customer is gone, the product is archived, and the payment records are just historical artifacts.
Task 6
Reflection
Related findings: F-007
OperatorStep 1
Looking back at everything you just did — discovering Stripe, onboarding, completing the payment workflow, handling errors, and cleaning up: > 1. Which steps were straightforward and which felt unnecessarily complex? 2. Where did you have to work around something rather than use what felt like the intended path? 3. What would have made this easier? > Be specific — refer to actual moments from the tasks above.
AgentStep 2
## Retrospective
### What was straightforward
**The core payment flow was remarkably smooth.** Creating a customer, product, price, PaymentIntent, and confirming it took five sequential `curl` calls with no surprises. The API is consistent — every object comes back with an `id`, you pass that `id` to the next call. The response from confirming the PaymentIntent included the full charge object inline, so I didn't need a separate verification step. That's good API design.
**Error handling was the cleanest part.** All three error scenarios returned structured, actionable responses. The invalid currency error literally listed every valid option. The declined card error gave me a `decline_code`, an `advice_code`, and left the PaymentIntent in `requires_payment_method` status so it could be retried. I didn't have to guess at anything — every error told me what went wrong and what to do about it.
**Cleanup was mostly straightforward.** `DELETE /v1/customers/{id}` just worked. Product archival via `active: false` was a single field update.
---
### Where I had to work around things
**1. The declined card test was a two-attempt detour.** My first instinct was to pass a raw card number (`4000000000000002`) in the `payment_method_data[card][number]` field. Stripe rejected this because raw card numbers aren't allowed through the API without special access — this is a security measure for PCI compliance. I had to switch to using the test token `pm_card_chargeDeclined`. This is the *intended* path, but it wasn't obvious from the PaymentIntent docs that test tokens like `pm_card_chargeDeclined` exist as shortcuts. I found it by knowing the naming convention, not from documentation.
**2. The `llms.txt` file was useful for orientation but the docs pages didn't fully render.** When I tried to look up the specific declined test card numbers from `docs.stripe.com/testing`, the page rendered partially — the decline card table (which is likely dynamically loaded or in a tab) never came through. I tried three different URL variations (`/testing`, `/testing#declined-payments`, `/testing.md`) and none returned the decline card numbers. I had to fall back on knowing that `pm_card_chargeDeclined` exists as a token alias.
**3. Products can't be deleted, only archived.** This isn't a workaround exactly, but it was a moment where the API didn't do what you'd naively expect. Same with PaymentIntents and Charges being immutable. For a test/evaluation workflow where you want a clean slate, having to go to the dashboard UI to wipe test data is a friction point.
---
### What would have made this easier
**A machine-readable test fixtures reference.** The hardest single moment was finding the right declined card token. Stripe has dozens of test tokens (`pm_card_visa`, `pm_card_chargeDeclined`, `pm_card_chargeDeclinedInsufficientFunds`, etc.) but there's no single API endpoint or structured file that lists them. Something like `GET /v1/test_helpers/fixtures` or a JSON file at `docs.stripe.com/test-tokens.json` would have eliminated the guesswork entirely.
**The `llms.txt` file could link to raw-content URLs.** It gave a good high-level map of Stripe's product surface, but when I followed up by fetching actual doc pages, the content was incomplete because the rendered HTML didn't include tabbed/dynamic content. If `llms.txt` linked to `.md` source files that fully rendered (like GitHub raw files), the entire discovery phase would have been one fetch instead of four.
**A `DELETE /v1/test_data` API endpoint.** The dashboard has a "delete all test data" button, but there's no API equivalent. For an automated evaluation workflow — spin up test objects, exercise them, tear everything down — this is a missing piece. You're left with objects you can't delete (PaymentIntents, Charges, Prices) cluttering the test environment.
**Explicit "API-only quickstart" in the docs.** Stripe's onboarding docs lead with the Checkout Sessions flow (hosted UI + webhooks), which is the right default for most users. But for my use case — pure server-side, no frontend, just charge a card — I had to mentally filter out the UI integration parts to find the minimal PaymentIntent-based flow. A dedicated "charge a card from your server with no frontend" guide would have saved orientation time.