API Reference - Abyssale (1.0.0)

Download OpenAPI specification:

License: Proprietary

Abyssale API Reference

Abyssale is a programmatic creative asset generation API for creating marketing visuals, ad creatives, videos, and print-ready PDFs at scale. Design once in Abyssale, then generate thousands of personalized variations — across every format, channel, and language — via a single REST API call.

This documentation is about the Abyssale Rest API. If you would like to discover other Abyssale features or to have a comprehensive understanding on how everything works, go to the Abyssale developers hub.

Base URL: https://api.abyssale.com

General Rest API information:

  • Data exchange format: JSON. All API calls must contain the Content-Type: application/json header.
  • Rate limits: 10 requests/second
  • Only successful generated assets are counted in your API usage.
  • Trial plan: 30 requests are included.
  • Available Integrations: Zapier, Make (ex Integromat), Airtable & n8n (if you prefer using nocode)

Which approach should I use?

Use case Recommended approach
Personalized images in emails (rendered on open) Static design → Dynamic image URL
Embed a live, customizable image on a website Static design → Dynamic image URL
Single image on demand (synchronous response) Synchronous generation
Bulk campaign creatives across multiple formats Async generation
Animated GIF or video for social/ads Animated design → Async generation with gif or video options
HTML5 banner ads for ad networks Animated design → Async generation with html5 options
Print-ready PDF (single page) Printer design → Async generation with print options
Multi-page print document (brochure, catalog) Printer multipage design → Multi-page PDF

Authentication

Abyssale uses API Key Authentication. Your API key is passed along with every API call, allowing Abyssale to identify your company account and access your data.

How to get your API Key?

api_key

All of your Abyssale requests must contain a x-api-key header with your API Key.

Security Scheme Type: API Key
Header parameter name: x-api-key

Common error responses (applicable to all endpoints):

  • 401 Unauthorized — missing or invalid API key
  • 429 Too Many Requests — rate limit exceeded (10 req/s) or insufficient credits
  • 500 Internal Server Error — unexpected server-side failure

Designs

A design is a layout including at least:

  • one format (dimension, i.e. Facebook feed 1200x628 or IAB 300x250)
  • one element (text, button, image, shape...)

All elements have their own properties that can be customized (color, text payload, image...).

Once designed, all properties of the design will act as a reference for subsequent image generation. Obviously, those properties can be overridden by sending new parameters in the generation API call.

Abyssale provides a list of free template designs in the Template Library page. Feel free to use one to start designing your design instead of doing it from scratch.

All of your designs are listed in the different project pages, only those are accessible via API.

List all designs

Retrieve all designs available in your Abyssale workspace. Each design defines the visual layout, available formats (dimensions), and configurable elements (text, images, shapes, etc.) that can be overridden during image generation. Filter by design type or project using query parameters.

A design lives in a project. Organisation-level master designs are workspace templates, live in a category, and are listed by GET /workspace-templates instead — they never appear here.

Authorizations:
api_key
query Parameters
project_id
string <uuid>

Unique identifier (UUID) of a project. Filter designs by project.

category_id
string <uuid>
Deprecated

Deprecated alias of project_id. Ignored when project_id is also sent.

type
string
Enum: "static" "animated" "printer" "printer_multipage"

Filter designs by one of these types static, animated, printer, printer_multipage

Responses

Response samples

Content type
application/json
[]

Get design details

Retrieve the full specification of a design: its formats (dimensions and preview URLs), all configurable elements with their properties, and any template variables defined in text layers. Use this endpoint to discover what data to send in a generation request.

For printer designs, each format additionally carries its print settings read-only: dpi (integer render DPI computed at import time, capped at 300), and bleed_size / safe_size (floats in the format's unit, present only when the corresponding zone is enabled).

For animated designs, the response additionally carries the animation model: a top-level animation object (duration — timeline length in seconds; screenshot_at_s — the HTML5 backup-screenshot moment, nullable on legacy designs), a per-element animation object (start_at_s, end_at_s, tweens [{id, type, keyframes}] with raw keyframe objects) on elements that carry timing or tweens, and video/audio media attributes (video_url/audio_url, video_duration, video_muted/audio_muted, max_volume) in the standard attribute shape.

Multipage print designs (printer_multipage) return a different shape. A multipage design has no formats — each page is one format row — so the response carries pages and elements_per_page instead of formats, elements, variables and dynamic_image_url. A client coded against formats[] will not work on a multipage design. pages[] items carry id (page_1 … page_N), width, height, unit, preview_url and the read-only dpi/bleed_size/safe_size print settings; elements_per_page is an object keyed by page id (not an array), each value being that page's element list with group layers included.

Authorizations:
api_key
path Parameters
designId
required
string <uuid>

Unique identifier (UUID) of the design

Responses

Response samples

Content type
application/json
{}

Get format details

Retrieve detailed information for a specific format within a design, including dimensions, unit, preview URL, dynamic image URL, element layout, and variables. Useful for inspecting a single format before generating or building dynamic image URLs.

For printer designs the response additionally carries the format's print settings read-only: dpi (integer render DPI computed at import time, capped at 300), and bleed_size / safe_size (floats in the format's unit, present only when the corresponding zone is enabled).

