> ## Documentation Index
> Fetch the complete documentation index at: https://docs.moda.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Getting Started

> Programmatic access to Moda canvases, designs, brand kits, and AI design tasks via the REST API.

The Moda REST API provides direct HTTP access to your canvases, designs, brand kits, and AI design capabilities. Use it to build integrations, automate workflows, or embed Moda functionality in your own applications.

## Base URL

All API requests use the following base URL:

```
https://api.moda.app/v1
```

## Authentication

Authenticate by including an API key as a Bearer token in the `Authorization` header. Generate API keys from **Settings > Developer > REST API** in the Moda app.

```
Authorization: Bearer moda_live_abc123...
```

See [Authentication](/api-reference/authentication) for details on creating keys, available scopes, and security best practices.

## Pin an API version

Add a `Moda-Version` header to every request so your integration's response shapes stay stable across our releases:

```
Moda-Version: 2026-05-01
```

Omitting the header resolves to the current default, which advances on each [sunset date](/api-reference/versioning). Pinning keeps your client on a known shape until you explicitly upgrade. See [Versioning](/api-reference/versioning) for supported versions and the migration map.

## Quick example

List your canvases with a single curl command:

```bash theme={null}
curl https://api.moda.app/v1/canvases \
  -H "Authorization: Bearer moda_live_abc123..." \
  -H "Moda-Version: 2026-05-01"
```

Response:

```json theme={null}
{
  "data": [
    {
      "id": "cvs_01HT9WK8N3M2J4A5Z6P7Q8R9TV",
      "name": "Marketing Website",
      "url": "https://moda.app/canvas/...",
      "category": "slides",
      "visibility": "team",
      "created_at": "2026-04-15T12:00:00+00:00",
      "updated_at": "2026-04-15T13:00:00+00:00"
    }
  ],
  "next_cursor": "eyJ2IjoxLCJzIjoiMjAy..."
}
```

Pass `next_cursor` back as `?cursor=` to fetch the next page; iterate until `next_cursor` is `null`.

## What you can do

| Area              | Capabilities                                                                                                                            |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| **Canvases**      | List, search, and share canvases; extract semantic pseudo-HTML, design tokens, page metadata; export PNG/JPEG/PDF/PPTX                  |
| **Tasks**         | Start AI design tasks, poll for progress, list and cancel recent tasks                                                                  |
| **Organizations** | List your organizations and teams                                                                                                       |
| **Brand Kits**    | List, create, and update brand kits                                                                                                     |
| **Uploads**       | Upload files for use as attachments in design tasks. Files above \~32 MiB use the [signed-URL flow](/api-reference/large-file-uploads). |
| **Remix**         | Duplicate a canvas and optionally apply AI edits                                                                                        |

## Rate limiting

The API allows **120 requests per minute** per API key. Your organization also has a cap on **concurrent design tasks** (3 on `free`, 10 on `paid`, 15 on `ultra`). Exceeding either limit returns `429 Too Many Requests` with a `Retry-After` header.

See [Usage Limits](/api-reference/usage-limits) for full details and how to request a higher cap.

## Error format

Every error response carries a single structured envelope nested under an `error` key:

```json theme={null}
{
  "error": {
    "type": "not_found",
    "code": "file_not_found",
    "message": "Canvas cvs_abc123 not found",
    "doc_url": "https://docs.moda.app/errors/file_not_found",
    "request_id": "019d8996-16b3-73ee-841a-5bc5038eb972"
  }
}
```

### Fields

