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

# Quick Start

> Create your first payment intent and process a payment in 5 minutes

# Quick Start: Your First Payment

This guide walks you through creating a complete payment flow from merchant registration to payment completion. You'll learn how to use Payment Intents to create a secure, hosted checkout experience for your customers.

<Info>
  **What You'll Build:**
  A payment flow where your customer is redirected to a secure checkout page, completes payment, and is redirected back to your site.
</Info>

***

## Overview: Payment Intent Flow

```mermaid theme={null}
sequenceDiagram
    participant You as Your Server
    participant API as Payment Gateway API
    participant Customer as Customer Browser
    participant Checkout as Checkout Page
    
    Note over You,Checkout: Step 1-2: Setup
    You->>API: 1. Register & Get API Key
    API-->>You: {access_token, api_key}
    
    Note over You,Checkout: Step 3: Create Payment Intent
    You->>API: 2. POST /payment-intents<br/>{amount, currency, urls}
    API-->>You: {id, client_secret, checkout_url}
    
    Note over You,Checkout: Step 4: Customer Checkout
    You->>Customer: 3. Redirect to checkout_url
    Customer->>Checkout: 4. Opens checkout page
    Customer->>Checkout: 5. Enters card details
    Checkout->>API: 6. Confirm payment
    API-->>Checkout: {status: "authorized"}
    Checkout->>You: 7. Redirect to success_url
    
    Note over You,Checkout: Step 5: Webhook (Async)
    API->>You: 8. POST webhook_url<br/>{event: "payment.authorized"}
```

***

## Prerequisites

Before you start, you'll need:

<CardGroup cols={2}>
  <Card title="API Endpoint" icon="globe">
    ```
    https://paymentgateway.redahaloubi.com
    ```
  </Card>

  <Card title="Test Card" icon="credit-card">
    ```
    4242 4242 4242 4242
    Exp: 12/2027
    CVV: 123
    ```
  </Card>
</CardGroup>

<Warning>
  **Production Environment:**
  This guide uses the live production API. All payments are simulated (no real money is charged), but use test cards only.
</Warning>

***

## Step 1: Register Your Account

First, create a user account to access the platform.

### Register User

```bash theme={null}
curl -X POST https://paymentgateway.redahaloubi.com/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Merchant",
    "email": "john@yourstore.com",
    "password": "SecurePass123!"
  }'
```

<Accordion title="Expected Response (201 Created)">
  ```json theme={null}
  {
    "success": true,
    "data": {
      "user": {
        "id": "{user_id}",
        "name": "John Merchant",
        "email": "john@yourstore.com",
        "email_verified": false,
        "status": "pending_verification",
        "created_at": "2026-01-24T10:00:00Z"
      }
    },
    "message": "Registration successful. Please verify your email."
  }
  ```
</Accordion>

<Accordion title="Common Errors">
  **400 Bad Request** - Email already exists

  ```json theme={null}
  {
    "success": false,
    "error": "email already registered"
  }
  ```

  **400 Bad Request** - Weak password

  ```json theme={null}
  {
    "success": false,
    "error": "password must be at least 8 characters"
  }
  ```
</Accordion>

***

## Step 2: Login & Get Access Token

Login to receive a JWT access token for API authentication.

### Login

```bash theme={null}
curl -X POST https://paymentgateway.redahaloubi.com/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "john@yourstore.com",
    "password": "SecurePass123!"
  }'
```

<Accordion title="Expected Response (200 OK)">
  ```json theme={null}
  {
    "success": true,
    "data": {
      "user": {
        "id": "{user_id}",
        "name": "John Merchant",
        "email": "john@yourstore.com",
        "status": "active"
      },
      "access_token": "{jwt_access_token}",
      "refresh_token": "{jwt_refresh_token}",
      "token_type": "Bearer",
      "expires_in": 86400
    }
  }
  ```
</Accordion>

