> ## 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.

# HTTP Endpoints

> Stripe webhooks, health checks, and configuration endpoints

## Overview

The HTTP Endpoints provide essential web services including Stripe webhook processing for automatic order creation, health monitoring, and configuration retrieval for client applications.

**Location:** `convex/http.ts`

## Stripe Webhook

Handles Stripe webhook events for automatic payment processing and order creation.

<ParamField path="endpoint" type="string">
  `POST /stripe/webhook`
</ParamField>

<ParamField path="stripe-signature" type="string" required>
  Stripe webhook signature header for verification
</ParamField>

### Supported Events

<CardGroup cols={3}>
  <Card title="Payment Succeeded" icon="check-circle">
    **Event**: `payment_intent.succeeded`\
    **Action**: Creates order from cart items
  </Card>

  <Card title="Payment Failed" icon="x-circle">
    **Event**: `payment_intent.payment_failed`\
    **Action**: Logs failure and notifies customer
  </Card>

  <Card title="Payment Canceled" icon="ban">
    **Event**: `payment_intent.canceled`\
    **Action**: Cleans up resources and preserves cart
  </Card>
</CardGroup>

### Webhook Processing Flow

<Steps>
  <Step title="Signature Verification">
    Validates Stripe webhook signature for security
  </Step>

  <Step title="Event Parsing">
    Extracts payment data and metadata from webhook payload
  </Step>

  <Step title="Order Processing">
    Creates orders for successful payments or handles failures
  </Step>

  <Step title="Cart Cleanup">
    Removes items from customer cart after successful order creation
  </Step>

  <Step title="Notifications">
    Sends confirmation notifications to customers and stores
  </Step>
</Steps>

<CodeGroup>
  ```typescript Webhook Handler theme={null}
  // This runs automatically when Stripe sends webhook events
  // Location: convex/http.ts

  export default httpRouter;

  httpRouter.route({
    path: "/stripe/webhook",
    method: "POST",
    handler: async (request: Request) => {
      const signature = request.headers.get("stripe-signature");
      const body = await request.text();

      try {
        // Verify webhook signature
        const event = stripe.webhooks.constructEvent(
          body,
          signature!,
          process.env.STRIPE_WEBHOOK_SECRET!
        );

        switch (event.type) {
          case 'payment_intent.succeeded':
            // Automatic order creation
            const paymentIntent = event.data.object;
            const metadata = paymentIntent.metadata;
            
            // Create order from cart
            await convex.mutation("customers.cartToOrder.createOrderFromCart", {
              customerId: metadata.customerId,
              storeId: metadata.storeId,
              deliveryAddress: JSON.parse(metadata.deliveryAddress),
              deliveryType: metadata.deliveryType,
              deliveryFee: parseFloat(metadata.deliveryFee),
              paymentMethod: "card",
              paymentIntentId: paymentIntent.id,
              paymentStatus: "paid"
            });
            
            break;

          case 'payment_intent.payment_failed':
            // Handle payment failure
            console.error('Payment failed:', event.data.object);
            break;

          case 'payment_intent.canceled':
            // Handle payment cancellation
            console.log('Payment canceled:', event.data.object);
            break;
        }

        return new Response("Webhook processed", { status: 200 });
      } catch (error) {
        console.error('Webhook error:', error);
        return new Response("Webhook failed", { status: 400 });
      }
    }
  });
  ```

  ```bash Webhook Setup theme={null}
  # Configure webhook endpoint in Stripe Dashboard
  # 1. Go to Stripe Dashboard → Webhooks
  # 2. Add endpoint: https://your-domain.convex.cloud/stripe/webhook
  # 3. Select events:
  #    - payment_intent.succeeded
  #    - payment_intent.payment_failed  
  #    - payment_intent.canceled
  # 4. Copy webhook signing secret to environment variables

  # Environment variables required:
  STRIPE_WEBHOOK_SECRET=whsec_1234567890abcdef...
  STRIPE_SECRET_KEY=sk_test_1234567890abcdef...
  ```

  ```curl Test Webhook theme={null}
  # Test webhook locally (Stripe CLI required)
  stripe listen --forward-to localhost:3000/stripe/webhook

  # Trigger test events
  stripe trigger payment_intent.succeeded
  stripe trigger payment_intent.payment_failed
  ```
</CodeGroup>

## Health Check

Simple health check endpoint for monitoring and uptime verification.

<ParamField path="endpoint" type="string">
  `GET /health`
</ParamField>

<CodeGroup>
  ```bash cURL theme={null}
  curl https://your-deployment.convex.cloud/health
  ```

  ```typescript TypeScript theme={null}
  const health = await fetch('https://your-deployment.convex.cloud/health');
  const message = await health.text();
  console.log(message); // "Twigz Backend is healthy!"
  ```

  ```javascript JavaScript theme={null}
  fetch('/health')
    .then(response => response.text())
    .then(message => console.log(message));
  ```

  ```python Python theme={null}
  import requests

  response = requests.get('https://your-deployment.convex.cloud/health')
  print(response.text)  # "Twigz Backend is healthy!"
  ```
</CodeGroup>

<ResponseExample>
  ```text Response theme={null}
  Twigz Backend is healthy!
  ```
</ResponseExample>

## Stripe Configuration

Retrieve Stripe publishable key for client-side integration.

<ParamField path="endpoint" type="string">
  `GET /stripe/config`
</ParamField>

