ogmake

API reference

Generated from the API's own OpenAPI document (GET /v1/openapi.json) — every route and schema here is proven against real responses by apps/api/src/openapi.contract.test.ts.

Background images (bg)

Pass bg as a top-level POST /v1/images field (or query param on the signed/public GET routes) to render one of the 40 curated free-pack background photos full-bleed behind the card, e.g. bg=bg-01. The template's title/description text gets its own contained backdrop panel so it stays legible over the photo — the photo itself is never dimmed or scrimmed.

Only templates whose design isn't a deliberate physical/mechanical artifact (a receipt, a punchcard, a ballot, ...) accept it: basic, blog, docs, changelog, product, event, podcast, job, release, case-study, testimonial, lesson, newsletter, spotlight, aurora, signal and verbatim. An unrecognized bg id is rejected with invalid_input; a valid id passed to a template that doesn't support backgrounds is silently ignored, same as any other param a template's schema doesn't declare.

Array fields on GET routes

POST /v1/images takes an array field as a real JSON array in the request body. The two GET routes — signed GET /i/{keyId}/{sig} (Signing) and unsigned GET /p/{keyId}/{template} (Public URLs) — have no JSON body, so an array field is carried as bracket-indexed query keys instead: field[0]=first&field[1]=second, up to that field's own max length, indexes contiguous starting at 0. A plain repeated key (field=a&field=b) is rejected as a duplicate, not merged into an array.

10 templates require at least one array field, so a request for them cannot be built without this syntax:

Template Array field(s)
changelog changes
receipt items
patch added
ledger rows
snellen lines
redacted lines
ballot options
metro stops
facts rows
bracket contenders, finalists

POST /v1/images

Requires Authorization: Bearer og_live_....

Request body — PostImagesBody

Field Type Required
template string yes
params object no
format "png" | "jpg" | "webp" no
preset "og" | "x" | "square" no
scale "1" | "2" no
v string no
bg string no

Responses

Status Type Description Retry-After
201 PostImagesResponse Image resolved (rendered or served from cache) no
400 object Invalid request no
401 object Missing/unknown/revoked API key no
413 object Request body too large no
429 object | QuotaExceeded Rate limited or quota exhausted yes
500 object Unexpected server error (e.g. a database dependency failure) no
503 object Render engine unavailable yes

GET /v1/usage

Requires Authorization: Bearer og_live_....

Responses

Status Type Description Retry-After
200 UsageResponse Current-period usage for the authenticated account no
401 object Missing/unknown/revoked API key no
429 object Rate limited yes

GET /v1/templates

Responses

Status Type Description Retry-After
200 TemplatesResponse Every registered template's id, version, and params JSON Schema no

Error codes

Every error response is JSON { "error": <code> }.

Code Meaning
invalid_input Request body or params failed validation.
unknown_template `template` does not match a registered template id.
params_too_large Encoded params exceeded the size limit.
invalid_json Request body was not valid JSON.
unauthorized Missing or unknown API key.
unauthenticated No session — sign in first.
key_revoked The API key exists but has been revoked.
forbidden Authenticated, but not allowed to perform this action.
not_found Nothing at this path/id.
rate_limited Per-key burst limit hit; see `Retry-After`.
quota_exceeded Past the monthly cap and its grace window.
render_unavailable The render engine is temporarily unavailable.
key_limit This account already has the maximum of 5 active API keys.
invalid_signature The webhook signature did not verify (or no webhook secret is configured).
no_subscription No billing subscription exists yet for this account.
billing_unavailable The billing provider's API failed; retry after the given `Retry-After`.