Changes

Comparing empty160dc49.

@@ -1,0 +1,77 @@
1+---
2+title: Stripe
3+sort: 1
4+tags: [payments]
5+---
6+
7+# Stripe
8+
9+Stripe is the default payment provider for new tenants. The integration covers:
10+
11+- Card payments via Stripe Payment Intents
12+- Stored payment methods on the customer record
13+- Stripe Tax handoff for jurisdictions where we don't run our own engine
14+- Refunds, partial refunds, and disputes
15+
16+## Set up your Stripe account
17+
18+Two keys, in your tenant's **Settings → Payments → Stripe** page:
19+
20+| Field | Where to find it |
21+|------------------------|----------------------------------------------------------------------|
22+| Publishable key | Stripe Dashboard → Developers → API keys → "Publishable key" |
23+| Secret key | Stripe Dashboard → Developers → API keys → "Secret key" (test or live) |
24+| Webhook signing secret | We register the webhook with Stripe on save and store the secret |
25+
26+When you save, ZephyrCart calls Stripe to register a webhook endpoint at
27+`https://api.zephyrcart.io/v1/internal/stripe/webhook` scoped to your account.
28+
29+## Stripe Tax handoff
30+
31+Inside the EU, ZephyrCart's tax engine handles VAT. In the US sales-tax jurisdictions and a few
32+others, Stripe Tax is the smoother experience. Flip per-tenant:
33+
34+```bash
35+zephyr settings set payments.stripe.use_stripe_tax true
36+```
37+
38+Effect:
39+
40+- Tax is computed on the Stripe side during Payment Intent creation
41+- The order's `tax_calculation_source` is `stripe_tax` (was `zephyr`)
42+- The line-item-level breakdown is preserved verbatim from Stripe
43+
44+## Code sample — TypeScript SDK
45+
46+```typescript
47+import { Zephyr } from "@zephyrcart/sdk";
48+
49+const client = new Zephyr({ apiKey: process.env.ZEPHYR_API_KEY! });
50+
51+const checkout = await client.checkouts.create({
52+ cart: cartId,
53+ payment: {
54+ method: "stripe",
55+ return_url: "https://shop.example.com/return",
56+ },
57+});
58+
59+// checkout.checkout_url is the hosted page; redirect the customer there
60+```
61+
62+## Refund flow
63+
64+A refund triggered through ZephyrCart's API also refunds through Stripe automatically. There is no
65+"refund only in Stripe" mode — refunds must always originate in ZephyrCart so the order record
66+stays the source of truth.
67+
68+```bash
69+curl -sS https://api.zephyrcart.io/v1/orders/order_…/refunds \
70+ -H "Authorization: Bearer $ZEPHYR_API_KEY" \
71+ -d '{ "amount_cents": 1490, "reason": "requested_by_customer" }'
72+```
73+
74+## Disputes
75+
76+When a chargeback is opened in Stripe, we emit `order.disputed`. The order's status is unchanged;
77+the dispute is a sidecar object you query via `GET /v1/orders/{id}/disputes`.