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

# Python SDK

> Official Python SDK for PayBridgeNP. Requires Python 3.9+.

## Installation

```bash theme={null}
pip install paybridge-np
```

## Initialization

```python theme={null}
from paybridge_np import PayBridgeNP

paybridgenp = PayBridgeNP(
    api_key="sk_test_...",                 # sk_test_... or sk_live_...
    base_url="https://api.paybridgenp.com",  # optional, this is the default
    timeout=30.0,                            # optional, seconds. default: 30
    max_retries=2,                           # optional. default: 2
)
```

You can also use the client as a context manager:

```python theme={null}
with PayBridgeNP(api_key="sk_live_...") as paybridgenp:
    session = paybridgenp.checkout.create({...})
# HTTP client is closed automatically
```

***

## `paybridgenp.checkout`

### `checkout.create(params)`

Creates a checkout session.

```python theme={null}
session = paybridgenp.checkout.create({
    "amount": 10000,                              # required - paisa (NPR x 100)
    "returnUrl": "https://yoursite.com/success",  # required
    "cancelUrl": "https://yoursite.com/cart",     # optional
    "provider": "khalti",                         # optional - omit to let customer pick
    "currency": "NPR",                            # optional, default: "NPR"
    "metadata": {"orderId": "ORD-001"},           # optional
})

print(session["checkout_url"])  # redirect customer here
print(session["id"])            # cs_...
print(session["expires_at"])    # ISO timestamp
```

**Parameters:**

| Name        | Type   | Required | Description                                    |
| ----------- | ------ | -------- | ---------------------------------------------- |
| `amount`    | `int`  | Yes      | In paisa. NPR 100.00 = `10000`                 |
| `returnUrl` | `str`  | Yes      | Redirect URL after payment                     |
| `cancelUrl` | `str`  | No       | Redirect URL on cancellation                   |
| `provider`  | `str`  | No       | `"esewa"`, `"khalti"`, `"fonepay"`             |
| `currency`  | `str`  | No       | Default: `"NPR"`                               |
| `metadata`  | `dict` | No       | Passed through to webhooks and payment records |

### `checkout.expire(id)`

Marks a session as expired so it can no longer accept payment. Use this when you mint a fresh session for a logical purchase that already had one outstanding (e.g. a customer requesting a new payment link), so the old URL stops being payable immediately rather than waiting for its 30-minute TTL.

```python theme={null}
paybridgenp.checkout.expire("cs_6f2jHn2…")
```

Idempotent: calling on an already-terminal session is a no-op that returns the current row state without error.

***

## `paybridgenp.payments`

### `payments.list(**kwargs)`

```python theme={null}
response = paybridgenp.payments.list(
    limit=20,   # optional, default 10, max 100
    offset=0,   # optional, default 0
)

print(response["meta"]["total"])

for payment in response["data"]:
    print(payment["id"], payment["amount"], payment["status"])
```

### `payments.retrieve(id)`

```python theme={null}
payment = paybridgenp.payments.retrieve("pay_6f2jHn2...")

print(payment["status"])       # "success" | "failed"
print(payment["amount"])       # paisa
print(payment["provider"])     # "esewa" | "khalti" | ...
print(payment["provider_ref"])  # provider's transaction reference
print(payment["metadata"])     # whatever you passed at checkout
```

***

## `paybridgenp.webhooks`

### `webhooks.create(**kwargs)`

```python theme={null}
endpoint = paybridgenp.webhooks.create(
    url="https://yoursite.com/webhooks/paybridgenp",
    events=["payment.succeeded", "payment.failed"],  # optional - omit for all
)

print(endpoint["signing_secret"])  # save this - shown only once
```

### `webhooks.list()`

```python theme={null}
response = paybridgenp.webhooks.list()
for wh in response["data"]:
    print(wh["id"], wh["url"], wh["enabled"])
```

### `webhooks.delete(id)`

```python theme={null}
paybridgenp.webhooks.delete("wh_...")
```

### `WebhooksResource.construct_event(body, signature, secret)` (static)

Verifies a webhook signature and returns the parsed event. Use this in your webhook handler.