<Note>
  **Save Your Access Token:**
  Copy the `access_token` value. You'll need it for all subsequent API calls.

  Example: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...`
</Note>

***

## Step 3: Create a Merchant Account

Create a merchant profile to start accepting payments.

### Create Merchant

```bash theme={null}
curl -X POST https://paymentgateway.redahaloubi.com/api/v1/merchants \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {jwt_access_token}" \
  -d '{
    "business_name": "Your Store Inc",
    "email": "billing@yourstore.com",
    "business_type": "corporation",
    "website": "https://yourstore.com"
  }'
```

<Accordion title="Expected Response (201 Created)">
  ```json theme={null}
  {
    "success": true,
    "data": {
      "merchant": {
        "id": "{merchant_id}",
        "merchant_code": "mch_abc123def456",
        "business_name": "Your Store Inc",
        "email": "billing@yourstore.com",
        "status": "pending_review",
        "owner_id": "{user_id}",
        "created_at": "2026-01-24T10:05:00Z"
      }
    },
    "message": "Merchant created successfully"
  }
  ```
</Accordion>

<Note>
  **Save Your Merchant ID:**
  Copy the `id` value from the response. You'll need it to generate API keys.

  Example: `550e8400-e29b-41d4-a716-446655440000`
</Note>

***

## Step 4: Generate API Key

Create an API key to authenticate payment requests from your server.

### Create API Key

```bash theme={null}
curl -X POST https://paymentgateway.redahaloubi.com/api/v1/merchants/api-keys \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {jwt_access_token}" \
  -d '{
    "merchant_id": "{merchant_id}",
    "name": "Production API Key"
  }'
```

<Accordion title="Expected Response (201 Created)">
  ```json theme={null}
  {
    "success": true,
    "data": {
      "api_key": {
        "id": "{api_key_id}",
        "name": "Production API Key",
        "key_prefix": "pk_live_",
        "created_at": "2026-01-24T10:10:00Z"
      },
      "plain_key": "pk_live_abc123def456ghi789jkl012mno345pqr678stu901vwx234yz"
    },
    "message": "⚠️ Save this API key! It won't be shown again."
  }
  ```
</Accordion>

<Warning>
  **IMPORTANT: Save Your API Key!**

  The `plain_key` is only shown once. Store it securely in your environment variables.

  Example:

  ```bash theme={null}
  export PAYMENT_GATEWAY_API_KEY="pk_live_abc123def456..."
  ```

  If you lose it, you'll need to generate a new key.
</Warning>

***

## Step 5: Create a Payment Intent

Now you're ready to create your first payment! A Payment Intent represents a customer's payment session.

### Create Payment Intent

```bash theme={null}
curl -X POST https://paymentgateway.redahaloubi.com/api/v1/payment-intents \
  -H "Content-Type: application/json" \
  -H "X-API-Key: {your_api_key}" \
  -d '{
    "merchant_id": "{merchant_id}",
    "amount": 9999,
    "currency": "USD",
    "success_url": "https://yourstore.com/order/success?session_id={CHECKOUT_SESSION_ID}",
    "cancel_url": "https://yourstore.com/order/cancel",
    "description": "Order #12345 - Premium Plan",
    "metadata": {
      "order_id": "12345",
      "customer_id": "cus_abc123"
    }
  }'
