API reference · v1

Everything Meetzy does, from your code.

244 endpoints — the same ones the Meetzy app and Claude use. Contacts, companies, deals, sequences, email, workflows, LinkedIn, WhatsApp, the mailbox, the Finder, analytics, ERP documents and data sources.

Base URLhttps://meetzy.me/api/v1
In a chat
Copy a ready promptPaste it in any AI: it reads the docs and follows the rules of the API.
Open in Claude or ChatGPTA new conversation with the prompt already written.
The full docs as MarkdownFor an AI that cannot open links: paste the text itself.
In your editor
Claude Code or CodexAdd this line to CLAUDE.md or AGENTS.md.Meetzy API reference (read before calling the API): https://www.meetzy.ai/llms-full.txt
CursorSettings › Indexing & Docs › Add Doc, then type @Meetzy in the chat.https://www.meetzy.ai/llms-full.txt
Connect Meetzy as tools (MCP)The AI can then read and change your CRM itself — Claude Code:claude mcp add --transport http meetzy https://meetzy.me/api/mcp/mcp
Same for Codexcodex mcp add meetzy --url https://meetzy.me/api/mcp/mcp

Only /api/v1 is the API. The other /api/… addresses you may see in the browser are internal to the Meetzy app: they are not documented, not supported, and change without notice. Everything you can do in Meetzy is available under /api/v1.

Quick start

  1. Create a key in Meetzy › Sales › Integrations & API › API keys. Copy it — it is shown once.
  2. Call the API with the key as a Bearer token. GET /me tells you who the key belongs to.
  3. Build: create a contact, open a deal, enroll them in a sequence, subscribe to deal.won.
Check the keycURL
curl https://meetzy.me/api/v1/me \
  -H "Authorization: Bearer $MEETZY_API_KEY"
Create a contact, then a dealJavaScript
const api = (path, body) => fetch(`https://meetzy.me/api/v1/${path}`, {
  method: body ? "POST" : "GET",
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}`, "Content-Type": "application/json" },
  body: body && JSON.stringify(body),
}).then(r => r.json());

const contact = await api("contacts", { email: "camille@payfit.com", first_name: "Camille", company: "Payfit" });
const deal = await api("deals", { name: "Payfit — rollout", amount: 12000, primary_lead_id: contact.id });

Authentication

Every request carries an API key: Authorization: Bearer mz_live_…. A key belongs to the teammate who created it and acts as them — it sees their workspace and what it creates is signed with their name. Keys are revoked in the same screen; a revoked key answers 401 at once. The only calls that need no key are GET /catalog and the inbound workflow trigger, whose URL is its own secret.

ScopeAllows
readRead CRM data — every GET
writeCreate & update records — POST, PUT and PATCH
deleteDelete records — DELETE (not given by default)
webhooksManage webhooks — /webhooks and /hooks
mcpUse as MCP token (Codex, Cursor, …) — the same key works as a static MCP token

New keys get read, write, webhooks and mcp; tick delete when you need it. Give each integration its own key, with only what it needs.

Requests and responses

  • JSON in, JSON out: send Content-Type: application/json. Field names are snake_case.
  • Ids are UUIDs. Dates are ISO 8601 (2026-10-07, 2026-10-07T09:30:00+02:00); times are returned in UTC.
  • Amounts are numbers in the record’s currency (no cents conversion).
  • PATCH changes only the fields you send. Fields Meetzy does not know are ignored.
  • A POST that creates answers 201; other successes 200. Deletes answer { "deleted": true }.
  • Creating something that exists by its natural key — a contact by email, a company by domain — returns the existing record instead of a duplicate.

Errors

Errors have a status code and a JSON body with a readable error, and sometimes details (for example { "code": "duplicate" }).

HTTP/1.1 409 Conflict
{ "error": "create property failed: this record already exists ((user_from, object_type, key)=(acme, contact, shoe_size))", "details": { "code": "duplicate" } }
StatusMeaningWhen
400Bad requestA field is missing or wrong — the message says which. Includes values of the wrong type.
401UnauthorizedNo key, a revoked key, or a key from a removed account.
402Payment requiredNot enough credits (Prospect Finder searches and reveals, AI actions — nothing is charged), or no seat left on the plan.
403ForbiddenThe key lacks the scope (API key is missing the "write" scope), the feature is not enabled for the workspace, or the call is reserved to the app (API keys, MCP connections, push keys).
404Not foundThe id does not exist in your workspace, or the route does not exist.
405Method not allowedThe path exists with another method.
409ConflictThe record already exists, the state does not allow it (e.g. deleting a non-empty pipeline), an account is not connected (mailbox_not_connected), or an Idempotency-Key request is still running.
413Too largeMore than 5,000 records in one batch — split it.
429Too many requestsOver 120 requests a minute for this key (wait Retry-After seconds), or over the plan’s quota (details.code: api_quota_exceeded).
500 / 502Server / provider errorSomething failed on our side or at a provider (Gmail, LinkedIn, your ERP). Safe to retry with an Idempotency-Key.

Pagination, limits and retries

Pagination

Lists take limit and offset and return total. Most cap limit at 1,000 (documents at 500). For incremental syncs, filter with updated_since (contacts, documents) and page until you have total.

Rate limit

120 requests a minute per key, and a quota per workspace from its plan: 1,000 a month on Free, 1,000 a day on Starter, 10,000 on Growth, 50,000 on Scale (+50,000 with Automation). Every answer carries X-RateLimit-Limit, X-RateLimit-Remaining, X-Quota-Limit, X-Quota-Remaining and X-Quota-Period; a 429 carries Retry-After (seconds). Use the bulk endpoints for volume: /contacts/upsert per record, /tasks/bulk, /products/bulk, /companies/bulk, /sync/ingest (5,000 records a call).

Idempotency

Send Idempotency-Key: <uuid> on any write to retry it safely after a timeout: the first answer is replayed for 48 hours with Idempotent-Replayed: true. A failed request can be retried with the same key.

CORS

The API answers browsers (Access-Control-Allow-Origin: *) — but never ship a key in front-end code. Call it from your server.

Webhooks and events

Instead of polling, subscribe to events: contact.created, contact.replied, deal.won, quote.accepted, task.overdue, contact.website_visit and 51 more. Deliveries are signed (HMAC-SHA256) and retried for about 8 hours. See Webhooks & events.

Tools

The reference