```python theme={null}
from paybridge_np.resources.webhooks import WebhooksResource
from paybridge_np.errors import SignatureVerificationError

body = request.get_data(as_text=True)  # raw body string
signature = request.headers.get("X-PayBridgeNP-Signature")

try:
    event = WebhooksResource.construct_event(
        body,
        signature,
        os.environ["PAYBRIDGENP_WEBHOOK_SECRET"],
    )
except SignatureVerificationError:
    return {"error": "Invalid signature"}, 400

if event["type"] == "payment.succeeded":
    # event["data"]["id"], event["data"]["amount"], event["data"]["metadata"]
    fulfill_order(event["data"]["metadata"].get("orderId"))
elif event["type"] == "payment.failed":
    notify_order_failed(event["data"]["session_id"])
```

Raises `SignatureVerificationError` if:

* The signature header is missing or malformed
* The HMAC doesn't match
* The timestamp is more than 5 minutes old (replay attack protection)

***

## `paybridgenp.billing`

The billing methods provide access to plans, customers, subscriptions, and invoices. Billing API access requires the Growth plan or higher.

### Plans

```python theme={null}
# Create a plan
plan = paybridgenp.plans.create({
    "name": "Pro Monthly",
    "amount": 99900,         # paisa - NPR 999/month
    "intervalUnit": "month",
    "intervalCount": 1,
    "trialDays": 14,         # optional
})

# List plans
response = paybridgenp.plans.list()

# Get a plan
plan = paybridgenp.plans.get("plan_...")

# Update a plan
updated = paybridgenp.plans.update("plan_...", {"name": "Pro Monthly v2"})
```

### Customers

```python theme={null}
# Create a customer
customer = paybridgenp.customers.create({
    "name": "Aarav Sharma",
    "email": "aarav@example.com",
    "externalCustomerId": "user_123",  # optional
})

# List customers
response = paybridgenp.customers.list()

# Get a customer
customer = paybridgenp.customers.get("cus_...")

# Update a customer
updated = paybridgenp.customers.update("cus_...", {"email": "new@example.com"})

# Delete a customer
paybridgenp.customers.delete("cus_...")
```

### Subscriptions

```python theme={null}
# Create a subscription
sub = paybridgenp.subscriptions.create({
    "customerId": "cus_...",
    "planId": "plan_...",
})

# List subscriptions
response = paybridgenp.subscriptions.list()

# Get a subscription
sub = paybridgenp.subscriptions.get("sub_...")

# Lifecycle actions
paybridgenp.subscriptions.pause("sub_...")
paybridgenp.subscriptions.resume("sub_...")
paybridgenp.subscriptions.cancel("sub_...")

# Change plan
paybridgenp.subscriptions.change_plan("sub_...", {"newPlanId": "plan_..."})
```

### Invoices

```python theme={null}
# List invoices
response = paybridgenp.invoices.list(
    subscription_id="sub_...",  # optional
)

# Get an invoice
invoice = paybridgenp.invoices.get("inv_...")

print(invoice["status"])       # "open" | "paid" | "overdue" | "void" | "uncollectible" | "write_off"
print(invoice["amount_due"])   # paisa
print(invoice["due_at"])       # ISO timestamp
```

***

## Error handling

All SDK methods raise typed exceptions you can catch and inspect:

```python theme={null}
from paybridge_np import PayBridgeNP, PayBridgeError, AuthenticationError

try:
    paybridgenp.checkout.create({"amount": 1000, "returnUrl": "..."})
except AuthenticationError:
    # Invalid API key
    print("Check your PAYBRIDGENP_API_KEY")
except PayBridgeError as e:
    print(e)              # human-readable message
    print(e.status_code)  # HTTP status
    print(e.code)         # machine-readable code
```

### Exception classes

| Class                        | Status | When                            |
| ---------------------------- | ------ | ------------------------------- |
| `AuthenticationError`        | 401    | Invalid or missing API key      |
| `InvalidRequestError`        | 400    | Bad request parameters          |
| `NotFoundError`              | 404    | Resource not found              |
| `RateLimitError`             | 429    | Too many requests               |
| `PayBridgeError`             | 5xx    | Server error                    |
| `SignatureVerificationError` | -      | Webhook HMAC mismatch or replay |

***

## Type hints

The SDK ships with a `py.typed` marker and full type annotations. All parameter types are exported as `TypedDict` classes:

```python theme={null}
from paybridge_np.types import (
    CreateCheckoutParams,
    CheckoutSession,
    Payment,
    PaymentStatus,
    Provider,
    CreateRefundParams,
    CreatePlanParams,
    CreateCustomerParams,
    CreateSubscriptionParams,
)
```

