CRM

Contacts

People in your CRM: create, search, update, their full 360° view, notes, emails and everything that happened with them.

A contact is one person. It carries their details, owner, lifecycle stage, temperature, score and tags, and links to a company. Creating a contact with an email that already exists returns the existing contact instead of a duplicate — use POST /contacts/upsert to create or update in one call.

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.
This page 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
GET/contacts

List and search contacts

Contacts sorted by lead score (highest first) by default. Combine any filters. Returns total for paging.

Scope: read

Query parameters

qstring
Search in name, email, company and job title.
company_iduuid
Only people of this company.
ownerstring
Owner email (assigned_to).
stagestring
CRM board stage (pipeline_stage).
lifecycle_stagestring
Lifecycle stage.
min_scoreinteger
Minimum lead score.
updated_sincedatetime
Only contacts changed since this ISO date — use it to sync incrementally.
sortstring
Column to sort by (lead_score, created_at, updated_at, display_name…). Default lead_score.
orderstring
asc or desc (default).
limitinteger
Page size, 1–1000. Default 50.
offsetinteger
Rows to skip. Default 0.
Request
curl "https://meetzy.me/api/v1/contacts?q=payfit&min_score=40&limit=20" \
  -H "Authorization: Bearer $MEETZY_API_KEY"
const res = await fetch("https://meetzy.me/api/v1/contacts?q=payfit&min_score=40&limit=20", {
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}` },
});
const data = await res.json();
import os, requests

res = requests.get(
    "https://meetzy.me/api/v1/contacts?q=payfit&min_score=40&limit=20",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
)
data = res.json()
Response200
{
  "contacts": [
    {
      "id": "8028ff76-1da4-451f-a0e7-dd91db772c20",
      "display_name": "Camille Laurent",
      "first_name": "Camille",
      "last_name": "Laurent",
      "primary_email": "camille@payfit.com",
      "phone": "+33612345678",
      "title": "Head of Sales",
      "company": "Payfit",
      "company_id": "166c436d-a874-4730-a0d8-c8d7fa090268",
      "avatar_url": null,
      "lead_score": 0,
      "lead_status": "cold",
      "pipeline_stage": "new_leads",
      "lifecycle_stage": "lead",
      "assigned_to": null,
      "primary_source": "manual",
      "last_contact_at": null,
      "created_at": "2026-10-07T13:22:38.585893+00:00",
      "linkedin_profile_url": null,
      "country": null,
      "city": null,
      "tags": [
        "inbound"
      ]
    }
  ],
  "total": 1
}
POST/contacts

Create a contact

Creates a contact and links it to a company (found by email domain or company name, created if needed). If a contact with the same email exists, it is returned unchanged — the response then has the same id. Needs an email or a name.

Scope: write

Body

emailstringemail or name
Email address. Also accepted as primary_email.
first_namestring
First name.
last_namestring
Last name.
display_namestring
Full name as shown in the app. Built from first and last name when omitted.
phonestring
Phone number, ideally in international format (+33612345678).
titlestring
Job title.
companystring
Company name as written on the contact. Meetzy links the contact to its company when it is clear (email domain of one company, else exactly the same name) unless associate_company is false.
company_iduuid
Link to an existing company.
company_websitestring
Company website, used to find the company by domain.
lifecycle_stagestring
Where the person is in the funnel: subscriber, lead, mql, sql, opportunity, customer, evangelist, churned, other. Default lead.
pipeline_stagestring
Stage on the CRM board of their sales cycle (see Sales cycles). Default new_leads.
sales_cycle_idstring
Sales cycle the contact belongs to (default or a cycle id from GET /crm/cycles).
lead_statusstring
Temperature: hot, warm or cold. Default cold. Setting it by hand stops the automatic temperature.
lead_scoreinteger
Score from 0 to 100. Usually moved by scoring and workflows.
assigned_tostring
Owner — email of a teammate.
countrystring
Country.
citystring
City.
regionstring
Region or state.
headlinestring
Professional headline (LinkedIn).
linkedin_profile_urlstring
LinkedIn profile URL — needed for LinkedIn steps.
tagsstring[]
Free labels, e.g. ["inbound", "webinar"].
custom_propertiesobject
Values of your custom properties, keyed by property key (see Properties).
do_not_contactboolean
Never email or message this person (sequences and campaigns skip them).
reminder_datedate
Follow-up date (YYYY-MM-DD) shown in Follow-ups.
reminder_notestring
What the follow-up is about.
reminder_assigned_tostring
Teammate who should do the follow-up (email).
label_iduuid
CRM board label.
notesstring
Free text notes field (for timestamped notes use POST /contacts/{id}/notes).
secondary_emailsstring[]
Other addresses of the same person — their emails are matched to this contact.
instagram_usernamestring
Instagram handle.
facebook_usernamestring
Facebook handle.
twitter_usernamestring
X / Twitter handle.
tiktok_usernamestring
TikTok handle.
threads_usernamestring
Threads handle.
sourcestring
Where the contact comes from (website, event, import…). Default manual.
associate_companyboolean
Link to a company automatically. Default true.
Request
curl -X POST "https://meetzy.me/api/v1/contacts" \
  -H "Authorization: Bearer $MEETZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "camille@payfit.com",
    "first_name": "Camille",
    "last_name": "Laurent",
    "title": "Head of Sales",
    "company": "Payfit",
    "assigned_to": "olivia@acme.com",
    "lifecycle_stage": "mql",
    "tags": [
      "inbound"
    ],
    "source": "website"
  }'
const res = await fetch("https://meetzy.me/api/v1/contacts", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "email": "camille@payfit.com",
    "first_name": "Camille",
    "last_name": "Laurent",
    "title": "Head of Sales",
    "company": "Payfit",
    "assigned_to": "olivia@acme.com",
    "lifecycle_stage": "mql",
    "tags": [
      "inbound"
    ],
    "source": "website"
  }),
});
const data = await res.json();
import os, requests

res = requests.post(
    "https://meetzy.me/api/v1/contacts",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
    json={
        "email": "camille@payfit.com",
        "first_name": "Camille",
        "last_name": "Laurent",
        "title": "Head of Sales",
        "company": "Payfit",
        "assigned_to": "olivia@acme.com",
        "lifecycle_stage": "mql",
        "tags": ["inbound"],
        "source": "website"
    },
)
data = res.json()
Response201
{
  "id": "8028ff76-1da4-451f-a0e7-dd91db772c20",
  "display_name": "Camille Laurent",
  "first_name": "Camille",
  "last_name": "Laurent",
  "primary_email": "camille@payfit.com",
  "phone": null,
  "title": "Head of Sales",
  "company": "Payfit",
  "company_id": null,
  "avatar_url": null,
  "lead_score": 0,
  "lead_status": "cold",
  "pipeline_stage": "new_leads",
  "lifecycle_stage": "lead",
  "assigned_to": null,
  "primary_source": "manual",
  "last_contact_at": null,
  "created_at": "2026-10-07T13:22:38.585893+00:00",
  "linkedin_profile_url": null,
  "country": null,
  "city": null,
  "tags": [
    "inbound"
  ]
}
POST/contacts/upsert

Create or update a contact by email

The safest call for syncing from another tool: creates the contact, or updates every field you send on the existing one with the same email. The response has created: true or false.

Scope: write

Body

emailstringrequired
Email address used to find the contact.
first_namestring
First name.
last_namestring
Last name.
display_namestring
Full name as shown in the app. Built from first and last name when omitted.
phonestring
Phone number, ideally in international format (+33612345678).
titlestring
Job title.
companystring
Company name as written on the contact. Meetzy links the contact to its company when it is clear (email domain of one company, else exactly the same name) unless associate_company is false.
company_iduuid
Link to an existing company.
company_websitestring
Company website, used to find the company by domain.
lifecycle_stagestring
Where the person is in the funnel: subscriber, lead, mql, sql, opportunity, customer, evangelist, churned, other. Default lead.
pipeline_stagestring
Stage on the CRM board of their sales cycle (see Sales cycles). Default new_leads.
sales_cycle_idstring
Sales cycle the contact belongs to (default or a cycle id from GET /crm/cycles).
lead_statusstring
Temperature: hot, warm or cold. Default cold. Setting it by hand stops the automatic temperature.
lead_scoreinteger
Score from 0 to 100. Usually moved by scoring and workflows.
assigned_tostring
Owner — email of a teammate.
countrystring
Country.
citystring
City.
regionstring
Region or state.
headlinestring
Professional headline (LinkedIn).
linkedin_profile_urlstring
LinkedIn profile URL — needed for LinkedIn steps.
tagsstring[]
Free labels, e.g. ["inbound", "webinar"].
custom_propertiesobject
Values of your custom properties, keyed by property key (see Properties).
do_not_contactboolean
Never email or message this person (sequences and campaigns skip them).
reminder_datedate
Follow-up date (YYYY-MM-DD) shown in Follow-ups.
reminder_notestring
What the follow-up is about.
reminder_assigned_tostring
Teammate who should do the follow-up (email).
label_iduuid
CRM board label.
notesstring
Free text notes field (for timestamped notes use POST /contacts/{id}/notes).
secondary_emailsstring[]
Other addresses of the same person — their emails are matched to this contact.
instagram_usernamestring
Instagram handle.
facebook_usernamestring
Facebook handle.
twitter_usernamestring
X / Twitter handle.
tiktok_usernamestring
TikTok handle.
threads_usernamestring
Threads handle.
Request
curl -X POST "https://meetzy.me/api/v1/contacts/upsert" \
  -H "Authorization: Bearer $MEETZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "camille@payfit.com",
    "phone": "+33612345678",
    "lead_score": 55,
    "tags": [
      "inbound",
      "demo-requested"
    ]
  }'
const res = await fetch("https://meetzy.me/api/v1/contacts/upsert", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "email": "camille@payfit.com",
    "phone": "+33612345678",
    "lead_score": 55,
    "tags": [
      "inbound",
      "demo-requested"
    ]
  }),
});
const data = await res.json();
import os, requests

res = requests.post(
    "https://meetzy.me/api/v1/contacts/upsert",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
    json={
        "email": "camille@payfit.com",
        "phone": "+33612345678",
        "lead_score": 55,
        "tags": ["inbound", "demo-requested"]
    },
)
data = res.json()
Response201
{
  "id": "8028ff76-1da4-451f-a0e7-dd91db772c20",
  "display_name": "Camille Laurent",
  "first_name": "Camille",
  "last_name": "Laurent",
  "primary_email": "camille@payfit.com",
  "phone": "+33612345678",
  "title": "Head of Sales",
  "company": "Payfit",
  "company_id": "166c436d-a874-4730-a0d8-c8d7fa090268",
  "avatar_url": null,
  "lead_score": 0,
  "lead_status": "cold",
  "pipeline_stage": "new_leads",
  "lifecycle_stage": "lead",
  "assigned_to": null,
  "primary_source": "manual",
  "last_contact_at": null,
  "created_at": "2026-10-07T13:22:38.585893+00:00",
  "linkedin_profile_url": null,
  "country": null,
  "city": null,
  "tags": [
    "inbound"
  ],
  "created": false
}
GET/contacts/{id}

Get a contact (360° view)

Everything about one person: their record (with email engagement totals, LinkedIn status and AI summary), their company with company_summary (last 12 months bought, last order, orders, open quotes, unpaid — from any ERP or shop synced), deals, tasks, timeline activities, notes, sequence enrollments and the CRM board context (sales cycle, stages, labels).

Scope: read

Path parameters

idstringrequired
Id of the record (UUID).
Request
curl "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc" \
  -H "Authorization: Bearer $MEETZY_API_KEY"
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc", {
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}` },
});
const data = await res.json();
import os, requests

