API Reference
Manage invoices, subscription packages, and customer billing flows programmatically with the PayLinkr REST API. API access requires a Pro subscription.
01 Authentication
All API requests must include your API key as a Bearer token in the Authorization header.
Generating an API key
- Go to Settings in your dashboard.
- Click Generate API Key.
- Copy and store the key securely — it is shown only once.
API keys can also be limited to per-key scopes such as `invoices:read`, `invoices:write`, `subscription_packages:read`, `subscription_packages:write`, `subscriptions:read`, `subscriptions:write`, `recurring_plans:write`, `webhooks:read`, or `api_logs:read`. If a key is missing the required scope, the API returns `403`.
Every PRO API response also includes an X-Request-Id header so you can correlate client-side failures with PayLinkr request logs.
API keys are also restricted to the allowed origins set when the key is created. Browser apps usually sendOrigin automatically. For server-side integrations, send an explicit X-Api-Origin header that matches the key's approved origin.
# All requests use this header: Authorization: Bearer plr_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
02 Base URL
https://your-paylinkr-domain.com/api/v1
Replace your-paylinkr-domain.com with your self-hosted instance domain or the hosted URL you were given.
03 OpenAPI and SDK
PayLinkr exposes a machine-readable OpenAPI document at /api/openapi. You can use that spec to generate your own SDKs or import the API into the tooling your team already uses.
curl https://your-paylinkr-domain.com/api/openapi curl -OJ https://your-paylinkr-domain.com/api/postman/collection
The Postman download includes `baseUrl`, `apiKey`, and `apiOrigin` variables so developers can import and test quickly. If you prefer typed clients, use the OpenAPI document to generate an SDK in the language or framework your team prefers.
04 Idempotency
`POST /api/v1/invoices`, `POST /api/v1/recurring-plans`, `POST /api/v1/subscription-packages`, and `POST /api/v1/subscriptions` support the Idempotency-Key header. Replaying the same request body with the same key returns the original response instead of creating a duplicate resource.
curl -X POST https://your-paylinkr-domain.com/api/v1/invoices \
-H "Authorization: Bearer plr_live_xxxx" \
-H "Idempotency-Key: inv_01hzyouruniqueclientkey" \
-H "Content-Type: application/json" \
-d '{ "title": "Consulting Deposit", "amount": "250.00", "asset": "USDC" }'If the same key is reused with a different request body, the API returns `409 Conflict`.
05 Rate Limits
The PRO API is rate limited per API key. Responses include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. If you exceed the limit, the API returns `429` with a Retry-After header.
05 Endpoints
/api/v1/invoicesCreate a new payment link invoice.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Display name for the invoice |
| amount | string | number | Yes* | Fixed crypto amount (e.g. "50.00"). Omit when allowCustomAmount is true or when using pricingCurrency + pricingAmount. |
| asset | "USDC" | "XLM" | "XRP" | No | Settlement asset. Defaults to "USDC". |
| pricingCurrency | "USD" | "EUR" | "GBP" | No | Optional fiat pricing currency for live auto-convert quotes. |
| pricingAmount | string | number | No | Required when pricingCurrency is set. |
| allowCustomAmount | boolean | No | If true, the payer can enter any amount. Default false. |
| orderId | string | No | Your internal reference ID. |
| expiresIn | "never" | "30min" | "1h" | "24h" | "7d" | No | Invoice expiry window. Defaults to "24h". |
curl
curl -X POST https://your-paylinkr-domain.com/api/v1/invoices \
-H "Authorization: Bearer plr_live_xxxx" \
-H "Content-Type: application/json" \
-d '{
"title": "Consulting Deposit",
"amount": "250.00",
"asset": "USDC",
"orderId": "ORD-9001",
"expiresIn": "24h"
}'JavaScript / TypeScript
const res = await fetch('https://your-paylinkr-domain.com/api/v1/invoices', {
method: 'POST',
headers: {
'Authorization': 'Bearer plr_live_xxxx',
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'Consulting Deposit',
amount: '250.00',
asset: 'USDC',
orderId: 'ORD-9001',
expiresIn: '24h',
}),
})
const invoice = await res.json()
console.log(invoice.payUrl) // https://your-domain.com/pay/a1b2c3d4Response
{
"id": "clxxxxxxxxxxxxx",
"publicId": "a1b2c3d4e5f6g7h8",
"title": "Consulting Deposit",
"status": "unpaid",
"paymentNetwork": "STELLAR",
"expectedAmount": "250.00",
"receivedAmount": "0",
"asset": "USDC",
"memo": "PLR-A1B2C3D4",
"reference": "PLR-A1B2C3D4",
"referenceLabel": "Memo",
"destinationAddress": "G...",
"orderId": "ORD-9001",
"payUrl": "https://your-paylinkr-domain.com/pay/a1b2c3d4e5f6g7h8",
"createdAt": "2024-01-15T10:00:00.000Z",
"expiresAt": "2024-01-16T10:00:00.000Z"
}/api/v1/invoices/:idRetrieve a single invoice by its internal ID or public ID.
curl
curl https://your-paylinkr-domain.com/api/v1/invoices/clxxxxxxxxxxxxx \ -H "Authorization: Bearer plr_live_xxxx"
Response
{
"id": "clxxxxxxxxxxxxx",
"publicId": "a1b2c3d4e5f6g7h8",
"title": "Consulting Deposit",
"status": "paid",
"paymentNetwork": "STELLAR",
"expectedAmount": "250.00",
"receivedAmount": "250.00",
"asset": "USDC",
"memo": "PLR-A1B2C3D4",
"reference": "PLR-A1B2C3D4",
"referenceLabel": "Memo",
"destinationAddress": "G...",
"orderId": "ORD-9001",
"payUrl": "https://your-paylinkr-domain.com/pay/a1b2c3d4e5f6g7h8",
"createdAt": "2024-01-15T10:00:00.000Z",
"paidAt": "2024-01-15T10:05:32.000Z",
"expiresAt": "2024-01-16T10:00:00.000Z"
}/api/v1/invoicesList your invoices with optional pagination and status filtering.
Query parameters
| Param | Default | Description |
|---|---|---|
| page | 1 | Page number (1-indexed) |
| limit | 20 | Results per page (max 100) |
| status | (all) | Filter by status: unpaid, pending, paid, expired, … |
curl "https://your-paylinkr-domain.com/api/v1/invoices?page=1&limit=10&status=paid" \
-H "Authorization: Bearer plr_live_xxxx"
# Response
{
"data": [ /* array of invoice objects */ ],
"total": 42,
"page": 1,
"limit": 10,
"pages": 5
}/api/v1/invoices/:id/notify/api/v1/invoices/:id/remind/api/v1/invoices/:id/settle/api/v1/invoices/:id/expireUse invoice action endpoints to resend the initial payment request, send a manual reminder, mark a partially paid invoice as accepted, or expire an open invoice from your own system.
curl -X POST https://your-paylinkr-domain.com/api/v1/invoices/a1b2c3d4e5f6g7h8/notify \
-H "Authorization: Bearer plr_live_xxxx" \
-H "Content-Type: application/json" \
-d '{"channel":"EMAIL"}'
curl -X POST https://your-paylinkr-domain.com/api/v1/invoices/a1b2c3d4e5f6g7h8/remind \
-H "Authorization: Bearer plr_live_xxxx"
curl -X POST https://your-paylinkr-domain.com/api/v1/invoices/a1b2c3d4e5f6g7h8/settle \
-H "Authorization: Bearer plr_live_xxxx"
curl -X POST https://your-paylinkr-domain.com/api/v1/invoices/a1b2c3d4e5f6g7h8/expire \
-H "Authorization: Bearer plr_live_xxxx"06 Recurring Plans
/api/v1/recurring-plans/api/v1/recurring-plans/api/v1/recurring-plans/:id/api/v1/recurring-plans/:idCreate and manage merchant subscription schedules. The worker will generate cycle invoices automatically using the same recurring engine as the dashboard.
curl -X POST https://your-paylinkr-domain.com/api/v1/recurring-plans \
-H "Authorization: Bearer plr_live_xxxx" \
-H "Content-Type: application/json" \
-d '{
"title": "Monthly Support Retainer",
"asset": "USDC",
"expectedAmount": "250.00",
"interval": "MONTHLY",
"invoiceExpiresIn": "7d",
"clientEmail": "client@example.com",
"startsAt": "2026-04-15T09:00:00.000Z",
"autoRemindersEnabled": true,
"reminderPreset": "STANDARD"
}'
curl https://your-paylinkr-domain.com/api/v1/recurring-plans \
-H "Authorization: Bearer plr_live_xxxx"
curl -X PATCH https://your-paylinkr-domain.com/api/v1/recurring-plans/clxxxxxxxxxxxxx \
-H "Authorization: Bearer plr_live_xxxx" \
-H "Content-Type: application/json" \
-d '{"active":false}'07 Subscription Packages
/api/v1/subscription-packages/api/v1/subscription-packages/api/v1/subscription-packages/:id/api/v1/subscription-packages/:idSubscription packages are reusable billing products. Create one package, then onboard customers through a hosted page, JavaScript widget, iframe embed, or direct API call.
curl -X POST https://your-paylinkr-domain.com/api/v1/subscription-packages \
-H "Authorization: Bearer plr_live_xxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Pro Support",
"slug": "pro-support",
"description": "Monthly support and account reviews",
"asset": "USDC",
"amount": "99.00",
"interval": "MONTHLY",
"trialDays": 14,
"widgetButtonLabel": "Start subscription"
}'
curl https://your-paylinkr-domain.com/api/v1/subscription-packages \
-H "Authorization: Bearer plr_live_xxxx"
curl -X PATCH https://your-paylinkr-domain.com/api/v1/subscription-packages/pro-support \
-H "Authorization: Bearer plr_live_xxxx" \
-H "Content-Type: application/json" \
-d '{"active":false}'08 Subscriptions
/api/v1/subscriptions/api/v1/subscriptions/api/v1/subscriptions/:id/api/v1/subscriptions/webhook-logsUse subscriptions to enroll a customer into a package, optionally create the first invoice immediately, and later pause, resume, or cancel that relationship.
curl -X POST https://your-paylinkr-domain.com/api/v1/subscriptions \
-H "Authorization: Bearer plr_live_xxxx" \
-H "Content-Type: application/json" \
-d '{
"packageId": "cm9pkgxxxxxxxxxxxx",
"customerEmail": "buyer@example.com",
"customerName": "Alex Buyer",
"externalCustomerRef": "cust_2048",
"startImmediately": true
}'
curl https://your-paylinkr-domain.com/api/v1/subscriptions \
-H "Authorization: Bearer plr_live_xxxx"
curl https://your-paylinkr-domain.com/api/v1/subscriptions/webhook-logs?limit=10 \
-H "Authorization: Bearer plr_live_xxxx"
curl -X PATCH https://your-paylinkr-domain.com/api/v1/subscriptions/cusub_xxxxxxxxxxxx \
-H "Authorization: Bearer plr_live_xxxx" \
-H "Content-Type: application/json" \
-d '{"action":"pause"}'09 Widget Embed
Every active subscription package can be embedded directly on your site. The recommended option is the PayLinkr widget loader, which mounts an iframe for each package container you place on the page.
JavaScript widget
<script src="https://your-paylinkr-domain.com/widget/subscription.js" async></script> <div data-paylinkr-package="subpkg_xxxxxxxxxxxx" data-paylinkr-width="420" data-paylinkr-height="520" ></div>
Iframe fallback
<iframe src="https://your-paylinkr-domain.com/embed/subscription/subpkg_xxxxxxxxxxxx" width="420" height="520" frameborder="0" style="border:none;border-radius:16px;overflow:hidden;" title="Subscribe with PayLinkr" ></iframe>
10 Webhooks
/api/v1/webhooks/api/v1/webhooks/api/v1/webhooks/test/api/v1/webhooks/logsManage your merchant webhook destination, rotate the signing secret, send a test event, and inspect recent delivery attempts from code.
curl https://your-paylinkr-domain.com/api/v1/webhooks \
-H "Authorization: Bearer plr_live_xxxx"
curl -X PATCH https://your-paylinkr-domain.com/api/v1/webhooks \
-H "Authorization: Bearer plr_live_xxxx" \
-H "Content-Type: application/json" \
-d '{
"webhookUrl": "https://example.com/paylinkr/webhooks",
"regenerateSecret": false
}'
curl -X POST https://your-paylinkr-domain.com/api/v1/webhooks/test \
-H "Authorization: Bearer plr_live_xxxx"
curl https://your-paylinkr-domain.com/api/v1/webhooks/logs?limit=25 \
-H "Authorization: Bearer plr_live_xxxx"11 API Logs
/api/v1/requests/logsInspect recent authenticated API requests, including request IDs, status codes, durations, idempotency keys, and which API key made the call.
curl https://your-paylinkr-domain.com/api/v1/requests/logs?limit=25 \ -H "Authorization: Bearer plr_live_xxxx" curl "https://your-paylinkr-domain.com/api/v1/requests/logs?requestId=4f9cb77a-2a1b-4e3d-a2a4-7fdc6e9b6d2f" \ -H "Authorization: Bearer plr_live_xxxx" curl "https://your-paylinkr-domain.com/api/v1/requests/logs?method=POST&statusCode=422" \ -H "Authorization: Bearer plr_live_xxxx"
12 Error codes
| HTTP status | Meaning |
|---|---|
| 400 Bad Request | Missing or invalid request parameters. |
| 401 Unauthorized | API key is missing, invalid, or belongs to a non-Pro account. |
| 403 Forbidden | The API key does not include the required scope or account capability. |
| 404 Not Found | The requested invoice, package, or subscription does not exist. |
| 429 Too Many Requests | Rate limit exceeded. Slow down and retry after the Retry-After header. |
| 409 Conflict | Idempotency key already used with a different body, or another matching request is still in progress. |
| 422 Unprocessable Entity | Validation failed. |
| 500 Internal Server Error | Unexpected server error. Contact support if it persists. |
All error responses follow the shape: { "error": "Human-readable message" }