***

## Framework examples

<AccordionGroup>
  <Accordion title="Django">
    ```python theme={null}
    # views.py
    import json
    import os
    from django.http import JsonResponse
    from django.views.decorators.csrf import csrf_exempt
    from paybridge_np import PayBridgeNP
    from paybridge_np.resources.webhooks import WebhooksResource
    from paybridge_np.errors import SignatureVerificationError

    paybridgenp = PayBridgeNP(api_key=os.environ["PAYBRIDGENP_API_KEY"])

    def create_checkout(request):
        data = json.loads(request.body)

        session = paybridgenp.checkout.create({
            "amount": data["amount"],
            "returnUrl": "https://yoursite.com/success",
            "cancelUrl": "https://yoursite.com/cart",
            "metadata": {"orderId": data["orderId"]},
        })

        return JsonResponse({"checkoutUrl": session["checkout_url"]})

    @csrf_exempt
    def webhook(request):
        try:
            event = WebhooksResource.construct_event(
                request.body.decode(),
                request.headers.get("X-PayBridgeNP-Signature"),
                os.environ["PAYBRIDGENP_WEBHOOK_SECRET"],
            )
        except SignatureVerificationError:
            return JsonResponse({"error": "Invalid signature"}, status=400)

        if event["type"] == "payment.succeeded":
            Order.objects.filter(
                id=event["data"]["metadata"].get("orderId")
            ).update(status="paid")

        return JsonResponse({"received": True})
    ```
  </Accordion>

  <Accordion title="Flask">
    ```python theme={null}
    import os
    from flask import Flask, request, jsonify
    from paybridge_np import PayBridgeNP
    from paybridge_np.resources.webhooks import WebhooksResource
    from paybridge_np.errors import SignatureVerificationError

    app = Flask(__name__)
    paybridgenp = PayBridgeNP(api_key=os.environ["PAYBRIDGENP_API_KEY"])

    @app.post("/create-checkout")
    def create_checkout():
        data = request.json

        session = paybridgenp.checkout.create({
            "amount": data["amount"],
            "returnUrl": "https://yoursite.com/success",
            "metadata": {"orderId": data["orderId"]},
        })

        return jsonify(checkoutUrl=session["checkout_url"])

    @app.post("/webhooks/paybridgenp")
    def webhook():
        try:
            event = WebhooksResource.construct_event(
                request.get_data(as_text=True),
                request.headers.get("X-PayBridgeNP-Signature"),
                os.environ["PAYBRIDGENP_WEBHOOK_SECRET"],
            )
        except SignatureVerificationError:
            return jsonify(error="Invalid signature"), 400

        if event["type"] == "payment.succeeded":
            fulfill_order(event["data"]["metadata"].get("orderId"))

        return jsonify(received=True)
    ```
  </Accordion>

  <Accordion title="FastAPI">
    ```python theme={null}
    import os
    from fastapi import FastAPI, Request, HTTPException
    from paybridge_np import PayBridgeNP
    from paybridge_np.resources.webhooks import WebhooksResource
    from paybridge_np.errors import SignatureVerificationError

    app = FastAPI()
    paybridgenp = PayBridgeNP(api_key=os.environ["PAYBRIDGENP_API_KEY"])

    @app.post("/create-checkout")
    async def create_checkout(request: Request):
        data = await request.json()

        session = paybridgenp.checkout.create({
            "amount": data["amount"],
            "returnUrl": "https://yoursite.com/success",
            "metadata": {"orderId": data["orderId"]},
        })

        return {"checkoutUrl": session["checkout_url"]}

    @app.post("/webhooks/paybridgenp")
    async def webhook(request: Request):
        body = (await request.body()).decode()
        signature = request.headers.get("X-PayBridgeNP-Signature")

        try:
            event = WebhooksResource.construct_event(
                body, signature, os.environ["PAYBRIDGENP_WEBHOOK_SECRET"],
            )
        except SignatureVerificationError:
            raise HTTPException(status_code=400, detail="Invalid signature")

        if event["type"] == "payment.succeeded":
            await fulfill_order(event["data"]["metadata"].get("orderId"))

        return {"received": True}
    ```
  </Accordion>
</AccordionGroup>