res = requests.get(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
)
data = res.json()
Response200
{
  "contact": {
    "id": "8028ff76-1da4-451f-a0e7-dd91db772c20",
    "display_name": "Camille Laurent",
    "first_name": "Camille",
    "last_name": "Laurent",
    "primary_email": "camille@payfit.com",
    "phone": "+33612345678",
    "title": "Head of Sales",
    "company": "Payfit",
    "company_id": "166c436d-a874-4730-a0d8-c8d7fa090268",
    "avatar_url": null,
    "lead_score": 0,
    "lead_status": "cold",
    "pipeline_stage": "new_leads",
    "lifecycle_stage": "lead",
    "assigned_to": null,
    "primary_source": "manual",
    "last_contact_at": null,
    "created_at": "2026-10-07T13:22:38.585893+00:00",
    "linkedin_profile_url": null,
    "country": null,
    "city": null,
    "tags": [
      "inbound"
    ],
    "headline": null,
    "about": null,
    "seniority": null,
    "organization_industry": null,
    "organization_num_employees": null,
    "company_website": null,
    "total_emails_sent": 0,
    "total_emails_opened": 0,
    "total_emails_clicked": 0,
    "total_email_replies": 0,
    "total_website_visits": 0,
    "total_meetings_booked": 0,
    "linkedin_connection_status": null,
    "score_breakdown": {},
    "ai_summary": null,
    "custom_properties": {},
    "do_not_contact": false,
    "reminder_date": null,
    "reminder_note": null,
    "reminder_assigned_to": null,
    "label_id": null,
    "pipeline_history": [],
    "pipeline_changed_at": null,
    "pipeline_changed_by": null,
    "assigned_at": null,
    "added_at": "2026-10-07T13:22:38.553+00:00",
    "secondary_emails": null,
    "instagram_username": null,
    "facebook_username": null,
    "twitter_username": null,
    "tiktok_username": null,
    "threads_username": null
  },
  "company": {
    "id": "166c436d-a874-4730-a0d8-c8d7fa090268",
    "user_from": "acme",
    "name": "Payfit",
    "domain": "payfit.com",
    "website": null,
    "industry": "Software",
    "employees": 42,
    "annual_revenue": null,
    "country": null,
    "city": null,
    "address": null,
    "phone": null,
    "linkedin_url": null,
    "description": null,
    "logo_url": null,
    "owner_email": "olivia@acme.com",
    "lifecycle_stage": "lead",
    "company_type": "prospect",
    "tier": "B",
    "health_score": null,
    "tags": [
      "api",
      "vip"
    ],
    "custom": {},
    "parent_company_id": null,
    "apollo_id": null,
    "last_activity_at": null,
    "created_by": "olivia@acme.com",
    "created_at": "2026-10-07T13:22:31.105534+00:00",
    "updated_at": "2026-10-07T13:22:37.766452+00:00"
  },
  "deals": [],
  "tasks": [],
  "activities": [],
  "notes": [],
  "enrollments": [],
  "crm": {
    "cycle_id": "default",
    "cycles": [
      {
        "id": "default",
        "name": "Main pipeline",
        "color": "#007AFF",
        "is_default": true,
        "stages": [
          {
            "id": "new_leads",
            "name": "New leads",
            "color": "#8E8E93",
            "fixed": true
          },
          {
            "id": "in_discussion",
            "name": "In discussion",
            "description": null,
            "color": "#5856D6",
            "won": false
          },
          {
            "id": "negotiation",
            "name": "Negotiation",
            "description": null,
            "color": "#007AFF",
            "won": false
          }
        ],
        "count": 1
      }
    ],
    "multi_supported": true,
    "stages": [
      {
        "id": "new_leads",
        "name": "New leads",
        "color": "#8E8E93",
        "fixed": true
      },
      {
        "id": "in_discussion",
        "name": "In discussion",
        "description": null,
        "color": "#5856D6",
        "won": false
      },
      {
        "id": "negotiation",
        "name": "Negotiation",
        "description": null,
        "color": "#007AFF",
        "won": false
      }
    ],
    "labels": []
  }
}
PATCH/contacts/{id}