For animated designs the response additionally carries the design's animation object (duration, screenshot_at_s — seconds), per-element animation timing/tween data, and video/audio media attributes — the same read surface as GET /designs/{designId}.

Multipage print designs (printer_multipage): a multipage design has no formats — each page is one format row named page_1 … page_N, so page_N is the formatSpecifier for this endpoint. The response is that page's object at the root (id, width, height, unit, preview_url, plus the read-only dpi/bleed_size/safe_size print settings) together with a design object (id, name, type, category_name, created_at, updated_at) and the page's elements array (group layers included). dynamic_image_url and variables are not returned for print designs. An unknown or malformed page identifier yields 404 with id: format_not_found.

Authorizations:
api_key
path Parameters
designId
required
string

Unique identifier of the design

formatSpecifier
required
string

Format name or UID. For a printer_multipage design this is the page identifier page_1 … page_N (a multipage design has no formats — each page is one format row).

Responses

Response samples

Content type
application/json
{}

Asset Generation

Generate images, animated videos, GIFs, HTML5 banners, and print-ready PDFs programmatically from your Abyssale designs.

The generation workflow is simple:

  1. Build your design in Abyssale (or pick one from the Template Library)
  2. Send your dynamic data — text, images, colors — via the API
  3. Receive the generated asset URL in the response

Use the synchronous endpoint for single-image generation with an immediate response. Use the asynchronous endpoint for bulk banner creation across multiple formats at once — ideal for marketing automation, personalized ad campaigns, and batch asset production at scale.

Generate an image (synchronous)

Synchronously generate a single image from a design. Send your dynamic data (text, images, colors) as element overrides in the request body and receive the generated file URL immediately in the response.

Best for: real-time image generation, single-asset workflows, or when you need the result inline without polling.

For bulk generation across multiple formats, use the asynchronous endpoint instead.

Authorizations:
api_key
path Parameters
designId
required
string <uuid>

Unique identifier (UUID) of the design

Request Body schema: application/json
required
object (Elements)

A dictionary containing all elements with properties you would like to override form the default design (keys correspond to layer names)

template_format_name
string

Corresponds to the format ID you would like to generate (only mandatory when your design contains several formats).

image_file_type
string
Enum: "png" "jpeg" "webp" "avif" "pdf" "auto"

Output file type. Defaults to the design's configured type when omitted.

file_compression_level
integer [ 1 .. 100 ]

Percentage of compression applied.

Responses

Request samples

Content type
application/json
{
  • "elements": {
    },
  • "template_format_name": "facebook-post",
  • "image_file_type": "png",
  • "file_compression_level": 80
}

Response samples

Content type
application/json
{}

Generate images/videos/PDFs asynchronously (multi-format)

Asynchronously generate multiple formats of an image, video, GIF, HTML5 banner, or PDF in a single API call. Ideal for bulk banner production, multi-channel marketing campaigns, and programmatic ad creative generation at scale.

Specify one or more format IDs to generate, or omit the list to generate all formats defined in the design. Provide a callback_url to receive a webhook notification when generation is complete, or poll GET /generation-request/{generationRequestId} for status.

You can find available formats and elements by calling GET /designs/{designId}.

Authorizations:
api_key
path Parameters
designId
required
string <uuid>

Unique identifier (UUID) of the design

Request Body schema: application/json
required
object (AsyncElements)

Same as Elements, but its image element also exposes AI generation properties (text_to_image, inpainting, background removal model) that are only available for asynchronous generation.

template_format_names
Array of strings

Format IDs you would like to generate.

The array can be empty or not provided if you want to generate all formats of this design.

callback_url
string <uri>

The url that will be called once generation of your images is done.

We will do a POST request of the NewBannerBatch event on this URL with a JSON payload.

image_file_type
string
Enum: "png" "jpeg" "webp" "avif" "gif" "pdf" "html5" "mp4" "auto"

Output file type. Depends on the design type (static/animated/printer). Defaults to the design's configured type when omitted.

file_compression_level
integer [ 1 .. 100 ]

Percentage of compression applied.

object

HTML5 output options (animated designs only)

object

GIF output options (animated designs only)

object

Video output options (animated designs only)

object

Print output options (printer/printer_multipage designs only)

original_visual_id
string <uuid>

UUID of the original visual this generation is based on.

Responses

Request samples

Content type
application/json
{
  • "elements": {
    },
  • "template_format_names": [
    ],
  • "callback_url": "http://example.com",
  • "image_file_type": "png",
  • "file_compression_level": 1,
  • "html5": {
    },
  • "gif": {
    },
  • "video": {
    },
  • "print": {
    },
  • "original_visual_id": "efce0750-ba21-49c4-be6f-4e6125cdc6bb"
}

