Loops Email Contacts & Events
For SaaS teams running product email on Loops: keep contacts and their custom properties in sync, check suppression, fire the events that start your loops, and send a published transactional email by its id with data variables filled in.
Connect this API to an AI agent Browse all specs
What you can do with Loops Email Contacts & Events via MCP
Every endpoint below becomes a governed tool your AI agent (Claude, ChatGPT, or a customer-facing VX agent) can call — with scoped permissions, sandbox testing, and audit logs.
| Method | Path | Operation | Description |
|---|---|---|---|
| GET | /v1/api-key |
testApiKey | Check the API key and see which Loops team it belongs to |
| GET | /v1/contacts/find |
findContact | Find a contact by email address or user id |
| POST | /v1/contacts/create |
createContact | Add a contact with properties and mailing list subscriptions |
| PUT | /v1/contacts/update |
updateContact | Update a contact's properties or subscriptions (creates it if missing) |
| GET | /v1/contacts/suppression |
getContactSuppression | Check whether a contact is suppressed from receiving email |
| GET | /v1/contacts/properties |
listContactProperties | List default and custom contact properties |
| GET | /v1/lists |
listMailingLists | List mailing lists and their ids |
| GET | /v1/event-patterns |
listEventPatterns | List the event names your loops can be triggered by |
| POST | /v1/events/send |
sendEvent | Send an event for a contact to trigger loops |
| GET | /v1/transactional-emails |
listTransactionalEmails | List transactional emails |
| GET | /v1/transactional-emails/{transactionalId} |
getTransactionalEmail | Get a transactional email and its data variables |
| GET | /v1/transactional-emails/{transactionalId}/metrics |
getTransactionalEmailMetrics | Delivery, open and click totals for a transactional email |
| POST | /v1/transactional |
sendTransactionalEmail | Send a transactional email to one address with data variables |
Authentication
apiKey
Bearer token — sent as Authorization: Bearer <token>
Loops API key, sent as Authorization: Bearer <key>.
How to get a credential
- Sign in to Loops and open Settings > API.
- Click Generate key and give it a name you will recognise.
- Copy the key. It is tied to your Loops team and has full API access.
- Check it with
testApiKey: a valid key returns your team name.
Permissions used
| Access | Operations |
|---|---|
| Read account | testApiKey, listMailingLists, listContactProperties, listEventPatterns |
| Read contacts | findContact, getContactSuppression |
| Write contacts | createContact, updateContact |
| Send events | sendEvent |
| Transactional email | listTransactionalEmails, getTransactionalEmail, getTransactionalEmailMetrics, sendTransactionalEmail |
Loops keys are not scoped: every key can do everything the API allows, so keep it private.
Common errors
| Status | Meaning | Fix |
|---|---|---|
| 401 | Key missing, deleted or mistyped | Generate a new key under Settings > API |
| 400 | Invalid body, e.g. unknown contact property, missing email/userId, or a transactional id that is not published | Check names with listContactProperties and ids with listTransactionalEmails |
| 404 | Contact or transactional email not found | Create the contact first or pass the right id |
| 409 | A contact with this email or userId already exists | Use updateContact instead of createContact |
| 429 | Rate limit (10 requests per second per team) | Wait for the time in the rate-limit headers and retry |
Store the key as a VX Agents credential (bearer token) so it is never pasted into chats or prompts.
Usage guide
Setup
- Credential: a Loops API key (Settings > API > Generate key), stored as a VX Agents bearer-token credential. Run
testApiKeyonce to confirm it works. - Worth pinning: the
mailingListsids you subscribe people to (fromlistMailingLists) and thetransactionalIdof emails the agent may send.
Sync a user and trigger email
listContactPropertiesto learn the exact property names (custom ones too) before writing; unknown names are rejected.findContactwithemailoruserId. Before emailing someone,getContactSuppressiontells you if they are suppressed.- Show the user the change and confirm, then:
- new person:
createContactwithemail(+firstName,lastName,userId,userGroup,mailingListsas{listId: true}); - existing person:
updateContactwithemailoruserIdand only the fields that change (it creates the contact if missing).
- new person:
- Start a loop:
listEventPatternsfor the event names in use, thensendEventwitheventName(case-sensitive),emailoruserId, and optionaleventProperties. - Send a one-off message:
listTransactionalEmails/getTransactionalEmailto find the id and its data variables, thensendTransactionalEmailwithtransactionalId,emailanddataVariables. getTransactionalEmailMetricsto see how a transactional email performs.
Good to know
- Contacts are identified by
emailoruserId. To change someone's email, the contact needs auserId: sendupdateContactwith thatuserIdand the newemail. mailingListsis an object of list id → true (subscribe) / false (unsubscribe). Settingsubscribed= false unsubscribes the contact from all email.- Transactional emails must be published in Loops before they can be sent; every required data variable must be in
dataVariables. - List endpoints page with
perPageand thecursorfrompagination.nextCursor. - Rate limit: 10 requests per second per team (60 per minute for
/v1/transactional-emails/*); on 429 wait and retry. - Events, transactional sends and contact edits email or change real customers: always confirm with the user first. This spec has no delete operations.
Source: Loops API reference (https://loops.so/docs/api-reference/intro), checked 2026-10-16.
How to use this spec
- Create a free VX Agents account (sandbox tools included).
- Open the marketplace and connect “Loops Email Contacts & Events” to an agent.
- Expose it as an MCP server for Claude/ChatGPT, or chat with it directly.