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

# API Reference

> Complete reference for the Migma.ai API

## Overview

The Migma.ai API provides programmatic access to our AI Email Engine that creates pixel-perfect, on-brand emails in 30 seconds. Build custom integrations, automate email creation workflows, track customer events, export to platforms like Mailchimp and HubSpot, and manage your entire email marketing infrastructure programmatically.

Generate emails 200x faster and 95% cheaper with AI that learns your brand voice, fetches live content, and creates cross-client compatible HTML.

## Base URL

All API requests should be made to:

```
https://api.migma.ai
```

## Authentication

All API endpoints require authentication using API keys. Include your API key in the `Authorization` header:

```http theme={null}
Authorization: Bearer YOUR_API_KEY
```

<Card title="Authentication Guide" icon="key" href="/authentication">
  Learn how to create and manage API keys
</Card>

## API structure

The Migma.ai API is organized around REST principles:

* **Predictable resource-oriented URLs**
* **Standard HTTP response codes**
* **JSON request and response bodies**
* **Bearer token authentication**

## Request format

All `POST`, `PATCH`, and `PUT` requests should use JSON format:

```http theme={null}
Content-Type: application/json
```

Example request:

```bash theme={null}
curl -X POST https://api.migma.ai/v1/projects/import \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["https://yourbrand.com"], "name": "My Brand"}'
```

## Response format

All API responses follow a consistent structure:

### Success response

```json theme={null}
{
  "success": true,
  "data": {
    // Response data here
  },
  "metadata": {
    "timestamp": "2024-09-30T12:34:56.789Z",
    "requestId": "req_1234567890"
  }
}
```

### Error response

```json theme={null}
{
  "success": false,
  "error": "Error message describing what went wrong"
}
```

## HTTP status codes

The API uses standard HTTP status codes:

| Code  | Meaning               | Description                        |
| ----- | --------------------- | ---------------------------------- |
| `200` | OK                    | Request succeeded                  |
| `201` | Created               | Resource was created successfully  |
| `400` | Bad Request           | Invalid request parameters         |
| `401` | Unauthorized          | Invalid or missing API key         |
| `403` | Forbidden             | API key lacks required permissions |
| `404` | Not Found             | Resource doesn't exist             |
| `429` | Too Many Requests     | Rate limit exceeded                |
| `500` | Internal Server Error | Something went wrong on our end    |
| `503` | Service Unavailable   | Service temporarily unavailable    |

## Rate limiting

API requests are rate limited based on your plan:

| Plan       | Requests / minute | Requests / day |
| ---------- | ----------------- | -------------- |
| Standard   | 500               | 10,000         |
| Enterprise | 1,000             | 50,000         |

Rate limit information is included in response headers:

```http theme={null}
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1609459200
```

<Tip>
  When rate limited (429 response), wait for the time specified in `X-RateLimit-Reset` before retrying. Enterprise agreements may use different limits — contact [sales@migma.ai](mailto:sales@migma.ai).
</Tip>

## Pagination

List endpoints support pagination using `limit` and `offset` parameters:

```bash theme={null}
GET /v1/projects?limit=20&offset=0
```

Response includes pagination metadata:

```json theme={null}
{
  "success": true,
  "data": {
    "projects": [...],
    "total": 45,
    "limit": 20,
    "offset": 0
  }
}
```

## Idempotency

`POST` endpoints accept an optional `Idempotency-Key` request header so you can safely retry a request after a network error or timeout without doing the work twice. It is opt-in: a request without the header is processed normally.

```http theme={null}
Idempotency-Key: campaign-send-camp_123
```

The header is a string up to 100 characters. Keys are scoped per API key, so the same key used by two different keys never collides.

### Replay behavior

Within a 24 hour window, the first request with a given key runs normally and its response is cached. After that:

* **Same key and same body** returns the original cached response, with the same status and body. The replay carries the response header `Idempotent-Replayed: true`, so you can tell a replay from a fresh execution.
* **Same key but a different body** returns `409` with `error` code `IDEMPOTENCY_CONFLICT`. Mint a fresh key whenever the request genuinely changes.
* **A key longer than 100 characters** is rejected with `400` and code `IDEMPOTENCY_KEY_INVALID`.

`429` (rate limited) and `5xx` (server) responses are **not** cached, so a retry with the same key runs again. This is what makes a retry after a transient failure safe.