Response samples

Content type
application/json
{
  • "generation_request_id": "06399fcd-0c21-47da-bd9b-1e653e0453e8"
}

Generate a multi-page PDF (asynchronous)

Asynchronously generate a multi-page print-ready PDF from a printer_multipage design. Each page is defined by a pages dictionary entry, allowing different element overrides per page — ideal for brochures, catalogs, and variable data printing.

Provide a callback_url to receive a webhook when the PDF is ready, or poll GET /generation-request/{generationRequestId} for status.

You can find available formats and elements by calling GET /designs/{designId}.

Authorizations:
api_key
path Parameters
designId
required
string <uuid>

Unique identifier (UUID) of the design

Request Body schema: application/json
required
required
object (Pages)

A dictionary containing all pages with properties you would like to override form the default design (keys correspond to layer names)

callback_url
string <uri>

The url that will be called once generation of your PDF is done.

We will do a POST request of the NewBannerBatch event on this URL with a JSON payload.

object

Print output options

original_visual_id
string <uuid>

UUID of the original visual this generation is based on.

Responses

Request samples

Content type
application/json
{
  • "pages": {
    },
  • "callback_url": "http://example.com",
  • "print": {
    },
  • "original_visual_id": "efce0750-ba21-49c4-be6f-4e6125cdc6bb"
}

Response samples

Content type
application/json
{
  • "generation_request_id": "06399fcd-0c21-47da-bd9b-1e653e0453e8"
}

Poll async generation request status

Poll the status of an asynchronous generation request. Use this endpoint to track the progress of a batch generation operation started with the async generate endpoint. The result is available for 7 days after generation.

Authorizations:
api_key
path Parameters
generationRequestId
required
string <uuid>

Unique identifier (UUID) of the generation request

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "is_finalized": true,
  • "banners": [],
  • "errors": [
    ]
}

Fonts

Retrieve the fonts available in your Abyssale workspace. Fonts can be applied to text and button elements during image generation. Two types are supported: Google Fonts (free, always available) and custom fonts uploaded to your workspace.

Reference a font by its ID when overriding the font property in a generation request.

List available fonts

Retrieve all fonts available in your Abyssale workspace, including Google Fonts and any custom fonts you have uploaded. Use a font's id to override the font on text or button elements in a generation request.

Authorizations:
api_key
query Parameters
type
string
Enum: "google" "custom"

Filter fonts by type. Omit to return both Google and custom fonts.

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Exports

Export a collection of previously generated banners as a single ZIP archive. Useful for downloading bulk assets for offline use, sharing with creative teams, or archiving a campaign's outputs. The export is processed asynchronously — provide a callback URL to receive a webhook notification when the archive is ready.

Banner export archive ready Webhook

An asynchronous banner export has completed. The ZIP archive containing all requested banners is available at the provided archive_url.

Request Body schema: application/json
export_id
string <uuid>

ID of the export

archive_url
string <uri>

The zip public URL

requested_at
number

Timestamp at which the export has been requested

generated_at
number

Timestamp at which the export has been done

Responses

Request samples

Content type
application/json
{}

Export banners as ZIP archive (asynchronous)

Asynchronously package a set of previously generated banners into a single ZIP archive for download. Provide a callback_url to receive a webhook notification when the export is ready, containing the archive URL.

Authorizations:
api_key
Request Body schema: application/json
required
ids
required
Array of strings <uuid> [ items <uuid > ]

An array of string that corresponds to the banners IDs you would like to export.

callback_url
string <uri>

The url that will be called once the generation of your export is done.

Responses

Request samples

Content type
application/json
{}

Response samples

Content type
application/json
{
  • "export_id": "64238d01-d402-474b-8c2d-fbc957e9d290"
}

Files

Retrieve metadata and download URLs for generated files (images, videos, GIFs, HTML5 banners, and PDFs). Listen to webhook events to be notified in real time when a file or batch generation completes.

File generated Webhook

A new file (image, video, GIF, HTML5 banner, or PDF) has been generated and is ready to download.

Request Body schema: application/json
id
required
string <uuid>
version
integer

Version number of the generated file.

sharing_id
string <uuid>

Identifier used for sharing this generated file.

required
object (File)
object (Format)
object (Design)

Responses

Request samples

Content type
application/json
{}

Batch generation completed Webhook

An asynchronous batch generation request has completed. Contains the full list of generated files and any per-format errors. Triggered by POST /async/banner-builder/{designId}/generate.

Request Body schema: application/json
id
required
string <uuid>

Unique identifier (UUID) of the batch generation

required
Array of objects (Banner)

List of generated images

Array of objects

If any errors occur, they will be listed under that property

Responses

Request samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "banners": [],
  • "errors": [
    ]
}

