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

# Payment links

> Create, list, update, and quote payment links via REST.

Payment links are fixed or open-amount checkout URLs scoped to your business and TEST or LIVE environment.

Base path: `/api/v1/merchant/links`

## Endpoints

| Method  | Path                           | Description                    |
| ------- | ------------------------------ | ------------------------------ |
| `GET`   | `/links`                       | List links with filters        |
| `GET`   | `/links/:id`                   | Get one link                   |
| `POST`  | `/links`                       | Create link                    |
| `PATCH` | `/links/:id`                   | Update link                    |
| `GET`   | `/links/:id/checkout-sessions` | Checkout sessions and payments |
| `POST`  | `/links/:id/quote`             | Fiat clearing quote for a link |

## List links

`GET /api/v1/merchant/links`

| Query           | Type    | Description          |
| --------------- | ------- | -------------------- |
| `page`, `limit` | number  | Pagination           |
| `q`             | string  | Search title or slug |
| `productId`     | uuid    | Filter by product    |
| `active`        | boolean | `true` or `false`    |
| `amountType`    | string  | `fixed` or `open`    |

<RequestExample>
  ```bash cURL theme={null}
  curl -s "https://api.morapay.io/api/v1/merchant/links?page=1&limit=20&active=true" \
    -H "Morapay-Key: $MORAPAY_PUBLIC_KEY" \
    -H "Morapay-Timestamp: $TIMESTAMP" \
    -H "Morapay-Signature: v1=$SIGNATURE"
  ```
</RequestExample>

<ResponseExample>
  <CodeGroup>
    ```json 200 OK theme={null}
    {
      "success": true,
      "data": [
        {
          "id": "link_uuid",
          "title": "Invoice #42",
          "amount": 100,
          "currency": "USD",
          "publicCode": "abc123xyz",
          "slug": "invoice-42",
          "isActive": true,
          "isOneTime": false,
          "paidAt": null
        }
      ],
      "meta": { "page": 1, "limit": 20, "total": 1 }
    }
    ```

    ```json 401 Unauthorized theme={null}
    {
      "success": false,
      "error": "Invalid request signature.",
      "code": "auth.signature.mismatch",
      "requestId": "req_links401"
    }
    ```
  </CodeGroup>
</ResponseExample>

## Get link

`GET /api/v1/merchant/links/:id`

<RequestExample>
  ```bash cURL theme={null}
  curl -s "https://api.morapay.io/api/v1/merchant/links/link_uuid" \
    -H "Morapay-Key: $MORAPAY_PUBLIC_KEY" \
    -H "Morapay-Timestamp: $TIMESTAMP" \
    -H "Morapay-Signature: v1=$SIGNATURE"
  ```
</RequestExample>

<ResponseExample>
  <CodeGroup>
    ```json 200 OK theme={null}
    {
      "success": true,
      "data": {
        "id": "link_uuid",
        "title": "Invoice #42",
        "amount": 100,
        "currency": "USD",
        "publicCode": "abc123xyz",
        "isActive": true,
        "paidAt": null
      }
    }
    ```

    ```json 404 Not Found theme={null}
    {
      "success": false,
      "error": "Payment link not found.",
      "code": "resource.not_found",
      "requestId": "req_link404"
    }
    ```
  </CodeGroup>
</ResponseExample>

## Create link

`POST /api/v1/merchant/links`

| Field                   | Type    | Required | Description                        |
| ----------------------- | ------- | -------- | ---------------------------------- |
| `title`                 | string  | Yes      | Display title                      |
| `amount`                | number  | No       | Fixed amount; omit for open amount |
| `currency`              | string  | No       | Default `USD`                      |
| `description`           | string  | No       | Optional subtitle                  |
| `slug`                  | string  | No       | Custom URL slug; must be unique    |
| `productId`             | uuid    | No       | Attach catalog product             |
| `isOneTime`             | boolean | No       | Deactivate after first payment     |
| `isActive`              | boolean | No       | Default `true`                     |
| `gasSponsorshipEnabled` | boolean | No       | Sponsor payer gas when supported   |
| `metadata`              | object  | No       | Arbitrary key-value metadata       |

<RequestExample>
  ```bash cURL theme={null}
  curl -s -X POST "https://api.morapay.io/api/v1/merchant/links" \
    -H "Content-Type: application/json" \
    -H "Morapay-Key: $MORAPAY_PUBLIC_KEY" \
    -H "Morapay-Timestamp: $TIMESTAMP" \
    -H "Morapay-Signature: v1=$SIGNATURE" \
    -d '{
      "title": "Invoice #42",
      "amount": 100,
      "currency": "USD",
      "isOneTime": false
    }'
  ```
</RequestExample>