```

<Accordion title="Expected Response (201 Created)">
  ```json theme={null}
  {
    "success": true,
    "data": {
      "id": "pi_abc123def456ghi789",
      "client_secret": "pi_abc123def456ghi789_secret_xyz789uvw456rst123",
      "checkout_url": "https://checkout-page-amber.vercel.app/checkout/pi_abc123def456ghi789?client_secret=pi_abc123def456ghi789_secret_xyz789uvw456rst123",
      "amount": 9999,
      "currency": "USD",
      "status": "created",
      "success_url": "https://yourstore.com/order/success",
      "cancel_url": "https://yourstore.com/order/cancel",
      "description": "Order #12345 - Premium Plan",
      "expires_at": "2026-01-24T11:10:00Z",
      "created_at": "2026-01-24T10:10:00Z"
    }
  }
  ```
</Accordion>

### Understanding the Response

<Steps>
  <Step title="Payment Intent ID">
    `id`: Unique identifier for this payment session

    Use this to check payment status or cancel the intent.
  </Step>

  <Step title="Client Secret">
    `client_secret`: Browser-safe authentication token

    Include this in the checkout URL to authenticate the customer's session securely.
  </Step>

  <Step title="Checkout URL">
    `checkout_url`: Ready-to-use checkout page URL

    Pre-built URL with payment intent ID and client secret included. Simply redirect your customer to this URL.
  </Step>

  <Step title="Expiration">
    `expires_at`: Automatic expiration timestamp (1 hour)

    Payment intents expire automatically for security. Customer must complete payment before this time.
  </Step>
</Steps>

***

## Step 6: Redirect Customer to Checkout

The payment intent response includes a ready-to-use `checkout_url`. Simply redirect your customer to this URL.

### Option 1: Use the checkout\_url (Recommended)

The response includes a pre-built checkout URL with all required parameters:

```javascript theme={null}
// From the payment intent response
const checkoutUrl = paymentIntent.checkout_url;
// Example: https://checkout-page-amber.vercel.app/checkout/pi_abc123def456?client_secret=pi_abc123_secret_xyz789
```

### Option 2: Build the URL manually

```bash theme={null}
# Base URL
CHECKOUT_URL="https://checkout-page-amber.vercel.app/checkout"

# Add payment intent ID and client secret
FULL_URL="${CHECKOUT_URL}/{payment_intent_id}?client_secret={client_secret}"

