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

> ## Agent Instructions
> Use hosted checkout for a new payment integration unless the user explicitly needs an SDK or Direct QR flow.
> Keep secret API keys on the server. Never place an sk_test_ or sk_live_ key in browser or mobile code.
> Never treat a browser return URL as proof of payment. Verify a signed webhook and confirm status, amount, and currency on the server before fulfillment.
> Fonepay has no sandbox. A Fonepay payment made from a sandbox project uses the merchant's real Fonepay account and moves real money within the documented caps.
> Do not recommend direct integration with Mobile SDK device endpoints. Use the PayBridgeNP Mobile SDK and the merchant-facing session creation API.

# Create or reuse an invoice checkout



## OpenAPI

````yaml POST /v1/invoices/{id}/checkout
openapi: 3.1.0
info:
  title: PayBridgeNP API
  version: 1.0.0
  description: >-
    PayBridgeNP is Nepal's payment gateway - accept eSewa, Khalti, and Fonepay
    through a single API.


    **Base URL:** `https://api.paybridgenp.com`


    **Dashboard:**
    [dashboard.paybridgenp.com](https://dashboard.paybridgenp.com)


    All monetary amounts are in **paisa** (1 NPR = 100 paisa). An amount of
    `10000` represents Rs. 100.00.
  contact:
    name: PayBridgeNP Support
    url: https://paybridgenp.com
servers:
  - url: https://api.paybridgenp.com
    description: Production
security:
  - BearerAuth: []
tags:
  - name: Authentication
    description: >-
      ## API Keys


      All merchant-facing API endpoints require a Bearer API key in the
      `Authorization` header:


      ```

      Authorization: Bearer sk_live_your_api_key_here

      ```


      You can find and rotate your API keys in the [PayBridgeNP
      Dashboard](https://dashboard.paybridgenp.com) under **Settings → API
      Keys**.


      ### Key prefixes


      | Prefix | Mode | Use |

      |--------|------|-----|

      | `sk_test_` | Sandbox | eSewa and Khalti test flows; see the Fonepay
      warning below |

      | `sk_live_` | Live | Production - real payments |


      The mode is fixed per key. A sandbox key creates sandbox records; a live
      key creates live payments. **Never expose a secret key in client-side
      code.**
  - name: Sandbox & Live Modes
    description: >-
      ## Sandbox Mode


      Sandbox mode lets you test eSewa and Khalti without real money. To use
      sandbox mode:


      1. Generate a sandbox key (`sk_test_...`) from the dashboard.

      2. Use it exactly like a live key - the API behaves identically.

      3. On the hosted checkout page, use the built-in test credentials below.


      ### Built-in test credentials


      | Provider | Test credential |

      |----------|-----------------|

      | eSewa | ID `9806800001`, password `Nepal@123`, MPIN `1122`, OTP `123456`
      |

      | Khalti | Phone `9800000001`, MPIN `1111`, OTP `987654` |


      Sandbox payments appear in your dashboard under the **Sandbox** tab.


      **Fonepay has no sandbox.** If you enable Fonepay on a sandbox project,
      PayBridgeNP uses your real Fonepay merchant account and the payment moves
      real money. Sandbox Fonepay is capped at NPR 1,000 per payment and NPR
      5,000 per month. Every sandbox Fonepay QR minted in the last 30 minutes
      also counts at full value towards the monthly cap until it is paid or the
      30 minutes pass, even if it was replaced or never scanned, so unpaid test
      QRs use up the cap until they age out. Use a small amount such as NPR 10.


      ### Switching to live


      Configure your live provider credentials, replace the `sk_test_` key with
      a `sk_live_` key, and run the go-live checks before accepting customers.
  - name: Errors
    description: >-
      ## Error Responses


      All errors return a single nested envelope:


      ```json

      {
        "error": {
          "message": "amount must be a positive integer (in paisa)",
          "type": "invalid_request_error",
          "code": "invalid_request_error",
          "request_id": "req_2Je91NlWKuXkdXUJOK9gaHNW"
        }
      }

      ```


      Read `error.message` for the human-readable string, `error.type` for the
      broad category (SDKs map it to a typed exception), `error.code` to branch
      on, and `error.request_id` (matches `X-Request-Id`) when contacting
      support.


      ### HTTP status codes


      | Status | Meaning |

      |--------|---------|

      | `400` | Bad request - check the `error` field for details |

      | `401` | Unauthorized - missing or invalid API key |

      | `404` | Resource not found |

      | `409` | Conflict - e.g. concurrent idempotent request, customer has
      active subscriptions |

      | `422` | Unprocessable - business logic violation |

      | `429` | Rate limit exceeded - back off and retry |

      | `500` | Internal server error |


      ### Common error types and codes


      | `error.type` | Example `error.code` | Meaning |

      |------|------|-------------|

      | `authentication_error` | `api_key_invalid` | Missing or invalid API key
      |

      | `invalid_request_error` | `not_found` | Validation failure, or the
      resource does not exist or belongs to another project |

      | `idempotency_error` | `idempotency_conflict` | Two concurrent requests
      sent the same `Idempotency-Key` |

      | `rate_limit_error` | `rate_limited` | Rate-limit window exhausted |

      | `api_error` | `api_error` | Server-side failure - safe to retry |


      For the full list of `type` and `code` values, see the [Errors
      reference](https://docs.paybridgenp.com/api-reference/errors).
  - name: Payments
  - name: Refunds
  - name: Webhooks
  - name: Billing
  - name: One-time Invoices
    description: >-
      Issue and collect merchant one-time invoices. Sandbox is available on
      every plan. Live changes return 403 until live invoicing is enabled.
  - name: Account
  - name: Sessions
    description: Read-only access to the checkout sessions created via `POST /v1/checkout`.
  - name: Payment Links
    description: Create and manage reusable hosted payment pages through the API.
  - name: Analytics
    description: >-
      Aggregated KPIs for the authenticated project - payment totals, success
      rate, provider breakdown, and the checkout funnel.
  - name: Providers
    description: >-
      Lists the payment providers enabled and configured for the authenticated
      project, so an integrator can decide which "Pay with X" options to render.
  - name: QR
    description: >-
      Direct-QR API for Fonepay - mint a Dynamic QR server-side and listen for
      scan/pay events over SSE, bypassing the hosted checkout page. Pro.
  - name: SMS
    description: >-
      Send transactional SMS on the merchant's behalf with the merchant's plan
      limits, audit trail, and anti-abuse guards applied. Live SMS is
      plan-metered: Free 0/month, Growth 200/month, Pro 1,000/month (sandbox is
      always logged, never delivered).
  - name: Mobile
    description: >-
      Native mobile SDK endpoints. Create a checkout session that returns
      provider native-SDK params, then verify the result after the native flow
      completes.
  - name: Public
paths:
  /v1/invoices/{id}/checkout:
    post:
      tags:
        - One-time Invoices
      summary: Create or reuse an invoice checkout
      operationId: checkoutStandaloneInvoice
      parameters:
        - name: id
          in: path
          required: true
          description: One-time invoice ID (prefix `oinv_`).
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: >-
            Stable command key. Reusing it with a different method, target,
            query, or body returns 409.
          schema:
            type: string
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - provider
              properties:
                provider:
                  type: string
                  enum:
                    - esewa
                    - khalti
                    - fonepay
      responses:
        '201':
          description: Checkout session created or reused.
          content:
            application/json:
              schema:
                type: object
                properties:
                  checkout_session_id:
                    type: string
                  checkout_url:
                    type: string
                    format: uri
                  reused:
                    type: boolean
        '400':
          description: Invalid request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            Missing scope, or live one-time invoices are disabled. Sandbox
            remains available.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Invoice not found in this project and mode.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: State conflict or Idempotency-Key reused for another request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    Error:
      type: object
      description: >-
        All error responses share a single nested envelope:


        ```json

        {
          "error": {
            "message": "Human-readable explanation.",
            "type": "authentication_error",
            "code": "api_key_invalid",
            "request_id": "req_..."
          }
        }

        ```


        The `type` field gives a broad category useful for SDK error class
        hierarchies. The `code` field is fine-grained and stable for
        programmatic branching. `request_id` is the same value as the
        `X-Request-Id` response header - quote it in support requests so we can
        find the exact request in logs.


        Some error types include extra detail objects (e.g. `error.suspension`
        on `account_suspended`, `error.pause` on `token_paused`).
      required:
        - error
      properties:
        error:
          type: object
          required:
            - message
            - type
          properties:
            message:
              type: string
              description: >-
                Human-readable error message - safe to surface to a developer,
                may include the action they need to take.
            type:
              type: string
              enum:
                - authentication_error
                - account_error
                - permission_error
                - invalid_request_error
                - idempotency_error
                - rate_limit_error
                - api_error
              description: >-
                Broad category used by SDKs to instantiate a typed exception
                (e.g. `AuthenticationError`, `InvalidRequestError`).
            code:
              type: string
              description: >-
                Specific, stable identifier for programmatic handling. Common
                values:


                - `api_key_missing` - Authorization header absent or empty
                (401).

                - `api_key_invalid` - key not recognised (401).

                - `api_key_revoked` - key was explicitly revoked (401).

                - `api_key_expired` - key passed its expiration timestamp (401).

                - `api_key_must_be_secret` - endpoint requires `sk_...`; a
                publishable `pk_...` was sent (403).

                - `account_suspended` - merchant account is suspended (403); see
                `error.suspension`.

                - `token_paused` - MCP token paused (423); see `error.pause`.

                - `forbidden` - permission check failed (403).

                - `not_found` - resource not found (404).

                - `idempotency_conflict` - concurrent request with same
                Idempotency-Key (409).

                - `rate_limited` - rate-limit window exhausted (429).
            request_id:
              type: string
              description: >-
                Same value as the `X-Request-Id` response header. Quote in
                support requests for fastest triage.
              example: req_2Je91NlWKuXkdXUJOK9gaHNW
            detail:
              type: string
              description: >-
                Optional provider or validation detail. Refund failures use this
                for the provider's readable reason.
            refund:
              $ref: '#/components/schemas/Refund'
              description: >-
                Optional refund record. Present when a refund failed
                definitively or is held because the provider outcome is
                uncertain.
            suspension:
              type: object
              description: Present only when `code === 'account_suspended'`.
              properties:
                suspended_at:
                  type: string
                  format: date-time
                reason:
                  type: string
                  nullable: true
            pause:
              type: object
              description: Present only when `code === 'token_paused'`.
              properties:
                paused_at:
                  type: string
                  format: date-time
                reason:
                  type: string
                  nullable: true
    Refund:
      type: object
      properties:
        id:
          type: string
          example: ref_01j9x2k3m4n5p6q7r8s9t0u1v2
        livemode:
          type: boolean
          description: '`true` when created with a live key, `false` for sandbox.'
        paymentId:
          type: string
          example: pay_01j9x2k3m4n5p6q7r8s9t0u1v2
        projectId:
          type: string
        mode:
          type: string
          enum:
            - sandbox
            - live
        amount:
          type: integer
          description: Refunded amount in paisa.
          example: 10000
        currency:
          type: string
          example: NPR
        reason:
          type: string
          enum:
            - customer_request
            - duplicate
            - fraudulent
            - other
        status:
          type: string
          enum:
            - processing
            - succeeded
            - failed
            - requires_action
          description: >-
            `succeeded` - refund processed. `requires_action` - eSewa: must be
            processed manually via merchant portal. `failed` - provider rejected
            the refund.
        providerRefundId:
          type: string
          nullable: true
          description: Provider's refund reference (Khalti only).
        failureReason:
          type: string
          nullable: true
          description: Set when status is `failed` or `requires_action`.
        notes:
          type: string
          nullable: true
        mobileNumber:
          type: string
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: >-
        Your PayBridgeNP API key. Obtain one from the dashboard under Settings →
        API Keys. Prefix: `sk_test_` for testing, `sk_live_` for production.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.