Prism/Storefront API

Storefront API

Read your catalog, start checkouts and manage products and licenses over HTTP.

Prism's store site uses the same public API you can call yourself. Every endpoint lives under /api/v1/ on your API address, and on your site address, which forwards /api/v1/ to the API.

https://shop.example.com/api/v1/products

Authentication

CallerHowCan use
AnyoneNo headerCatalog, reviews, updates, checkout and coupons.
API tokenAuthorization: Bearer prism_...Everything its scopes allow.

Create tokens under System > API Tokens. Pick the scopes the token needs, such as products.view or licenses.create, or * for everything. The full token is shown once. A token can have an expiry date, and the page shows when each one was last used. Calls with an unknown token are written to the audit log.

Signed Responses

Storefront responses carry an x-prism-signature header: an Ed25519 signature of the raw response body, in base64. Check it against the key from GET /api/v1/public-key so a client knows the answer came from your shop.

{
    "algorithm": "ed25519",
    "publicKey": "-----BEGIN PUBLIC KEY-----\n...",
    "raw": "base64-encoded-32-byte-key"
}
import { createPublicKey, verify } from "node:crypto";

const response = await fetch("https://shop.example.com/api/v1/products");
const body = await response.text();
const valid = verify(null, Buffer.from(body), createPublicKey(publicKeyPem), Buffer.from(response.headers.get("x-prism-signature"), "base64"));

Catalog

EndpointReturns
GET /api/v1/products{ success, total, products }. Published products, featured first.
GET /api/v1/products/:slug{ success, product }. One published product by slug or ID.
GET /api/v1/products/:slug/reviews{ success, items, total, average, distribution }.
GET /api/v1/products/:slug/updates{ success, updates }. Newest first.

GET /api/v1/products takes search, limit, offset, featured=true and slugs=a,b,c. Each is limited to 120 requests a minute per IP.

{
    "id": 1,
    "slug": "my-product",
    "name": "My Product",
    "price": 9.99,
    "sale": null,
    "currency": "USD",
    "points_earned": 0,
    "points_price": 0,
    "summary": "One short line.",
    "description": "[b]BBCode[/b] body",
    "cover": "https://...",
    "addons": [{ "name": "Extra", "icon": "Puzzle", "price": 4.99, "originalPrice": null, "sale": false, "download": true }],
    "links": [{ "label": "Docs", "url": "https://...", "icon": "BookOpen" }],
    "featured": true,
    "download": true,
    "created_at": "2026-10-01T12:00:00.000Z",
    "updated_at": "2026-10-01T12:00:00.000Z"
}

Public responses never include download links. During a sale, price is the sale price and sale holds { name, discount, originalPrice, price }.

A token with products.view gets every product, drafts included, with all fields.

Checkout

EndpointWhat it does
GET /api/v1/checkout/configCurrency, cart, terms, sale, points and which gateways are on.
POST /api/v1/checkout/couponChecks a coupon. Body: { code, items }.
POST /api/v1/checkoutStarts a checkout.
POST /api/v1/checkout/webhook/:gatewayWhere gateways report payments. See Checkout.
POST /api/v1/checkout
{
    "items": [{ "productId": 1, "addons": [0] }],
    "provider": "stripe",
    "couponCode": "LAUNCH",
    "points": 0,
    "customer": { "email": "[email protected]" }
}

addons are indexes into the product's addons. provider defaults to the primary gateway. The response holds provider, mode (embedded or hosted), and a url to send the customer to or a clientSecret for an embedded checkout. A free order returns { success, free: true, url }.

Management

These need an API token with the matching scope. Responses use { success, ... } and errors are { error } with an HTTP status.

EndpointScope
POST /api/v1/productsproducts.create
GET, PATCH, DELETE /api/v1/products/:idproducts.view, .edit, .delete
GET, POST /api/v1/products/:id/updatesproducts.view, .edit
GET, POST /api/v1/licenseslicenses.view, .create
GET, PATCH, DELETE /api/v1/licenses/:idlicenses.view, .edit, .delete
POST /api/v1/licenses/:id/activatelicenses.edit
POST /api/v1/licenses/:id/deactivatelicenses.edit
GET /api/v1/licenses/keylicenses.create. Returns a new unused key.
GET, POST /api/v1/usersteam.view, .create
GET, PATCH, DELETE /api/v1/users/:idteam.view, .edit, .delete
GET, POST /api/v1/rolesteam.view, .create
GET, PATCH, DELETE /api/v1/roles/:idteam.view, .edit, .delete

/api/v1/customers is the same as /api/v1/users. Lists take search, limit (up to 500) and offset.

curl -X POST https://shop.example.com/api/v1/licenses \
  -H "Authorization: Bearer prism_..." \
  -H "Content-Type: application/json" \
  -d '{ "product_id": 1, "user_id": 4, "addons": ["Extra"], "expires_at": null }'

Health

EndpointReturns
GET /api/health on the API port200 when Prism is running with the database up and no failed modules, otherwise 503. Point uptime monitors here.