### Recommended keys

Use a deterministic key derived from the logical operation, so the same retry always produces the same key:

| Operation      | Recommended key                                             |
| -------------- | ----------------------------------------------------------- |
| Send email     | `send-<emailId>-<recipientId or to>-<scheduledAt or "now">` |
| Send campaign  | `campaign-send-<campaignId>`                                |
| Generate email | `email-gen-<projectId>-<turn or prompt hash>`               |
| Add contact    | `contact-<email>`                                           |

### Anti-patterns

* **Never** use a random value such as `uuid()` or a per-attempt timestamp like `Date.now()`. A new value on each attempt defeats deduplication across retries and process restarts, which is exactly the case the key exists for.
* **Don't** hash the request body and use that as the key. The body is already part of the conflict check, and a body hash makes every distinct payload its own key rather than identifying one logical operation.

The header is honored on the endpoints where a duplicate call is costly: sending an email (`POST /v1/sending`), sending or scheduling a campaign (`POST /v1/campaigns/{id}/send` and `POST /v1/campaigns/{id}/schedule`), and the contact write endpoints (`POST /v1/contacts`, `POST /v1/contacts/bulk`, and `POST /v1/contacts/bulk-delete`).

## Brand / project scoping

An API key is scoped to your account, not to a single brand. Most resources (contacts, campaigns, segments, emails) live inside a project, so pass `projectId` on the requests that operate on them. Call `GET /v1/projects` first to discover the project IDs available to your key.

A resource that belongs to a different project than the one you reference returns `404`, the same as a resource that does not exist. The API does not reveal that a resource exists in a project you did not name.

## Events & Webhooks

Use webhooks to receive supported Migma API and contact events in your own app, queue, or automation tool:

<Card title="Events & Webhooks" icon="bolt" href="/webhooks">
  Learn how to set up event notifications
</Card>

## API endpoints

### Projects

Manage brand projects and imports:

* `GET /v1/projects` - List all projects
* `GET /v1/projects/{projectId}` - Get project details
* `POST /v1/projects/import` - Import a new brand

### Project editing

Edit project content including knowledge base, images, and logos:

* `GET /v1/projects/{projectId}/knowledge-base` - List knowledge base entries
* `POST /v1/projects/{projectId}/knowledge-base` - Add knowledge base entry
* `PUT /v1/projects/{projectId}/knowledge-base/{entryId}` - Update entry
* `DELETE /v1/projects/{projectId}/knowledge-base/{entryId}` - Remove entry
* `POST /v1/projects/{projectId}/images` - Add image (URL-only)
* `PUT /v1/projects/{projectId}/images` - Update image metadata
* `DELETE /v1/projects/{projectId}/images` - Remove image
* `PUT /v1/projects/{projectId}/logos` - Update logos

<Info>
  Project editing endpoints require the `project:write` permission.
</Info>

### Email generation

Generate AI-powered, on-brand emails with async processing:

* `POST /v1/projects/emails/generate` - Generate an email (async)
* `GET /v1/projects/emails/{conversationId}/status` - Check generation status and get `result.emails[]` with `emailId`, HTML, screenshots, and series order
* `GET /v1/emails/{emailId}` - Fetch one generated email by ID
* `POST /v1/emails/{emailId}/edit` - Prompt Migma to edit one generated email

### Email validation

Comprehensive email testing and quality analysis:

* `POST /v1/emails/validate/compatibility` - Compatibility report for major webmail, desktop, and mobile clients
* `POST /v1/emails/validate/links` - Check all links for validity
* `POST /v1/emails/validate/spelling` - AI-powered spell/grammar check
* `POST /v1/emails/validate/deliverability` - Predict inbox placement
* `POST /v1/emails/validate/all` - Run all validation checks

<Card title="Email validation API" icon="check-circle" href="/email-editor/email-preflight">
  Learn about email compatibility testing, link analysis, and deliverability prediction
</Card>

### Email previews

Generate screenshots on real devices and email clients:

* `POST /v1/emails/previews` - Create device previews
* `GET /v1/emails/previews/{previewId}` - Get preview status & results
* `GET /v1/emails/devices/supported` - List supported preview device IDs (web, desktop, mobile)

<Card title="Email preview API" icon="eye" href="/api-reference/introduction">
  See the auto-generated preview endpoint docs in the API reference