Get generated file

Retrieve the metadata and download URLs for a previously generated file (image, video, GIF, HTML5 banner, or PDF). Returns both the S3 storage URL and a CDN-hosted URL suitable for embedding directly in websites or emails.

Authorizations:
api_key
path Parameters
bannerId
required
string <uuid>

Unique identifier (UUID) of the file

Responses

Response samples

Content type
application/json
{}

Projects

Projects let you organize your designs into logical groups — for example by campaign, client, or content type. All designs must belong to a project to be accessible via the API. Use projects to scope design retrieval and keep large design libraries manageable.

List projects

Retrieve all projects in your workspace. Projects group designs into logical collections. Only designs that belong to a project are accessible via the API.

Authorizations:
api_key

Responses

Response samples

Content type
application/json
[
  • {
    },
  • {
    }
]

Create a project

Create a new project to organize your designs. Assign designs to this project in the Abyssale editor to make them accessible via the API.

Authorizations:
api_key
Request Body schema: application/json
required
name
required
string [ 2 .. 100 ] characters

Name of the project

Responses

Request samples

Content type
application/json
{
  • "name": "Summer Campaign 2024"
}

Response samples

Content type
application/json
{
  • "id": "cb2c4add-4867-11f0-96f2-0a00d9eb8f78",
  • "name": "Summer Campaign 2024",
  • "created_at_ts": 1749827107
}

Workspace Templates

Workspace templates are master designs shared across your organization. Duplicate them into any project to create editable copies — useful for spinning up campaign variants, onboarding new clients, or maintaining brand-consistent starting points. The duplication is processed asynchronously; poll the status endpoint to track progress.

List all workspace templates

Retrieve the organisation-level master designs shared across your workspace.

A workspace template lives in a category (category_id), not a project — it belongs to the organisation until you duplicate it into a project with POST /workspace-templates/{companyTemplateId}/use. Designs, which do live in a project, are listed by GET /designs; the two listings never overlap.

Items have the same shape as a design, except the grouping fields are named category_id / category_name.

Authorizations:
api_key
query Parameters
category_id
string <uuid>

Unique identifier (UUID) of a workspace category. List the available ids with GET /workspace-template-categories. Categories are optional, so this filter only ever returns categorised templates — omit it to include those at the workspace root.

type
string
Enum: "static" "animated" "printer" "printer_multipage"

Filter workspace templates by one of these types static, animated, printer, printer_multipage

Responses

Response samples

Content type
application/json
[
  • {
    }
]

List workspace template categories

The categories that group your workspace templates. Use an id from here as the category_id filter on GET /workspace-templates.

This is the workspace-template counterpart of GET /projects, which groups designs.

Authorizations:
api_key

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Duplicate a workspace template into a project

Copy a shared workspace template into one of your projects, creating an editable design instance. The duplication is asynchronous — use the returned duplication_request_id to poll for completion via GET /design-duplication-requests/{duplicateRequestId}.

Authorizations:
api_key
path Parameters
companyTemplateId
required
string <uuid>
Example: 0c967bd0-4137-4690-ad70-249aa021c68b

Unique identifier (UUID) of the workspace template to duplicate

Request Body schema: application/json
required
project_id
required
string <uuid>

Target project ID where the template will be duplicated

name
string [ 2 .. 100 ] characters

Optional custom name for the duplicated template

Responses

Request samples

Content type
application/json
Example
{
  • "project_id": "d59adee9-4867-11f0-96f2-0a00d9eb8f78"
}

Response samples

Content type
application/json
{
  • "duplication_request_id": "40c32a4e-4869-11f0-96f2-0a00d9eb8f78"
}

Poll template duplication request status

Poll the status of a template duplication request. Use this endpoint to track the progress of an asynchronous duplication operation.

Authorizations:
api_key
path Parameters
duplicateRequestId
required
string <uuid>
Example: 40c32a4e-4869-11f0-96f2-0a00d9eb8f78

Unique identifier (UUID) of the duplication request

Responses

Response samples

Content type
application/json
Example
{
  • "request_id": "40c32a4e-4869-11f0-96f2-0a00d9eb8f78",
  • "status": "COMPLETED",
  • "created_at_ts": 1749827734,
  • "completed_at_ts": 1749827736,
  • "errored_at_ts": null,
  • "target_project": {
    },
  • "designs": [
    ]
}

Template Import

Alpha. This API is in Alpha. The contract may change without notice and imports created with it are not guaranteed to remain compatible. It is not covered by deprecation policy.

This applies to every operation in this section.

Import a design from a JSON structure. The flow is three steps:

  1. POST /templates/import/json — Submit your template structure. Receive an import ID, a links block, and a flat uploads[] array of presigned S3 POSTs (one per image/logo layer whose src is a filename).
  2. Upload assets — POST each file to its presigned URL using the returned fields.
  3. PUT /templates/import/json/{importId} — Validate the import. The edge API performs a pre-flight HEAD on every expected upload, then queues the import for backend processing. Use the links.dashboard URL to track progress in the platform.

