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

# Quick Start Guide

> Get started with the CeyPay API in minutes. This guide walks you through creating your first payment.

<Note>
  This guide walks you through creating your first payment in under 5 minutes.
</Note>

## Prerequisites

<CardGroup cols={3}>
  <Card title="Merchant Account" icon="user-check">
    A CeyPay merchant account ([sign up here](https://merchant.ceypay.io))
  </Card>

  <Card title="KYC Verification" icon="id-card">
    Completed merchant onboarding and KYC verification
  </Card>

  <Card title="Programming Language" icon="code">
    Your preferred programming language (Node.js, Python, PHP, etc.)
  </Card>
</CardGroup>

***

## Base URL

<CardGroup cols={1}>
  <Card title="Production" icon="rocket">
    Live environment for real transactions

    ```
    https://api.ceypay.io
    ```
  </Card>

  <Card title="Sandbox" icon="flask">
    Test environment for integration testing

    ```
    https://sandbox-api.ceypay.io
    ```
  </Card>
</CardGroup>

<Note>
  **Getting Started**

  If you want to integrate CeyPay without signing up for a sandbox account, use the sandbox API key below.

  **Sandbox API Key:**

  ```
  ak_live_d86855bbd8651fcb5f469203621c88e3.sk_live_6985fca378cd894dee359813bd6bb12f4a2922bc81f023f0d062631e3190ff3e
  ```

  Remember: The `x-api-key` header should contain ONLY the key ID (the part before the dot), NOT the full API key. The secret key is used locally to derive the signing key and is never transmitted.
</Note>

## Get Started

<Steps>
  <Step title="Generate API Key">
    1. Log in to your [CeyPay Dashboard](https://merchant.ceypay.io)
    2. Navigate to **Settings** → **API Keys**
    3. Click **Generate New API Key**
    4. Give it a descriptive name (e.g., "Production API Key")
    5. **Copy the API key immediately** (you'll only see it once!)

    Your API key looks like: `ak_live_abc123xyz.sk_live_def456uvw`

    * `ak_live_abc123xyz` - Public key ID (sent in `x-api-key` header)
    * `sk_live_def456uvw` - Secret key (used locally to derive signing key, NEVER transmitted)

    **Important**: Store your API key securely (environment variable, secrets manager, etc.)
  </Step>

  <Step title="Make Your First API Call">
    ### Create a Payment

    Let's create a simple payment for \$100 USDT:

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

      // Your API key (store in environment variable)
      const API_KEY = process.env.CEYPAY_API_KEY; // e.g., ak_live_xxx.sk_live_yyy
      const [keyId, secret] = API_KEY.split(".");

      // Derive signing key from secret (do this once)
      const signingKey = crypto.createHash("sha256").update(secret).digest("hex");

      // Create payment
      async function createPayment() {
        const timestamp = Date.now().toString();
        const method = "POST";
        const path = "/v1/payment";

        const body = JSON.stringify({
          amount: 100,
          currency: "USDT",
          goods: [
            {
              name: "Premium Plan",
              description: "Monthly subscription to premium features",
            },
          ],
          customerBilling: {
            email: "customer@example.com",
            firstName: "John",
            lastName: "Doe",
          },
        });

        // Generate signature using derived key (NOT raw secret)
        const message = timestamp + method + path + body;
        const signature = crypto
          .createHmac("sha256", signingKey)
          .update(message)
          .digest("hex");

        // Make request - send ONLY key ID, not full API key
        const response = await axios.post(
          `https://api.ceypay.io${path}`,
          JSON.parse(body),
          {
            headers: {
              "Content-Type": "application/json",
              "x-api-key": keyId, // Only the key ID!
              "x-timestamp": timestamp,
              "x-signature": signature,
            },
          },
        );

        console.log("Payment created:", response.data);
        console.log("Checkout link:", response.data.checkoutLink);
        console.log("QR code:", response.data.qrContent);

        return response.data;
      }

      createPayment().catch(console.error);
      ```

      ```python Python theme={null}
      import os
      import hmac
      import hashlib
      import time
      import json
      import requests

      # Your API key (store in environment variable)
      API_KEY = os.getenv('CEYPAY_API_KEY')  # e.g., ak_live_xxx.sk_live_yyy
      key_id, secret = API_KEY.split('.')

      # Derive signing key from secret (do this once)
      signing_key = hashlib.sha256(secret.encode()).hexdigest()

      def create_payment():
          timestamp = str(int(time.time() * 1000))
          method = 'POST'
          path = '/v1/payment'

          body_dict = {
              'amount': 100,
              'currency': 'USDT',
              'goods': [
                  {
                      'name': 'Premium Plan',
                      'description': 'Monthly subscription to premium features'
                  }
              ],
              'customerBilling': {
                  'email': 'customer@example.com',
                  'firstName': 'John',
                  'lastName': 'Doe'
              }
          }
          body = json.dumps(body_dict)

          # Generate signature using derived key (NOT raw secret)
          message = f"{timestamp}{method}{path}{body}"
          signature = hmac.new(
              signing_key.encode(),
              message.encode(),
              hashlib.sha256
          ).hexdigest()

          # Make request - send ONLY key ID, not full API key
          response = requests.post(
              f'https://api.ceypay.io{path}',
              json=body_dict,
              headers={
                  'x-api-key': key_id,  # Only the key ID!
                  'x-timestamp': timestamp,
                  'x-signature': signature
              }
          )

          data = response.json()
          print('Payment created:', data)
          print('Checkout link:', data['checkoutLink'])
          print('QR code:', data['qrContent'])

          return data

      if __name__ == '__main__':
          create_payment()
      ```

      ```bash cURL theme={null}
      #!/bin/bash
      export PATH="/usr/bin:/bin:$PATH"
      # Your API key
      API_KEY="ak_live_d86855bbd8651fcb5f469203621c88e3.sk_live_6985fca378cd894dee359813bd6bb12f4a2922bc81f023f0d062631e3190ff3e"

      # Split into key ID and secret
      KEY_ID="${API_KEY%%.*}"
      SECRET="${API_KEY#*.}"

      # Derive signing key from secret (matches PHP: hash('sha256', $secret))
      SIGNING_KEY=$(echo -n "$SECRET" | sha256sum | cut -d' ' -f1)

      TIMESTAMP=$(date +%s)000
      METHOD="POST"
      API_PATH="/v1/payment"

      BODY='{"amount":12,"currency":"USDT","provider":"BYBIT","goods":[{"name":"Wireless Headphones","description":"Noise-cancelling Bluetooth headphones","mccCode":"5732"}],"webhookUrl":"https://mystore.com/api/payment-webhook","customerBilling":{"email":"customer@example.com","firstName":"John","lastName":"Doe","phone":"+94771234567","address":"123 Main Street"}}'

      MESSAGE="${TIMESTAMP}${METHOD}${API_PATH}${BODY}"
      SIGNATURE=$(echo -n "$MESSAGE" | openssl dgst -sha256 -hmac "$SIGNING_KEY" | cut -d' ' -f2)

      # Send ONLY key ID in header, not full API key
      curl -X POST "https://sandbox-api.ceypay.io${API_PATH}" \
        -H "Content-Type: application/json" \
        -H "x-api-key: $KEY_ID" \
        -H "x-timestamp: $TIMESTAMP" \
        -H "x-signature: $SIGNATURE" \
        -d "$BODY"
      ```
    </CodeGroup>

    ### Response

    ```json theme={null}
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "payId": "bybit_pay_abc123",
      "merchantTradeNo": "TXN-2025-12345",
      "amount": 100,
      "currency": "USDT",
      "status": "INITIATED",
      "qrContent": "bybit://pay?id=abc123",
      "checkoutLink": "https://checkout.bybit.com/pay/abc123",
      "createdAt": "2025-01-15T10:30:00.000Z",
      "feeBreakdown": {
        "exchangeFeePercentage": 1.0,
        "exchangeFeeAmount": 1.0,
        "ceypayFeePercentage": 0.5,
        "ceypayFeeAmount": 0.5,
        "netAmount": 98.5
      }
    }
    ```

    <Tip>
      Save the `id` and `qrContent` from the response. You'll need them to direct customers to payment.
    </Tip>
  </Step>

  <Step title="Direct Customer to Payment">
    You have two options to collect payment:

    <CardGroup cols={1}>
      <Card title="Redirect to Checkout" icon="arrow-up-right-from-square">
        Redirect users to the hosted checkout page:

        ```javascript theme={null}
        // Redirect user to the checkout link
        window.location.href = response.data.checkoutLink;
        ```
      </Card>

      <Card title="Display QR Code" icon="qrcode">
        Show a QR code for mobile wallet scanning:

        ```javascript theme={null}
        // Show QR code for mobile wallet scanning
        <img src={`https://api.qrserver.com/v1/create-qr-code/?data=${encodeURIComponent(response.data.qrContent)}&size=300x300`} />
        ```
      </Card>
    </CardGroup>
  </Step>

  <Step title="Handle Webhook Notifications">
    Set up a webhook endpoint to receive payment status updates. CeyPay uses **ED25519** signatures for security.

    ```javascript theme={null}
    const express = require("express");
    const crypto = require("crypto");
    const app = express();

    const CEYPAY_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
    MCowBQYDK2VwAyEAs+hotF0u5tdoATwAIezK58lzfMZIoKDTlRgoUU+6Qr4=
    -----END PUBLIC KEY-----`;

    // Use raw body for signature verification
    app.use("/webhooks/ceypay", express.raw({ type: "application/json" }));

    app.post("/webhooks/ceypay", (req, res) => {
      const signature = req.headers["x-webhook-signature"];
      const timestamp = req.headers["x-webhook-timestamp"];
      const rawBody = req.body.toString("utf8");

      // Verify signature using ED25519
      const message = timestamp + rawBody;

      try {
        const isValid = crypto.verify(
          null,
          Buffer.from(message),
          CEYPAY_PUBLIC_KEY,
          Buffer.from(signature, "base64"),
        );

        if (!isValid) {
          return res.status(401).send("Invalid signature");
        }
      } catch (err) {
        return res.status(401).send("Invalid signature");
      }

      // Process webhook
      const payload = JSON.parse(rawBody);
      if (payload.status === "PAID") {
        console.log("Payment successful! Fulfill order:", payload.paymentId);
      }

      res.status(200).json({ received: true });
    });

    app.listen(3000, () => console.log("Webhook server running on port 3000"));
    ```

    See [webhooks.md](/api/v1/webhooks) for complete webhook integration guide.
  </Step>
</Steps>

## Step 5: Test Your Integration

### Test Webhook Endpoint

```bash theme={null}
# Derive signing key first
SIGNING_KEY=$(echo -n "$SECRET" | sha256sum | cut -d' ' -f1)

# Generate signature
TIMESTAMP=$(date +%s)000
MESSAGE="${TIMESTAMP}POST/v1/webhooks/test{\"webhookUrl\": \"https://your-app.com/webhooks/ceypay\"}"
SIGNATURE=$(echo -n "$MESSAGE" | openssl dgst -sha256 -hmac "$SIGNING_KEY" | cut -d' ' -f2)

curl -X POST https://api.ceypay.io/v1/webhooks/test \
  -H "x-api-key: $KEY_ID" \
  -H "x-timestamp: $TIMESTAMP" \
  -H "x-signature: $SIGNATURE" \
  -d '{"webhookUrl": "https://your-app.com/webhooks/ceypay"}'
```

### Test Payment Flow

<Steps>
  <Step title="Create a test payment" />

  <Step title="Open the checkout link in your browser" />

  <Step title="Complete the payment (use Bybit test account if available)" />

  <Step title="Verify webhook is received" />

  <Step title="Check payment status via API" />
</Steps>

## Common Use Cases

### E-commerce Checkout

```javascript theme={null}
// Create payment from shopping cart
const payment = await createPayment({
  amount: cart.total,
  currency: "USDT",
  goods: cart.items.map((item) => ({
    name: item.name,
    description: item.description,
  })),
  customerBilling: {
    email: customer.email,
    firstName: customer.firstName,
    lastName: customer.lastName,
  },
  webhookUrl: "https://mystore.com/api/webhooks/payment",
});

// Redirect to checkout
res.redirect(payment.checkoutLink);
```

### Payment Link for Products

```javascript theme={null}
// Create reusable payment link
const paymentLink = await createPaymentLink({
  name: "Premium Plan - Monthly",
  description: "Subscription to premium features",
  amount: 49.99,
  currency: "USDT",
  reusable: true,
});

// Share the link
console.log("Payment link:", `https://pay.ceypay.io/${paymentLink.slug}`);
```

### Invoice Payment

```javascript theme={null}
// Create single-use payment link for invoice
const invoice = await createPaymentLink({
  name: `Invoice #${invoiceNumber}`,
  description: "Web development services",
  amount: invoiceAmount,
  currency: "USDT",
  reusable: false,
  expirationDate: "2025-02-28T23:59:59Z",
});

// Email invoice link to customer
sendEmail({
  to: customer.email,
  subject: `Invoice #${invoiceNumber}`,
  body: `Pay your invoice: ${invoice.checkoutUrl}`,
});
```

## Next Steps

### Learn More

<CardGroup cols={2}>
  <Card title="Authentication" icon="key" href="/api/v1/authentication">
    Deep dive into HMAC signature
  </Card>

  <Card title="Webhooks" icon="webhook" href="/api/v1/webhooks">
    Complete webhook integration guide
  </Card>

  <Card title="Payment Links" icon="link" href="/api/v1/payment-links">
    Guide to using payment links
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation" href="/api/v1/errors">
    Error codes and troubleshooting
  </Card>

  <Card title="Rate Limits" icon="gauge-high" href="/api/v1/rate-limits">
    API rate limiting policies
  </Card>
</CardGroup>

### Explore API Endpoints

**Payments**:

* `POST` `/v1/payment` - Create payment
* `GET` `/v1/payment/:id` - Get payment details
* `GET` `/v1/payment` - List payments

**Payment Links**:

* `POST` `/v1/payment-link` - Create payment link
* `GET` `/v1/payment-link/:id` - Get payment link
* `GET` `/v1/payment-link` - List payment links
* `PATCH` `/v1/payment-link/:id` - Update payment link
* `DELETE` `/v1/payment-link/:id` - Deactivate payment link

**Webhooks**:

* `GET` `/v1/webhooks/config` - Get webhook configuration
* `POST` `/v1/webhooks/test` - Test webhook delivery

### API Reference

Full API documentation available at: [https://api.ceypay.io/api-docs](https://api.ceypay.io/api-docs)

### Support

* **Email**: [support@ceypay.io](mailto:support@ceypay.io)
* **Documentation**: [https://docs.ceypay.io](https://docs.ceypay.io)
* **Status**: [https://status.ceypay.io](https://status.ceypay.io)

## Checklist

Before going live, ensure you:

* [ ] Completed merchant onboarding and KYC
* [ ] Generated production API key
* [ ] Stored API key securely (environment variable)
* [ ] Implemented HMAC signature authentication with derived signing key
* [ ] Set up webhook endpoint with signature verification
* [ ] Tested payment flow end-to-end
* [ ] Implemented error handling
* [ ] Configured monitoring and logging
* [ ] Reviewed security best practices
* [ ] Read rate limiting policies

## Tips

### Security

* Never commit API keys to version control
* Use environment variables for secrets
* Always verify webhook signatures
* Use HTTPS for all webhook endpoints
* Send only the key ID in `x-api-key`, never the full API key

### Performance

* Cache exchange rates when possible
* Implement idempotent webhook handling
* Use exponential backoff for retries
* Monitor rate limit headers

### Testing

* Use ngrok for local webhook testing
* Create test payments regularly
* Monitor webhook delivery logs
* Set up alerts for failed webhooks

Happy coding!
