Reference

API reference

Every public endpoint on api.snowcone.app, grouped by resource. Most of what you build needs no API at all — a mockup is a URL — so reach here only for orders, uploads, realtime grants, and managing shops.

Most pages aren't here on purpose

Rendering and buying are plain URLs (img/buy) and the catalog is a public search index — none of them touch this API. See Authentication for which credential each endpoint wants, and Errors for status codes.

Base URL & auth

All endpoints are JSON over HTTPS. Secret endpoints take a server-side secret key in the x-api-key header (or Authorization: Bearer); the listed scope is the minimum that key must carry.

bash
# Everything below is relative to this base.
https://api.snowcone.app

# Public endpoints take no auth (a per-IP rate limit is the gate).
# Secret endpoints take a server-side key:  -H "x-api-key: sk_…"

Shops

Mint, claim, and release sandbox shops. All three are public — minting is gated by a per-IP rate limit, and the claim/release calls are authorized by the token or secret you got at mint time (see Authentication).

POST/shops/sandbox
Mint a sandbox shop. Returns shop_id, shop_secret, and a claim object. Use shop_id as &shop= immediately.
Auth: None (rate-limited: 60 mints/hr, 200 unclaimed/IP)
GET/shops/claim
Poll claim status for a minted shop (unclaimed → claimed once a human activates it).
Auth: Bearer {claim_token}
DELETE/shops/sandbox/:id
Release an unclaimed sandbox shop, freeing your per-IP mint budget. Refused for a claimed shop.
Auth: Bearer {shop_secret}
bash
curl -X POST https://api.snowcone.app/shops/sandbox \
  -H 'Content-Type: application/json' -d '{}'
# → {
#   "shop_id": "ab3dPq7Rms",
#   "shop_secret": "scsec_…",
#   "claim": { "user_code": "WXYZ-1234",
#              "verification_uri_complete": "https://snowcone.app/activate?code=WXYZ-1234" }
# }

Realtime

Mint the short-lived grant that opens the realtime render socket. Full socket protocol on the realtime page.

POST/realtime/grant
Returns { token, expiresAt } (expiresAt is epoch seconds). Open wss://cdn.snowcone.app/realtime?token=… with it.
Auth: None for sandbox shops (body {shop}); else sk_ key, scope mockups:realtime

Orders

Bring-your-own-checkout: you take the payment, then POST the order for fulfillment. Body wraps the order under a top-level json field. Guide on the Orders API page.

POST/orders
Create an order. Returns { id, orderNumber, json, created_at, updated_at }.
Auth: sk_ key, scope orders:add
GET/orders
List your orders.
Auth: sk_ key, scope orders:read
GET/orders/:id
Fetch one order by id to reconcile status.
Auth: sk_ key, scope orders:read
PUT/orders/:id
Update an existing order.
Auth: sk_ key, scope orders:add
DELETE/orders/:id
Delete an order.
Auth: sk_ key, scope orders:add

Uploads

Push artwork into Snowcone storage so the renderer can fetch it. Returns the hosted asset URL.

POST/uploads/base64
Body: { base64Image } — a data URL (data:image/png;base64,…) or raw base64. Allowed types: png, jpg, jpeg, webp, gif, svg. Max 50 MB. Returns { url } — a permanent URL on your shop’s {shop-id}.storage.snowcone.app origin.
Auth: sk_ key, scope uploads:write
The asset lands in your shop’s storage origin. A shop-scoped sk_ key with the uploads:write scope writes to {shop-id}.storage.snowcone.app, which is already on your shop’s asset-origin allowlist — so the upload is renderable with zero extra config. You don’t have to upload at all, though: the realtime renderer and mockup URLs fetch assets by URL, so any CORS-enabled public image URL (Unsplash, S3, your own host) works without a round-trip through this endpoint.

Catalog (search host)

The product catalog is not on api.snowcone.app — it’s a public Meilisearch index on search.snowcone.app, read with a public read-only key. Look up a product with GET /indexes/snowcone/documents/{PRODUCT}. Details and the public key are on the catalog page.