Update a contact

Send only the fields to change. Moving pipeline_stage records the move in the stage history; changing assigned_to sets the assignment date. Changes fire events (contact.stage_changed, contact.owner_changed…) that workflows and webhooks react to.

Scope: write

Path parameters

idstringrequired
Id of the record (UUID).

Body

first_namestring
First name.
last_namestring
Last name.
display_namestring
Full name as shown in the app. Built from first and last name when omitted.
phonestring
Phone number, ideally in international format (+33612345678).
titlestring
Job title.
companystring
Company name as written on the contact. Meetzy links the contact to its company when it is clear (email domain of one company, else exactly the same name) unless associate_company is false.
company_iduuid
Link to an existing company.
company_websitestring
Company website, used to find the company by domain.
lifecycle_stagestring
Where the person is in the funnel: subscriber, lead, mql, sql, opportunity, customer, evangelist, churned, other. Default lead.
pipeline_stagestring
Stage on the CRM board of their sales cycle (see Sales cycles). Default new_leads.
sales_cycle_idstring
Sales cycle the contact belongs to (default or a cycle id from GET /crm/cycles).
lead_statusstring
Temperature: hot, warm or cold. Default cold. Setting it by hand stops the automatic temperature.
lead_scoreinteger
Score from 0 to 100. Usually moved by scoring and workflows.
assigned_tostring
Owner — email of a teammate.
countrystring
Country.
citystring
City.
regionstring
Region or state.
headlinestring
Professional headline (LinkedIn).
linkedin_profile_urlstring
LinkedIn profile URL — needed for LinkedIn steps.
tagsstring[]
Free labels, e.g. ["inbound", "webinar"].
custom_propertiesobject
Values of your custom properties, keyed by property key (see Properties).
do_not_contactboolean
Never email or message this person (sequences and campaigns skip them).
reminder_datedate
Follow-up date (YYYY-MM-DD) shown in Follow-ups.
reminder_notestring
What the follow-up is about.
reminder_assigned_tostring
Teammate who should do the follow-up (email).
label_iduuid
CRM board label.
notesstring
Free text notes field (for timestamped notes use POST /contacts/{id}/notes).
secondary_emailsstring[]
Other addresses of the same person — their emails are matched to this contact.
instagram_usernamestring
Instagram handle.
facebook_usernamestring
Facebook handle.
twitter_usernamestring
X / Twitter handle.
tiktok_usernamestring
TikTok handle.
threads_usernamestring
Threads handle.
Request
curl -X PATCH "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc" \
  -H "Authorization: Bearer $MEETZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "lifecycle_stage": "sql",
    "assigned_to": "olivia@acme.com",
    "reminder_date": "2026-10-14",
    "reminder_note": "Send the pricing"
  }'
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc", {
  method: "PATCH",
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "lifecycle_stage": "sql",
    "assigned_to": "olivia@acme.com",
    "reminder_date": "2026-10-14",
    "reminder_note": "Send the pricing"
  }),
});
const data = await res.json();
import os, requests