# Example:
https://checkout-page-amber.vercel.app/checkout/pi_abc123def456ghi789?client_secret=pi_abc123def456ghi789_secret_xyz789uvw456rst123
```

### Implementation Examples

<Tabs>
  <Tab title="HTML (Redirect)">
    ```html theme={null}
    <!-- On your order confirmation page -->
    <script>
      // Use the checkout_url from payment intent response
      const checkoutUrl = "https://checkout-page-amber.vercel.app/checkout/pi_abc123def456?client_secret=pi_abc123_secret_xyz789";
      window.location.href = checkoutUrl;
    </script>
    ```
  </Tab>

  <Tab title="HTML (Button)">
    ```html theme={null}
    <a href="https://checkout-page-amber.vercel.app/checkout/pi_abc123def456?client_secret=pi_abc123_secret_xyz789" 
       class="btn btn-primary">
      Complete Payment
    </a>
    ```
  </Tab>

  <Tab title="Node.js/Express">
    ```javascript theme={null}
    // After creating payment intent, use the checkout_url
    res.redirect(paymentIntent.checkout_url);

    // Or build manually:
    // const checkoutUrl = `https://checkout-page-amber.vercel.app/checkout/${paymentIntent.id}?client_secret=${paymentIntent.client_secret}`;
    // res.redirect(checkoutUrl);
    ```
  </Tab>

  <Tab title="Python/Flask">
    ```python theme={null}
    from flask import redirect

    # After creating payment intent, use the checkout_url
    return redirect(payment_intent['checkout_url'])

    # Or build manually:
    # checkout_url = f"https://checkout-page-amber.vercel.app/checkout/{payment_intent['id']}?client_secret={payment_intent['client_secret']}"
    # return redirect(checkout_url)
    ```
  </Tab>
</Tabs>

***

## Step 7: Customer Completes Payment

Your customer will see a secure checkout page where they can enter their card details.

<Frame>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/redahl/images/checkout-example.png" alt="Checkout Page" />
</Frame>

### What Happens on the Checkout Page

<Steps>
  <Step title="Payment Intent Validation">
    The checkout page validates the `client_secret` to ensure the session is valid and not expired.
  </Step>

  <Step title="Customer Enters Card Details">
    Customer enters:

    * Card number (e.g., 4242 4242 4242 4242)
    * Cardholder name
    * Expiry date (MM/YY)
    * CVV (3 digits)

    All validation happens client-side first (Luhn algorithm, expiry checks).
  </Step>

  <Step title="Payment Processing">
    When customer clicks "Pay \$99.99":

    1. Card data sent to Payment API (secured by client\_secret)
    2. Card tokenized (never stored in plain text)
    3. Transaction authorized or declined
    4. Payment intent status updated
  </Step>

  <Step title="Automatic Redirect">
    Based on payment result:

    * ✅ **Success**: Redirects to `success_url` with payment intent ID
    * ❌ **Declined**: Shows error, allows retry (max 5 attempts)
    * ⏱️ **Expired**: Redirects to `cancel_url`
  </Step>
</Steps>

### Test Cards for Development

<CardGroup cols={2}>
  <Card title="✅ Successful Payment" icon="circle-check">
    **Card Number:** 4242 4242 4242 4242

    **Expiry:** Any future date (e.g., 12/2027)

    **CVV:** Any 3 digits (e.g., 123)

    **Result:** Authorization approved
  </Card>

  <Card title="❌ Declined - Insufficient Funds" icon="circle-xmark">
    **Card Number:** 4000 0000 0000 9995

    **Expiry:** Any future date

    **CVV:** Any 3 digits

    **Result:** Declined with code 51
  </Card>

  <Card title="❌ Declined - Expired Card" icon="clock">
    **Card Number:** 4000 0000 0000 0069

    **Expiry:** Any future date

    **CVV:** Any 3 digits

    **Result:** Declined with code 54
  </Card>

  <Card title="❌ Declined - CVV Mismatch" icon="hashtag">
    **Card Number:** 4000 0000 0000 0127

    **Expiry:** Any future date

    **CVV:** Any 3 digits

    **Result:** Declined with code N7
  </Card>
</CardGroup>

<Info>
  **All test cards:**

  * Use any future expiry date (e.g., 12/2027)
  * Use any cardholder name
  * For Mastercard, use: 5555 5555 5555 4444 (approved)
</Info>

***

## Step 8: Handle Success Redirect

After successful payment, the customer is redirected back to your `success_url`.

### Success URL Parameters

```
https://yourstore.com/order/success?session_id=pi_abc123def456ghi789&payment_intent=pi_abc123def456ghi789
```

<ParamField path="payment_intent" type="string" required>
  The payment intent ID that was just completed
</ParamField>

<ParamField path="session_id" type="string">
  Same as payment\_intent (included if you used `{CHECKOUT_SESSION_ID}` placeholder)
</ParamField>

### Verify Payment Status

Always verify the payment status on your server (don't trust client-side redirects alone).

```bash theme={null}
curl -X GET https://paymentgateway.redahaloubi.com/api/v1/payment-intents/{payment_intent_id} \
  -H "X-API-Key: {your_api_key}"
