/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 |
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"
200 OK
{
"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 }
}
401 Unauthorized
{
"success": false,
"error": "Invalid request signature.",
"code": "auth.signature.mismatch",
"requestId": "req_links401"
}
Get link
GET /api/v1/merchant/links/:id
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"
200 OK
{
"success": true,
"data": {
"id": "link_uuid",
"title": "Invoice #42",
"amount": 100,
"currency": "USD",
"publicCode": "abc123xyz",
"isActive": true,
"paidAt": null
}
}
404 Not Found
{
"success": false,
"error": "Payment link not found.",
"code": "resource.not_found",
"requestId": "req_link404"
}
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 |
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
}'
201 Created
{
"success": true,
"data": {
"id": "link_uuid",
"title": "Invoice #42",
"amount": 100,
"currency": "USD",
"publicCode": "abc123xyz",
"checkoutUrl": "https://checkout.morapay.io/abc123xyz"
}
}
400 Bad Request
{
"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"
}
403 Forbidden
{
"success": false,
"error": "Complete KYB before creating LIVE payment links.",
"code": "kyb.forbidden",
"requestId": "req_kyb403"
}
409 Conflict
{
"success": false,
"error": "Slug already in use.",
"code": "links.slug.duplicate",
"requestId": "req_slug"
}
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.
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 }'
200 OK
{
"success": true,
"data": {
"id": "link_uuid",
"isActive": false
}
}
404 Not Found
{
"success": false,
"error": "Payment link not found.",
"code": "resource.not_found",
"requestId": "req_patch404"
}
Link quote
POST /api/v1/merchant/links/:id/quote
Body optional: { "invoice_major": 100 } for fiat invoice amount in major units.
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 }'
200 OK
{
"success": true,
"data": {
"merchantClearingUsd": "98.50",
"invoiceMajor": 100,
"currency": "GHS"
}
}
422 Unprocessable Entity
{
"success": false,
"error": "Link does not support fiat settlement quote.",
"code": "request.validation_failed",
"requestId": "req_quote422"
}
Checkout sessions
GET /api/v1/merchant/links/:id/checkout-sessions?limit=20
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"
{
"success": true,
"data": {
"items": [
{
"id": "session_uuid",
"status": "COMPLETED",
"transactionId": "txn_uuid",
"createdAt": "2026-03-01T12:00:00.000Z"
}
]
}
}
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 |

