STRIPE_SHOP - BevvyTech/BrewskiDocs GitHub Wiki

STRIPE_SHOP.md

Here’s a full implementation brief in a code-block style, suitable to hand to an LLM or engineer. It describes what to build, how the flows should behave, and which Stripe concepts & APIs to use (you can map to your local Stripe API docs).

## Payment Flow & Order Lifecycle — Implementation Brief

### Objectives

- Use **Stripe Connect** to orchestrate payments, commissions, and payouts.  
- Support a **pre-authorization (manual capture)** model: hold funds when customer places an order, but capture only after merchant acceptance.  
- Deduct a **configurable platform fee** (e.g. 2% + £10) at the time of capture.  
- Maintain order status transitions in our system (e.g. `review` → `accepted` → `paid` / `cancelled`).  
- Use Stripe webhooks to confirm capture or cancellation and update our database reliably.

---

### Key Concepts & Stripe APIs

| Concept | Description / Use |
|---|----------------------|
| **PaymentIntent with manual capture** | Create a `PaymentIntent` with `capture_method = "manual"` so that Stripe authorises (places a hold) but doesn’t immediately take the funds. |
| **application_fee_amount + transfer_data.destination** | Use `application_fee_amount` to specify your platform’s commission, and `transfer_data.destination` to route the remainder to the merchant’s Stripe connected account. |
| **Capture / Cancel** | When merchant accepts: call `stripe.paymentIntents.capture(id)`. When merchant rejects: call `stripe.paymentIntents.cancel(id)`. |
| **Webhooks** | Listen for `payment_intent.succeeded` (capture completed), `payment_intent.canceled` (authorization voided / cancelled). Verify signatures. |
| **Order status transitions** | Map Stripe state changes to your internal order statuses. Use idempotent updates. |

---

### Flow Outline

1. **Order placement (customer action)**
   - Customer submits order.
   - Backend computes commission: `commission = round(order_total * percent_fee + fixed_fee)`.
   - Create a Stripe `PaymentIntent`:
     - `amount = order_total`
     - `currency = …`
     - `capture_method = "manual"`
     - `application_fee_amount = commission`
     - `transfer_data.destination = merchant_stripe_account_id`
     - Add metadata: `order_id`, maybe `merchant_id`.
   - Store in your database:
     - `order.status = "review"`
     - `order.stripe_payment_intent_id = <the id>`

2. **Merchant decision**
   - If merchant **accepts**:
     - Backend calls `stripe.paymentIntents.capture(intent_id)`.
     - Update `order.status = "accepted"`.
   - If merchant **rejects** or order expires:
     - Backend calls `stripe.paymentIntents.cancel(intent_id)`.
     - Update `order.status = "cancelled"`.

3. **Stripe webhooks**
   - Set up webhook endpoints and subscribe to relevant events:
     - `payment_intent.succeeded` → map to `order.status = "paid"`.
     - `payment_intent.canceled` → map to `order.status = "cancelled"`.
   - Verify webhook signatures using your Stripe webhook secret.
   - Handle idempotency (don’t double-apply status changes).

4. **Configuration & dynamic fees**
   - Store `percent_fee` and `fixed_fee` in config or a table, so you can change them without code changes.
   - Always compute commission at the moment you create the PaymentIntent.

---

### Status Transitions (simplified)

pending / draft → review (when order placed, before capture) review → accepted → trigger capture → Stripe → on success → paid review → cancelled (if merchant rejects or timeouts) → cancel intent


Stripe may automatically cancel uncaptured PaymentIntents after 7 days (or card-specific hold expiry) — typical behaviour in Stripe’s manual capture model.  
(Stripe docs: *“you can place a hold … later capture”* for eligible payment methods) :contentReference[oaicite:0]{index=0}

---

### Implementation Checklist for LLM / Engineer

- Initialize Stripe SDK with API version pinned (e.g. “2024-09-30” or your version).  
- Build function to **create PaymentIntent** with `capture_method = "manual"`, `application_fee_amount`, and `transfer_data.destination`.  
- Build **capture** and **cancel** functions calling Stripe’s API.  
- Store / update order statuses in your database according to outcomes.  
- Build webhook listener to handle `payment_intent.succeeded` and `payment_intent.canceled`.  
- Validate webhook signatures.  
- Ensure idempotency and safe error handling.  
- Expose merchant action triggers (accept / reject) to call the capture / cancel logic.  
- Allow commission parameters to be loaded dynamically.  
- Use Stripe test mode to test end-to-end: auth, capture, cancel, webhooks.

---

### Notes / Refs for Offline Use

- Stripe supports **manual capture** flows (authorisation then capture) via `capture_method = "manual"`. :contentReference[oaicite:1]{index=1}  
- The “Capture a charge” API (for older Charge objects) shows concept of capturing a previously authorised charge. :contentReference[oaicite:2]{index=2}  
- Stripe automatically expires/voids authorizations you never capture after a time window. :contentReference[oaicite:3]{index=3}  

---  

This brief gives a self-contained specification of what needs to be implemented (without prescribing your internal API design). Use it to guide your LLM / engineer to build the correct pre-authorization + capture + commission split flow with Stripe Connect.  
⚠️ **GitHub.com Fallback** ⚠️