Install
openclaw skills install drivethru-stripeLook up products in the Stripe catalog and create a Stripe Checkout Session that returns a hosted checkout URL. Use whenever the user needs to browse what's for sale, bill a customer, collect a one-time payment, or start a subscription via a Stripe-hosted page.
openclaw skills install drivethru-stripeThis skill does two things against the Stripe API:
A typical flow: call list_products.py to find the right price_... id(s), then pass them to create_checkout_session.py as line_items.
The agent host MUST expose STRIPE_SECRET_KEY in the environment before this skill is invoked.
sk_test_... (use during development; charges are not real)sk_live_... (real money — only after explicit user confirmation)If STRIPE_SECRET_KEY is missing, stop and tell the user to set it. Do not prompt the user to paste the key into chat — secrets must come from the environment.
Optional environment variables:
| Variable | Purpose |
|---|---|
STRIPE_API_VERSION | Pin a Stripe API version (defaults to the account's pinned version). |
STRIPE_DEFAULT_SUCCESS_URL | Fallback success_url when the user does not provide one. |
STRIPE_DEFAULT_CANCEL_URL | Fallback cancel_url when the user does not provide one. |
price_..."| Script | Purpose |
|---|---|
scripts/list_products.py | Query products (list / search / by id) + their prices |
scripts/create_checkout_session.py | Create a Checkout Session and return the hosted checkout URL |
Call scripts/list_products.py with an optional JSON filter on stdin. With no input, it returns the first 10 active products.
{
"query": "shirt",
"ids": ["prod_abc", "prod_def"],
"active": true,
"limit": 10,
"starting_after": "prod_xyz",
"include_inactive_prices": false
}
query — free-text search against product name. If the string contains a :, it is passed through as a raw Stripe Search query (e.g. metadata['sku']:'A-100' AND active:'true'). Search results may lag writes by up to a minute.ids — retrieve specific products by id (skips list/search). Up to ~50 is reasonable.active — defaults to true. Pass false to include archived products, or null for both.limit — 1–100, defaults to 10.starting_after — pagination cursor (returned as next_starting_after). Only applies to plain list mode.include_inactive_prices — defaults to false. Each returned product's prices array only contains active prices unless this is true.echo '{"query": "shirt", "limit": 5}' | python3 scripts/list_products.py
{
"products": [
{
"id": "prod_NabcXYZ",
"name": "Cotton T-shirt",
"description": "100% cotton, unisex",
"image": "https://files.stripe.com/.../shirt-front.png",
"images": ["https://files.stripe.com/.../shirt-front.png"],
"metadata": {"sku": "TS-001", "color": "navy"},
"active": true,
"default_price": "price_1Nabc...",
"prices": [
{
"id": "price_1Nabc...",
"unit_amount": 1500,
"currency": "usd",
"recurring": null,
"nickname": null,
"active": true
}
]
}
],
"has_more": false,
"next_starting_after": null
}
unit_amount is in the smallest currency unit (cents for USD).image is the first entry from images for convenience; use images if you need them all.metadata is the product's free-form key/value map set in the Stripe dashboard.has_more is true, pass next_starting_after back as starting_after to get the next page.When the user asks about pricing for a product, prefer the default_price if set; otherwise, surface all prices so they can pick.
Call scripts/create_checkout_session.py with a JSON payload on stdin. The script prints a JSON object with url, id, and expires_at on success.
{
"mode": "payment | subscription | setup",
"line_items": [
{"price": "price_123", "quantity": 1},
{
"price_data": {
"currency": "usd",
"unit_amount": 1500,
"product_data": {"name": "Custom T-shirt", "description": "Size M"}
},
"quantity": 2
}
],
"success_url": "https://example.com/success?session_id={CHECKOUT_SESSION_ID}",
"cancel_url": "https://example.com/cancel",
"customer_email": "optional@example.com",
"client_reference_id": "optional-internal-id",
"metadata": {"order_id": "1234"},
"allow_promotion_codes": true
}
mode defaults to "payment" (one-time). Use "subscription" when any line item references a recurring price.line_items[*] entry MUST contain either price (existing Stripe Price ID) OR price_data (inline price), plus quantity.unit_amount is in the smallest currency unit (cents for USD).success_url is required by Stripe. Use {CHECKOUT_SESSION_ID} to receive the session id back as a query param.echo '{
"mode": "payment",
"line_items": [{"price": "price_1Nabc...", "quantity": 1}],
"success_url": "https://example.com/success?session_id={CHECKOUT_SESSION_ID}",
"cancel_url": "https://example.com/cancel"
}' | python3 scripts/create_checkout_session.py
Successful output:
{
"url": "https://checkout.stripe.com/c/pay/cs_test_...",
"id": "cs_test_a1B2c3D4...",
"expires_at": 1716595200,
"mode": "payment",
"livemode": false
}
Return the url to the user — that is the link they (or their customer) should open to complete payment.
The script exits non-zero and prints a JSON {"error": {...}} object on failure. Common cases:
auth_error — STRIPE_SECRET_KEY is missing, malformed, or revoked.invalid_request — bad price id, currency mismatch, missing success_url.validation_error — the input JSON does not satisfy the schema.Surface the human-readable message to the user and suggest the obvious fix. Do not retry on auth_error or validation_error.
STRIPE_SECRET_KEY. The script reads it from the environment and never echoes it.url as sensitive-ish: anyone with the link can pay. Share it only with the intended customer.See references/checkout_options.md for the less-common Checkout Session fields (shipping, tax, automatic_payment_methods, etc.).