Skip to content

Madoo Public API — Developer Guide (v1)

Welcome. This guide is everything you need to integrate Madoo into your own product or backend. It is written for developers who have never seen Madoo before: by the end of this page you will understand what Madoo does, how an integration is shaped, and where to go next for the details.

You do not need to read our source code, and you do not need to understand how the engine works internally. You only need to understand a handful of concepts — and this page introduces all of them.


Madoo is a workflow engine for AI-powered media generation — images, video, audio, 3D, text and print-ready documents — for marketing, advertising, publishing, e-commerce and more. A workflow is a pipeline that someone has designed in Madoo’s visual editor: it takes some inputs (a product photo, a brand description, a title…), runs them through a series of AI steps, and produces some outputs (a hero image, a piece of marketing copy, a video…).

The Public API lets your application do, programmatically, what a person would otherwise do by hand in the Madoo dashboard:

  1. Discover the workflows available to you and learn exactly what each one expects.
  2. Run a workflow by submitting inputs.
  3. Track the run as it progresses.
  4. Retrieve the generated outputs.

A useful mental model: a workflow is like a function, and the Public API is how you call that function over HTTP. The function’s signature — its parameters and its return values — is what we call the workflow’s interface (see §4). Your job as an integrator is to read that interface, fill in the inputs, call the function, and collect the results.

One workflow, run thousands of times. Workflows are designed once (by you or by a Madoo author) and then executed repeatedly with different inputs. That is the whole point: a “newsletter hero image” workflow is built once and then run for every product in a catalog.


2. The core mental model: Organization → Workspace → API key

Section titled “2. The core mental model: Organization → Workspace → API key”

Everything in Madoo is scoped by a two-level tenancy model. You must understand it because it determines what your API calls can see and do.

Organization (your company / account — billing lives here)
└── Workspace (a project / brand / environment inside the org)
└── API key (credentials your app uses — scoped to a workspace)
└── Workflows, Executions, Assets… (everything you touch via the API)
  • An Organization is the top-level account. Your plan, credits, and billing belong to the organization.
  • A Workspace is a subdivision of the organization — think of it as a project or a brand. All resources (workflows, executions, uploaded files) live inside a workspace.
  • An API key is the credential your application uses. Every API key is bound to a single workspace. When you authenticate, the resulting access token already “knows” which organization and workspace it belongs to — so your calls automatically operate inside that workspace, and cannot see another workspace’s data.

This is why workspace context is mandatory for almost every endpoint: the API needs to know which workspace you are acting in, and that information comes from your API key. (The only exception is the token endpoint itself, which is how you authenticate in the first place.)

There are two flavours of API key — workspace-level (bound to one specific workspace) and organization-level (which resolves to the organization’s default workspace). For most integrations a workspace-level key is the right choice. See 01-authentication.md for how to create one.


3. How an integration is shaped (the request lifecycle)

Section titled “3. How an integration is shaped (the request lifecycle)”

Almost every Madoo integration follows the same five-step shape. The whole guide is organised around it.

┌─────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 1. Get a │ │ 2. Discover │ │ 3. Submit an │ │ 4. Poll until│ │ 5. Read the │
│ token │──▶│ the │──▶│ execution │──▶│ it is │──▶│ outputs │
│ │ │ workflow │ │ (inputs) │ │ finished │ │ │
└─────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
auth/token GET workflows/{id} POST executions GET executions/{id} (status loop)
  1. Authenticate — exchange your client_id + client_secret for a short-lived bearer token. → 01-authentication.md
  2. Discover the workflow — read its interface to learn the exact input keys, their types, and which are required. → 03-workflows.md
  3. Submit an execution — POST the inputs. You get back an execution ID immediately (the work runs in the background). → 04-executions.md
  4. Wait for completion — poll the execution, or configure an outbound completion webhook for a push notification. → 04-executions.md, 11-webhooks.md
  5. Read the outputs — download URLs, inline text/JSON, and image thumbnails. → 04-executions.md

If your inputs include files (images, video…), there is a half-step between 2 and 3: upload the file first to get a storage path, then reference that path in your inputs. → 05-assets.md

The 02-quickstart.md runs through all five steps end-to-end with working copy-paste examples. If you like to learn by doing, start there and come back here for the concepts.


4. The most important concept: the workflow interface

Section titled “4. The most important concept: the workflow interface”

This is the idea that makes Madoo integrable in a parametric way, so it deserves its own section even in the overview. (The full treatment, with examples, is in 03-workflows.md.)

A workflow does not accept arbitrary data. It declares what it accepts and what it produces, through special input nodes and output nodes placed on its canvas by the author. Together, those declarations form the workflow’s interface — the contract between your code and the workflow.