```

<Accordion title="Expected Response (200 OK)">
  ```json theme={null}
  {
    "success": true,
    "data": {
      "id": "pi_abc123def456ghi789",
      "status": "authorized",
      "payment_id": "pay_xyz123abc456",
      "amount": 9999,
      "currency": "USD",
      "card_brand": "visa",
      "card_last4": "4242",
      "auth_code": "123456",
      "created_at": "2026-01-24T10:10:00Z",
      "confirmed_at": "2026-01-24T10:15:23Z"
    }
  }
  ```
</Accordion>

### Implementation Example

<CodeGroup>
  ```javascript Node.js/Express theme={null}
  app.get('/order/success', async (req, res) => {
    const paymentIntentId = req.query.payment_intent;
    
    // Verify payment status server-side
    const response = await fetch(
      `https://paymentgateway.redahaloubi.com/api/v1/payment-intents/${paymentIntentId}`,
      {
        headers: {
          'X-API-Key': process.env.PAYMENT_GATEWAY_API_KEY
        }
      }
    );
    
    const data = await response.json();
    
    if (data.data.status === 'authorized' || data.data.status === 'captured') {
      // Payment successful - fulfill order
      await fulfillOrder(data.data.payment_id);
      res.render('order-success', { payment: data.data });
    } else {
      // Payment not completed
      res.redirect('/order/cancel');
    }
  });
  ```

  ```python Python/Flask theme={null}
  @app.route('/order/success')
  def order_success():
      payment_intent_id = request.args.get('payment_intent')
      
      # Verify payment status server-side
      response = requests.get(
          f'https://paymentgateway.redahaloubi.com/api/v1/payment-intents/{payment_intent_id}',
          headers={'X-API-Key': os.environ['PAYMENT_GATEWAY_API_KEY']}
      )
      
      data = response.json()
      
      if data['data']['status'] in ['authorized', 'captured']:
          # Payment successful - fulfill order
          fulfill_order(data['data']['payment_id'])
          return render_template('order-success.html', payment=data['data'])
      else:
          # Payment not completed
          return redirect('/order/cancel')
  ```

  ```php PHP theme={null}
  <?php
  $paymentIntentId = $_GET['payment_intent'];

  // Verify payment status server-side
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, "https://paymentgateway.redahaloubi.com/api/v1/payment-intents/{$paymentIntentId}");
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
      'X-API-Key: ' . getenv('PAYMENT_GATEWAY_API_KEY')
  ]);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  $response = curl_exec($ch);
  $data = json_decode($response, true);

  if ($data['data']['status'] === 'authorized' || $data['data']['status'] === 'captured') {
      // Payment successful - fulfill order
      fulfillOrder($data['data']['payment_id']);
      include 'order-success.php';
  } else {
      // Payment not completed
      header('Location: /order/cancel');
  }
  ?>
  ```
</CodeGroup>

***

## Step 9: Receive Webhook Notifications (Optional)

For asynchronous payment confirmation, configure webhooks to receive real-time updates.

### Configure Webhook URL

First, set your webhook URL in merchant settings:

```bash theme={null}
curl -X PATCH https://paymentgateway.redahaloubi.com/api/v1/merchants/{merchant_id}/settings \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {jwt_access_token}" \
  -d '{
    "webhook_url": "https://yourstore.com/webhooks/payment",
    "webhook_secret": "{your_webhook_secret}"
  }'
```

### Webhook Payload

When payment status changes, you'll receive a POST request:

```json theme={null}
{
  "event": "payment.authorized",
  "timestamp": "2026-01-24T10:15:23Z",
  "id": "evt_abc123def456",
  "data": {
    "payment_intent_id": "pi_abc123def456ghi789",
    "payment_id": "pay_xyz123abc456",
    "merchant_id": "{merchant_id}",
    "status": "authorized",
    "amount": 9999,
    "currency": "USD",
    "card_brand": "visa",
    "card_last4": "4242",
    "auth_code": "123456",
    "created_at": "2026-01-24T10:15:23Z"
  }
}
```

### Verify Webhook Signature

<Warning>
  Always verify webhook signatures to ensure requests are from Payment Gateway.
</Warning>

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

  app.post('/webhooks/payment', (req, res) => {
    const signature = req.headers['x-webhook-signature'];
    const payload = JSON.stringify(req.body);
    
    // Compute expected signature
    const expected = crypto
      .createHmac('sha256', process.env.WEBHOOK_SECRET)
      .update(payload)
      .digest('hex');
    
    if (signature !== expected) {
      return res.status(401).send('Invalid signature');
    }
    
    // Process webhook
    const event = req.body;
    if (event.event === 'payment.authorized') {
      fulfillOrder(event.data.payment_id);
    }
    
    res.status(200).send('OK');
  });
  ```

  ```python Python theme={null}
  import hmac
  import hashlib

  @app.route('/webhooks/payment', methods=['POST'])
  def webhook():
      signature = request.headers.get('X-Webhook-Signature')
      payload = request.get_data(as_text=True)
      
      # Compute expected signature
      expected = hmac.new(
          os.environ['WEBHOOK_SECRET'].encode(),
          payload.encode(),
          hashlib.sha256
      ).hexdigest()
      
      if signature != expected:
          return 'Invalid signature', 401
      
      # Process webhook
      event = request.json
      if event['event'] == 'payment.authorized':
          fulfill_order(event['data']['payment_id'])
      
      return 'OK', 200
  ```