res = requests.patch(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
    json={
        "lifecycle_stage": "sql",
        "assigned_to": "olivia@acme.com",
        "reminder_date": "2026-10-14",
        "reminder_note": "Send the pricing"
    },
)
data = res.json()
Response200
{
  "id": "8028ff76-1da4-451f-a0e7-dd91db772c20",
  "display_name": "Camille Laurent",
  "first_name": "Camille",
  "last_name": "Laurent",
  "primary_email": "camille@payfit.com",
  "phone": "+33612345678",
  "title": "Head of Sales",
  "company": "Payfit",
  "company_id": "166c436d-a874-4730-a0d8-c8d7fa090268",
  "avatar_url": null,
  "lead_score": 40,
  "lead_status": "cold",
  "pipeline_stage": "new_leads",
  "lifecycle_stage": "mql",
  "assigned_to": null,
  "primary_source": "manual",
  "last_contact_at": null,
  "created_at": "2026-10-07T13:22:38.585893+00:00",
  "linkedin_profile_url": null,
  "country": null,
  "city": null,
  "tags": [
    "inbound"
  ]
}
DELETE/contacts/{id}

Delete a contact

Deletes the contact permanently. Its deals and tasks stay, without the link.

Scope: delete

Path parameters

idstringrequired
Id of the record (UUID).
Request
curl -X DELETE "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc" \
  -H "Authorization: Bearer $MEETZY_API_KEY"
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc", {
  method: "DELETE",
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}` },
});
const data = await res.json();
import os, requests

res = requests.delete(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
)
data = res.json()
Response200
{
  "deleted": true
}
POST/contacts/{id}/notes

Add a note

Adds a timestamped note on the contact, signed by the key’s user. Notes show on the timeline and fire contact.note_added.

Scope: write

Path parameters

idstringrequired
Id of the record (UUID).

Body

contentstringrequired
Text of the note. Also accepted as note.
Request
curl -X POST "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/notes" \
  -H "Authorization: Bearer $MEETZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Met at the Paris fair — wants a demo in November."
  }'
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/notes", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "content": "Met at the Paris fair — wants a demo in November."
  }),
});
const data = await res.json();
import os, requests

res = requests.post(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/notes",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
    json={
        "content": "Met at the Paris fair — wants a demo in November."
    },
)
data = res.json()
Response201
{
  "id": "e1c95777-748f-40ba-a93e-d272c644e0f1",
  "lead_id": "8028ff76-1da4-451f-a0e7-dd91db772c20",
  "user_from": "acme",
  "author_email": "olivia@acme.com",
  "author_name": "Olivia Martin",
  "content": "Met at the fair",
  "mentions": [],
  "created_at": "2026-10-07T13:22:43.291381+00:00",
  "updated_at": "2026-10-07T13:22:43.291381+00:00",
  "read_by": []
}
GET/contacts/{id}/interactions

Everything that happened with a contact

One feed, newest first, beyond logged activities: website visits and forms, email opens, clicks, replies, bounces and unsubscribes, LinkedIn invitation, connection and messages, WhatsApp messages, meetings, sequences joined or left, stage, owner and status changes, deals, quotes and tasks. Plus a summary (visits, opens, clicks, messages, last inbound).

Scope: read

Path parameters

idstringrequired
Id of the record (UUID).

Query parameters

socialstring
0 to skip reading LinkedIn and WhatsApp messages live (faster). Default on.
Request
curl "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/interactions" \
  -H "Authorization: Bearer $MEETZY_API_KEY"
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/interactions", {
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}` },
});
const data = await res.json();
import os, requests

