Appearance
List the public product catalog
GET /v1/public/products
- Operation ID:
listPublicProducts - Tags: Public site
- Base URL:
http://localhost:8787
Active, public plans and credit packs ordered by sort_order. Returned as a bare array.
Workflow: Integration guide.
Authentication: none (public).
Authentication
- Auth: none (public endpoint, no token required).
Responses
200
Product catalog.
- Header
x-request-id: Request identifier; quote it when reporting an error. Content type:application/json
Schema: (object (PublicProduct))[]
| Field | Type | Required | Description |
|---|---|---|---|
[].id | string<uuid> | yes | - |
[].key | string | yes | - |
[].name | string | yes | - |
[].description | string | null | yes | - |
[].type | string | yes | Product type, e.g. a subscription plan or credit_pack. |
[].tier_key | string | yes | - |
[].credits_included | integer | yes | - |
[].features | any | no | Marketing feature list; shape defined by the catalog. |
[].sort_order | integer | yes | - |
[].highlight | boolean | yes | - |
[].badge | string | null | yes | - |
[].pack_credits | integer | null | yes | Credit packs only. |
[].pack_bonus_credits | integer | null | yes | Credit packs only. |
[].pack_expires_after | string | null | yes | Credit packs only; Postgres interval text. |
[].default_stripe_price_id | string | null | yes | - |
[].prices | any | no | Price list for the product (Stripe price ids, currency, amounts). |
Errors
500
Unexpected server error (internal). No details are returned.
- Header
x-request-id: Request identifier; quote it when reporting an error. Content type:application/json
Schema: object (ErrorBody)
| Field | Type | Required | Description |
|---|---|---|---|
error | string | yes | Stable machine-readable error code, e.g. forbidden, not_found. |
details | any | no | Optional structured context. For 403 it is { perm }. |
Error response
json
{
"error": "internal"
}Examples
curl
bash
curl -X GET 'http://localhost:8787/v1/public/products'TypeScript
ts
const response = await fetch("http://localhost:8787/v1/public/products", {
method: "GET",
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
const data = response.status === 204 || response.status === 205
? undefined
: response.headers.get("content-type")?.includes("json")
? await response.json()
: await response.text();