Products & prices
Your catalog has two levels, just like Stripe:
- Product (
prod_…) — the thing you sell (“Pro plan”). - Price (
price_…) — a recurring amount + interval attached to a product (“NPR 499 / month”). Subscriptions reference a price, not a product.
A product can have many prices (monthly vs. annual, different tiers).
Create a product
Section titled “Create a product”curl -s "$TRILE_API/v1/catalog/products" \ -H "x-api-key: $TRILE_KEY" -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "name": "Pro plan", "description": "Everything in Pro." }'import { Configuration, CatalogApi } from '@trilehq/sdk'
const catalog = new CatalogApi(new Configuration({ apiKey: process.env.TRILE_KEY }))
const { data: product } = await catalog.createProduct({ createProduct: { name: 'Pro plan', description: 'Everything in Pro.' }, idempotencyKey: crypto.randomUUID(),})// product.id → "prod_…"You can attach a product image with POST /v1/catalog/products/:productId/image (multipart;
SVG/PNG/JPEG up to 2 MB):
curl -s "$TRILE_API/v1/catalog/products/prod_01ARZ3.../image" \ -H "x-api-key: $TRILE_KEY" -H "Idempotency-Key: $(uuidgen)" \ -F "file=@logo.png"import { readFile } from 'node:fs/promises'
const { data } = await catalog.uploadProductImage({ productId: product.id, file: new Blob([await readFile('logo.png')], { type: 'image/png' }), idempotencyKey: crypto.randomUUID(),})Prices
Section titled “Prices”A price pins down how much and how often. Amounts are in paisa, as a string.
curl -s "$TRILE_API/v1/catalog/prices" \ -H "x-api-key: $TRILE_KEY" -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "productId": "prod_01ARZ3NDEKTSV4RRFFQ69G5FAX", "amountPaisa": "49900", "currency": "NPR", "interval": "month", "intervalCount": 1, "trialDays": 14 }'const { data: price } = await catalog.createPrice({ createPrice: { productId: 'prod_01ARZ3NDEKTSV4RRFFQ69G5FAX', amountPaisa: '49900', currency: 'NPR', interval: 'month', intervalCount: 1, trialDays: 14, }, idempotencyKey: crypto.randomUUID(),})// price.id → "price_…"| Field | Notes |
|---|---|
amountPaisa | Recurring amount in paisa, as a string. "49900" = NPR 499.00. |
interval | day, week, month, or year. |
intervalCount | Multiplier. interval: "month", intervalCount: 3 → quarterly. |
trialDays | Optional free trial before the first charge. With a trial, the first wallet debit is deferred to the end of the trial. |
Retrieve, list, update
Section titled “Retrieve, list, update”# Retrievecurl "$TRILE_API/v1/catalog/products/prod_01ARZ3..." -H "x-api-key: $TRILE_KEY"curl "$TRILE_API/v1/catalog/prices/price_01ARZ3..." -H "x-api-key: $TRILE_KEY"
# List (cursor paginated)curl "$TRILE_API/v1/catalog/products?limit=50" -H "x-api-key: $TRILE_KEY"curl "$TRILE_API/v1/catalog/prices?productId=prod_01ARZ3..." -H "x-api-key: $TRILE_KEY"
# Update non-financial fields (PATCH — Idempotency-Key required)curl -X PATCH "$TRILE_API/v1/catalog/products/prod_01ARZ3..." \ -H "x-api-key: $TRILE_KEY" -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "description": "Everything in Pro, plus support." }'// Retrieveconst { data: prod } = await catalog.getProduct({ productId: 'prod_01ARZ3...' })const { data: pri } = await catalog.getPrice({ priceId: 'price_01ARZ3...' })
// List (cursor paginated)const { data: products } = await catalog.listProducts({ limit: '50' })const { data: prices } = await catalog.listPrices({ productId: 'prod_01ARZ3...' })
// Update non-financial fieldsconst { data: updated } = await catalog.updateProduct({ productId: 'prod_01ARZ3...', updateProduct: { description: 'Everything in Pro, plus support.' }, idempotencyKey: crypto.randomUUID(),})Archiving
Section titled “Archiving”Prices and products are immutable in the ways that matter — you don’t edit an amount, you create a new price and archive the old one:
curl -X DELETE "$TRILE_API/v1/catalog/prices/price_01ARZ3..." -H "x-api-key: $TRILE_KEY"const { data } = await catalog.archivePrice({ priceId: 'price_01ARZ3...' })// archiveProduct({ productId }) works the same wayArchiving a price (soft delete) stops new subscriptions from using it; existing subscriptions on
that price keep billing. PATCH is for metadata and non-financial fields, not the amount.
Put a customer on a price: Subscriptions.