Dry-run validation: add ?validate_only=true to the POST to run the full schema plus every payload-only cross-field validator without creating an import or generating presigned URLs. Returns 204 No Content on success and the structured error contract on failure. Exactly three checks are excluded because they require I/O rather than the payload alone: unknown_font and project_not_found (database lookups) and unreachable_src (a network HEAD). A 204 therefore means the payload is structurally valid; it does not guarantee the referenced fonts, URLs and project exist.

Sync short-circuit: when every src is a public URL or data URI, the POST returns the import already in QUEUED and uploads[] is empty — no PUT needed.

Use GET /templates/import/json/{importId} to poll the import status at any time. The response includes next_check_after_ms (suggested polling cadence), structured warnings[] (non-fatal processing decisions), and a structured error object when status is FAILED.

Thumbnails are backend-generated — the payload carries no preview image field (preview_image is rejected as unknown_field). After the design is built, the backend renders every format and copies the first rendered visual to the design thumbnail; the import stays in PROCESSING while previews render and reaches DONE once the thumbnail exists.

Errors use a unified, machine-readable shape across all template-import endpoints:

{
  "errors": [
    { "path": "layers[2].properties.font_size", "code": "out_of_range",
      "message": "font_size must be between 2 and 1000",
      "expected": { "min": 2, "max": 1000 }, "received": 1500 }
  ]
}

Round-trip helper: GET /designs/{designUuid}/as-import?as=v1 returns an existing static, printer or animated design in the exact shape POST /templates/import/json accepts — useful as an agent few-shot or for round-trip regression tests.

Printer designs (v2): type: "printer" produces single-page print PDF designs. The payload is authored in physical units: each printer format declares a required unit (mm | in) and all geometry in that format (format dims, layer layout, geometric properties, bleed_size/safe_size) is a float in that unit; font_size/min_font_size are floats in pt (0.48–240). Colors are stored as cmyk(c,m,y,k) / cmyka(c,m,y,k[,a]) tokens (integers 0–100, no %), but a solid hex value is accepted and converted to cmyk with a color_converted warning; a cmyk token on a static/animated import is likewise converted to hex. Conversion uses no ICC profile and is approximate — author cmyk(...) directly when the exact print color matters. Gradients on printer stay rejected with unsupported_for_type, because converting one would collapse it to a flat fill. Format sizes and layer layouts must additionally stay within the platform's pixel limits when converted at the fixed 300 DPI (violations → out_of_range; individual geometric properties carry no upper bound on printer; 300 DPI is only this layout bridge — the stored per-format render DPI is computed by the backend, capped at 300, and surfaced read-only on GET /designs/{designId}). Printer layer assets uploaded via presigned URL may be up to 500 MB (20 MB for static); inline data URIs are capped at 2 MB decoded on every design type — the overall request body is capped at 20 MB; TIFF layer sources are accepted on printer and printer_multipage — print originals are stored untouched (ICC profile preserved) and a display proxy is generated automatically for TIFF or >20 MB inputs.

Animated designs (v3): type: "animated" produces animated (video) designs. The payload is px-authored like static (integer geometry, hex colors) plus a required top-level animation object: duration (float seconds, 1–60 — the timeline length) and optional screenshot_at_s (0 ≤ value ≤ duration, default = duration — the moment the HTML5 backup screenshot is taken). Each layer may carry an optional animation object: start_at_s (default 0), end_at_s (default = duration; must be ≤ duration and > start_at_s), and tweens{ type: slide | fade | scale | rotate | audioFade | typeWriting, keyframes: [...] }. Keyframe items are deliberately loose (raw objects — several keyframe schema generations coexist); the only requirement is that every keyframe carries a numeric data.time. Tween ids are generated by the backend and are not payload fields. Two new layer types exist on animated only: video (src mp4/webm + muted) and audio (src mp3/wav + muted + max_volume 0–1; muted: true renders silent). Every animated format must fit within a 1920×1200 bounding box in either orientation (max side ≤ 1920 and min side ≤ 1200 — violations → out_of_range). Layer assets uploaded via presigned URL are capped per layer type on animated — 100 MB video, 25 MB audio, 20 MB image/logo; inline data URIs stay capped at 2 MB decoded. animation on static/printer, video/audio layers off-animated, and group auto_layout/direction/placement/gap on animated are rejected (unsupported_for_type / unknown_enum_value).