res = requests.get(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/interactions",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
)
data = res.json()
Response200
{
  "items": [
    {
      "id": "ev-3295",
      "type": "system",
      "subject": "Lifecycle: mql",
      "occurred_at": "2026-10-07T13:22:42.488773+00:00",
      "actor_email": null
    },
    {
      "id": "ev-3291",
      "type": "system",
      "subject": "Added to the CRM",
      "occurred_at": "2026-10-07T13:22:38.585893+00:00",
      "actor_email": null
    }
  ],
  "summary": {
    "website_visits": 0,
    "email_opens": 0,
    "email_clicks": 0,
    "linkedin_messages": 0,
    "whatsapp_messages": 0,
    "meetings": 0,
    "last_30_days": 2,
    "last_inbound_at": null
  }
}
GET/contacts/{id}/copilot

What to do next with a contact

The lead copilot reads everything Meetzy knows and answers with ONE next step (next) and the other suggestions (rules), each with why, often how (the stage’s playbook, their usual basket) and an action. It looks at every conversation wherever it happened — the team’s mailboxes, the key’s user’s WhatsApp and LinkedIn, logged calls and meetings, sequences — to know who wrote last and on which channel; at the contact’s sales cycle and what its next stage takes (an order form, a demo, a proforma…); at what the ERP says about their company (order rhythm, usual basket, reorder due or late, orders that arrived while the lead sat in an early stage, open quotes, unpaid invoices, colleagues already in touch); and at follow-ups, tasks, order forms, quotes, deals and meetings. signals carries those facts; priority the 0-100 score with its reasons. When a channel knew a newer touch than the CRM, the contact’s last_contact_at is updated (lead_patch).

