POST /api/v1/booking-links/{orgSlug}/{linkSlug}/leads
Saves the prospect's details for a booking link and returns a leadId. The
prospect is added to the school's directory — or found there — before any slot
is chosen. Each link shows the phone, the email or both, and shows the name or
not: every field the link shows is required, and a field it hides is ignored.
The response is the same whether the person was new or already known: it never
tells a caller whether an email or a phone number existed.
This endpoint is public: it takes no API key. It is rate-limited per client
address.
| Role in the organization | This endpoint |
|---|
OWNER | Allowed — no key is read |
ADMIN | Allowed — no key is read |
MEMBER | Allowed — no key is read |
| Requirement | Rule for this endpoint |
|---|
| Business role | None |
| Resource scope | The school and link named by the address |
| Participation | None |
| Resource state | Same as listing slots |
| Parameter | Type | Description |
|---|
orgSlug | string | The school's public address segment |
linkSlug | string | The booking link's address segment |
| Header | Required | Description |
|---|
Idempotency-Key | no | Stable key for this submission; a retry with the same key returns the same leadId |
X-Correlation-Id | no | Caller correlation id, returned or generated |
Request body
| Field | Type | Required | Nullable | Description |
|---|
name | string | conditional | no | Full name, at most 120 characters; required when the link shows the name |
email | string | conditional | no | Required when the link shows the email; must be able to receive email |
phoneCountry | string | no | no | Country code: +33, +32, +41, +352, +1, +212 or +262; default +33 |
phone | string | conditional | no | National number; required when the link shows the phone |
consent | boolean | yes | no | Must be true: the prospect agrees to be contacted |
answers | object | conditional | no | Answers to the link's published questions, keyed by question key; required answers must be present |
{"name": "Camille Martin", "phone": "6 12 34 56 78", "consent": true}
curl -X POST "$COHORTE_API_BASE_URL/api/v1/booking-links/mike-academy/appel-decouverte/leads" \
-H "Idempotency-Key: $(uuidgen)" \
-H 'Content-Type: application/json' \
-d '{"name":"Camille Martin","phoneCountry":"+33","phone":"612345678","consent":true}'
201 Created — the lead is saved; replayed is false.
200 OK — a retry with the same Idempotency-Key; replayed is true and nothing is written again.
400 Bad Request — invalid body: a field the link shows is missing, invalid email or phone, an email that cannot receive mail, missing consent, or an invalid answer; code is invalid_request and error names the fields.
404 Not Found — the address serves no booking page.
429 Too Many Requests — too many attempts from this address; code is rate_limited and Retry-After gives the seconds to wait.
| Field | Type | Nullable | Description |
|---|
success | boolean | no | true for a successful request |
replayed | boolean | no | true when the same Idempotency-Key was already used |
data.leadId | UUID | no | The saved lead, to pass to Book a call |
correlationId | UUID | no | Correlation id for support |
{
"success": true,
"replayed": false,
"data": {"leadId": "4e7a75bb-0000-4000-8000-000000000000"},
"correlationId": "f4775dad-0000-4000-8000-000000000000"
}
- A lead is not a booking. Book the slot with
Book a call for a prospect under your
key, or send the prospect to the booking page.
- A person already known by the same email — or, without email, the same phone
number — is reused and never modified.
Keep one idempotency key for one normalized intention. Current authorization is checked again on retry. A different payload or resource with that key, or an older key whose intention cannot be verified, returns 409 conflict without another mutation. Inspect the original outcome before creating a new command. Identical retries do not resend notifications.