coal
coal

Payment Links

Payment Links are shareable URLs that let you accept crypto payments without writing a single line of code. Send one in an email, post it on social media, or drop it in a Notion page — anyone who clicks it lands on a hosted Coal checkout page branded with your merchant profile.

This is a console-managed surface. The public merchant API uses x-api-key; these /api/console/* routes use Privy Bearer tokens.

Note: Payment Links are ideal for direct sales, content creators, and no-code use cases. If you need programmatic control over the checkout flow, see Checkout Sessions.


Types of Payment Links

Product-Linked

A product-linked link is tied to a specific item in your product catalog. The checkout page automatically displays the product name, image, description, and fixed price. The buyer cannot change the amount.

Use this for: fixed-price digital goods, SaaS plan purchases, event tickets.

Flexible (Custom Amount)

A flexible link has no product attached. The buyer enters any amount they choose before paying. You can provide a title and description to give context.

Use this for: donations, tips, pay-what-you-want offers, open-source sponsorships.


Creating a Payment Link in the Console

  1. Go to the Console and navigate to Payment Links in the sidebar.
  2. Click Create Link.
  3. Choose a type:
    • Select a product from the dropdown to create a product-linked link.
    • Leave the product field empty to create a flexible link.
  4. Set a slug (optional). The slug becomes the last segment of your URL: usecoal.xyz/pay/{slug}. If you leave it blank, Coal generates a random one for you.
  5. For flexible links, add a Title and Description so buyers know what they are paying for.
  6. Click Create — your link is live instantly.

Creating a Payment Link via API

POST /api/console/links

Requires a valid session (authenticated merchant). All requests must include:

text
1Authorization: Bearer <Privy JWT>

Product-linked link

bash
1curl -X POST https://api.usecoal.xyz/api/console/links \
2 -H "Content-Type: application/json" \
3 -H "Authorization: Bearer <Privy JWT>" \
4 -d '{
5 "productId": "clxxx",
6 "slug": "pro-plan"
7 }'

Flexible link

bash
1curl -X POST https://api.usecoal.xyz/api/console/links \
2 -H "Content-Type: application/json" \
3 -H "Authorization: Bearer <Privy JWT>" \
4 -d '{
5 "title": "Donation",
6 "description": "Support our open-source project",
7 "slug": "donate"
8 }'

Request body parameters

FieldTypeRequiredDescription
productIdstringNoID of a product from your catalog. Mutually exclusive with title.
slugstringNoCustom URL-safe slug. Auto-generated if omitted.
titlestringNoDisplay title for flexible links.
descriptionstringNoDescription shown on the checkout page.

Response

json
1{
2 "id": "clz9abc123",
3 "slug": "pro-plan",
4 "url": "https://usecoal.xyz/pay/pro-plan",
5 "active": true,
6 "productId": "clxxx",
7 "title": null,
8 "description": null,
9 "createdAt": "2026-03-22T10:00:00.000Z"
10}

URL Structure

Every payment link resolves to:

text
1https://usecoal.xyz/pay/{slug}

The slug must be URL-safe (letters, numbers, hyphens). Slugs are globally unique across Coal — if a slug is already taken, the API returns a 409 SLUG_TAKEN error.


Listing Payment Links

GET /api/console/links

Returns all active links for your account, including the resolved product name and price.

bash
1curl https://api.usecoal.xyz/api/console/links \
2 -H "Authorization: Bearer <Privy JWT>"
json
1{
2 "links": [
3 {
4 "id": "clz9abc123",
5 "slug": "pro-plan",
6 "url": "https://usecoal.xyz/pay/pro-plan",
7 "productName": "Pro Plan",
8 "productImage": "https://cdn.example.com/pro.png",
9 "price": "49.00",
10 "active": true,
11 "createdAt": "2026-03-22T10:00:00.000Z"
12 },
13 {
14 "id": "clz9def456",
15 "slug": "donate",
16 "url": "https://usecoal.xyz/pay/donate",
17 "productName": "Donation",
18 "productImage": null,
19 "price": "Flexible",
20 "active": true,
21 "createdAt": "2026-03-20T08:30:00.000Z"
22 }
23 ]
24}

Deleting a Payment Link

DELETE /api/console/links/:id

Links are soft-deleted — the record is kept in the database but active is set to false. The URL immediately stops resolving for buyers.

bash
1curl -X DELETE https://api.usecoal.xyz/api/console/links/clz9abc123 \
2 -H "Authorization: Bearer <Privy JWT>"

Returns the updated link object with active: false.


Node.js Examples

Create a product-linked link

typescript
1const response = await fetch('https://api.usecoal.xyz/api/console/links', {
2 method: 'POST',
3 headers: {
4 'Content-Type': 'application/json',
5 'Authorization': 'Bearer <Privy JWT>',
6 },
7 body: JSON.stringify({
8 productId: 'clxxx',
9 slug: 'pro-plan',
10 }),
11});
12
13const link = await response.json();
14console.log(link.url); // https://usecoal.xyz/pay/pro-plan

Create a flexible donation link

typescript
1const response = await fetch('https://api.usecoal.xyz/api/console/links', {
2 method: 'POST',
3 headers: {
4 'Content-Type': 'application/json',
5 'Authorization': 'Bearer <Privy JWT>',
6 },
7 body: JSON.stringify({
8 title: 'Support Us',
9 description: 'Every payment helps keep the servers on.',
10 slug: 'support',
11 }),
12});
13
14const link = await response.json();
15console.log(link.url); // https://usecoal.xyz/pay/support

List and delete links

typescript
1// List
2const res = await fetch('https://api.usecoal.xyz/api/console/links', {
3 headers: { 'Authorization': 'Bearer <Privy JWT>' },
4});
5const { links } = await res.json();
6
7// Delete the first link
8const deleteRes = await fetch(
9 `https://api.usecoal.xyz/api/console/links/${links[0].id}`,
10 {
11 method: 'DELETE',
12 headers: { 'Authorization': 'Bearer <Privy JWT>' },
13 }
14);

Embedding Payment Links

Payment links are plain URLs — you can embed them anywhere a hyperlink works.

Email campaigns — Link a button to https://usecoal.xyz/pay/your-slug. No redirects, no tracking pixels required.

Social media — Post the link directly. The checkout page has Open Graph meta tags so it renders a preview card on Twitter/X, LinkedIn, and Discord.

Notion / Confluence — Paste the URL as a linked button block. Notion automatically unfurls it as a bookmark card.

QR codes — Use any QR generator (e.g. qrcode.react) to encode the URL for print materials or event badges.

Direct messages — Drop the URL in Telegram, Slack, or iMessage. Coal handles the rest.