Documentation

Use your own images and fonts

Upload a file once, then point at it with the reference string the upload response returns. There are two kinds, and the upload’s category decides which one you get:

ReferenceGoes inResolved as
asset:<id>an image_url override, or a template image layer’s srcthe image bytes, inlined server-side
font:<id>a fontFamily override, or a template text layer’s style.fontFamilyan injected @font-face block

The renderer resolves both from your account server-side, so you never need a public URL. For images you can also pass a base64 data:image/* URI directly.

References are private to the account that uploaded them. A reference to another account’s upload, or to one you have since deleted, is not an error: the render completes with an asset_unresolved warning, the image layer is left blank, and the text layer falls back to its default font. The App → Assets page lists which templates use each upload, so check it before deleting.

Prefer a UI?

Manage your uploads and copy references under App → Assets.

Upload, list, and reference

Asset references

# 1. Upload a file (multipart). 'name' is optional.
curl -X POST https://yourdomain.com/api/uploads \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -F '[email protected]' \
  -F 'name=hero shot'
# → 201 { "id": "...", "name": "hero shot", "reference": "asset:...", ... }

Custom fonts (Pro)

Upload a font file and reference it in a text layer’s fontFamily with its font:<id> reference. The same value works in three places: a per-render layers override on /api/generate and the batch endpoint, the generate_render and update_layer MCP tools, and the template JSON itself. The editor’s font picker writes the same marker when you choose an uploaded font.

One static face per upload, so upload bold or italic variants as separate files and reference each by its own id. There is no in-place replacement: to swap a font, upload the new file and update the templates that use the old id.

Custom fonts

# Font uploads require the Pro plan. Max 5MB, OTF/TTF/WOFF/WOFF2 only
# (validated by content, not filename).
curl -X POST https://yourdomain.com/api/uploads \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -F '[email protected]' \
  -F 'category=font' \
  -F 'name=Brand Sans'
# → 201 { "id": "...", "name": "Brand Sans", "category": "font", "reference": "font:...", ... }

Non-Pro accounts

Custom fonts are a Pro plan feature. Uploading a font file on a non-Pro account is rejected with a 403 at upload time. If a template's font:<id> reference is rendered by an account that has since downgraded from Pro, the render still completes, the custom face is skipped and the layer falls back to its default font, with a custom_fonts_blocked warning in the response's warnings array. The public, unauthenticated /api/render URL endpoint never resolves custom fonts, whatever the owner's plan, so templates meant for Render URLs should use the built-in font list.