Multipage print designs (v6): type: "printer_multipage" produces a multi-page print PDF. All pages of a multipage design have the same dimensions, so the print setup is declared once at the top level: required unit (mm | in), width, height, plus optional bleed_size/safe_size (floats in unit) and an optional global dpi (integer 10–300). Instead of formats + top-level layers, the payload carries a top-level ordered pages array (1–30 pages; the backend names them page_1 … page_N in array order). A page object carries only background_color (required) and its own layers array (1–80 layers). A page is single-format, so its layer layout/properties may be flat or keyed under default; any other key on a page, including the print settings and name, is rejected with unknown_field. Every per-layer rule inherits type: "printer" unchanged (cmyk color storage with hex converted and gradients rejected, physical-unit geometry, pt font sizes 0.48–240, TIFF sources, 500 MB presigned / 2 MB data-URI / 1 MB qrcode-icon caps, shadow/text_shadow/pattern_name/pattern_color/overlay_* accepted and dropped with a property_dropped_for_type warning, gradients rejected). There are no shared layers and no layer ordering field — an element repeated across pages is included in each page. dpi is one global optional field (10–300) capped at the document's single area-based ceiling; omitted, the backend computes that ceiling as the default for every page. GET /designs/{designId}/as-import?as=v1 emits the same top-level-print-setup + pages[] shape and multipage designs round-trip. GET /designs/{designId} returns pages[] + elements_per_page for multipage designs (no formats), and GET /designs/{designId}/formats/page_N reads a single page.

Company API keys only. User API keys are not accepted on these routes.

List Imports

Alpha. This API is in Alpha. The contract may change without notice and imports created with it are not guaranteed to remain compatible. It is not covered by deprecation policy.

List this company's JSON template imports, newest first.

Use this to recover an import whose id you no longer have. Because the flow is POST → upload → PUT, a client that loses the id between those steps leaves behind an import it cannot otherwise resume or inspect; listing is how you find it again.

Rows are summaries. The unbounded warnings[] array and the error object are served by GET /templates/import/json/{importId} — a row carries warning_count instead, and a links.status pointing at that endpoint.

status filters on the effective status, matching what the item endpoint reports: an import whose presigned upload window has closed counts as FAILED, not WAITING_FOR_VALIDATION, even though the stored row is untouched.

Lists JSON imports exclusively — imports created through other channels are not returned.

No cursor. Results are capped by limit; narrow with created_after / created_before to reach imports beyond the cap.

Authorizations:
api_key
query Parameters
status
string
Enum: "WAITING_FOR_VALIDATION" "QUEUED" "PROCESSING" "DONE" "FAILED"

Return only imports whose effective status matches.

created_after
integer

Unix timestamp (seconds). Return imports created at or after this moment.

created_before
integer

Unix timestamp (seconds). Return imports created at or before this moment.

limit
integer [ 1 .. 200 ]
Default: 50

Maximum number of imports to return.

Responses

Response samples

Content type
application/json
[]

Import Template from JSON

Alpha. This API is in Alpha. The contract may change without notice and imports created with it are not guaranteed to remain compatible. It is not covered by deprecation policy.

Submit a template structure as JSON. Returns an import ID, a links block, and a flat uploads[] array of presigned S3 POSTs for any image/logo src filenames. When every src is a public URL or data URI, the import is returned already in QUEUED with an empty uploads[] — no PUT call is needed.

The payload carries no preview image: design thumbnails are generated by the backend after import (every format is rendered and the first visual becomes the thumbnail; the import reports PROCESSING while previews render).

Dry run: pass ?validate_only=true to validate the payload without creating an import. Runs the full schema and all payload-only structural validators (conflicting filename sources, data-URI validity and decoded-size caps, TIFF type constraints, video/audio extensions, animated keyframes, qrcode icons). Excluded: unknown_font, project_not_found (database lookups) and unreachable_src (network HEAD). Returns 204 No Content on success.

Company API keys only. User API keys receive 401 Unauthorized.

Authorizations:
api_key
query Parameters
validate_only
boolean
Default: false

When true, runs schema and cross-field validation and returns 204 No Content without creating an import row or generating presigned URLs.

strict
boolean
Default: false

When true, a text layer that cannot fit its box even at min_font_size fails the import (text_fit_failed error) instead of importing with a text_fit_failed warning.

Request Body schema: application/json
required
name
required
string [ 1 .. 100 ] characters
type
required
string
Enum: "static" "printer" "animated" "printer_multipage"

Design type. static = single image; printer = single-page print PDF (v2); animated = animated/video design (v3); printer_multipage = multi-page print PDF (v6). Printer payloads are authored in physical units — each format requires a unit (mm | in), geometry is floats in that unit, font sizes are pt, and colors are stored as cmyk (a solid hex is converted with a color_converted warning; gradients are rejected). Animated payloads are px-authored like static and require a top-level animation object; they may use video/audio layers and per-layer animation timing/tweens. Multipage payloads (printer_multipage) drop formats/layers, declare the print setup once at the top level (unit/width/height required, bleed_size/safe_size/dpi optional), and carry a top-level ordered pages array (1–30 pages); each page is a self-contained print page (own background_color + layers, inheriting the document-wide print setup) that inherits every per-layer printer rule. No shared layers exist — a repeated element is included per page.