Scope: read

Path parameters

idstringrequired
Id of the record (UUID).

action.type: message (open the conversation on channel), email, task, reminder, stage, cycle_stage, assign_me, deal, order_form, company or link.

Request
curl "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/copilot" \
  -H "Authorization: Bearer $MEETZY_API_KEY"
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/copilot", {
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}` },
});
const data = await res.json();
import os, requests

res = requests.get(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/copilot",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
)
data = res.json()
Response200
{
  "priority": {
    "score": 71,
    "level": "now",
    "reasons": [
      "Hot",
      "Reorder late"
    ]
  },
  "next": {
    "id": "reorder_late",
    "score": 90,
    "tone": "amber",
    "channel": "whatsapp",
    "title": "Reorder 23 days late",
    "why": "Orders about every 62 days — last one 30 Jul, €4,180. It was expected around 30 Sep and has not come.",
    "how": "Usually: Erba Pura EDP 100ML, Naxos EDP 100ML · about €4,200 an order. Ask if something changed.",
    "action": {
      "type": "message",
      "channel": "whatsapp",
      "label": "Open WhatsApp"
    }
  },
  "rules": [
    {
      "id": "follow_up",
      "score": 80,
      "tone": "blue",
      "channel": "whatsapp",
      "title": "Follow up with Camille on WhatsApp",
      "why": "You wrote 6 days ago and had no answer.",
      "action": {
        "type": "message",
        "channel": "whatsapp",
        "label": "Open WhatsApp"
      }
    }
  ],
  "signals": {
    "ball": "ours",
    "last_touch": {
      "channel": "whatsapp",
      "direction": "out",
      "at": "2026-10-02T09:12:00Z",
      "days": 6
    },
    "unanswered_outbound": 1,
    "stage": {
      "cycle": "Already client",
      "name": "Follow-up",
      "days": 4,
      "next": {
        "name": "Order form Sent",
        "kind": "document",
        "object": "order_form",
        "verb": "send"
      }
    },
    "buying": {
      "status": "at_risk",
      "last_order": {
        "date": "2026-07-30",
        "amount": 4180
      },
      "rhythm": {
        "every": 62,
        "usual_amount": 4200,
        "next": "2026-09-30",
        "lateness": 0.37
      }
    }
  },
  "lead_patch": null,
  "ai_available": true,
  "ai": null
}
POST/contacts/{id}/copilot

What to do next, with the AI’s read

Same as GET, plus ai: a summary, a temperature, a next action, risks, a ready email and — when WhatsApp or LinkedIn is the right channel — a short chat message, all written from the same facts. Uses AI credits.

Scope: read

Path parameters

idstringrequired
Id of the record (UUID).

Works with a read-only key: it changes nothing in the CRM.

Request
curl -X POST "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/copilot" \
  -H "Authorization: Bearer $MEETZY_API_KEY"
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/copilot", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}` },
});
const data = await res.json();
import os, requests

res = requests.post(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/copilot",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
)
data = res.json()
Response201

See the notes on the left.

POST/contacts/{id}/associate-company

Link the contact to its company

Links the contact when its company is clear: the website or email domain of exactly one company, else exactly the same company name. Nothing is created; ambiguous is true when several companies match (choose with PUT /contacts/{id}/company).

Scope: write

Path parameters

idstringrequired
Id of the record (UUID).
Request
curl -X POST "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/associate-company" \
  -H "Authorization: Bearer $MEETZY_API_KEY"
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/associate-company", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}` },
});
const data = await res.json();
import os, requests

res = requests.post(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/associate-company",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
)
data = res.json()
Response201
{
  "company_id": "3cdc3e21-931a-4e8b-a189-3cab5dfbd636",
  "company_name": "Lumière Paris",
  "created": false,
  "ambiguous": false
}
GET/contacts/{id}/company-suggestions

Companies this contact may belong to

The companies matching the contact’s email domain (reason: domain) or company name (reason: name), best when one is clear, and with q a search by name, domain or ERP code.

Scope: read

Path parameters

idstringrequired
Id of the record (UUID).

Query parameters

qstring
Search companies.
Request
curl "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/company-suggestions" \
  -H "Authorization: Bearer $MEETZY_API_KEY"
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/company-suggestions", {
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}` },
});
const data = await res.json();
import os, requests

res = requests.get(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/company-suggestions",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
)
data = res.json()
Response200
{
  "current": null,
  "link": null,
  "domain": "lumiere.fr",
  "best": "3cdc3e21-931a-4e8b-a189-3cab5dfbd636",
  "suggested": [
    {
      "id": "3cdc3e21-931a-4e8b-a189-3cab5dfbd636",
      "name": "Lumière Paris",
      "domain": "lumiere.fr",
      "code": "C000412",
      "reason": "domain"
    }
  ],
  "results": [],
  "create": {
    "name": "Lumière",
    "domain": "lumiere.fr"
  }
}
GET/contacts/{id}/companies

All the contact’s companies

A contact can work for several companies: primary is their main company (company_id, used by default everywhere), others the rest. The contact shows on each of them (people, timeline, counts).

Scope: read

Path parameters

idstringrequired
Id of the record (UUID).
Request
curl "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/companies" \
  -H "Authorization: Bearer $MEETZY_API_KEY"
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/companies", {
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}` },
});
const data = await res.json();
import os, requests

