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

# Complete Integration Examples

> Full working code for the three Payviox setups: backend-created session handed to the SDK (recommended), SDK on its own, and REST API on its own. Includes webhook handlers in JS, PHP, and Python

## Complete Integration Examples

Three complete setups. Option 1 is the [recommended integration](/quickstart/integration-methods) — use it if you have a backend.

## Option 1: Backend session + SDK — Recommended

Your server creates the session (amount computed from your own data, `ip` passed for fraud prevention), the browser only receives a session ID.

```javascript server.js — Express theme={null}
app.post('/api/checkout', async (req, res) => {
  const cart = await getCart(req.user.id); // amount comes from YOUR data, not the browser

  const response = await fetch('https://api.payviox.com/session', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.PAYVIOX_SECRET_KEY}`, // sk_
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      amount: cart.totalCents,
      currency: 'USD',
      customer: req.user.email,
      description: `Order #${cart.id}`,
      order_id: `order_${cart.id}`,
      ip: req.ip, // fraud prevention — requires the secret key
      items: cart.items.map((i) => ({ name: i.name, quantity: i.qty, price: i.priceCents })),
    }),
  });

  if (!response.ok) return res.status(502).json({ error: 'Unable to start payment' });

  const { session_id } = await response.json();
  res.json({ session_id });
});
```

```html checkout.html theme={null}
<button onclick="initiatePayment()">Pay Now</button>

<script src="https://sdk.payviox.com/payviox.js"></script>
<script>
  const payviox = new Payviox('pk_live_your_key'); // public key — safe in the browser

  async function initiatePayment() {
    try {
      const res = await fetch('/api/checkout', { method: 'POST' });
      if (!res.ok) throw new Error('Payment could not be started');

      const { session_id } = await res.json();
      payviox.openSession(session_id); // SDK takes the customer to the payment page
    } catch (error) {
      alert('Payment failed: ' + error.message);
    }
  }
</script>
```

<Check>
  The amount never travels through the browser, so it can't be tampered with — and you still get the SDK's redirect handling.
</Check>

## Option 2: SDK only (no backend)

The SDK creates the session itself with your public key. Best for static sites, prototypes, and evaluating Payviox.

Full HTML page with SDK integration:

```html theme={null}
<!DOCTYPE html>
<html>
<head>
  <title>Payviox Payment</title>
</head>
<body>
  <h1>Complete your purchase</h1>
  <p>Total: $10.00</p>
  <button onclick="initiatePayment()">Pay Now</button>

  <script src="https://sdk.payviox.com/payviox.js"></script>
  <script>
    const payviox = new Payviox('your_api_token');

    async function initiatePayment() {
      try {
        await payviox.createSession({
          amount: 1000,
          currency: 'USD',
          customer: 'customer_123',
          description: 'Premium Subscription',
          paymentMethodId: 'stripe_credit',
          order_id: 'order_' + Date.now(),
          items: [{
            name: 'Premium Subscription',
            quantity: 1,
            price: 1000
          }]
        }, {
          redirect: true // Automatically redirect
        });
      } catch (error) {
        alert('Payment failed: ' + error.message);
      }
    }
  </script>
</body>
</html>
```

<Check>
  When you click "Pay Now", the SDK automatically creates a session and redirects to the secure payment page.
</Check>

<Warning>
  Here the amount originates in the browser and can be modified by the customer. Always verify `amount` and `order_id` in your [webhook handler](/webhooks/integration) before fulfilling the order — or use Option 1.
</Warning>

## Option 3: REST API only (no browser)

For backend services, mobile app backends, non-JavaScript stacks, and payment links sent by email.

```bash theme={null}
curl -X POST https://api.payviox.com/session \
  -H "Authorization: Bearer your_api_token" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 1000,
    "currency": "USD",
    "customer": "customer_123",
    "description": "Premium Subscription",
    "order_id": "order_12345",
    "items": [{
      "name": "Premium Subscription",
      "quantity": 1,
      "price": 1000
    }]
  }'
