Skip to main content
See payment links for what a link is and how it behaves.

Merchant endpoints

Each call acts on the mode of the key or dashboard session that makes it.

Who can call

  • A secret key needs the payment_links:read scope to read and payment_links:write to create, change or archive.
  • In the dashboard, reading needs account:read and writing needs money:request. No step-up is needed.
  • Publishable keys and shopper sessions are refused.
  • POST honours the Idempotency-Key header, see idempotency.

Create

POST /v1/payment_links. Unknown fields are rejected.

List

GET /v1/payment_links?status=active&include_archived=false&limit=20&starting_after=plink_... Returns { "data": [link, ...], "has_more": boolean }, newest first. limit is 1 to 100 (default 20). Archived links are left out unless include_archived=true. Pass the last id as starting_after for the next page.

Update

PATCH /v1/payment_links/:id with any subset of the create fields, plus archived (boolean).
  • null clears expires_at, max_uses, description, min_amount, fee_payer, gas_payer and gas_max_usd. An omitted key is unchanged.
  • slug cannot be changed: the request is a 400.
  • Switching amount_type clears the fields that no longer apply.
  • Changing currency on a fixed link needs the new amount in the same request (else 400, field amount). On an open link it clears min_amount unless you send a new one.
  • A change that touches the fixed amount or currency is re-checked against the $1.00 minimum.
Payments already in progress keep the price they started with.

Archive

DELETE /v1/payment_links/:id archives the link and returns it. Restore it with PATCH { "archived": false }.

Public endpoints

The pay page at /pay/<store>/<link> uses two endpoints that need no key. They are documented so you know what the payer’s page does; they are not an integration surface. Browsers can call them only from Tendr’s checkout origin (CORS), so a page on your own site cannot use them. To take a link’s payment from your own page, create a session with your secret key (POST /v1/checkout/sessions with payment_link_id). Add ?mode=test to address a test link. GET /v1/payment_links/public/:merchant/:link
  • minor_units is the currency’s decimal places. Format and check amounts with it.
  • usd_rate is 1 USD = X currency, null for USD or when no rate is available.
  • min_amount (open links) is the effective minimum, rounded up to the currency’s decimals.
  • An archived link reads as inactive. No ids, use counts or limits are returned.
  • An unknown store and an unknown link give the same 404 NOT_FOUND.

Pay

POST /v1/payment_links/public/:merchant/:link/sessions
amount is required for open links and ignored for fixed ones. note is cleaned and capped at 280 characters, and ignored when the link has note: "off". The answer is 201:
Send the payer to url. expires_at is the session’s expiry at creation (5 minutes until its first quote, then the normal session lifetime); the page uses it to offer “Continue your payment” to a payer who comes back. The session has no external_ref. Responses are never cached.

Limits

Past a rate limit the API answers 429 RATE_LIMITED.

Errors

POST /v1/checkout/sessions accepts payment_link_id. The session takes the link’s fee and gas settings, counts towards its max_uses, and keeps the expiry and external_ref you give it. Every session event then carries payment_link_id, see webhooks.