A reference guide for building AI agents: every method, how to authenticate, and the permissions each one needs.
The Iterable API is how an app or AI agent works with an Iterable project: updating user profiles, tracking events, sending a transactional email, creating and triggering campaigns, and exporting analytics. Access is granted through an API key whose type, such as a standard or restricted server-side key, decides what it can do, and a key reaches only the project and data center it was created for. Iterable runs one continuously updated API rather than dated versions, and it can push message events like opens and clicks to a registered webhook.
How an app or AI agent connects to Iterable determines what it can reach. There is a route for making calls and a server that exposes Iterable tools to agents, and each is governed by the API key behind it and the access that key's type allows.
The REST API takes JSON request bodies and returns JSON. A call authenticates with an API key sent in the Api-Key header. The base URL is https://api.iterable.com for US-hosted projects and https://api.eu.iterable.com for EU-hosted ones, and a key works only against the data center where it was created.
Iterable POSTs system webhooks to a registered URL when message events happen, such as an email send, open, click, bounce, complaint, or unsubscribe, and for SMS and push events. The receiver verifies deliveries against a shared signing secret. This lets an integration learn about message activity without polling.
Iterable's first-party, open-source Model Context Protocol server lets an AI client like Claude or Cursor call Iterable through MCP. It runs locally, installed with npx @iterable/mcp setup, and authenticates with an Iterable API key. The setup wizard defaults to a safe, read-only mode with no PII tools, writes, or sends, and can expose up to 105 tools when fully enabled. It is in beta. The source is at github.com/Iterable/mcp-server.
A standard server-side key has the highest level of access to read and update data, and is meant to be kept secret on a server. Iterable keys carry a key type rather than granular per-resource scopes, so this key can reach the full API for its project.
A restricted server-side key is created with a narrower set of allowed calls than a standard key, so a leaked key reaches less. The restriction is set on the key, not chosen per request, because Iterable keys are typed rather than scoped.
A JWT-enabled key requires every request to carry a valid, signed, time-limited JSON Web Token, tied to a specific user. It adds per-user authentication on top of the key. A key is JWT-enabled only when created and cannot be converted later, and a missing or expired token returns 401.
A mobile key is meant for client-side use in a mobile or web app, where it cannot be kept fully secret, so it is limited to the client-safe calls the SDKs make. It can be paired with JWT authentication for per-user security.
The Iterable API is split into areas an agent can act on, like users, events, email, campaigns, lists, templates, catalogs, and data export. Each area has its own methods, and writes in some areas send live messages or change customer records.
Create and update user profiles, read a user by email or userId, manage subscriptions, merge users, and forget a user for GDPR.
Track a custom event for a user, bulk track events, and read the events recorded for a user.
Send a transactional email to a specific address from a template, and cancel a scheduled send.
List campaign metadata, read a single campaign, create a campaign from a template, trigger one, and read metrics.
Read the lists in a project, create a static list, read its members, and subscribe or unsubscribe users.
Read project templates, read an email template, and create or update an email template.
Read catalog names, create a catalog, and create, replace, or read its items, used for personalization data.
Start a data export job, list jobs, export campaign analytics as JSON, and export a single user's events.
Filter by method, access, or permission, or search any path. Select a row for version detail, rate limits, the related webhook event, and the source.
| Method | Endpoint | What it does | Access | Permission | Version | |
|---|---|---|---|---|---|---|
UsersCreate and update user profiles, read a user by email or userId, manage subscriptions, merge users, and forget a user for GDPR.9 | ||||||
| POST | /api/users/update | Update a user's data, or add the user if none exists. Data is merged, so missing fields are not deleted. | write | — | Current | |
Authorized by the API key's type, not a per-endpoint scope; a server-side key can write here. A soft limit caps the unique fields a user can have. Acts onuser Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /api/users/getByEmail | Get a user's full profile by email address. | read | — | Current | |
Returns personal data, so a key restricted to non-PII access cannot call it. Acts onuser Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /api/users/byUserId/{userId} | Get a user's full profile by userId. | read | — | Current | |
Used in userID-based and hybrid projects. Returns personal data. Acts onuser Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /api/users/bulkUpdate | Bulk update user data, adding and overwriting profile fields as needed across many users in one call. | write | — | Current | |
Does not modify top-level fields omitted from the request. Acts onuser Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /api/users/updateSubscriptions | Update a user's subscriptions, such as message channels and subscription groups. | write | — | Current | |
This endpoint overwrites, it does not merge, any non-null fields in the request. Acts onsubscription Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /api/users/merge | Merge two users into one, combining their profile data and history. | write | — | Current | |
Specify a source and a destination by email or userId, but not both forms for either side. Acts onuser Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /api/users/{email} | Delete a user by email. This is asynchronous and does not prevent future data collection. | write | — | Current | |
Deletes the profile but, unlike forget, does not block future collection. Irreversible. Acts onuser Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /api/users/forget | Forget a user for GDPR, deleting their data and preventing future data collection about them. | write | — | Current | |
Irreversible except by unforget. Each forget and unforget endpoint is capped at 1,000 calls per project per 24 hours, after which calls return 429. Acts onuser Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limit1,000 requests per 24 hours, per project SourceOfficial documentation ↗ | ||||||
| GET | /api/users/getSentMessages | Get the messages sent to a user, by email or userId. Returns 10 by default, up to 1,000. | read | — | Current | |
Returns message history tied to a person. Acts onmessage Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limit3 requests per second, per project SourceOfficial documentation ↗ | ||||||
EventsTrack a custom event for a user, bulk track events, and read the events recorded for a user.3 | ||||||
| POST | /api/events/track | Track a custom event for a user. Events are created asynchronously and processed separately from the bulk endpoint. | write | — | Current | |
To keep events in order, send a user's events all to this endpoint or all to the bulk one, not a mix. Acts onevent Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /api/events/trackBulk | Bulk track events for many users in a single request. | write | — | Current | |
Stricter limit than the single-event endpoint, at 10 requests per second per project. Acts onevent Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limit10 requests per second, per project SourceOfficial documentation ↗ | ||||||
| GET | /api/events/{email} | Get the events recorded for a user, by email. | read | — | Current | |
On the API documentation page this does not work for emails containing a slash; the byUserId form avoids that. Acts onevent Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /api/email/target | Send a transactional email to a specific address, rendered from a template, with request fields overriding profile fields. | write | — | Current | |
Sends a live email. A key restricted from sends cannot call it. Acts onemail Permission (capability)None required VersionAvailable since the API’s base version Webhook event emailSendRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /api/email/cancel | Cancel a scheduled email to a user before it sends. | write | — | Current | |
Only cancels a send that has not yet gone out. Acts onemail Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
CampaignsList campaign metadata, read a single campaign, create a campaign from a template, trigger one, and read metrics.5 | ||||||
| GET | /api/campaigns | List metadata about the campaigns in a project, paginated by page and pageSize. | read | — | Current | |
Read-only. Acts oncampaign Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /api/campaigns/{id} | Get a single campaign by id. | read | — | Current | |
Read-only. Acts oncampaign Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /api/campaigns/create | Create a blast or triggered campaign from an existing template, for email, push, web push, SMS, in-app, or embedded messages. | write | — | Current | |
Creates a real campaign tied to a template and lists. Acts oncampaign Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /api/campaigns/trigger | Trigger a campaign to send to the given lists. | write | — | Current | |
Sends a real campaign to real recipients. Acts oncampaign Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /api/campaigns/metrics | Get metrics for one or more campaigns. | read | — | Current | |
Read-only; one of the slower endpoints at 10 requests per minute per project. Acts oncampaign Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limit10 requests per minute, per project SourceOfficial documentation ↗ | ||||||
ListsRead the lists in a project, create a static list, read its members, and subscribe or unsubscribe users.5 | ||||||
| GET | /api/lists | Get all lists within a project. | read | — | Current | |
Read-only. Acts onlist Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limit100 requests per second, per project SourceOfficial documentation ↗ | ||||||
| POST | /api/lists | Create a new static list. | write | — | Current | |
A core list write. Acts onlist Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /api/lists/getUsers | Get all users within a list. | read | — | Current | |
Returns the people on a list, so it exposes personal data. One of the slower endpoints at 5 requests per minute per project. Acts onlist Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limit5 requests per minute, per project SourceOfficial documentation ↗ | ||||||
| POST | /api/lists/subscribe | Add specific subscribers to a list. | write | — | Current | |
Changes who receives a list's campaigns. Acts onlist Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /api/lists/unsubscribe | Remove specific users from a list. | write | — | Current | |
Changes who receives a list's campaigns. Acts onlist Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
TemplatesRead project templates, read an email template, and create or update an email template.3 | ||||||
| GET | /api/templates | Get the templates in a project, paginated by page and pageSize. | read | — | Current | |
Read-only. Acts ontemplate Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /api/templates/email/get | Get an email template by templateId. | read | — | Current | |
Read-only. Acts ontemplate Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limit100 requests per second, per project SourceOfficial documentation ↗ | ||||||
| POST | /api/templates/email/upsert | Create an email template if none matches the name, otherwise update every email template with that name. | write | — | Current | |
Matches by template name, so it can update more than one template at once. Acts ontemplate Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
CatalogsRead catalog names, create a catalog, and create, replace, or read its items, used for personalization data.4 | ||||||
| GET | /api/catalogs | Get the catalog names in a project. | read | — | Current | |
Read-only. Acts oncatalog Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limit100 requests per second, per API key SourceOfficial documentation ↗ | ||||||
| POST | /api/catalogs/{catalogName} | Create a catalog with a unique name, used to hold personalization data referenced in messages. | write | — | Current | |
A name can be at most 255 characters and use only letters, numbers, and dashes. Acts oncatalog Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /api/catalogs/{catalogName}/items | Create up to 1,000 catalog items in a single request. This is asynchronous. | write | — | Current | |
Each item needs a unique id of letters, numbers, and dashes. Acts oncatalog item Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /api/catalogs/{catalogName}/items/{itemId} | Get a single catalog item by id. | read | — | Current | |
Read-only. Acts oncatalog item Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
ExportStart a data export job, list jobs, export campaign analytics as JSON, and export a single user's events.3 | ||||||
| POST | /api/export/start | Start a data export, which runs as a background job. Check status and get download links with the export files endpoint. | read | — | Current | |
Reads and exports project data; the underlying export is rate limited to a few requests per minute. Acts onexport job Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limit4 requests per minute, per project SourceOfficial documentation ↗ | ||||||
| GET | /api/export/data.json | Export campaign analytics data as JSON, one entry per line, over a date range. | read | — | Current | |
Requires either a range or an explicit start and end date. Acts onexport data Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limit4 requests per minute, per project SourceOfficial documentation ↗ | ||||||
| GET | /api/export/userEvents | Export all events for a single user, by email or userId, as JSON with one event per line. | read | — | Current | |
Returns one person's full event history. Acts onexport data Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Iterable can notify an app or AI agent when something happens to a message, like an email being opened, clicked, or marked as spam. It posts a system webhook to a registered URL, so an integration learns about message activity without polling.
| Event | What it signals | Triggered by |
|---|---|---|
emailSend | Fires when Iterable sends an email to a user. | /api/email/target |
emailOpen | Fires when a user opens an email. | In-app only |
emailClick | Fires when a user clicks a link in an email. | In-app only |
emailBounce | Fires when an email hard or soft bounces. | In-app only |
emailComplaint | Fires when a recipient marks an email as spam. | In-app only |
emailUnSubscribe | Fires when a user unsubscribes from email. | In-app only |
Iterable limits how fast an app or AI agent can call, by a request rate set per endpoint and measured per project, with some endpoints far stricter than others.
Iterable sets rate limits per endpoint, measured per project, rather than by a single account-wide quota or a point cost. Many endpoints allow 100 requests per second per project, but several are far stricter: bulk event tracking is 10 per second, the get-sent-messages endpoint is 3 per second, getting the users in a list is 5 per minute, campaign metrics is 10 per minute, and the export endpoints are 4 per minute. The GDPR forget and unforget endpoints are each capped at 1,000 calls per project per 24 hours. Going over returns HTTP 429. As of 10 November 2025, sending the API key in the query string or request body, rather than the Api-Key header, is subject to stricter limiting, so the key should always go in the header.
List endpoints such as campaigns and templates page through results with page and pageSize parameters. Some projects can enable an unpaginated mode that returns all campaigns or templates at once. Export endpoints stream results as JSON or CSV with one record per line, rather than paging.
Bulk endpoints cap a single request, for example up to 1,000 catalog items per bulk create call, and getSentMessages returns up to 1,000 messages. A custom event has a soft limit, default 8,000, on its unique field names, and a user profile has a soft limit, default 1,000, on unique fields. A catalog name is at most 255 characters.
The status codes an agent should handle, and what to do about each.
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 200 | Success | The call succeeded. Iterable returns a JSON body with a code of Success, a human-readable msg, and an optional params object. | Read the body for any returned ids or details. Note that some endpoints process asynchronously, so a Success here means the request was accepted, not that processing finished. |
| 400 | BadParams / InvalidJsonBody | A required parameter is missing or invalid, or the JSON body could not be parsed. The body names the problem in msg and may detail it in params. | Read msg and params, correct the named fields, and resend. The request is not retryable as-is. |
| 401 | BadApiKey / InvalidApiKey | The API key is missing, invalid, or of the wrong type for the call. For a JWT-enabled key, a missing, invalid, or expired JWT also returns 401. | Send a valid key in the Api-Key header for the right data center and project, and a valid signed JWT if the key requires one. |
| 429 | RateLimitExceeded | The per-endpoint, per-project rate limit was exceeded. As of 10 November 2025, passing the key in the query string or body instead of the header is subject to stricter limiting. | Back off and retry with exponential backoff, and always send the key in the Api-Key header. |
| 500 | GenericError | An error on Iterable's side. It is uncommon. | Retry with backoff, and contact Iterable support if it persists. |
Iterable does not pin a dated API version, so there is a single, continuously updated API, and changes ship through dated release notes rather than version numbers an integration selects.
Iterable runs one continuously updated API with no dated or numbered version an integration selects per request. The published spec is labeled 1.8. Notable changes ship through dated release notes rather than version strings, so an integration tracks those notes rather than pinning a version.
The Spring '26 release moved Iterable toward a goal-driven, agentic experience, adding the Iterable Command Center homepage and Iterable Data Sync for exporting data to external cloud storage and warehouses. These are platform changes delivered without a new API version string.
There is no version to pin; an integration tracks the release notes for changes.
Iterable release notes ↗Bollard AI sits between a team's AI agents and Iterable. Grant each agent exactly the access it needs, read or write, action by action, and every call is checked and logged.