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

# Create a Payment Link

> Create a hosted payment link and return the URL to share with customers

<Info>
  Returns a `201 Created` with the full payment link object wrapped in `data`. Share the returned `hosted_url` with your customer to collect payment.
</Info>

## Idempotency

This endpoint requires an `Idempotency-Key` header — a unique client-generated identifier (letters, digits, dot, hyphen, underscore; 8–64 characters, e.g. your own order ID). Reusing the same key with an identical body returns the original response without creating a duplicate. Reusing it with a different body returns `409 idempotency_mismatch`. Keys expire after 24 hours.

## Amount validation

The `amount` must equal the sum of every line item (`unit_price × quantity`). For the example below, `75000 × 2 = 150000`.

<Note>
  `merchant_branch_reference_number` is required when your API key is scoped to a **partner** or **merchant**. Branch-scoped keys can omit it — the link is created against that branch automatically.
</Note>

## Required scope

`payment_links.create`


## OpenAPI

````yaml api-reference/ecom/openapi.json POST /checkout
openapi: 3.0.3
info:
  title: Ecom API
  description: >-
    REST API for creating and managing hosted payment links (checkout). Generate
    a shareable, hosted checkout URL, accept one-time or multi-use payments, and
    reconcile results through webhooks.


    **Entity scoping:** Every API key is scoped to an entity in the organization
    hierarchy (Partner → Merchant → Branch). Data access is automatically
    restricted to the key's level.


    **Amounts:** All monetary values are integers in the smallest currency unit
    (centavos for PHP). `150000` represents PHP 1,500.00.


    **Idempotency:** Mutating `POST` requests require an `Idempotency-Key`
    header to safely retry without creating duplicates.
  version: 1.0.0
  contact:
    name: API Support
    email: support@moduluslabs.io
  license:
    name: Proprietary
servers:
  - url: https://api.sbx.moduluslabs.io/ecom/v1
    description: Sandbox
security:
  - BearerAuth: []
tags:
  - name: Payment Links
    description: Create and manage hosted payment links