</Card>

### Contacts

Manage your contacts via API:

* `GET /v1/contacts` - List contacts
* `POST /v1/contacts` - Add a contact
* `POST /v1/contacts/bulk` - Bulk import contacts
* `POST /v1/contacts/bulk-delete` - Batch delete contacts by email
* `POST /v1/contacts/status` - Change contact status

### Campaigns

Create and manage named marketing campaigns with lifecycle tracking:

* `GET /v1/campaigns` - List campaigns
* `POST /v1/campaigns` - Create a campaign from a generated email
* `GET /v1/campaigns/{id}` - Get campaign details
* `POST /v1/campaigns/{id}/send` - Send immediately
* `POST /v1/campaigns/{id}/schedule` - Schedule for future delivery
* `POST /v1/campaigns/{id}/cancel` - Cancel a scheduled campaign
* `POST /v1/campaigns/{id}/archive` - Archive a campaign
* `POST /v1/campaigns/{id}/unarchive` - Restore an archived campaign
* `GET /v1/campaigns/{id}/stats` - Engagement stats
* `GET /v1/campaigns/{id}/logs` - Per-recipient delivery logs

### Exports

Export generated emails to files or platforms:

* `GET /v1/export/html/{conversationId}` - Export as production HTML
* `GET /v1/export/mjml/{conversationId}` - Export as MJML
* `GET /v1/export/pdf/{conversationId}` - Export as PDF
* `GET /v1/export/klaviyo/{conversationId}` - Export for Klaviyo
* `GET /v1/export/mailchimp/{conversationId}` - Export for Mailchimp
* `POST /v1/export/hubspot` - Export for HubSpot
* `GET /v1/export/status/{conversationId}` - Poll export status

## Error handling

Failed requests return the matching [HTTP status code](#http-status-codes) with this body:

```json theme={null}
{
  "success": false,
  "error": "Insufficient permissions"
}
```

The response does not include a separate machine-readable `code` field. Branch on the **HTTP status code** for programmatic handling, and treat `error` as a human-readable message for logging and display. For example, a missing scope returns HTTP `403` with `error: "Insufficient permissions"`.

## Environments

Use different API keys for different environments:

### Production

```
Base URL: https://api.migma.ai
API Key: sk_live_...
```

### Development/Testing

```
Base URL: https://api.migma.ai
API Key: sk_test_...
```

<Info>
  Test keys are separate from production keys and don't affect your production data or rate limits.
</Info>

## SDKs & libraries

### Node.js / TypeScript (available now)

<CodeGroup>
  ```bash npm theme={null}
  npm install migma
  ```

  ```bash yarn theme={null}
  yarn add migma
  ```

  ```bash pnpm theme={null}
  pnpm add migma
  ```
</CodeGroup>

```typescript theme={null}
import Migma from 'migma';

const migma = new Migma(process.env.MIGMA_API_KEY);

const email = await migma.emails.generateAndWait({
  projectId: 'proj_123',
  prompt: 'Create a welcome email for new subscribers',
  languages: ['en']
});

const selectedEmail = email.data.result.emails[0];
console.log(selectedEmail.emailId);
console.log(selectedEmail.html);
```

<Card title="SDK Documentation" icon="book" href="/sdk">
  Full SDK guide — configuration, error handling, polling helpers, and all 14 resources
</Card>

### CLI (available now)

<CodeGroup>
  ```bash npm theme={null}
  npm install -g @migma/cli
  ```

  ```bash yarn theme={null}
  yarn global add @migma/cli
  ```
</CodeGroup>

```bash theme={null}
migma login
migma generate "Create a welcome email" --wait
migma validate all --conversation conv_123
migma send --to user@example.com --email email_123
```

<Card title="CLI Documentation" icon="terminal" href="/cli">
  Full CLI guide — all commands, workflows, and configuration
</Card>

## Need help?

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/quickstart">
    Get started in under 5 minutes
  </Card>

  <Card title="Events & Webhooks" icon="bolt" href="/webhooks">
    Set up event notifications
  </Card>

  <Card title="Authentication" icon="key" href="/authentication">
    Learn about API keys and security
  </Card>

  <Card title="Join Discord" icon="discord" href="https://discord.gg/ZB6c2meCUA">
    Connect with developers and get support
  </Card>
</CardGroup>
