Skip to main content

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:

Authentication

All API endpoints require a bearer token. Get one with migma login, hosted MCP OAuth, or agent registration. CI sets MIGMA_API_KEY. Include it in the Authorization header:

Authentication Guide

Learn how to create and manage API keys

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:
Example request:

Response format

All API responses follow a consistent structure:

Success response

Error response

HTTP status codes

The API uses standard HTTP status codes:

Rate limiting

API request allowances follow your account’s plan. All API keys belonging to the same account share each route group’s budget, including keys used by separate applications or agents. Creating another key does not increase that allowance. For example, an account capped at 5 recipients/second receives at least 300 sending API requests/minute without an account-specific API override. An account capped at 300 recipients/second receives at least 18,000 requests/minute. These examples describe request allowances, not guaranteed processing speed. A configured zero allowance disables the corresponding API budget; it does not mean unlimited. Find your effective allowances in Settings → Developers → API Keys → API limits. Annual plans use their configured plan limits. Account-specific agreements can change the displayed allowance. Request budgets use a 60-second window starting with its first request. Pace requests throughout the minute: using the entire request budget at once does not bypass recipient/second limits. This limiter has no separate daily request quota or extra burst allowance. Email daily/monthly quotas still apply. Email reading, editing, and test previews under /v1/emails use the general plan allowance in a separate group, so they do not consume the /v1/sending budget. Campaign endpoints have their own general-plan group. Expensive operations such as imports can have a lower endpoint-specific cap. Requests that reach a limiter count even if later validation fails or an idempotent response is replayed. Responses that reach the request limiter include these headers. Values below are illustrative:
X-RateLimit-Reset is a Unix timestamp in seconds. When the request budget is exhausted, the API returns HTTP 429 and Retry-After, expressed in seconds:
If the shared request limiter or account-limit lookup is unavailable, the API returns HTTP 503 with Retry-After: 1 before running the endpoint. Actual sending capacity is checked separately. A direct send can return 429 with code: "SENDING_CAPACITY" and data.retryAfterMs even when request budget remains. Campaign recipients wait for available capacity in the sending queue. One audience-send request can create many deliveries; every recipient still counts against throughput and volume limits.
On a request-limit response, wait for Retry-After. On a sending-capacity response, wait for data.retryAfterMs. Retry the same send with the same API key, body, and Idempotency-Key; use bounded retries with backoff and jitter.

Pagination

List endpoints support pagination using limit and offset parameters:
Response includes pagination metadata:

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.
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.
  • A request still running with the same key returns 503 with code IDEMPOTENCY_IN_PROGRESS and a Retry-After header. Retry after that delay; you get the first request’s response.
  • Sending an email (POST /v1/sending to one recipient) is identified by the key itself, so even a retry after a 5xx never sends a second copy: it returns the original send’s outcome.
Use a deterministic key derived from the logical operation, so the same retry always produces the same key:

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:

Events & Webhooks

Learn how to set up event notifications

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
Project editing endpoints require the project:write permission.

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

Email validation API

Learn about email compatibility testing, link analysis, and deliverability prediction

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)

Email preview API

See the auto-generated preview endpoint docs in the API reference

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/png/{conversationId} - Export as PNG
  • 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 with this body:
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

Development/Testing

Separate keys help organize integrations. Keys belonging to the same account share its request budgets; a different key does not provide a separate quota.

SDKs & libraries

Node.js / TypeScript (available now)

SDK Documentation

Full SDK guide — configuration, error handling, polling helpers, and all 14 resources

CLI (available now)

CLI Documentation

Full CLI guide — all commands, workflows, and configuration

Need help?

Quickstart

Get started in under 5 minutes

Events & Webhooks

Set up event notifications

Authentication

Learn about API keys and security

Join Discord

Connect with developers and get support
Last modified on September 30, 2026