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

# Quickstart

> Accept your first payment in under 5 minutes.

This guide walks through the full payment flow - from creating a checkout session on your server to receiving a webhook when payment succeeds.

## 1. Get your API keys

Sign up at [dashboard.paybridgenp.com](https://dashboard.paybridgenp.com) and copy your API key from **Settings → API Keys**.

* Sandbox keys start with `sk_test_` - use these for testing
* Live keys start with `sk_live_` - use these for real payments

<Warning>
  Never expose your API key in client-side code or commit it to version control. Use environment variables.
</Warning>

## 2. Install the SDK

<CodeGroup>
  ```bash npm theme={null}
  npm install @paybridge-np/sdk
  ```

  ```bash yarn theme={null}
  yarn add @paybridge-np/sdk
  ```

  ```bash bun theme={null}
  bun add @paybridge-np/sdk
  ```
</CodeGroup>

## 3. Create a checkout session

Call this from your server when a customer is ready to pay.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { PayBridgeNP } from "@paybridge-np/sdk";

  const paybridgenp = new PayBridgeNP({
    apiKey: process.env.PAYBRIDGENP_API_KEY!, // sk_test_... or sk_live_...
  });

  const session = await paybridgenp.checkout.create({
    amount: 10000,                              // NPR 100.00 - always in paisa (NPR × 100)
    returnUrl: "https://yoursite.com/success",
    cancelUrl: "https://yoursite.com/cart",    // optional
    metadata: { orderId: "ORD-001" },          // optional, returned in webhook
  });

  // Redirect the customer
  redirect(session.checkout_url);
  ```

  ```javascript JavaScript (fetch) theme={null}
  const res = await fetch("https://api.paybridgenp.com/v1/checkout", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.PAYBRIDGENP_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      amount: 10000,
      returnUrl: "https://yoursite.com/success",
      cancelUrl: "https://yoursite.com/cart",
      metadata: { orderId: "ORD-001" },
    }),
  });

  const session = await res.json();
  // Redirect customer to session.checkout_url
  ```
</CodeGroup>

The response looks like:

```json theme={null}
{
  "id": "cs_01j9x2k3m4n5p6q7r8s9t0u1v2",
  "checkout_url": "https://checkout.paybridgenp.com/checkout/cs_01j9x2k3m...",
  "flow": "hosted",
  "provider": null,
  "expires_at": "2026-03-31T12:30:00.000Z"
}
```

Redirect your customer to `checkout_url`. They'll see the PayBridgeNP hosted checkout page and can pay with any provider you've configured.

<Note>
  **`cancelUrl` is optional.** If you omit it, cancellations fall back to your
  `returnUrl` with `?status=cancelled` appended - and the hosted picker hides
  its "Cancel" link. Set `cancelUrl` only if you want a dedicated cancel page
  and a visible Cancel link on the picker.
</Note>

## 4. Handle the return redirect

After the customer pays (or cancels), they're redirected to your `returnUrl` (or `cancelUrl` if set and the customer cancelled) with query parameters:

```
https://yoursite.com/success?session_id=cs_xxx&status=success&payment_id=pay_xxx
```

| Parameter    | Value                               |
| ------------ | ----------------------------------- |
| `session_id` | The checkout session ID             |
| `status`     | `success`, `failed`, or `cancelled` |
| `payment_id` | The payment ID (only on success)    |

<Warning>
  Do not fulfill orders based solely on the redirect. The customer could manipulate query parameters. Always verify payment server-side using webhooks or `GET /v1/payments/:id`.
</Warning>

## 5. Verify payment server-side

<CodeGroup>
  ```typescript TypeScript (webhook - recommended) theme={null}
  // In your webhook handler
  app.post("/webhooks/paybridgenp", async (req) => {
    const body = await req.text(); // raw body string
    const sig = req.headers.get("x-paybridgenp-signature");

    const event = await PayBridgeNP.webhooks.constructEvent(
      body,
      sig,
      process.env.PAYBRIDGENP_WEBHOOK_SECRET!,
    );

    if (event.type === "payment.succeeded") {
      const { metadata } = event.data;
      await fulfillOrder(metadata?.orderId);
    }
  });
  ```

  ```typescript TypeScript (API poll - simpler for testing) theme={null}
  const payment = await paybridgenp.payments.retrieve("pay_xxx");

  if (payment.status === "success") {
    await fulfillOrder(payment.metadata?.orderId);
  }
  ```
</CodeGroup>

Only have the `session_id` from the redirect? Fetch the session - once it's paid, the response includes `paymentId`:

```bash theme={null}
curl https://api.paybridgenp.com/v1/sessions/cs_xxx \
  -H "Authorization: Bearer sk_live_your_key"
# → { "id": "cs_xxx", "status": "success", "paymentId": "pay_xxx", ... }
```

See [Get a checkout session](/api-reference/checkout/get-session).

## 6. Set up a webhook endpoint

Go to **Webhooks** in the [dashboard](https://dashboard.paybridgenp.com), click **Add endpoint**, enter your URL, and select the events you want to receive. Save the signing secret - it's shown only once.

See the [webhook verification guide](/guides/webhook-verification) for full details on signature verification.

***

## Next steps

<CardGroup cols={2}>
  <Card title="Sandbox Testing" icon="flask" href="/guides/sandbox-testing">
    Test the full flow with built-in test credentials before going live.
  </Card>

  <Card title="Provider Setup" icon="gear" href="/guides/provider-setup">
    Add your real eSewa, Khalti, and Fonepay credentials.
  </Card>

  <Card title="Idempotency" icon="shield-check" href="/guides/idempotency">
    Make retries safe - avoid duplicate payments on network failures.
  </Card>

  <Card title="Billing" icon="repeat" href="/guides/billing">
    Set up recurring subscriptions and automated invoicing.
  </Card>
</CardGroup>