When you call GET /api/v1/workflows/{id}, the response contains an interface object describing exactly:

  • which inputs the workflow expects — each with a name (the key you use), a type (text, image, number…), whether it is required, and an optional default_value;
  • which outputs the workflow produces — each with a name and a type.
{
"id": "wf_53fb2f6576fa4bc9a6d3c91a7e84de47",
"name": "Newsletter Hero",
"interface": {
"inputs": [
{ "name": "block_title", "type": "text", "label": "Block Title", "required": true },
{ "name": "product_image_0", "type": "image", "label": "Product Image 0", "required": true },
{ "name": "product_image_1", "type": "image", "label": "Product Image 1", "required": false }
],
"outputs": [
{ "name": "hero_image", "type": "image", "label": "Hero Image" },
{ "name": "copy_json", "type": "text", "label": "Copy JSON" }
]
}
}

The golden rule that follows from this:

Never hard-code input keys. Always read GET /api/v1/workflows/{id} first and use the name values it returns. A workflow’s interface is the source of truth; it can change between versions, and guessing keys is the #1 cause of broken integrations.

On top of the auto-generated default interface, a workflow author can also publish one or more custom interfaces — curated, named subsets of inputs/outputs (with friendlier field keys, constraints, and defaults) tailored to a specific use case. You select one at execution time by its id. Custom interfaces are fully explained in 03-workflows.md.


Madoo runs in several environments. They are completely isolated — credentials, workflows, executions, and uploaded assets in one environment do not exist in another. An API key you create in Testing only works against Testing.

Pick the environment you are integrating against and use its base URL everywhere. Every endpoint in this guide is written as a path (e.g. POST /api/v1/executions); prepend the base URL of your environment to form the full URL.

Environment Base URL Notes
Development https://localhost:5001 Local machine only. Uses a self-signed TLS certificate — pass -k to curl / disable cert validation in your HTTP client.
Testing https://testing-api.madoo.ai Shared, stable test deployment. The right place to build and validate your integration.
Pre-prod https://preprod-api.madoo.ai Production-like staging for final verification.
Production https://api.madoo.ai Live environment. Real credits are consumed.

Full URL example (creating an execution in Testing):

https://testing-api.madoo.ai/api/v1/executions
└──────────── base URL ─────┘└──── endpoint path ────┘

Throughout the rest of this guide we use a BASE_URL placeholder in examples. Set it once:

Terminal window
BASE_URL="https://testing-api.madoo.ai" # change to match your environment

Each environment also serves a live, browsable API reference and a machine-readable spec:

  • Interactive docs (Scalar UI): {BASE_URL}/docs
  • OpenAPI/Swagger JSON: {BASE_URL}/swagger/public-v1/swagger.json

The OpenAPI document (group public-v1) is generated directly from the code, so it is always an exact, up-to-date description of the request/response shapes. This guide is the narrative layer on top of it: use the guide to understand concepts and flows, and the OpenAPI spec to generate clients or check the precise schema of any field.


These rules apply to every endpoint. Knowing them up front means you will not be surprised later. The exhaustive reference (status codes, error code catalogue, rate-limit details) is in 08-reference.md.

Madoo exposes resource IDs as prefixed, opaque strings (Stripe-style), not raw numbers. The prefix tells you the resource type at a glance:

Prefix Resource Example
wf_ Workflow wf_53fb2f6576fa4bc9a6d3c91a7e84de47
run_ Execution (a “run”) run_b4c8d3e29f5a4b6c8d1e2f3a4b5c6d7e
bat_ Batch execution bat_9a1c…
emb_ Embed token emb_7f2e…

Treat them as opaque: pass back whatever the API gave you. (Under the hood they are a prefix plus a GUID in compact hex form, but you should not need to parse them.)

Every endpoint except the token endpoint requires a bearer token:

Authorization: Bearer <access_token>

Request and response bodies are JSON. Field names are snake_case (e.g. created_at, asset_path). Timestamps are ISO 8601 / RFC 3339 strings in UTC (e.g. 2026-05-27T14:32:10.123+00:00).

List endpoints return a consistent envelope and page with a cursor, not an offset:

{
"data": [ /* … items … */ ],
"has_more": true,
"next_cursor": "wf_…", // pass this as ?starting_after= to get the next page
"total_count": 137
}
  • limit — items per page (1–100, default 25).
  • starting_after — pass the previous page’s next_cursor to fetch the next page.
  • Stop when has_more is false.

Every error response uses the same JSON shape, the RFC 7807 “Problem Details” format:

{
"type": "https://docs.madoo.ai/public-api/errors/workflow-not-found",
"title": "Not Found",
"status": 404,
"detail": "Workflow wf_… not found.",
"code": "workflow_not_found", // machine-readable — branch on this
"instance": "/api/v1/executions",
"request_id": "0HMÉ…" // quote this when contacting support
}