<CodeGroup>
  ```typescript TypeScript theme={null}
  const config = await fetch('https://your-deployment.convex.cloud/stripe/config');
  const { publishableKey } = await config.json();

  // Use with Stripe.js
  import { loadStripe } from '@stripe/stripe-js';
  const stripe = await loadStripe(publishableKey);
  ```

  ```javascript JavaScript theme={null}
  fetch('/stripe/config')
    .then(response => response.json())
    .then(config => {
      console.log('Stripe publishable key:', config.publishableKey);
      // Initialize Stripe with the key
    });
  ```

  ```python Python theme={null}
  import requests

  response = requests.get('https://your-deployment.convex.cloud/stripe/config')
  config = response.json()
  publishable_key = config['publishableKey']
  ```

  ```curl cURL theme={null}
  curl https://your-deployment.convex.cloud/stripe/config
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  {
    "publishableKey": "pk_test_51234567890abcdef..."
  }
  ```
</ResponseExample>

## Webhook Security

<AccordionGroup>
  <Accordion title="Signature Verification">
    All webhooks are verified using Stripe's signature verification:

    ```typescript theme={null}
    const signature = request.headers.get("stripe-signature");
    const event = stripe.webhooks.constructEvent(
      body,
      signature!,
      process.env.STRIPE_WEBHOOK_SECRET!
    );
    ```
  </Accordion>

  <Accordion title="Idempotency">
    Webhook events are processed idempotently to handle retries:

    ```typescript theme={null}
    // Check if order already exists for this payment
    const existingOrder = await convex.query("customers.orders.getOrderByPaymentIntent", {
      paymentIntentId: paymentIntent.id
    });

    if (existingOrder) {
      return new Response("Order already processed", { status: 200 });
    }
    ```
  </Accordion>

  <Accordion title="Error Handling">
    Robust error handling for webhook processing:

    ```typescript theme={null}
    try {
      await processWebhookEvent(event);
      return new Response("Success", { status: 200 });
    } catch (error) {
      console.error('Webhook processing failed:', error);
      // Return 500 to trigger Stripe retry
      return new Response("Processing failed", { status: 500 });
    }
    ```
  </Accordion>
</AccordionGroup>

## Webhook Testing

<CodeGroup>
  ```bash Stripe CLI Setup theme={null}
  # Install Stripe CLI
  # macOS
  brew install stripe/stripe-cli/stripe

  # Login to Stripe
  stripe login

  # Forward webhooks to local development
  stripe listen --forward-to localhost:3000/stripe/webhook

  # In another terminal, trigger test events
  stripe trigger payment_intent.succeeded
  stripe trigger payment_intent.payment_failed
  ```

  ```typescript Local Testing theme={null}
  // Test webhook endpoint locally
  const testWebhook = async () => {
    const testPayload = {
      id: "evt_test_123",
      type: "payment_intent.succeeded",
      data: {
        object: {
          id: "pi_test_123",
          amount: 5000, // $50.00
          currency: "usd",
          status: "succeeded",
          metadata: {
            customerId: "c123456789",
            storeId: "j123456789",
            deliveryType: "delivery",
            deliveryFee: "5.00",
            deliveryAddress: JSON.stringify({
              fullAddress: "123 Test St",
              city: "ct123456789",
              area: "ar123456789",
              phoneNumber: "+971501234567"
            })
          }
        }
      }
    };

    const response = await fetch('/stripe/webhook', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'stripe-signature': 'test_signature'
      },
      body: JSON.stringify(testPayload)
    });

    console.log('Webhook response:', await response.text());
  };
  ```
</CodeGroup>

## Monitoring & Observability

<CardGroup cols={2}>
  <Card title="Health Monitoring" icon="heart-pulse">
    Use the `/health` endpoint for uptime monitoring and load balancer health checks
  </Card>

  <Card title="Webhook Logs" icon="list">
    Monitor webhook processing in Convex logs for debugging payment issues
  </Card>

  <Card title="Error Tracking" icon="bug">
    Failed webhooks are logged with full context for troubleshooting
  </Card>

  <Card title="Performance Metrics" icon="gauge">
    Track webhook processing times and success rates
  </Card>
</CardGroup>

## CORS Configuration

The endpoints include proper CORS headers for web applications:

```typescript theme={null}
// CORS headers included in responses
const headers = {
  'Content-Type': 'application/json',
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type, Authorization, stripe-signature'
};
```

## Error Responses

<AccordionGroup>
  <Accordion title="Invalid webhook signature">
    **Status Code**: `400`

    ```json theme={null}
    {
      "error": "Invalid webhook signature"
    }
    ```
  </Accordion>

  <Accordion title="Unsupported webhook event">
    **Status Code**: `200` (Success, but ignored)

    ```json theme={null}
    {
      "message": "Event type not supported",
      "eventType": "customer.created"
    }
    ```
  </Accordion>

  <Accordion title="Webhook processing failed">
    **Status Code**: `500`

    ```json theme={null}
    {
      "error": "Webhook processing failed",
      "eventId": "evt_123456789"
    }
    ```
  </Accordion>

  <Accordion title="Service unavailable">
    **Status Code**: `503`

    ```json theme={null}
    {
      "error": "Service temporarily unavailable",
      "retryAfter": 30
    }
    ```
  </Accordion>
</AccordionGroup>

<Note>
  Webhook endpoints are automatically secured and include signature verification. Failed webhook processing triggers Stripe's automatic retry mechanism.
</Note>

<Tip>
  Use the Stripe CLI during development to test webhook integration locally. Always verify webhook signatures in production for security.
</Tip>
