Products
Products are the catalog items that back your payment links. Each product has a fixed price, optional image, and optional SKU for inventory tracking. When you attach a product to a Payment Link, Coal automatically pulls in the name, image, and price on the checkout page.
Products are optional. If you want buyers to enter a custom amount, create a flexible Payment Link with no product attached. See Payment Links.
Product Object
1{2 "id": "clz9prod123",3 "name": "Pro Plan",4 "description": "Unlimited projects and priority support.",5 "price": "49.00",6 "image": "https://cdn.example.com/pro-plan.png",7 "sku": "PLAN-PRO-MONTHLY",8 "active": true,9 "sales": 142,10 "createdAt": "2026-03-01T09:00:00.000Z",11 "updatedAt": "2026-03-20T14:30:00.000Z"12}
Field reference
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier (CUID). |
name | string | Product display name shown on the checkout page. |
description | string? | Optional description shown below the name. |
price | string | Fixed price as a decimal string in the merchant's settlement currency. |
image | string? | URL of the product image. Displayed as a square thumbnail at checkout. |
sku | string? | Your internal SKU. Not shown to buyers; useful for inventory webhooks. |
active | boolean | false means the product is archived and cannot be linked to new links. |
sales | number | Count of confirmed checkout sessions for this product. |
createdAt | string | ISO 8601 timestamp. |
updatedAt | string | ISO 8601 timestamp of last modification. |
Creating a Product
Via the Console
- Go to Console → Products → New Product.
- Enter a name and price.
- Optionally add a description, upload an image, and set a SKU.
- Click Create Product. It appears in your catalog immediately.
Via the API
POST /api/console/products
This is a console-managed surface. The public merchant API uses x-api-key; /api/console/* routes use Privy Bearer tokens and are dashboard-only.
1Authorization: Bearer <Privy JWT>2Content-Type: application/json
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name. |
price | number | Yes | Price in the merchant's settlement currency. |
description | string | No | Short description. |
image | string | No | Publicly accessible image URL. |
sku | string | No | Your internal SKU or inventory code. |
cURL
1curl -X POST https://api.usecoal.xyz/api/console/products \2 -H "Content-Type: application/json" \3 -H "Authorization: Bearer <Privy JWT>" \4 -d '{5 "name": "Pro Plan",6 "description": "Unlimited projects and priority support.",7 "price": 49,8 "image": "https://cdn.example.com/pro-plan.png",9 "sku": "PLAN-PRO-MONTHLY"10 }'
Returns 201 Created with the full product object.
Node.js
1const res = await fetch('https://api.usecoal.xyz/api/console/products', {2 method: 'POST',3 headers: {4 'Content-Type': 'application/json',5 'Authorization': 'Bearer <Privy JWT>',6 },7 body: JSON.stringify({8 name: 'Pro Plan',9 description: 'Unlimited projects and priority support.',10 price: 49,11 image: 'https://cdn.example.com/pro-plan.png',12 sku: 'PLAN-PRO-MONTHLY',13 }),14});1516const product = await res.json();17console.log(product.id); // clz9prod123
Listing Products
GET /api/console/products
Returns all active products for your account, sorted newest first. Each product includes a sales count of confirmed payments.
1curl https://api.usecoal.xyz/api/console/products \2 -H "Authorization: Bearer <Privy JWT>"
1{2 "products": [3 {4 "id": "clz9prod123",5 "name": "Pro Plan",6 "description": "Unlimited projects and priority support.",7 "price": "49.00",8 "image": "https://cdn.example.com/pro-plan.png",9 "sales": 14210 },11 {12 "id": "clz9prod456",13 "name": "Starter Pack",14 "description": null,15 "price": "9.00",16 "image": null,17 "sales": 3818 }19 ]20}
Updating a Product
PUT /api/console/products/:id
All fields are optional — only send what you want to change.
1curl -X PUT https://api.usecoal.xyz/api/console/products/clz9prod123 \2 -H "Content-Type: application/json" \3 -H "Authorization: Bearer <Privy JWT>" \4 -d '{ "price": 59, "description": "Now includes AI features." }'
Price changes are not retroactive. Existing confirmed sessions keep the amount they were created with. Only new sessions created after the price change will use the updated price.
Deleting a Product
DELETE /api/console/products/:id
Products are soft-deleted — active is set to false. The product disappears from your catalog, and any Payment Links that reference it stop resolving.
1curl -X DELETE https://api.usecoal.xyz/api/console/products/clz9prod123 \2 -H "Authorization: Bearer <Privy JWT>"
Product Examples
Digital product
1{2 "name": "eBook: Crypto Payments Explained",3 "description": "A 60-page guide to building on Coal.",4 "price": 15,5 "image": "https://cdn.example.com/ebook-cover.png",6 "sku": "EBOOK-CRYPTO-V1"7}
After purchase, use a webhook (checkout.session.completed) to send the buyer a download link.
Physical product
1{2 "name": "Coal Merch Hoodie — Black L",3 "description": "100% organic cotton. Ships in 3–5 business days.",4 "price": 65,5 "image": "https://cdn.example.com/hoodie-black-l.jpg",6 "sku": "MERCH-HOODIE-BLK-L"7}
Use the sku field to match the confirmed payment to your inventory management system.
Subscription (recurring billing pattern)
Coal now supports recurring products natively:
- Create a product with
billingType: "subscription". - Set
billingIntervalandbillingIntervalCount, for example:
1{2 "name": "Pro Plan",3 "price": 49,4 "billingType": "subscription",5 "billingInterval": "month",6 "billingIntervalCount": 17}
On the first paid cycle, Coal stores the buyer's billing mandate and creates the subscription record. Future renewal checkout sessions are generated automatically on the configured cadence, and merchants can manage the billing state from the dashboard.
Best Practices
Use SKUs for inventory sync. The sku field is echoed back in webhook payloads. If your warehouse or fulfillment system uses SKUs, set the product SKU to match so you can look up the order automatically on confirmation.
Use images for branding. Products with a high-quality image convert better. Host images on a CDN (see Managing Products) and use HTTPS URLs. Coal does not resize images — aim for square images at 400×400 px or larger.
Do not delete products with active links. Deleting a product deactivates any Payment Links that reference it. Archive it only when you are certain no buyer will visit those links.