| Field            | Type      | Notes                                                                                                                                                                                                                                        |
| ---------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`           | `string`  | Stable high-level category. One of `invalid_request`, `authentication`, `permission`, `not_found`, `conflict`, `rate_limited`, `idempotency_conflict`, `unprocessable`, `upstream_error`, `internal_error`. Branch your retry logic on this. |
| `code`           | `string`  | Narrow machine-readable identifier for the specific failure. Stable once published; each code maps to a `doc_url`.                                                                                                                           |
| `message`        | `string`  | Human-readable message for developers. Not localized, not user-facing.                                                                                                                                                                       |
| `doc_url`        | `string`  | Permalink to the documentation page for this `code`.                                                                                                                                                                                         |
| `request_id`     | `string`  | Correlator echoed from the `X-Request-ID` response header. Include it when contacting support -- it's how we find your request in our logs.                                                                                                  |
| `causes`         | `array?`  | Optional. A list of nested error envelopes for aggregated failures (e.g. a multi-page export where individual pages failed). Each entry is itself a full `error` object.                                                                     |
| `details`        | `object?` | Optional. Code-specific structured detail. For validation errors (`code: "validation_failed"`), contains `{"fields": [{"field": "body.canvas_id", "code": "string_too_short"}, ...]}`.                                                       |
| `retry_after_ms` | `number?` | Optional. Hint in milliseconds for transient and rate-limited errors.                                                                                                                                                                        |

### Status codes

| Status            | Type                                | Typical causes                                                        |
| ----------------- | ----------------------------------- | --------------------------------------------------------------------- |
| `400`             | `invalid_request`                   | Bad parameters, malformed JSON, unknown canvas format                 |
| `401`             | `authentication`                    | Missing or invalid API key                                            |
| `403`             | `permission`                        | Key lacks the required scope, or resource belongs to a different team |
| `404`             | `not_found`                         | Resource does not exist or is not visible to the key                  |
| `409`             | `conflict` / `idempotency_conflict` | Name collision, or an idempotency key reused with a different body    |
| `422`             | `unprocessable`                     | Request is well-formed but fails validation                           |
| `429`             | `rate_limited`                      | Per-key or per-org rate / concurrency limit exceeded                  |
| `502`/`503`/`504` | `upstream_error`                    | A third-party service (e.g. web scrape, model provider) failed        |
| `500`             | `internal_error`                    | Unexpected server error -- include `request_id` if reporting          |

### Client guidance

* **Branch on `type`, not status code alone.** Status codes collapse distinct failure modes together; `type` separates `rate_limited` from `idempotency_conflict` even though both are `409`-adjacent.
* **Log `request_id` on every error.** It is present on every response (success and failure) both in the body and in the `X-Request-ID` header. Pass it to support if you need help diagnosing a specific call.
* **Retry on `upstream_error` and `rate_limited`.** Everything else is either permanent or requires you to fix the request.
* **Do not parse `message`.** It can change without notice. Use `type` and `code` for branching, `message` only for display.

## Use Moda docs in your AI editor

Give your AI agent direct access to these docs while building with the API. The docs are exposed as a hosted MCP server at `https://docs.moda.app/mcp` — your agent gets a search tool and a read-only filesystem over every page, no local install required.

<Tabs>
  <Tab title="Claude Code">
    ```bash theme={null}
    claude mcp add --transport http moda-docs https://docs.moda.app/mcp
    ```
  </Tab>

  <Tab title="Claude.ai">
    Go to [Customize](https://claude.ai/customize) in your sidebar, click the **+** button, choose **Add custom connector**. Set the name to `Moda Docs` and the URL to:

    ```text theme={null}
    https://docs.moda.app/mcp
    ```
  </Tab>

  <Tab title="Claude Desktop">
    Open Claude Desktop, click **Customize** in the sidebar, then the **+** button > **Add custom connector**. Set the name to `Moda Docs` and the URL to:

    ```text theme={null}
    https://docs.moda.app/mcp
    ```
  </Tab>

  <Tab title="Cursor">
    Open **Cursor Settings > MCP** and add a new server, or add to `~/.cursor/mcp.json`:

    ```json theme={null}
    {
      "mcpServers": {
        "moda-docs": {
          "url": "https://docs.moda.app/mcp"
        }
      }
    }
    ```
  </Tab>

  <Tab title="VS Code">
    Add to your VS Code settings (`settings.json`):

    ```json theme={null}
    {
      "mcp": {
        "servers": {
          "moda-docs": {
            "type": "http",
            "url": "https://docs.moda.app/mcp"
          }
        }
      }
    }
    ```
  </Tab>
</Tabs>

Agents that support [agent-skill](https://agentskills.io/specification) auto-discovery will also pick up the `moda-api` skill from `https://docs.moda.app/.well-known/agent-skills/` — covering the canonical Task envelope, `Moda-Version` pinning, prefixed IDs, the typed error envelope, `idempotency_key`, cursor pagination, and webhook HMAC verification.

You can also access the docs as plain text for any LLM:

* **Index:** [docs.moda.app/llms.txt](https://docs.moda.app/llms.txt)
* **Full docs:** [docs.moda.app/llms-full.txt](https://docs.moda.app/llms-full.txt)

## Next steps

* [Authentication](/api-reference/authentication) -- Create and manage API keys
* [Versioning](/api-reference/versioning) -- Pin a version with the `Moda-Version` header
* [Webhooks](/api-reference/webhooks) -- Receive notifications when tasks complete
