---
title: "Convert a lead into an event"
method: POST
path: "/leads/{id}/convert"
tags: ["Leads"]
---

# Convert a lead into an event

`POST /leads/{id}/convert`

## Request

- Base URL: `https://joinways.app/api/v1`
- URL: `https://joinways.app/api/v1/leads/{id}/convert`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://joinways.app/oauth/authorize`, token URL `https://joinways.app/api/oauth/token`, scopes: `mcp.write`)

Same service as the Inbox conversion: one event per request per venue. When an event already holds this request at this venue it is reused (`reused_existing_event: true`, `matched_via`); otherwise an event is created after the venue availability check, with its company and contact, and the lead, its siblings, requested rooms and emails move onto it. Calendars are synchronised and the automatic quote may be drafted. **Role permission:** `leads.manage`.

## Headers

- `Idempotency-Key` string

## Request body

- object
  - `venue_id` string, uuid, required
  - `title` string: Defaults to a title built from the request.
  - `start_date` string, date-time, required
  - `end_date` string, date-time, required
  - `status` 'option' | 'confirmed'

## Response `200`

The event holding the request.

- object
  - `success` boolean
  - `event` object: The stored event, as returned by `POST /events`, `PATCH /events/{id}` and the conversion of a lead. Every column of the event is returned except the internal search fields, the embedding and the public tokens; the main ones are listed. Amounts are `null` without `reports.view` or `quotes.manage`.
    - `id` string, uuid
    - `account_id` string, uuid
    - `event_number` integer, nullable
    - `internal_reference` string, nullable
    - `title` string
    - `description` string, nullable
    - `type` string, nullable
    - `category` string, nullable
    - `status` 'option' | 'confirmed' | 'lost' | 'cancelled': `option` = pending / tentative, `confirmed` = booked, `lost` = did not convert, `cancelled` = cancelled after booking.
    - `status_changed_at` string, date-time, nullable
    - `stage_id` string, uuid, nullable
    - `stage_changed_at` string, date-time, nullable
    - `pax` integer, nullable
    - `start_date` string, date-time
    - `end_date` string, date-time, nullable
    - `selected_dates` string[], nullable
    - `day_hours` DayHoursEntry[], nullable: Per-day hours of a multi-day event, by date: one entry per day when the days have different hours, `null` when every day has the same hours (the time of `start_date` to the time of `end_date`) or for a one-day event.
      - `date` string, date, required
      - `start` string, required
      - `end` string, required
    - `timezone` string, nullable
    - `is_virtual` boolean, nullable
    - `flexible` boolean, nullable
    - `language` string, nullable
    - `venue_id` string, uuid, nullable: The venue (internally `location_id`).
    - `location` string, nullable: Free-text place (legacy), not the venue.
    - `address` string, nullable
    - `city` string, nullable
    - `postal_code` string, nullable
    - `country` string, nullable
    - `source` string, nullable
    - `source_lead_id` string, uuid, nullable: Primary request (lead) of the event.
    - `budget` number, nullable
    - `expected_revenue` number, nullable
    - `currency` string, nullable
    - `confirmed_amount` number, nullable
    - `confirmed_amount_excl_tax` number, nullable
    - `cancellation_fee_excl_tax` number, nullable
    - `confirmed_at` string, date-time, nullable
    - `loss_reason` string, nullable
    - `loss_reason_detail` string, nullable
    - `cancellation_reason` string, nullable
    - `cancellation_reason_detail` string, nullable
    - `tags` string[], nullable
    - `notes` string, nullable
    - `company_id` string, uuid, nullable
    - `contact_person_id` string, uuid, nullable
    - `assigned_to_account_id` string, uuid, nullable
    - `created_by` string, uuid, nullable
    - `billing_company_id` string, uuid, nullable: Third-party company the quotes are billed to (instead of the client).
    - `quote_to_platform` boolean, nullable: The quotes are billed to the booking platform of `source`.
    - `event_group_id` string, uuid, nullable
    - `external_link` string, nullable
    - `setup_type` string, nullable
    - `setup_notes` string, nullable
    - `catering_notes` string, nullable
    - `dietary_notes` string, nullable: Diets and allergies (« Contraintes alimentaires »), for the whole event.
    - `technical_notes` string, nullable
    - `service_notes` string, nullable
    - `beo_context` string, nullable
    - `beo_remarks` string, nullable
    - `schedule` object[], nullable: BEO program lines (see `BeoUpdate.schedule`).
    - `beo_public_url` string, uri, nullable: Shareable, no-login URL of the public BEO page.
    - `archived_at` string, date-time, nullable
    - `archived_by` string, uuid, nullable
    - `created_at` string, date-time, nullable
    - `updated_at` string, date-time, nullable
    - `location_id` string, uuid, nullable
  - `lead_id` string, uuid
  - `reused_existing_event` boolean: Only present (true) when an existing event was reused.
  - `matched_via` string: Only with `reused_existing_event`; how the event was found.
  - `warnings` string[]

## Other responses

- `400`: Validation failed (`invalid_request`). For a body that fails the schema, `details` holds `formErrors` and `fieldErrors`.
- `401`: Missing, invalid, expired or revoked bearer token (`unauthorized`).
- `403`: `forbidden`: the token lacks the scope, its owner's role lacks the permission named by the operation, or the workspace has neither the Pro plan nor a trial (`details.reason` `plan_not_eligible`).
- `404`: Not found in this workspace, or the id of the path is not a UUID (`not_found`).
- `409`: The venue (or a booked space) is in `block` availability mode and the event's days or hours fall on a closure or outside its opening hours. `error.code` is `conflict`; `error.details` carries `reason: venue_unavailable`, `violation` (`VENUE_CLOSED` or `OUTSIDE_HOURS`) and the `closures` / `outside_hours` hit (see GET /venues/{venueId}/conflicts). In `warn` mode the event is saved.
- `429`: Too many requests (`rate_limited`). `details.reason`: `per-ip`, `per-account-minute`, `per-account-day`, or `email_rate_limited` (email budget). Always carries `Retry-After`: wait that many seconds.

---

[API](https://skmtc.dev/joinways/apis/joinways-public-api.md) · [All operations](https://skmtc.dev/joinways/apis/joinways-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/joinways/apis/joinways-public-api/revisions/39e84309953e?raw)
