> ## Documentation Index
> Fetch the complete documentation index at: https://twigz.arqqin.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Payment Integration

> Complete guide to integrating Stripe payments

# Payment Integration

This guide covers integrating Stripe payments into your Twigz application.

## Setup

### 1. Install Stripe SDK

```bash theme={null}
npm install @stripe/stripe-js
```

### 2. Initialize Stripe

```typescript theme={null}
import { loadStripe } from '@stripe/stripe-js';

const stripePromise = loadStripe('pk_test_your_publishable_key');
```

## Payment Flow

### 1. Create Payment Intent

```typescript theme={null}
// Create payment intent on backend
const paymentIntent = await convex.mutation(api.customers.payments.createPaymentIntent, {
  amount: 5000, // Amount in cents (50.00 AED)
  currency: "AED",
  customerId: "user_123",
  metadata: {
    orderId: "order_456",
    storeId: "store_789"
  }
});
```

### 2. Confirm Payment

```typescript theme={null}
// Confirm payment on frontend
const stripe = await stripePromise;
const { error } = await stripe.confirmPayment({
  clientSecret: paymentIntent.clientSecret,
  elements,
  confirmParams: {
    return_url: "https://yourapp.com/checkout/success"
  }
});
```

### 3. Handle Payment Status

```typescript theme={null}
// Check payment status
const status = await convex.query(api.customers.payments.getPaymentIntentStatus, {
  paymentIntentId: paymentIntent.id
});

if (status === "succeeded") {
  // Payment successful, proceed with order
} else if (status === "requires_payment_method") {
  // Payment failed, show error
}
```

## Payment Methods

### Card Payments

```typescript theme={null}
// Use Stripe Elements for card input
const elements = stripe.elements({
  clientSecret: paymentIntent.clientSecret
});

const cardElement = elements.create('card');
cardElement.mount('#card-element');
```

### Apple Pay / Google Pay

```typescript theme={null}
// Enable Apple Pay and Google Pay
const paymentRequest = stripe.paymentRequest({
  country: 'AE',
  currency: 'aed',
  total: {
    label: 'Total',
    amount: 5000,
  },
});

const prButton = elements.create('paymentRequestButton', {
  paymentRequest,
});
```

## Webhook Handling

### Stripe Webhook Endpoint

```typescript theme={null}
// Handle Stripe webhooks
app.post('/stripe/webhook', express.raw({type: 'application/json'}), async (req, res) => {
  const sig = req.headers['stripe-signature'];
  const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;

  try {
    const event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
    
    switch (event.type) {
      case 'payment_intent.succeeded':
        // Handle successful payment
        break;
      case 'payment_intent.payment_failed':
        // Handle failed payment
        break;
    }
    
    res.json({received: true});
  } catch (err) {
    console.error('Webhook error:', err.message);
    res.status(400).send(`Webhook Error: ${err.message}`);
  }
});
```

## Marketplace Fees

### Calculate Platform Commission

```typescript theme={null}
// Calculate platform commission
const commission = await convex.query(api.customers.checkoutHelpers.calculatePlatformCommission, {
  amount: 5000,
  categoryId: "food",
  storeId: "store_123"
});

console.log(`Platform commission: ${commission.commissionAmount} AED`);
console.log(`Store receives: ${commission.storeAmount} AED`);
```

## Error Handling

### Common Payment Errors

```typescript theme={null}
const handlePaymentError = (error) => {
  switch (error.code) {
    case 'card_declined':
      return 'Your card was declined. Please try a different payment method.';
    case 'insufficient_funds':
      return 'Insufficient funds. Please try a different card.';
    case 'expired_card':
      return 'Your card has expired. Please update your payment method.';
    default:
      return 'Payment failed. Please try again.';
  }
};
```

## Testing

### Test Cards

```typescript theme={null}
// Use Stripe test cards
const testCards = {
  success: '4242424242424242',
  declined: '4000000000000002',
  insufficient_funds: '4000000000009995',
  expired: '4000000000000069'
};
```

### Test Webhooks

```bash theme={null}
# Install Stripe CLI
stripe listen --forward-to localhost:3000/stripe/webhook
```

## Best Practices

1. **Always validate** payment amounts on the backend
2. **Use webhooks** for reliable payment status updates
3. **Handle errors gracefully** with user-friendly messages
4. **Test thoroughly** with Stripe test cards
5. **Secure your keys** - never expose secret keys in frontend code

<Note>
  Always use Stripe's test mode during development and switch to live mode only when ready for production.
</Note>