```

The response contains a `session_id`. Build the payment page URL from it and send the customer there — an HTTP redirect, a link in an email, wherever your product reaches them:

```
https://secure.payviox.com/{session_id}
```

<Tip>
  Passing an optional `paymentMethodId` sends the customer straight to that provider instead of the Payviox payment page. For redirect-based providers the response then contains a `redirect_url` — use it instead of building the URL above. See [POST /session](/api/endpoints/create-session).
</Tip>

## Webhook Handler Examples

All three setups require a webhook handler on your server — it's what confirms the payment.

<CodeGroup>
  ```php PHP theme={null}
  <?php
  // Receive webhook notification
  $payload = file_get_contents('php://input');
  $signature = $_SERVER['HTTP_SIGNATURE'];

  // Verify signature
  $computed = hash_hmac('sha256', $payload, 'your_webhook_token');
  if (!hash_equals($computed, $signature)) {
      http_response_code(401);
      exit('Invalid signature');
  }

  // Parse webhook data
  $data = json_decode($payload, true);

  // Handle successful payment
  if ($data['type'] === 'succeeded') {
      // Fulfill the order
      fulfillOrder($data['order_id']);
      
      // Send confirmation email
      sendConfirmationEmail($data);
  }

  // Return 200 OK
  http_response_code(200);
  echo json_encode(['status' => 'success']);
  ```

  ```javascript Node.js theme={null}
  const express = require('express');
  const crypto = require('crypto');

  const app = express();

  app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
    const payload = req.body.toString('utf8');
    const signature = req.headers['signature'];
    
    // Verify signature
    const computed = crypto
      .createHmac('sha256', process.env.WEBHOOK_TOKEN)
      .update(payload)
      .digest('hex');
    
    if (computed !== signature) {
      return res.status(401).json({ error: 'Invalid signature' });
    }
    
    // Parse webhook data
    const data = JSON.parse(payload);
    
    // Handle successful payment
    if (data.type === 'succeeded') {
      fulfillOrder(data.order_id);
      sendConfirmationEmail(data);
    }
    
    res.json({ status: 'success' });
  });

  app.listen(3000);
  ```

  ```python Python theme={null}
  from flask import Flask, request, jsonify
  import hmac
  import hashlib
  import json

  app = Flask(__name__)

  @app.route('/webhook', methods=['POST'])
  def webhook():
      payload = request.get_data(as_text=True)
      signature = request.headers.get('Signature')
      
      # Verify signature
      computed = hmac.new(
          webhook_token.encode('utf-8'),
          payload.encode('utf-8'),
          hashlib.sha256
      ).hexdigest()
      
      if not hmac.compare_digest(computed, signature):
          return jsonify({'error': 'Invalid signature'}), 401
      
      # Parse webhook data
      data = json.loads(payload)
      
      # Handle successful payment
      if data['type'] == 'succeeded':
          fulfill_order(data['order_id'])
          send_confirmation_email(data)
      
      return jsonify({'status': 'success'})

  if __name__ == '__main__':
      app.run(port=3000)
  ```
</CodeGroup>

## Testing Your Integration

<Steps>
  <Step title="Use test credentials">
    Use your test API token to avoid real charges:

    ```javascript theme={null}
    const payviox = new Payviox('pk_test_xxxxxxxxxxxxx');
    ```
  </Step>

  <Step title="Test card numbers">
    Use these test card numbers in the payment form:

    * `4242 4242 4242 4242` - Successful payment
    * `4000 0000 0000 0002` - Card declined
    * `4000 0000 0000 0341` - Insufficient funds
  </Step>

  <Step title="Test webhooks locally">
    Use [ngrok](https://ngrok.com) to expose your local server:

    ```bash theme={null}
    ngrok http 3000
    ```

    Then configure the ngrok URL as your webhook URL.
  </Step>

  <Step title="Monitor in dashboard">
    View all test transactions in your [dashboard](https://dash.payviox.com/payments).
  </Step>
</Steps>

## Next Steps

<CardGroup cols={2}>
  <Card title="SDK Documentation" icon="code" href="/sdk/introduction">
    Learn more about the SDK
  </Card>

  <Card title="API Documentation" icon="server" href="/api/introduction">
    Explore the REST API
  </Card>

  <Card title="Webhook Guide" icon="webhook" href="/webhooks/integration">
    Complete webhook documentation
  </Card>

  <Card title="Best Practices" icon="shield-check" href="/quickstart/best-practices">
    Security and best practices
  </Card>
</CardGroup>
