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

# Create a payment link

> Creates a reusable hosted payment page. Requires the `links:write` scope. Provide either a fixed `amount`, or `minAmount`/`maxAmount` bounds for a customer-entered amount.



## OpenAPI

````yaml POST /v1/payment-links
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 | Testing - no real money moves |

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


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


      Sandbox mode lets you test your integration 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. They
      are never sent to real payment providers.


      ### Switching to live


      Replace your `sk_test_` key with a `sk_live_` key - no other code changes
      are needed.
  - 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: Account
  - name: Sessions
    description: Read-only access to the checkout sessions created via `POST /v1/checkout`.
  - name: Payment Links
    description: >-
      Reusable hosted payment pages. Create and list links programmatically;
      update, cancel, and delete stay dashboard-only for now.
  - 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/payment-links:
    post:
      tags:
        - Payment Links
      summary: Create a payment link
      description: >-
        Creates a reusable hosted payment page. Requires the `links:write`
        scope. Provide either a fixed `amount`, or `minAmount`/`maxAmount`
        bounds for a customer-entered amount.
      operationId: createPaymentLink
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          description: >-
            A unique key to safely retry the request without creating duplicate
            links.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - title
              properties:
                title:
                  type: string
                  maxLength: 100
                  description: Shown on the payment page.
                  example: Donation
                description:
                  type: string
                  maxLength: 500
                  nullable: true
                amount:
                  type: integer
                  nullable: true
                  description: >-
                    Fixed amount in paisa. Omit to let the customer enter an
                    amount (then use `minAmount`/`maxAmount`).
                  example: 10000
                minAmount:
                  type: integer
                  nullable: true
                  description: Minimum customer-entered amount in paisa.
                maxAmount:
                  type: integer
                  nullable: true
                  description: Maximum customer-entered amount in paisa (max NPR 100,000).
                currency:
                  type: string
                  enum:
                    - NPR
                  default: NPR
                provider:
                  type: string
                  enum:
                    - esewa
                    - khalti
                    - fonepay
                  nullable: true
                  description: Lock to a provider, or omit to let the customer pick.
                maxUses:
                  type: integer
                  minimum: 1
                  maximum: 10000
                  nullable: true
                  description: Usage cap. Omit for unlimited.
                expiresAt:
                  type: string
                  format: date-time
                  nullable: true
                  description: ISO date; must be in the future and within 1 year.
                redirectUrl:
                  type: string
                  format: uri
                  nullable: true
                  description: >-
                    `https://` URL the customer is sent to after a successful
                    payment.
                inactiveMessage:
                  type: string
                  maxLength: 300
                  nullable: true
                metadata:
                  type: object
                  additionalProperties: true
                  nullable: true
                  description: Arbitrary key-value data (max 4 KB).
                customerName:
                  type: string
                  maxLength: 100
                  nullable: true
                customerEmail:
                  type: string
                  format: email
                  nullable: true
                customerPhone:
                  type: string
                  nullable: true
                  maxLength: 20
                referenceId:
                  type: string
                  maxLength: 100
                  nullable: true
                  description: Your internal identifier.
                collectAddress:
                  type: boolean
                  description: Collect a billing address on the checkout page.
      responses:
        '201':
          description: Payment link created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentLink'
        '400':
          description: Validation error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            API key lacks the `links:write` scope, or the project's payment-link
            limit (500) is reached.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      x-codeSamples:
        - lang: Shell
          label: curl
          source: |-
            curl -X POST https://api.paybridgenp.com/v1/payment-links \
              -H "Authorization: Bearer sk_test_your_key" \
              -H "Content-Type: application/json" \
              -d '{ "title": "Donation", "amount": 10000 }'
components:
  schemas:
    PaymentLink:
      type: object
      properties:
        id:
          type: string
          example: lnk_01j9x2k3m4n5p6q7r8s9t0u1v2
        livemode:
          type: boolean
          description: '`true` when created with a live key, `false` for sandbox.'
        mode:
          type: string
          enum:
            - sandbox
            - live
        title:
          type: string
          example: Donation
          description: Shown on the payment page.
        description:
          type: string
          nullable: true
        amount:
          type: integer
          nullable: true
          description: >-
            Fixed amount in paisa. `null` when the customer enters their own
            amount (see `minAmount`/`maxAmount`).
          example: 10000
        minAmount:
          type: integer
          nullable: true
          description: >-
            Minimum customer-entered amount in paisa (only when `amount` is
            null).
        maxAmount:
          type: integer
          nullable: true
          description: >-
            Maximum customer-entered amount in paisa (only when `amount` is
            null).
        currency:
          type: string
          example: NPR
        provider:
          type: string
          enum:
            - esewa
            - khalti
            - fonepay
          nullable: true
          description: Locked provider, or `null` if the customer picks.
        active:
          type: boolean
        maxUses:
          type: integer
          nullable: true
          description: Usage cap, or `null` for unlimited.
        usedCount:
          type: integer
          description: Number of completed payments through this link.
          example: 0
        expiresAt:
          type: string
          format: date-time
          nullable: true
        redirectUrl:
          type: string
          format: uri
          nullable: true
          description: Where the customer is sent after a successful payment.
        inactiveMessage:
          type: string
          nullable: true
          description: Shown when the link is not usable.
        customerName:
          type: string
          nullable: true
          description: Pre-filled on the checkout page.
        customerEmail:
          type: string
          nullable: true
        customerPhone:
          type: string
          nullable: true
        collectAddress:
          type: boolean
        customerLine1:
          type: string
          nullable: true
        customerLine2:
          type: string
          nullable: true
        customerCity:
          type: string
          nullable: true
        customerState:
          type: string
          nullable: true
        customerPostalCode:
          type: string
          nullable: true
        customerCountry:
          type: string
          nullable: true
        referenceId:
          type: string
          nullable: true
          description: Your internal identifier for this link.
        metadata:
          type: object
          nullable: true
          additionalProperties: true
        url:
          type: string
          format: uri
          description: Public hosted payment page for this link.
          example: https://paybridgenp.com/pay/lnk_01j9x2k3m4n5p6q7r8s9t0u1v2
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    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
            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
  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.

````