</CodeGroup>

***

## 🎉 Congratulations!

You've successfully:

<Steps>
  <Step title="✅ Registered an account">
    Created user credentials and logged in
  </Step>

  <Step title="✅ Created a merchant">
    Set up your business profile
  </Step>

  <Step title="✅ Generated API key">
    Obtained credentials for payment processing
  </Step>

  <Step title="✅ Created payment intent">
    Initiated a customer payment session
  </Step>

  <Step title="✅ Processed payment">
    Customer completed payment on hosted checkout
  </Step>

  <Step title="✅ Verified payment">
    Confirmed payment status on your server
  </Step>
</Steps>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Auth API Reference" icon="key" href="/api/auth">
    Explore user management, roles, and API keys
  </Card>

  <Card title="Merchant API Reference" icon="store" href="/api/merchant-api">
    Manage teams, settings, and webhooks
  </Card>

  <Card title="Payment API Reference" icon="credit-card" href="/api/payment-api">
    Learn about capture, void, refund operations
  </Card>

  <Card title="Checkout Integration" icon="browser" href="/integrations/checkout">
    Customize the checkout experience
  </Card>
</CardGroup>

***

## Common Issues

<AccordionGroup>
  <Accordion title="401 Unauthorized - Invalid API Key">
    **Cause:** API key is incorrect or expired

    **Solution:**

    * Verify you're using the correct API key (starts with `pk_live_` or `pk_test_`)
    * Check the key hasn't been deactivated
    * Generate a new API key if needed
  </Accordion>

  <Accordion title="400 Bad Request - Invalid Amount">
    **Cause:** Amount must be in cents (integer)

    **Solution:**

    * ❌ Wrong: `"amount": 99.99`
    * ✅ Correct: `"amount": 9999` (represents \$99.99)
  </Accordion>

  <Accordion title="403 Forbidden - Client Secret Invalid">
    **Cause:** Client secret doesn't match payment intent

    **Solution:**

    * Ensure you're using the correct `client_secret` from the payment intent response
    * Check the payment intent hasn't expired (1 hour limit)
    * Verify the payment intent ID in the URL matches the client secret
  </Accordion>

  <Accordion title="422 Unprocessable Entity - Payment Already Completed">
    **Cause:** Trying to confirm a payment intent that's already authorized

    **Solution:**

    * Check payment intent status first: `GET /payment-intents/:id`
    * If status is `authorized`, payment is already complete
    * Create a new payment intent for a new payment
  </Accordion>

  <Accordion title="Payment Declined">
    **Cause:** Test card triggered a decline scenario

    **Solution:**

    * Use approved test card: 4242 4242 4242 4242
    * Check you're using a future expiry date
    * See test cards section for specific decline scenarios
  </Accordion>
</AccordionGroup>

***

## Need Help?

<CardGroup cols={2}>
  <Card title="GitHub Issues" icon="github" href="https://github.com/rhaloubi/Payment-Gateway-Microservices/issues">
    Report bugs or request features
  </Card>

  <Card title="Email Support" icon="envelope" href="mailto:redahaloubi8@gmail.com">
    Contact for technical assistance
  </Card>
</CardGroup>

***

**Ready to integrate?** Head to the [API Reference](/api/auth) to explore all available endpoints!
