ekx-stripelisted
Install: claude install-skill Ekinoxis-evm/claude-skills
# Stripe
Our fiat rail everywhere except Colombia. (Onchain payments are USDC — see
[`../ekx-circle-usdc/SKILL.md`](../ekx-circle-usdc/SKILL.md); for Colombia see
[`../ekx-mercadopago/SKILL.md`](../ekx-mercadopago/SKILL.md).)
Authoritative: the **`stripe` MCP server** plus the bundled `stripe-best-practices` skill. Docs: https://docs.stripe.com
---
## Environment
```bash
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY= # pk_test_… / pk_live_…
STRIPE_SECRET_KEY= # SECRET sk_test_… / sk_live_…
STRIPE_WEBHOOK_SECRET= # SECRET whsec_…
STRIPE_PREMIUM_PRICE_ID= # price_…
```
The webhook secret is **per endpoint**. Local (Stripe CLI), preview and production
each have their own. Using production's secret against a CLI-forwarded event fails
signature verification — the most common Stripe bug we hit.
---
## Checkout Session — the default
Prefer a hosted Checkout Session over a custom Payment Element unless the design
genuinely requires an embedded form. It handles SCA, wallets, tax, and receipts for free.
```ts
// app/api/checkout/route.ts
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const { bookingId } = await req.json();
const session = await stripe.checkout.sessions.create({
mode: "payment",
line_items: [{ price: process.env.STRIPE_PREMIUM_PRICE_ID!, quantity: 1 }],
success_url: `${process.env.NEXT_PUBLIC_URL}/booking/success?session