res = requests.get(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/companies",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
)
data = res.json()
Response200
{
  "primary": {
    "id": "3cdc3e21-931a-4e8b-a189-3cab5dfbd636",
    "name": "Lumière Paris",
    "domain": "lumiere.fr"
  },
  "others": [
    {
      "id": "9d8e7f6a-5b4c-4d3e-8f2a-1b0c9d8e7f6a",
      "name": "Lumière Group",
      "domain": "lumiere-group.com"
    }
  ]
}
POST/contacts/{id}/companies

Add a company to the contact

Links one more company. The first company of a contact becomes its main one. create makes the company (or reuses the one with the same domain or name).

Scope: write

Path parameters

idstringrequired
Id of the record (UUID).

Body

company_iduuid
The company.
createobject
{ name, domain } to create it instead.
Request
curl -X POST "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/companies" \
  -H "Authorization: Bearer $MEETZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "company_id": "9d8e7f6a-5b4c-4d3e-8f2a-1b0c9d8e7f6a"
  }'
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/companies", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "company_id": "9d8e7f6a-5b4c-4d3e-8f2a-1b0c9d8e7f6a"
  }),
});
const data = await res.json();
import os, requests

res = requests.post(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/companies",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
    json={
        "company_id": "9d8e7f6a-5b4c-4d3e-8f2a-1b0c9d8e7f6a"
    },
)
data = res.json()
Response201
{
  "primary": {
    "id": "3cdc3e21-931a-4e8b-a189-3cab5dfbd636",
    "name": "Lumière Paris",
    "domain": "lumiere.fr"
  },
  "others": [
    {
      "id": "9d8e7f6a-5b4c-4d3e-8f2a-1b0c9d8e7f6a",
      "name": "Lumière Group",
      "domain": "lumiere-group.com"
    }
  ],
  "added": {
    "id": "9d8e7f6a-5b4c-4d3e-8f2a-1b0c9d8e7f6a",
    "name": "Lumière Group",
    "domain": "lumiere-group.com"
  },
  "existing": false
}
DELETE/contacts/{id}/companies/{companyId}

Remove a company from the contact

Removing the main company makes the next one the main one.

Scope: delete

Path parameters

idstringrequired
Id of the record (UUID).
companyIdstringrequired
Id of the company (UUID).
Request
curl -X DELETE "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/companies/%7BcompanyId%7D" \
  -H "Authorization: Bearer $MEETZY_API_KEY"
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/companies/%7BcompanyId%7D", {
  method: "DELETE",
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}` },
});
const data = await res.json();
import os, requests

res = requests.delete(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/companies/%7BcompanyId%7D",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
)
data = res.json()
Response200
{
  "primary": {
    "id": "3cdc3e21-931a-4e8b-a189-3cab5dfbd636",
    "name": "Lumière Paris",
    "domain": "lumiere.fr"
  },
  "others": []
}
POST/contacts/{id}/companies/{companyId}/main

Make it the main company

One of the contact’s other companies becomes the main one; the previous main one stays among the others.

Scope: write

Path parameters

idstringrequired
Id of the record (UUID).
companyIdstringrequired
Id of the company (UUID).
Request
curl -X POST "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/companies/%7BcompanyId%7D/main" \
  -H "Authorization: Bearer $MEETZY_API_KEY"
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/companies/%7BcompanyId%7D/main", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}` },
});
const data = await res.json();
import os, requests

res = requests.post(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/companies/%7BcompanyId%7D/main",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
)
data = res.json()
Response201
{
  "primary": {
    "id": "9d8e7f6a-5b4c-4d3e-8f2a-1b0c9d8e7f6a",
    "name": "Lumière Group",
    "domain": "lumiere-group.com"
  },
  "others": [
    {
      "id": "3cdc3e21-931a-4e8b-a189-3cab5dfbd636",
      "name": "Lumière Paris",
      "domain": "lumiere.fr"
    }
  ]
}
PUT/contacts/{id}/company

Choose the contact’s company

Links the contact to a company by hand — from then on, automatic linking leaves this contact alone. company_id: null unlinks it; create makes a new company (or reuses the one with the same domain or name).

Scope: write

Path parameters

idstringrequired
Id of the record (UUID).

Body