Branch your error handling on the code field (stable, machine-readable), not on detail (human prose, may change). The full status-code and error-code catalogue is in 08-reference.md.

API calls are rate-limited per organization/plan (a sliding window; the fallback is 60 requests per minute). The token endpoint is limited more strictly. Responses carry an X-RateLimit-Limit header, and exceeding the limit returns HTTP 429 with a Problem Details body (code: too_many_requests). Build a short backoff-and-retry into your client. Details and exact limits: 08-reference.md.


Read in order for a guided path, or jump straight to what you need.

Document What it covers
01-authentication.md The two auth modes: API key / client-credentials (create a key, obtain the bearer token) and the OAuth connector flow (Authorization Code + PKCE, zero-paste) for pre-registered app connectors.
02-quickstart.md A complete, copy-paste, end-to-end run: token → discovery → upload → execute → poll → outputs. curl and JavaScript/TypeScript.
03-workflows.md Listing workflows, reading the interface in depth, required/optional inputs, defaults, custom interfaces, and version pinning.
04-executions.md Submitting executions (the value vs asset_path rule, JSON double-encoding), polling, reading outputs (URLs, thumbnails, the GUID-suffix gotcha), cancelling, ZIP export.
05-assets.md Uploading files, structured-data inspection, and composing/validating portable multi-asset bundle manifests.
06-advanced-batch.md (Advanced) Running the same workflow over many input sets at once.
07-advanced-embed.md (Advanced) External embeds: workflow runtime widget, embedded workflow editor, embed tokens, iframe URLs, and postMessage contracts.
08-reference.md The reference appendix: HTTP status codes, error-code catalogue, rate-limit specifics, ID prefixes, status enums, plan & storage endpoints, machine discovery (/.well-known/api-catalog, agent-skills index).
09-catalog.md Catalog discovery: node types, the models behind each node (with the effective per-workspace default and credit costs), presets and effects.
10-authoring.md Workflow authoring: the public definition schema 1.0, creating/updating/validating workflows headlessly, definition export/import, metadata and deletion, lifecycle (publish/archive/revert/clone), versions, credit estimate, ETag/If-Match concurrency and Idempotency-Key retries.
11-design-templates.md DD7 DesignDocument discovery and authoring: portable IDs, immutable revisions, semantic commands, PDF/JPEG rendering, REST v1 and MCP parity.
11-webhooks.md Reliable completion notifications: endpoint setup, show-once signing secret, signature verification, tests, activation, logs, retry and replay.

For the complete cross-surface explanation of bundles—including the visual editor, REST v1, MCP, Madoo AI Agent, and the in-editor AI Assistant—see the canonical Bundle manifest authoring guide.

| 12-mcp-server.md | The MCP server: connecting Claude, Claude Code, ChatGPT, Codex, Cursor, VS Code, Lovable and other AI clients (OAuth, zero setup) or automation (API key), what the assistant can do, scopes and troubleshooting. |

Section titled “| 12-mcp-server.md | The MCP server: connecting Claude, Claude Code, ChatGPT, Codex, Cursor, VS Code, Lovable and other AI clients (OAuth, zero setup) or automation (API key), what the assistant can do, scopes and troubleshooting. |”

To make the shape concrete, here is the entire lifecycle in eight lines of shell. (Each step is explained properly in the linked documents — this is just to show you the silhouette.)

Terminal window
BASE_URL="https://testing-api.madoo.ai"
WF="wf_53fb2f6576fa4bc9a6d3c91a7e84de47"
# 1. Token (HTTP Basic with your client_id:client_secret)
TOKEN=$(curl -s -u "$CLIENT_ID:$CLIENT_SECRET" \
-d "grant_type=client_credentials" "$BASE_URL/api/v1/auth/token" | jq -r .access_token)
# 2. Discover the interface (what inputs does it want?)
curl -s -H "Authorization: Bearer $TOKEN" "$BASE_URL/api/v1/workflows/$WF" | jq .interface
# 3. Submit an execution
RUN=$(curl -s -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d "{\"workflow\":\"$WF\",\"inputs\":{\"block_title\":{\"value\":\"\\\"Spring in Bloom\\\"\"}}}" \
"$BASE_URL/api/v1/executions" | jq -r .id)
# 4. Poll until terminal, then 5. read outputs
curl -s -H "Authorization: Bearer $TOKEN" "$BASE_URL/api/v1/executions/$RUN" | jq '.status, .outputs'

Notice the \"\\\"Spring in Bloom\\\"\" in step 3 — text input values are JSON-encoded strings, so the literal Spring in Bloom is sent as the JSON string "Spring in Bloom". This “double encoding” trips up almost everyone the first time; it is explained carefully in 04-executions.md.

Ready? Head to 01-authentication.md to get your first token.