object

What the import produces. Defaults to { "kind": "template" } (a workspace template). With kind: design, project_uuid is required and the import produces a live design under that project; only kind=design results are addressable via GET /designs/{uuid}/as-import.

Array of objects (TemplateImportJsonFormat) [ 1 .. 20 ] items

List of formats (1-20). Required on static/printer/animated; omit on printer_multipage (use pages instead). A count outside 1-20 is rejected with out_of_range at formats. background_color is required on each format. There is no preview-image field — thumbnails are backend-generated (a preview_image key is rejected as unknown_field).

Array of objects (TemplateImportJsonLayer) [ 1 .. 80 ] items

Required on static/printer/animated; omit on printer_multipage (each page carries its own flat layers). 1-80 layers - an empty array is rejected with out_of_range at layers (expected: {min: 1, max: 80}), since required enforces key presence and not non-emptiness. Layers defined once at the top level. Each layer contains layout and properties keyed by format name. A "default" key may be used in either dict — it is merged under each per-format entry before validation, so overrides only need to specify the fields that differ.

unit
string
Enum: "mm" "in"

printer_multipage designs only — required (moved here from the page object on 2026-07-25). Physical authoring unit for everything in the document: page size, bleed/safe sizes and every layer's geometry on every page. Declared exactly once, because all pages of a multipage design have the same dimensions. Missing → missing_required at unit. On static/printer/animated payloads unit is a per-format field instead (see the format schema).

width
number > 0

printer_multipage designs only — required. Page width as a float in unit, shared by every page. Its pixel equivalent at 300 DPI must stay within 1–20000 (out_of_range at width).

height
number > 0

printer_multipage designs only — required. Page height as a float in unit, shared by every page. Same 1–20000 px-equivalence bound, reported at height.

bleed_size
number >= 0

printer_multipage designs only. Optional bleed size as a float in unit; presence enables bleed on every page.

safe_size
number >= 0

printer_multipage designs only. Optional safe-zone size as a float in unit; presence enables the safe zone on every page.

dpi
integer [ 10 .. 300 ]

printer_multipage designs only. Optional global render DPI for the whole document. Because the document has a single page size there is exactly one area-based ceiling min(300, floor(72*sqrt(225000000/(w_pt*h_pt)))); a higher value is rejected with out_of_range at dpi (carrying expected: {max: <ceiling>} and received). Omitted ⇒ the backend computes that same ceiling as the default, identically for every page. On printer designs dpi is a per-format field instead.

Array of objects (TemplateImportJsonPage) [ 1 .. 30 ] items

printer_multipage designs only (replaces formats + top-level layers; forbidden on other types). Ordered array of 1–30 self-contained print pages — array order is the page order (the backend names them page_1 … page_N). A count outside 1–30 → out_of_range at pages. Changed 2026-07-25: the print setup lives at the top level (unit/width/height/bleed_size/safe_size/dpi) because all pages share one size; a page object carries only background_color and a flat layers array (one format per page).

object

Animated designs only — required when type is animated, rejected with unsupported_for_type on static/printer. The design's timeline.

Responses

Request samples

Content type
application/json
{
  • "name": "My YouTube Template",
  • "type": "static",
  • "target": {
    },
  • "formats": [
    ],
  • "layers": [
    ],
  • "unit": "mm",
  • "width": 210,
  • "height": 297,
  • "bleed_size": 0,
  • "safe_size": 0,
  • "dpi": 300,
  • "pages": [
    ],
  • "animation": {
    }
}

Response samples

Content type
application/json
{}

Get Import Status

Alpha. This API is in Alpha. The contract may change without notice and imports created with it are not guaranteed to remain compatible. It is not covered by deprecation policy.

Poll the status of a JSON template import. Scoped to the caller's company.

Returns next_check_after_ms (suggested delay before the next poll, null on terminal states), a stable append-only warnings[] array, and a structured error object when status is FAILED.

Expired upload windows. An import that reaches WAITING_FOR_VALIDATION and is never validated before its presigned upload window closes is reported as terminal: status: "FAILED", next_check_after_ms: null, no validate link, and error: {path: "uploads", code: "missing_assets", ...}. This is derived at read time from the import's creation timestamp — the GET performs no write, so the stored row keeps its original state. A poller should therefore always drive off terminal states rather than waiting indefinitely.

Authorizations:
api_key
path Parameters
importId
required
string <uuid>

Import UUID returned by the POST endpoint.

Responses

Response samples

Content type
application/json
{}

Validate Import & Trigger Processing

Alpha. This API is in Alpha. The contract may change without notice and imports created with it are not guaranteed to remain compatible. It is not covered by deprecation policy.

Call this after every entry of uploads[] has been POSTed to S3. The edge API performs a pre-flight HEAD on every expected key. If any are missing, it returns 422 missing_assets with the list of unfulfilled targets.

