The Fable Editor API
Everything you design in Fable Editor is available programmatically. Render templates with live data, pull projects into your build pipeline and export HTML, MJML or PDF straight from your own systems.
Introduction
The Fable Editor API is organized around REST. It uses predictable resource URLs, accepts JSON request bodies, returns JSON responses and uses standard HTTP status codes and verbs. All requests must be made over HTTPS; plain HTTP requests are refused.
Every object has a stable, prefixed ID such as prj_ for projects and exp_ for exports, so you can tell what an ID refers to at a glance. Timestamps are Unix epoch seconds in UTC.
Authentication
Authenticate by sending your secret API key as a bearer token in the Authorization header. Keys start with fbl_live_ and are issued to your organization when your Unlimited Edition subscription starts.
curl https://api.fableditor.com/v1/me \
-H "Authorization: Bearer fbl_live_..."
Requests with a missing or invalid key return 401 Unauthorized. Requests made with a key whose subscription is no longer active return 403 Forbidden.
Errors
Codes in the 2xx range indicate success, 4xx indicates a problem with the request and 5xx indicates a problem on our side. Every error response has the same shape, including a request_id you can share with support.
{
"error": {
"type": "invalid_request",
"code": "parameter_missing",
"message": "The format parameter is required.",
"param": "format",
"request_id": "req_8fK2cQ1x"
}
}
| Status | Meaning |
|---|---|
| 200 OK | The request succeeded. |
| 202 Accepted | The job was queued. Poll the returned object for its status. |
| 400 Bad Request | The request was malformed or a parameter was invalid. |
| 401 Unauthorized | No valid API key was provided. |
| 403 Forbidden | The key is valid but its subscription is not active. |
| 404 Not Found | The requested object does not exist in your workspace. |
| 409 Conflict | An idempotency key was reused with different parameters. |
| 429 Too Many Requests | You exceeded the rate limit. Retry after the time in Retry-After. |
| 5xx | Something went wrong on our side. These are safe to retry with backoff. |
Pagination
List endpoints return results in pages using cursor based pagination. Pass limit (1 to 100, default 20) and, to fetch the next page, starting_after set to the ID of the last object you received. The response includes has_more to tell you whether another page exists.
{
"object": "list",
"data": [ ... ],
"has_more": true,
"next_cursor": "prj_3Hq8vLw2"
}
Idempotency
All POST requests accept an Idempotency-Key header. If a request with the same key is received again within 24 hours, the original response is returned instead of performing the action twice. Use a random UUID per logical operation so network retries never create duplicate exports.
curl https://api.fableditor.com/v1/projects/prj_3Hq8vLw2/exports \
-H "Authorization: Bearer fbl_live_..." \
-H "Idempotency-Key: 5f1c7e2a-9b3d-4c8e-a1f0-2d6b8e4c9a71" \
-H "Content-Type: application/json" \
-d '{ "format": "pdf" }'
Rate limits
Requests are rate limited per API key. Every response includes headers describing your current allowance, so your client can slow down before it hits the limit.
| Header | Description |
|---|---|
| RateLimit-Limit | Requests allowed in the current window. |
| RateLimit-Remaining | Requests left in the current window. |
| RateLimit-Reset | Seconds until the window resets. |
| Retry-After | Sent with 429 responses. Seconds to wait before retrying. |
Versioning
The API version is part of the URL. Within v1 we only make additive changes: new endpoints, new optional parameters and new fields on responses. Build your client to ignore fields it does not recognize. Breaking changes ship as a new major version, and the previous version keeps working with advance notice before retirement.
Account
Inspect the organization and subscription bound to the API key you are using. This is the quickest way to confirm a key works.
Retrieve account
Takes no parameters.
curl https://api.fableditor.com/v1/me \
-H "Authorization: Bearer fbl_live_..."
{
"object": "account",
"organization": {
"id": "org_7Tn4pXe9",
"name": "Acme Corporation"
},
"plan": "unlimited",
"subscription_status": "active",
"current_period_end": 1822291200
}
Projects
A project is anything built in Fable Editor: an email template, an interactive form or a document. Projects carry their design, their variables and their publishing state.
List projects
| Parameter | Description |
|---|---|
| typestring | Only return projects of this type: email, form or document. |
| updated_aftertimestamp | Only return projects changed after this time. Useful for incremental syncs. |
| limitinteger | Page size, 1 to 100. Defaults to 20. |
| starting_afterstring | Cursor for the next page. See Pagination. |
curl "https://api.fableditor.com/v1/projects?type=email&limit=2" \
-H "Authorization: Bearer fbl_live_..."
{
"object": "list",
"data": [
{
"id": "prj_3Hq8vLw2",
"object": "project",
"type": "email",
"name": "Order confirmation",
"updated_at": 1790688000
},
{
"id": "prj_9Rb1kDs6",
"object": "project",
"type": "email",
"name": "Monthly newsletter",
"updated_at": 1790601600
}
],
"has_more": true,
"next_cursor": "prj_9Rb1kDs6"
}
Retrieve a project
Returns a single project, including the variables it expects when rendered.
curl https://api.fableditor.com/v1/projects/prj_3Hq8vLw2 \
-H "Authorization: Bearer fbl_live_..."
{
"id": "prj_3Hq8vLw2",
"object": "project",
"type": "email",
"name": "Order confirmation",
"variables": [
{ "name": "first_name", "type": "string", "required": true },
{ "name": "order_id", "type": "string", "required": true },
{ "name": "items", "type": "array", "required": false }
],
"created_at": 1788009600,
"updated_at": 1790688000
}
Rendering
Merge data into a project and get the finished output back in a single synchronous call. Rendering is what you call from your application at send time, for example right before handing an email to your mail provider.
Render a project
| Parameter | Description |
|---|---|
| formatstring required | html for inbox ready HTML with inlined CSS, or text for the plain text alternative. |
| variablesobject | Values for the project's variables. Missing required variables return 400. |
| localestring | Locale used for dates and numbers, such as en-US or da-DK. |
curl https://api.fableditor.com/v1/projects/prj_3Hq8vLw2/render \
-H "Authorization: Bearer fbl_live_..." \
-H "Content-Type: application/json" \
-d '{
"format": "html",
"locale": "en-US",
"variables": {
"first_name": "Ada",
"order_id": "A1042"
}
}'
{
"object": "render",
"project": "prj_3Hq8vLw2",
"format": "html",
"subject": "Your order A1042 is confirmed",
"content": "<!doctype html><html>...",
"size_bytes": 48213
}
Exports
Exports produce downloadable files from a project. They run asynchronously: create an export, then retrieve it until its status is succeeded and a download URL is available.
Create an export
| Parameter | Description |
|---|---|
| formatstring required | html, mjml or pdf. |
| variablesobject | Optional data to merge before exporting. |
curl https://api.fableditor.com/v1/projects/prj_3Hq8vLw2/exports \
-H "Authorization: Bearer fbl_live_..." \
-H "Content-Type: application/json" \
-d '{ "format": "pdf" }'
{
"id": "exp_5Wc2mJa8",
"object": "export",
"project": "prj_3Hq8vLw2",
"format": "pdf",
"status": "processing",
"created_at": 1790774400
}
Retrieve an export
Status is one of processing, succeeded or failed. Download URLs are signed and expire after one hour; retrieve the export again for a fresh URL.
curl https://api.fableditor.com/v1/exports/exp_5Wc2mJa8 \
-H "Authorization: Bearer fbl_live_..."
{
"id": "exp_5Wc2mJa8",
"object": "export",
"project": "prj_3Hq8vLw2",
"format": "pdf",
"status": "succeeded",
"url": "https://files.fableditor.com/exp_5Wc2mJa8.pdf?sig=...",
"url_expires_at": 1790778000,
"created_at": 1790774400
}
Get your API key
Every Unlimited Edition subscription includes full API access for your organization.