API Reference · Public v1 surface
API Reference

/v1: the surface built for agents

The public developer surface authenticates with an API key instead of a user session. It currently exposes the template catalog — the same payloads as the unauthenticated /templates routes, gated by key so usage is attributable and revocable.

Authentication: x-api-key

Send any active key as the x-api-key header. Missing, invalid, or revoked keys all fail with 401 before the route runs — a revoked key is indistinguishable from an invalid one.

FieldTypeDescription
x-api-key*headerA key issued by POST /api-keys: pf_ followed by 48 hex characters.
FieldTypeDescription
401ApiError“Missing x-api-key header.” — the header was absent or empty.
401ApiError“Invalid API key.” — unknown or revoked key.
GET/v1/templatesx-api-key

Identical payload to /templates, including the category and q query parameters and the full-catalog category counts.

curl — everything
curl http://localhost/api/v1/templates \
  -H "x-api-key: pf_9f2c4e6a8b0d1f3e5a7c9b8d7e6f5a4b3c2d1e0f9a8b7c6d"
curl — filtered
curl "http://localhost/api/v1/templates?category=mailer-boxes&q=mailer" \
  -H "x-api-key: pf_9f2c4e6a8b0d1f3e5a7c9b8d7e6f5a4b3c2d1e0f9a8b7c6d"
200 OK
{
  "templates": [
    {
      "id": "mailer-box",
      "name": "Mailer Box",
      "category": "mailer-boxes",
      "kind": "box",
      "defaultDimensions": { "widthMm": 230, "heightMm": 160, "depthMm": 70 },
      "materials": ["cardboard", "kraft", "corrugated"],
      "finishes": ["matte", "gloss", "soft-touch", "foil"],
      "dielineAvailable": true,
      "description": "Self-locking e-commerce mailer with tuck-in flaps. The workhorse of subscription boxes and DTC shipping."
    }
  ],
  "total": 1,
  "categories": [
    { "id": "folding-cartons", "label": "Folding Cartons", "count": 1 },
    { "id": "mailer-boxes", "label": "Mailer Boxes", "count": 1 },
    { "id": "rigid-boxes", "label": "Rigid Boxes", "count": 1 },
    { "id": "shipping-boxes", "label": "Shipping Boxes", "count": 1 },
    { "id": "product-boxes", "label": "Product Boxes", "count": 2 },
    { "id": "bottles-jars", "label": "Bottles & Jars", "count": 2 },
    { "id": "cans-tins", "label": "Cans & Tins", "count": 1 },
    { "id": "pouches-bags", "label": "Pouches & Bags", "count": 1 },
    { "id": "tubes", "label": "Tubes", "count": 1 },
    { "id": "labels-sleeves", "label": "Labels & Sleeves", "count": 0 }
  ]
}
FieldTypeDescription
400ApiError“Unknown template category '<id>'.”
GET/v1/templates/:idx-api-key
curl
curl http://localhost/api/v1/templates/rsc-box \
  -H "x-api-key: pf_9f2c4e6a8b0d1f3e5a7c9b8d7e6f5a4b3c2d1e0f9a8b7c6d"
200 OK
{ "template": { "id": "rsc-box", "name": "RSC Shipping Box", … } }
FieldTypeDescription
404ApiError“Template '<id>' was not found.”

Why two surfaces?

The JWT surface is for the product itself — short-lived user sessions driving the web app. The v1 surface is for anything you build: scripts, integrations, AI agents. Keys are attributable (every key belongs to an account), revocable without touching the user credential, and safe to hand to an agent because they only unlock the public surface.

Handing this page to an AI agent

Give the agent three things: a base URL (http://localhost/api for the Docker deployment — substitute your domain — or http://localhost:4000 for a bare-metal dev api), a key, and this page. Every request and response on it is real — the agent can verify each curl against a running stack and get the same bytes back.