Koalaful API Reference

The API base is https://dash.koalaful.io/api. Browser sessions still work for first-party use, but external clients should authenticate with personal API keys sent as Authorization: Bearer ... or X-API-Key.

Manage API keys in dashboard Back to marketing site

Getting started

Authenticated endpoints accept either:

  • A logged-in browser session using the koalaful_session cookie.
  • A personal API key via Authorization: Bearer <key>.
  • The same key via X-API-Key: <key>.

Request conventions:

  • JSON bodies: Content-Type: application/json
  • File uploads: multipart/form-data
  • Design routes generally accept either numeric IDs or share codes.
  • Public routes include /templates, /templates/{id}, /fonts, and /categories.
Session cookies are fine for same-origin browser use. For scripts, CLI access, webhooks, server jobs, and external integrations, use personal API keys.
curl https://dash.koalaful.io/api/designs \
  -H "Authorization: Bearer kfl_..."

API keys

API keys are managed from the dashboard while logged in. Open /dashboard#api-keys to create, view, and revoke them. A new key is shown exactly once at creation time.

MethodEndpointDescription
GET/auth/api-keysList your existing keys. Session authentication required.
POST/auth/api-keysCreate a key with {"name":"CI","expires_at":"2026-12-31 23:59:59"}. expires_at is optional.
DELETE/auth/api-keys/{id}Revoke a key immediately.
These management endpoints use your current browser session, not an API key.
Sign in, then create a key here. The full key is returned once on creation.

Designs

Core design CRUD and collaboration. These routes require session or API key authentication.

MethodEndpointDescription
GET/designsList the current user’s designs ordered by updated_at.
GET/designs/{id}Fetch one design. HTML designs return html_content, css_content, and metadata.
POST/designsCreate a design. title is optional; width, height, type, and payload are optional.
PUT/designs/{id}Partial update. You can update title, dimensions, HTML, CSS, metadata, design data, and thumbnail independently.
DELETE/designs/{id}Delete one design.
POST/designs/bulk-deleteDelete or soft-delete multiple designs with {"ids":[...]} and optional permanent.
POST/designs/{id}/restoreRestore a soft-deleted design.
POST/designs/from-templateClone an active template into a new user-owned HTML design.
POST/designs/{id}/starToggle starred state.
POST/designs/{id}/folderAttach or detach a design from a folder via {"folder_id":123} or {"folder_id":null}.
GET/designs/{id}/collaboratorsList collaborators and return an editor link.
POST/designs/{id}/collaboratorsGrant edit access to an existing user with {"email":"..."}.
DELETE/designs/{id}/collaborators/{collaboratorId}Revoke collaborator edit access.
POST /api/designs
{
  "title": "Spring Campaign",
  "design_type": "html",
  "width": 1080,
  "height": 1920,
  "html_content": "<div class='html-element'>...</div>",
  "css_content": "width: 1080px; height: 1920px; position: relative; overflow: hidden;",
  "metadata": "{\"pages\":[...]}"
}

Folders

MethodEndpointDescription
GET/foldersList folders with design_count.
POST/foldersCreate a folder with {"name":"..."}.
PUT/folders/{id}Rename a folder with {"name":"..."}.
DELETE/folders/{id}Delete a folder. Designs remain and lose the association.

Templates, uploads, fonts, categories

MethodEndpointDescription
GET/templatesList active templates. Requires authentication like every /api route.
GET/templates/{id}Fetch one template payload. Requires authentication.
GET/uploadsList uploads for the authenticated user.
POST/uploadUpload multipart image/PDF or ingest metadata JSON with url.
POST/uploads/importImport a remote image into the authenticated user's uploads. Body: {image_url} or {image_base64, mime_type?, file_name?}. Response: {success, data: { id, url, width, height, ... }}.
POST/uploads/generateGenerate an image with the Koalaful image generator (gpt-image) and save it to the user's uploads (mirrored to Tonta on success). Body: {prompt, file_name?, width?, height?, orientation?, quality?, background?, output_format?}. Quality defaults to low (~$0.0004 per image). Response: {success, data: { id, url, storage: "tonta"|"local", ... }, provider, model, quality, size, usage}.
POST/uploads/remove-backgroundRemove the background from an image (synchronous; takes ~3s; ~$0.0004 per call). Body: {image_url}. Result is cached: re-calling with the same image_url returns the cached cutout for free. Response: {success, data: { processed_url, original_url, upload_id, storage: "tonta"|"local", cached }}. The original/cutout pairing is also reflected on the upload row as bg_removed_path for clients listing uploads.
DELETE/uploads/{id}Delete one upload.
GET/categoriesCurrently returns an empty list — the categories table is unpopulated.
GET/fontsNot working: the fonts table does not exist, so this returns 400. The editor uses a fixed Google Fonts set instead.
POST/cache-imageCache a remote image URL and receive a Koalaful-hosted URL.

