Resources
Upload a font
Upload a font file as base64 so templates can use its family.
POST /api/fontsRequires assets:create. Returns 201 with the font.
Request body
| Field | Required | Description |
|---|---|---|
workspaceId | Yes | Workspace id or slug. |
family | Yes | Family name, as templates refer to it. |
style | Yes | Style name such as Regular or Bold Italic. |
contentHash | Yes | A hash that identifies the bytes. Use the SHA-256 hex digest of the file. |
fontBytes | Yes | The font file, base64 encoded. |
weight | No | Fallback numeric weight, 400 by default. The weight read from the font file, or implied by style, takes precedence. |
italic | No | Fallback, false by default. The font file's own italic flag takes precedence. |
filename | No | File name. It must end in .ttf, .otf, .woff or .woff2. Defaults to {family}-{style}.ttf. |
curl --request POST "https://app.kalpana.one/api/fonts" \
--header "x-api-key: $KALPANA_API_KEY" \
--header "content-type: application/json" \
--data '{
"workspaceId": "acme",
"family": "Inter",
"style": "Bold",
"weight": 700,
"contentHash": "'"$(shasum -a 256 Inter-Bold.ttf | cut -d' ' -f1)"'",
"fontBytes": "'"$(base64 < Inter-Bold.ttf | tr -d '\n')"'",
"filename": "Inter-Bold.ttf"
}'The response is the font object shown in List fonts. If the workspace already holds a font with the same contentHash, that font is returned unchanged.
For large files, or many at once, use Upload fonts directly, which avoids sending the bytes inside JSON.
Errors
| Status | Cause |
|---|---|
400 | The file name does not end in a supported font extension. |
403 | Your role or key lacks assets:create. |
500 | The workspace already has a font with the same family, style, weight and italic flag from a different file. The message is Failed to upload font. |
Was this page helpful?
Updated 4 Nov 2026