PayLinkr

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

  1. Go to Settings in your dashboard.
  2. Click Generate API Key.
  3. Copy and store the key securely — it is shown only once.
Keep your API key secret. Do not expose it in client-side code or public repositories. Rotate the key immediately if you believe it has been compromised.

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

POST/api/v1/invoices

Create a new payment link invoice.

Request body

FieldTypeRequiredDescription
titlestringYesDisplay name for the invoice
amountstring | numberYes*Fixed crypto amount (e.g. "50.00"). Omit when allowCustomAmount is true or when using pricingCurrency + pricingAmount.
asset"USDC" | "XLM" | "XRP"NoSettlement asset. Defaults to "USDC".
pricingCurrency"USD" | "EUR" | "GBP"NoOptional fiat pricing currency for live auto-convert quotes.
pricingAmountstring | numberNoRequired when pricingCurrency is set.
allowCustomAmountbooleanNoIf true, the payer can enter any amount. Default false.
orderIdstringNoYour internal reference ID.
expiresIn"never" | "30min" | "1h" | "24h" | "7d"NoInvoice 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/a1b2c3d4

Response

{
  "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"
}
GET/api/v1/invoices/:id

Retrieve 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"
}
GET/api/v1/invoices

List your invoices with optional pagination and status filtering.

Query parameters

ParamDefaultDescription
page1Page number (1-indexed)
limit20Results 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
}
POST/api/v1/invoices/:id/notify
POST/api/v1/invoices/:id/remind
POST/api/v1/invoices/:id/settle
POST/api/v1/invoices/:id/expire

Use 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

POST/api/v1/recurring-plans
GET/api/v1/recurring-plans
GET/api/v1/recurring-plans/:id
PATCH/api/v1/recurring-plans/:id

Create 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

POST/api/v1/subscription-packages
GET/api/v1/subscription-packages
GET/api/v1/subscription-packages/:id
PATCH/api/v1/subscription-packages/:id

Subscription 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

POST/api/v1/subscriptions
GET/api/v1/subscriptions
PATCH/api/v1/subscriptions/:id
GET/api/v1/subscriptions/webhook-logs

Use 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

GET/api/v1/webhooks
PATCH/api/v1/webhooks
POST/api/v1/webhooks/test
GET/api/v1/webhooks/logs

Manage 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

GET/api/v1/requests/logs

Inspect 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 statusMeaning
400 Bad RequestMissing or invalid request parameters.
401 UnauthorizedAPI key is missing, invalid, or belongs to a non-Pro account.
403 ForbiddenThe API key does not include the required scope or account capability.
404 Not FoundThe requested invoice, package, or subscription does not exist.
429 Too Many RequestsRate limit exceeded. Slow down and retry after the Retry-After header.
409 ConflictIdempotency key already used with a different body, or another matching request is still in progress.
422 Unprocessable EntityValidation failed.
500 Internal Server ErrorUnexpected server error. Contact support if it persists.

All error responses follow the shape: { "error": "Human-readable message" }

Pro tip: Combine the API with webhooks— create an invoice via the API, then let webhooks notify your system when it's paid.