Exports, thumbnails, conversion

MethodEndpointDescription
POST/designs/{id}/thumbnailSave a base64 canvas screenshot and persist a smaller dashboard thumbnail.
POST/designs/{id}/captureServer-side thumbnail capture from stored HTML/CSS.
GET/designs/{id}/exportExport a finished asset. format = png, jpg, jpeg, pdf or html; page selects a page and all_pages=1 exports the whole document. Images return a Tonta URL, PDFs a /exports/… URL. No SVG or MP4.
POST/designs/{id}/renderRender with variable substitution. Supports variables, format, and page.
POST/convert/htmlConvert external HTML into Koalaful canvas JSON.
POST/convert/imageConvert an uploaded/reference image into design JSON.
POST/convert/pdfConvert a PDF into design JSON.

AI routes

These routes are live but include a mix of stable and experimental surfaces.

MethodEndpointDescription
POST/ai/generateGeneral AI design generation.
POST/ai/enhance-promptPrompt enhancement.
POST/ai/manipulateModify an existing design with minimal changes.
POST/ai-test3/placeholder-jobsInternal: queues the editor's image-placeholder generation. Not a stable public surface.
POST/ai-test2/generateExperimental generator v2.
POST/ai-test3/generateExperimental generator v3.
POST/ai-test3/generation-jobsCreate background generation jobs.
GET/ai-test3/generation-jobs/statusPoll background generation job status.
POST/ai-test3/generate-placeholder-imageGenerate one placeholder image.
POST/ai-test3/placeholder-jobsCreate multiple placeholder image jobs.
GET/ai-test3/placeholder-jobs/statusPoll placeholder job status.
POST/aigenlab/generateAIGenLab design generation.
POST/aigenlab/enhance-promptAIGenLab prompt enhancement.
POST/aigenlab/generation-jobsCreate AIGenLab background jobs.
GET/aigenlab/generation-jobs/statusPoll AIGenLab background job status.
GET/aigenlab/generation-jobs/recentList recent AIGenLab jobs.
POST/aigenlab/generate-placeholder-imageGenerate one placeholder image through AIGenLab.
POST/aigenlab/placeholder-jobsCreate multiple placeholder image jobs.
GET/aigenlab/placeholder-jobs/statusPoll placeholder job status.
These routes rely on server-side provider credentials configured through environment variables. Some are intentionally experimental.

Async & bulk rendering

For more than a handful of renders, queue the work rather than looping synchronously.

MethodEndpointDescription
POST/designs/{id}/export-asyncQueue one render. Body: {format, page, scale, variables, text_replacements, webhook_url}. Returns a job id immediately.
POST/designs/{id}/export-bulkUp to 1000 variants in one request. Body: {defaults, jobs:[{variables|text_replacements|format|page|scale}], webhook_url}.
GET/render-jobsList jobs. Payload key is jobs, not data.
GET/render-jobs/{uuid}Status/result of one job.
GET/designs/{id}/variablesList data-variable fields across all pages.
POST/designs/{id}/variablesTag elements as variables: {assignments:[{element_id, variable}]}.
GET/stock/search?query=treesStock photo proxy. Payload key is photos.

webhook_url is a per-job callback. There is no account-level webhook subscription.

Apps & integrations

MethodEndpointDescription
GET/appsList supported app integrations and connection state.
POST/apps/connectStore or update an app connection.
POST/apps/testValidate an app connection.
DELETE/apps/{provider}Disconnect one provider.
GET/apps/google-drive/oauth/startStart Google Drive OAuth.
GET/apps/google-drive/oauth/callbackHandle Google Drive OAuth callback.
GET/apps/dropbox/oauth/startStart Dropbox OAuth.
GET/apps/dropbox/oauth/callbackHandle Dropbox OAuth callback.
GET/apps/google-drive/filesList Google Drive files.
POST/apps/google-drive/importImport a Google Drive file.
POST/apps/google-drive/exportExport to Google Drive.
GET/apps/dropbox/filesList Dropbox files.
POST/apps/dropbox/importImport a Dropbox file.
POST/apps/dropbox/exportExport to Dropbox.
POST/apps/slack/exportExport to Slack.

Interactive console

Use your browser session, an API key, or both. If an API key is supplied below, the request is sent with both Authorization: Bearer and X-API-Key.

Response output will appear here.