On success, the import status transitions to QUEUED and backend processing picks it up. PUT is idempotent on QUEUED rows. PUT on a PROCESSING, DONE, or FAILED row returns 409 template_import_already_processed.

Authorizations:
api_key
path Parameters
importId
required
string <uuid>

Import UUID returned by the POST endpoint.

Responses

Response samples

Content type
application/json

Export Design as Import Payload

Alpha. This API is in Alpha. The contract may change without notice and imports created with it are not guaranteed to remain compatible. It is not covered by deprecation policy.

Return an existing static, printer, animated or printer_multipage design serialized into the exact shape that POST /templates/import/json accepts. Useful as a few-shot example for AI agents or as a round-trip regression test (as-importPOSTas-import, diff should be empty).

The returned src values are Abyssale-hosted https:// URLs — agents do not need to re-upload assets. The response always validates against the import schema before being returned; designs using features outside the import schema yield 400 not_round_trippable with structured details.

Printer designs: the payload is emitted verbatim in the physical-unit space the import contract is authored in — geometry as floats in each format's unit (mm | in), font sizes in pt (no DPI conversion). cmyk color tokens are normalised to the canonical cmyk()/cmyka() grammar, and a legacy RGB-authored (hex) solid color is converted to cmyk with a color_converted warning rather than failing the export; only a gradient on a printer design still fails with not_round_trippable. Star geometry exceeding the v1 pixel-equivalence caps is clipped with a warning (donor fidelity — import no longer enforces those caps). bleed_size/safe_size round-trip (read from the stored print settings and emitted on the exported formats), as do rectangle-shape strokes, untouched print image originals (the exported src prefers the original over any display proxy), and qrcode center icons (emitted as data URIs; the error-correction level is backend-chosen and never emitted). dpi round-trips as well: it is an import field (int 10–300, per format on printer, capped by the format's area-based ceiling), so the stored value is emitted and re-import reuses it rather than recomputing. A structured print_settings_not_recoverable warning is emitted when the print settings cannot be read at all.

Animated designs: the export carries the full animation model — top-level animation (duration from the stored timeline length, screenshot_at_s when stored) and per-layer animation (start_at_s/end_at_s timing plus tweens with keyframes passed through verbatim; stored tween ids are dropped — re-import regenerates them). video/audio layers export their hosted source URL as src plus muted/max_volume. Legacy designs with no stored timeline duration derive it from element timing and emit a structured animation_duration_derived warning; designs whose formats exceed the 1920×1200 either-orientation bounding box (legacy data only) fail with not_round_trippable. Values outside the import bounds (duration, timing) are clipped with warnings.

Multipage print designs (printer_multipage): the export emits the document-wide print setup at the top level (unit/width/height, plus bleed_size/safe_size/dpi when recoverable) and a pages[] array whose entries carry only background_color and layers — each page transformed via the printer path (geometry verbatim in the physical-unit space, colors normalised to cmyk, no DPI conversion). An image/logo layer whose slot was never filled is emitted with no src and keeps its layout, on every design type — src is optional on import so an empty slot round-trips. A legacy design whose stored pages disagree on a print setting cannot be expressed in the uniform shape: the first page's value is emitted with a print_settings_not_recoverable warning at width/height/unit, bleed_size, safe_size or dpi (a divergent dpi is omitted entirely so the backend recomputes it). A stored dpi above the document's ceiling is clamped to the ceiling with the same warning rather than failing the export. An export left with no layers at all yields not_round_trippable.

Authorizations:
api_key
path Parameters
designUuid
required
string <uuid>

UUID of an existing design.

query Parameters
as
string
Default: "v1"
Value: "v1"

Export-contract version. Pin to v1 to ensure forward compatibility.

Responses

Response samples

Content type
application/json
{
  • "payload": {
    },
  • "warnings": [
    ],
  • "version": "v1"
}

Dynamic Images

Dynamic images are live image URLs that render on-the-fly based on query parameters. Once created for a design, the URL can be embedded anywhere — emails, websites, social posts — and customized with different text, colors, or images per use case, without additional API calls. Ideal for personalization at scale.

Create a dynamic image URL

Creates a dynamic image URL for a given design. Only one dynamic image is allowed per design. Subsequent calls return the existing dynamic image. Use enable_rate_limit in the request body to enable API rate limiting for this image & enable_production_mode to enable production mode (default is test mode).

Authorizations:
api_key
path Parameters
designId
required
string

Unique identifier of the design

Request Body schema: application/json
required
enable_rate_limit
boolean
Default: false

Enable API rate limiting for this dynamic image

enable_production_mode
boolean
Default: false

Enable Production mode for this dynamic image

Responses

Request samples

Content type
application/json
{
  • "enable_rate_limit": true,
  • "enable_production_mode": true
}

Response samples

Content type
application/json
{}
Download spec