paths:
  /checkout:
    post:
      tags:
        - Payment Links
      summary: Create a payment link
      description: >-
        Creates a new payment link and returns the hosted URL to share with
        customers.


        Requires the `payment_links.create` scope. The `amount` must equal the
        sum of all line items (`unit_price × quantity`).
      operationId: createPaymentLink
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePaymentLinkRequest'
            example:
              merchant_branch_reference_number: SH-ANG-001
              type: multi_use
              currency: PHP
              amount: 150000
              line_items:
                - sku: PROD-001
                  name: Wireless Earbuds
                  unit_price: 75000
                  quantity: 2
                  metadata:
                    color: black
              description: Order for wireless earbuds
              order_reference: ORD-2026-0618-001
              redirect_urls:
                success: https://merchant.com/payment/success
                declined: https://merchant.com/payment/declined
                expired: https://merchant.com/payment/expired
              expires_at: '2026-07-18T00:00:00Z'
              max_uses: 10
              metadata:
                campaign_id: summer-2026
                internal_ref: CRM-4821
      responses:
        '201':
          description: Payment link created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentLinkResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      description: >-
        Unique client-generated identifier to prevent duplicate operations.
        Allowed characters: letters, digits, dot (`.`), hyphen (`-`), and
        underscore (`_`); 8–64 characters — e.g. your own order ID. Reusing the
        same key with an identical body returns the original response; reusing
        it with a different body returns `409 idempotency_mismatch`. Keys expire
        after 24 hours.
      schema:
        type: string
        pattern: ^[A-Za-z0-9._-]{8,64}$
  schemas:
    CreatePaymentLinkRequest:
      type: object
      required:
        - type
        - currency
        - amount
        - line_items
        - expires_at
      properties:
        type:
          $ref: '#/components/schemas/PaymentLinkType'
        merchant_branch_reference_number:
          type: string
          description: >-
            Required if your API key is scoped to a partner or merchant. Not
            required for branch-scoped keys.
          example: SH-ANG-001
        currency:
          type: string
          description: 'ISO 4217 currency code. Currently supported: `PHP`.'
          example: PHP
        amount:
          type: integer
          format: int64
          minimum: 1
          description: >-
            Total amount in the smallest currency unit. Must equal the sum of
            all line items (`unit_price × quantity`).
          example: 150000
        line_items:
          type: array
          minItems: 1
          maxItems: 100
          description: 1 to 100 line items.
          items:
            $ref: '#/components/schemas/LineItem'
        expires_at:
          type: string
          format: date-time
          description: ISO 8601 timestamp. Must be in the future.
          example: '2026-07-18T00:00:00Z'
        max_uses:
          type: integer
          nullable: true
          minimum: 2
          description: >-
            For `multi_use` only. Omit or set to `null` for unlimited. Must be
            greater than 1. Ignored for `one_time` links.
          example: 10
        description:
          type: string
          description: Free-form text displayed to the customer on the checkout page.
          example: Order for wireless earbuds
        order_reference:
          type: string
          maxLength: 100
          description: Your internal order identifier.
          example: ORD-2026-0618-001
        redirect_urls:
          $ref: '#/components/schemas/RedirectUrls'
        metadata:
          type: object
          description: >-
            Key-value pairs for your own use. Max 50 keys, key max 40
            characters, value max 500 characters.
          additionalProperties:
            type: string
    PaymentLinkResponse:
      type: object
      required:
        - data
      properties:
        data:
          $ref: '#/components/schemas/PaymentLink'
    PaymentLinkType:
      type: string
      description: >-
        `one_time` accepts exactly one successful payment then becomes
        `CONSUMED`. `multi_use` accepts multiple payments, optionally up to
        `max_uses`.
      enum:
        - one_time
        - multi_use
    LineItem:
      type: object
      required:
        - sku
        - name
        - unit_price
        - quantity
      properties:
        sku:
          type: string
          description: Merchant-defined SKU or product identifier.
          example: PROD-001
        name:
          type: string
          description: Product name displayed to the customer.
          example: Wireless Earbuds
        unit_price:
          type: integer
          format: int64
          minimum: 1
          description: >-
            Price per unit in the smallest currency unit. Must be greater than
            0.
          example: 75000
        quantity:
          type: integer
          minimum: 1
          description: Number of units. Must be greater than 0.
          example: 2
        metadata:
          type: object
          description: Optional key-value pairs for this line item.
          additionalProperties:
            type: string
    RedirectUrls:
      type: object
      description: URLs to redirect the customer after payment. Each URL must use HTTPS.
      properties:
        success:
          type: string
          format: uri
          description: URL to redirect after a successful payment.
          example: https://merchant.com/payment/success
        declined:
          type: string
          format: uri
          description: URL to redirect after a declined payment.
          example: https://merchant.com/payment/declined
        expired:
          type: string
          format: uri
          description: URL to redirect when the payment link has expired.
          example: https://merchant.com/payment/expired
    PaymentLink:
      type: object
      description: The payment link object returned by all endpoints.
      required:
        - id
        - type
        - merchant_branch_reference_number
        - merchant_branch_name
        - currency
        - amount
        - line_items
        - status
        - expires_at
        - hosted_url
        - successful_payment_count
        - metadata
        - created_at
        - updated_at
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier (UUID v4). Use this in API paths and for tracking.
          example: 550e8400-e29b-41d4-a716-446655440000
        type:
          $ref: '#/components/schemas/PaymentLinkType'
        merchant_branch_reference_number:
          type: string
          description: Reference number of the branch this link belongs to.
          example: SH-ANG-001
        merchant_branch_name:
          type: string
          description: Display name of the branch. Read-only.
          example: SM City Angeles - Branch 1
        currency:
          type: string
          description: ISO 4217 currency code.
          example: PHP
        amount:
          type: integer
          format: int64
          description: >-
            Payment amount in the smallest currency unit (centavos for PHP).
            `150000` = PHP 1,500.00.
          example: 150000
        line_items:
          type: array
          description: Items the customer is paying for.
          items:
            $ref: '#/components/schemas/LineItem'
        description:
          type: string
          nullable: true
          description: Merchant-defined description displayed to the customer.
          example: Order for wireless earbuds
        order_reference:
          type: string
          nullable: true
          maxLength: 100
          description: Merchant's internal order reference for reconciliation.
          example: ORD-2026-0618-001
        redirect_urls:
          allOf:
            - $ref: '#/components/schemas/RedirectUrls'
          nullable: true
        status:
          $ref: '#/components/schemas/PaymentLinkStatus'
        expires_at:
          type: string
          format: date-time
          description: ISO 8601 timestamp. When the link stops accepting payments.
          example: '2026-07-18T00:00:00Z'
        hosted_url:
          type: string
          format: uri
          description: The URL to share with customers. Read-only.
          example: >-
            https://pay.moduluslabs.io/checkout/550e8400-e29b-41d4-a716-446655440000
        max_uses:
          type: integer
          nullable: true
          description: >-
            Maximum number of successful payments allowed. `null` = unlimited.
            Only applicable for `multi_use` links.
          example: 10
        successful_payment_count:
          type: integer
          description: Number of successful payments completed so far.
          example: 3
        metadata:
          type: object
          description: >-
            Merchant key-value pairs. Max 50 keys, key max 40 characters, value
            max 500 characters.
          additionalProperties:
            type: string
        created_at:
          type: string
          format: date-time
          description: ISO 8601 timestamp. When the link was created.
          example: '2026-06-18T10:30:00Z'
        updated_at:
          type: string
          format: date-time
          description: ISO 8601 timestamp. When the link was last modified.
          example: '2026-06-18T14:22:00Z'
        cancelled_at:
          type: string
          format: date-time
          nullable: true
          description: >-
            ISO 8601 timestamp. When the link was cancelled. `null` if not
            cancelled.
        cancellation_reason:
          type: string
          nullable: true
          maxLength: 500
          description: Reason for cancellation. `null` if not cancelled.
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Machine-readable error code.
              example: invalid_request
            message:
              type: string
              description: Human-readable explanation of the error.
              example: Amount must be greater than zero.
            correlationId:
              type: string
              format: uuid
              description: Unique request identifier. Include this in support requests.
              example: a084e7ab-e80e-4232-b6b7-280167765883
    PaymentLinkStatus:
      type: string
      description: Current status of the payment link.
      enum:
        - ACTIVE
        - CONSUMED
        - EXPIRED
        - CANCELLED
  responses:
    BadRequest:
      description: The request body or parameters failed validation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            invalid_request:
              summary: Validation failed
              value:
                error:
                  code: invalid_request
                  message: Amount must equal the sum of all line items.
                  correlationId: a084e7ab-e80e-4232-b6b7-280167765883
            idempotency_key_required:
              summary: Missing Idempotency-Key header
              value:
                error:
                  code: idempotency_key_required
                  message: The Idempotency-Key header is required for this request.
                  correlationId: a084e7ab-e80e-4232-b6b7-280167765883
    Unauthorized:
      description: The API key is missing, expired, revoked, or invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: invalid_api_key
              message: API key is missing or invalid.
              correlationId: a084e7ab-e80e-4232-b6b7-280167765883
    Forbidden:
      description: The API key does not have the required scope for this operation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: insufficient_permissions
              message: API key lacks the required scope for this operation.
              correlationId: a084e7ab-e80e-4232-b6b7-280167765883
    NotFound:
      description: The requested resource does not exist or is not accessible by your key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: not_found
              message: The requested payment link does not exist.
              correlationId: a084e7ab-e80e-4232-b6b7-280167765883
    Conflict:
      description: The same idempotency key was used with a different request body.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: idempotency_mismatch
              message: >-
                This idempotency key was already used with a different request
                body.
              correlationId: a084e7ab-e80e-4232-b6b7-280167765883
    RateLimited:
      description: >-
        Too many requests. Retry after the time indicated in the `Retry-After`
        header.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: rate_limited
              message: Rate limit exceeded. Retry after 23 seconds.
              correlationId: a084e7ab-e80e-4232-b6b7-280167765883
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: >-
        API key passed as a bearer token. Use `sk_live_` keys for production and
        `sk_test_` keys for sandbox. Keys are provisioned during merchant
        onboarding.

````