Contacts, deals & journeys API
These endpoints let your own code, Zapier or n8n act on your account: add contacts, open and move deals, enroll contacts in journeys, and read the ids those calls need. They use the same API key as the Send API.
Authorization: Bearer mia_live_...
Each family of endpoints allows 60 requests a minute per key. Over that, you get 429. Errors come back as {"error": "…"} with a 4xx status. The complete contract, including every response shape, is in the OpenAPI spec.
Contacts
Create or update
POST /api/v1/contacts adds an address to a contacts list, or updates it if it's already there:
{
"listId": "list_abc123",
"email": "[email protected]",
"fields": { "first_name": "Ada", "company": "Analytical Engines" }
}
It answers 201 for a new contact and 200 for an update, with the stored contact. To send up to 500 at once, use {"listId": "…", "contacts": [{"email": "…", "first_name": "…"}, …]} instead, which answers with counts.
Every address is verified as it's saved. The API never records a consent answer, so these contacts are sent to as before. A single contact that would take the list past your plan's contact limit gets 409.
Find
GET /api/v1/[email protected] returns that address's contact in every list, newest first. Add &listId= to look in one list only. Each lookup is recorded in your account's personal-data access log, like a contact viewed in the dashboard.
Lists
GET /api/v1/lists returns each contacts list's id, name, fields and rowCount. No contact data.
Deals
Create
POST /api/v1/deals:
{
"email": "[email protected]",
"title": "Annual plan",
"value": 1200,
"currency": "EUR"
}
Name the contact with email, or with listId plus rowId. With only an email, the deal goes on the most recently updated list that has the address. Without pipelineId and stageId, it lands in the first open stage of your default pipeline. currency defaults to USD.
Send an Idempotency-Key header (an order id, for instance) to make retries safe. A repeat with the same key answers 200 with "created": false instead of creating a second deal.
Update or move
PATCH /api/v1/deals/{id} takes any of title, value, currency and stageId. Moving to a won or lost stage closes the deal. The whole body is checked first, so an unknown stage changes nothing. A move fires the Deal stage changed journey trigger and the deal.stage_changed webhook, the same as a move on the board.
Pipelines
GET /api/v1/pipelines returns your pipelines, default first, each with its stages (id, name, kind). Use it to find the stageId to move a deal to.
Journeys
GET /api/v1/journeys lists your journeys with their id, name, trigger and whether they're on. ?trigger=api returns only the ones your code can enroll contacts in.
POST /api/v1/journeys/{id}/trigger with {"email": "…", "listId": "…"} enrolls a contact in a journey whose trigger is API call. See journeys.
Sample events
GET /api/v1/events/sample?type=deal.stage_changed returns {"events": [ … ]} with one sample webhook envelope of that type, or one of every type without type. Automation tools use it to show you the fields before a real event arrives.
Webhooks
GET, POST /api/v1/webhooks and DELETE /api/v1/webhooks/{id} manage event subscriptions. See webhooks & events.