POST
/meetings
Log a meeting booked in an external system (e.g. GoHighLevel, Calendly, manual reps) against an existing Nexor lead. The meeting appears in the lead’s timeline and in GET /leads/{id}/meetings.
This endpoint is creation-only in v1 — cancellations, reschedules, and no-shows will be handled by dedicated endpoints in a later release.
Lead matching
Leads are matched by email, scoped to your client:
- If one lead matches → used.
- If multiple leads share the email → the most recently updated lead wins.
- If no lead matches →
404. Create the lead first via POST /leads.
You may also pass lead_id directly to skip email matching.
Idempotency
If you supply both external_calendar_provider and external_event_id, replaying the request updates the existing meeting instead of creating a duplicate. Safe for webhook retries.
Request Body
| Field | Type | Required | Description |
|---|
lead_email | string | Yes* | Matcher. *Not required if lead_id is provided. |
lead_id | string (uuid) | No | Bypass email matching. |
title | string | Yes | Meeting title |
starts_at | string (ISO 8601) | Yes | If no offset, interpreted in timezone |
ends_at | string (ISO 8601) | Yes† | †Required unless duration_minutes is given |
duration_minutes | integer | Yes† | †Required unless ends_at is given |
timezone | string | No | IANA tz, default UTC (e.g. America/Santiago) |
meeting_url | string | No | Meet / Zoom / Teams link |
location_type | string | No | video | phone | in_person, default video |
location_details | string | No | |
description | string | No | |
host_email | string | No | Host user email (must be active in your client) |
meeting_type_id | string (uuid) | No | |
attendee_name | string | No | Defaults to lead’s full name |
attendee_email | string | No | Defaults to matched email |
attendee_phone | string | No | Defaults to lead’s phone |
additional_attendees | array | No | [{ name, email }] |
external_calendar_provider | string | No | e.g. ghl, google, calendly |
external_event_id | string | No | Provider’s event id (enables dedup) |
status | string | No | scheduled (default) or confirmed |
Request Body Example
Minimal booked meeting, matched by lead email:
{
"lead_email": "tony.stark@gmail.com",
"title": "Discovery Call",
"starts_at": "2026-04-20T14:00:00",
"ends_at": "2026-04-20T15:00:00",
"timezone": "America/Santiago",
"meeting_url": "https://meet.google.com/abc-xyz-123",
"location_type": "video",
"status": "scheduled"
}
Full payload — GoHighLevel webhook (via Make), with dedup key and confirmation:
{
"lead_email": "tony.stark@gmail.com",
"title": "Discovery Call with Tony Stark",
"starts_at": "2025-12-29T14:00:00",
"ends_at": "2025-12-29T15:00:00",
"timezone": "America/Santiago",
"meeting_url": "https://meet.google.com/oki-fjnk-oyu",
"location_type": "video",
"description": "Confirmation and reminder emails",
"attendee_name": "Tony Stark",
"external_calendar_provider": "ghl",
"external_event_id": "1RZJ24WY65VGQFyhN0vJ",
"status": "confirmed"
}
Sending "status": "confirmed" stores the meeting as scheduled and flips the internal confirmed_by_lead flag — the lead shows up as having confirmed attendance.
cURL
curl -X POST https://api.getnexor.ai/api/public/meetings \
-H "Content-Type: application/json" \
-H "X-API-Key: nxr_live_your_api_key" \
-d '{
"lead_email": "tony.stark@gmail.com",
"title": "Discovery Call with Tony Stark",
"starts_at": "2025-12-29T14:00:00",
"ends_at": "2025-12-29T15:00:00",
"timezone": "America/Santiago",
"meeting_url": "https://meet.google.com/oki-fjnk-oyu",
"location_type": "video",
"description": "Confirmation and reminder emails",
"attendee_name": "Tony Stark",
"external_calendar_provider": "ghl",
"external_event_id": "1RZJ24WY65VGQFyhN0vJ",
"status": "confirmed"
}'
Responses
201 — Meeting created
{
"success": true,
"meeting": {
"id": "event-uuid",
"lead_id": "lead-uuid",
"title": "Discovery Call with Tony Stark",
"starts_at": "2025-12-29T17:00:00Z",
"ends_at": "2025-12-29T18:00:00Z",
"duration_minutes": 60,
"timezone": "America/Santiago",
"status": "confirmed",
"meeting_url": "https://meet.google.com/oki-fjnk-oyu",
"location_type": "video",
"location_details": null,
"host_name": null,
"meeting_type": null,
"attendee_name": "Tony Stark",
"attendee_email": "tony.stark@gmail.com",
"external_calendar_provider": "ghl",
"external_event_id": "1RZJ24WY65VGQFyhN0vJ",
"source": "api",
"created_at": "2026-04-15T12:00:00Z"
}
}
400 — Validation error
401 — Authentication error — see Authentication
404 — Lead not found for the provided email
409 — external_event_id already bound to a different lead
500 — Internal server error
Last modified on June 18, 2026