<ResponseExample>
  <CodeGroup>
    ```json 201 Created theme={null}
    {
      "success": true,
      "data": {
        "id": "link_uuid",
        "title": "Invoice #42",
        "amount": 100,
        "currency": "USD",
        "publicCode": "abc123xyz",
        "checkoutUrl": "https://checkout.morapay.io/abc123xyz"
      }
    }
    ```

    ```json 400 Bad Request theme={null}
    {
      "success": false,
      "error": "Amount is below the platform minimum.",
      "code": "links.amount.below_minimum",
      "displayMessage": "The transaction amount must be at least $1.00.",
      "requestId": "req_min"
    }
    ```

    ```json 403 Forbidden theme={null}
    {
      "success": false,
      "error": "Complete KYB before creating LIVE payment links.",
      "code": "kyb.forbidden",
      "requestId": "req_kyb403"
    }
    ```

    ```json 409 Conflict theme={null}
    {
      "success": false,
      "error": "Slug already in use.",
      "code": "links.slug.duplicate",
      "requestId": "req_slug"
    }
    ```
  </CodeGroup>
</ResponseExample>

## Update link

`PATCH /api/v1/merchant/links/:id`

Send only fields to change: `title`, `description`, `amount`, `currency`, `isActive`, `isOneTime`, `metadata`, and others supported by the API.

<RequestExample>
  ```bash cURL theme={null}
  curl -s -X PATCH "https://api.morapay.io/api/v1/merchant/links/link_uuid" \
    -H "Content-Type: application/json" \
    -H "Morapay-Key: $MORAPAY_PUBLIC_KEY" \
    -H "Morapay-Timestamp: $TIMESTAMP" \
    -H "Morapay-Signature: v1=$SIGNATURE" \
    -d '{ "isActive": false }'
  ```
</RequestExample>

<ResponseExample>
  <CodeGroup>
    ```json 200 OK theme={null}
    {
      "success": true,
      "data": {
        "id": "link_uuid",
        "isActive": false
      }
    }
    ```

    ```json 404 Not Found theme={null}
    {
      "success": false,
      "error": "Payment link not found.",
      "code": "resource.not_found",
      "requestId": "req_patch404"
    }
    ```
  </CodeGroup>
</ResponseExample>

## Link quote

`POST /api/v1/merchant/links/:id/quote`

Body optional: `{ "invoice_major": 100 }` for fiat invoice amount in major units.

<RequestExample>
  ```bash cURL theme={null}
  curl -s -X POST "https://api.morapay.io/api/v1/merchant/links/link_uuid/quote" \
    -H "Content-Type: application/json" \
    -H "Morapay-Key: $MORAPAY_PUBLIC_KEY" \
    -H "Morapay-Timestamp: $TIMESTAMP" \
    -H "Morapay-Signature: v1=$SIGNATURE" \
    -d '{ "invoice_major": 100 }'
  ```
</RequestExample>

<ResponseExample>
  <CodeGroup>
    ```json 200 OK theme={null}
    {
      "success": true,
      "data": {
        "merchantClearingUsd": "98.50",
        "invoiceMajor": 100,
        "currency": "GHS"
      }
    }
    ```

    ```json 422 Unprocessable Entity theme={null}
    {
      "success": false,
      "error": "Link does not support fiat settlement quote.",
      "code": "request.validation_failed",
      "requestId": "req_quote422"
    }
    ```
  </CodeGroup>
</ResponseExample>

## Checkout sessions

`GET /api/v1/merchant/links/:id/checkout-sessions?limit=20`

<RequestExample>
  ```bash cURL theme={null}
  curl -s "https://api.morapay.io/api/v1/merchant/links/link_uuid/checkout-sessions?limit=20" \
    -H "Morapay-Key: $MORAPAY_PUBLIC_KEY" \
    -H "Morapay-Timestamp: $TIMESTAMP" \
    -H "Morapay-Signature: v1=$SIGNATURE"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "success": true,
    "data": {
      "items": [
        {
          "id": "session_uuid",
          "status": "COMPLETED",
          "transactionId": "txn_uuid",
          "createdAt": "2026-03-01T12:00:00.000Z"
        }
      ]
    }
  }
  ```
</ResponseExample>

## Common errors

| Code                         | HTTP      | Cause                                   |
| ---------------------------- | --------- | --------------------------------------- |
| `links.amount.below_minimum` | 400 / 422 | Amount under platform or corridor floor |
| `links.slug.duplicate`       | 409       | Custom slug taken                       |
| `kyb.forbidden`              | 403       | LIVE create blocked until KYB approved  |
| `auth.signature.mismatch`    | 401       | Signing mistake                         |
| `resource.not_found`         | 404       | Wrong link id                           |

See [Conventions](/api-reference/conventions) for the full error envelope.

## Related

* [Products API](/api-reference/products)
* [Fiat checkout API](/api-reference/fiat-checkout)
* [Payment links concept](/concepts/payment-links)