company_iduuid
The company, or null to unlink.
createobject
{ name, domain } to create the company instead.
Request
curl -X PUT "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/company" \
  -H "Authorization: Bearer $MEETZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "company_id": "3cdc3e21-931a-4e8b-a189-3cab5dfbd636"
  }'
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/company", {
  method: "PUT",
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "company_id": "3cdc3e21-931a-4e8b-a189-3cab5dfbd636"
  }),
});
const data = await res.json();
import os, requests

res = requests.put(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/company",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
    json={
        "company_id": "3cdc3e21-931a-4e8b-a189-3cab5dfbd636"
    },
)
data = res.json()
Response200
{
  "company_id": "3cdc3e21-931a-4e8b-a189-3cab5dfbd636",
  "company": {
    "id": "3cdc3e21-931a-4e8b-a189-3cab5dfbd636",
    "name": "Lumière Paris",
    "domain": "lumiere.fr"
  },
  "existing": false
}
POST/contacts/{id}/email

Send an email to a contact

Sends one email now from the key user’s connected mailbox, with open and click tracking, and logs it on the timeline. Use a template or write a subject and body; merge tags like {{contact.first_name}} are filled. To reply inside an existing thread with attachments, use Mailbox › contact threads.

Scope: write

Path parameters

idstringrequired
Id of the record (UUID).

Body

subjectstring
Subject. Required without template_id.
bodystring
Body, plain text or HTML. Required without template_id.
template_iduuid
Email template to use (its subject and body fill what you leave empty).
deal_iduuid
Deal the email is about — {{deal.*}} tags become available.
trackboolean
Track opens and clicks. Default true.
Request
curl -X POST "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/email" \
  -H "Authorization: Bearer $MEETZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Your demo, {{contact.first_name}}",
    "body": "Hi {{contact.first_name}},\n\nHere is the recording of today’s demo…",
    "track": true
  }'
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/email", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "subject": "Your demo, {{contact.first_name}}",
    "body": "Hi {{contact.first_name}},\n\nHere is the recording of today’s demo…",
    "track": true
  }),
});
const data = await res.json();
import os, requests

res = requests.post(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/email",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
    json={
        "subject": "Your demo, {{contact.first_name}}",
        "body": "Hi {{contact.first_name}},\n\nHere is the recording of today’s demo…",
        "track": True
    },
)
data = res.json()
Response201
{
  "sent": true,
  "from": "olivia@acme.com",
  "subject": "Your demo, Camille",
  "send_id": "9b1f0c52-3c1e-4a8e-a2f1-6f0b2c7d1e44"
}
GET/contacts/{id}/emails

Emails sent to a contact

Emails Meetzy sent to this person (campaigns, workflows, one-off sends) with their status, opens, clicks and replies, and the mailing lists they are on.

Scope: read

Path parameters

idstringrequired
Id of the record (UUID).
Request
curl "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/emails" \
  -H "Authorization: Bearer $MEETZY_API_KEY"
const res = await fetch("https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/emails", {
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}` },
});
const data = await res.json();
import os, requests

res = requests.get(
    "https://meetzy.me/api/v1/contacts/e43414d6-f56f-42be-a64c-a836d6015efc/emails",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
)
data = res.json()
Response200
{
  "sends": [],
  "lists": []
}
POST/contacts/bulk/enroll

Enroll contacts in a sequence

Same as POST /sequences/{id}/enroll, with the sequence in the body. Contacts already in the sequence or marked do-not-contact are skipped and listed.

Scope: write

Body

sequence_iduuidrequired
Sequence.
contact_idsuuid[]required
Contacts to enroll.
Request
curl -X POST "https://meetzy.me/api/v1/contacts/bulk/enroll" \
  -H "Authorization: Bearer $MEETZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sequence_id": "4b3c7a10-5d5e-4f43-9b0e-1a2b3c4d5e6f",
    "contact_ids": [
      "e43414d6-f56f-42be-a64c-a836d6015efc"
    ]
  }'
const res = await fetch("https://meetzy.me/api/v1/contacts/bulk/enroll", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.MEETZY_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "sequence_id": "4b3c7a10-5d5e-4f43-9b0e-1a2b3c4d5e6f",
    "contact_ids": [
      "e43414d6-f56f-42be-a64c-a836d6015efc"
    ]
  }),
});
const data = await res.json();
import os, requests

res = requests.post(
    "https://meetzy.me/api/v1/contacts/bulk/enroll",
    headers={"Authorization": f"Bearer {os.environ['MEETZY_API_KEY']}"},
    json={
        "sequence_id": "4b3c7a10-5d5e-4f43-9b0e-1a2b3c4d5e6f",
        "contact_ids": ["e43414d6-f56f-42be-a64c-a836d6015efc"]
    },
)
data = res.json()
Response201
{
  "enrolled": 1,
  "skipped": []
}