> For the complete documentation index, see [llms.txt](https://docs.saleschat.pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.saleschat.pro/api-documentation/leads.md).

# Leads

This page provides API documentation for creating a lead in Saleschat.pro, including the required parameters and sample responses for successful lead creation.

## Create a new lead for the specified organization

> Creates a new lead with the provided details. The request must include either a valid bearer token or an x-org-api-key for authentication. The response will contain the details of the created lead.

```json
{"openapi":"3.0.1","info":{"title":"Saleschat API","version":"v0"},"servers":[{"url":"https://apis.saleschat.pro"}],"security":[{"bearer-key":[]},{}],"components":{"securitySchemes":{"bearer-key":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"CreateLeadV4Request":{"required":["attributes","crm_id","first_name","phone_number"],"type":"object","properties":{"crm_id":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"attributes":{"type":"object","additionalProperties":{"type":"object"}},"phone_number":{"type":"string"},"opt_in_date":{"type":"integer","format":"int64"}}},"CreateLeadV4Response":{"type":"object","properties":{"lead_id":{"type":"string"},"crm_id":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"attributes":{"type":"object","additionalProperties":{"type":"object"}},"phone_number":{"type":"string"},"opt_in_date":{"type":"integer","format":"int64"}}},"ErrorRespDto":{"type":"object","properties":{"error_code":{"type":"integer"},"error_message":{"type":"string"},"error_description":{"type":"string"},"payload":{"type":"object"}}}}},"paths":{"/v4/orgs/{orgId}/leads":{"post":{"tags":["Leads"],"summary":"Create a new lead for the specified organization","description":"Creates a new lead with the provided details. The request must include either a valid bearer token or an x-org-api-key for authentication. The response will contain the details of the created lead.","operationId":"createLead","parameters":[{"name":"orgId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLeadV4Request"}}},"required":true},"responses":{"200":{"description":"Successfully created lead","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLeadV4Response"}}}},"401":{"description":"Unauthorized - Authentication is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"403":{"description":"Forbidden - You don't have permission to access this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"404":{"description":"Org not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"422":{"description":"Invalid request payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"429":{"description":"Lead with this crm_id already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"500":{"description":"Failed to create lead","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}}}}}}}
```

## Assign a lead to a user

> Assigns the specified lead to a user. The request must include either a valid bearer token or an x-org-api-key for authentication. The request body should contain either the ID or the email of the user to assign the lead to.

```json
{"openapi":"3.0.1","info":{"title":"Saleschat API","version":"v0"},"servers":[{"url":"https://apis.saleschat.pro"}],"security":[{"bearer-key":[]},{}],"components":{"securitySchemes":{"bearer-key":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"AssignLeadRequest":{"type":"object","properties":{"user_id":{"type":"string"},"user_email":{"type":"string"}}},"ErrorRespDto":{"type":"object","properties":{"error_code":{"type":"integer"},"error_message":{"type":"string"},"error_description":{"type":"string"},"payload":{"type":"object"}}}}},"paths":{"/v4/orgs/{orgId}/leads/{leadId}/assign":{"put":{"tags":["Leads"],"summary":"Assign a lead to a user","description":"Assigns the specified lead to a user. The request must include either a valid bearer token or an x-org-api-key for authentication. The request body should contain either the ID or the email of the user to assign the lead to.","operationId":"assign","parameters":[{"name":"orgId","in":"path","required":true,"schema":{"type":"string"}},{"name":"leadId","in":"path","description":"Saleschat-generated lead ID (UUID) or the lead's CRM ID — both are resolved.","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignLeadRequest"}}},"required":true},"responses":{"202":{"description":"Successfully assigned lead"},"401":{"description":"Unauthorized - Authentication is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"403":{"description":"Forbidden - You don't have permission to access this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"404":{"description":"Org or lead not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"422":{"description":"Invalid request payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"500":{"description":"Failed to assign lead","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}}}}}}}
```

## Add an event for a lead

> Records a custom event for the specified lead. If the event type matches a known automation trigger it will be enqueued for processing. Uses distinct\_id for idempotency — duplicate requests with the same distinct\_id are silently accepted.

```json
{"openapi":"3.0.1","info":{"title":"Saleschat API","version":"v0"},"servers":[{"url":"https://apis.saleschat.pro"}],"security":[{"bearer-key":[]},{}],"components":{"securitySchemes":{"bearer-key":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"CreateLeadEventRequest":{"required":["event"],"type":"object","properties":{"distinct_id":{"maxLength":36,"minLength":0,"type":"string","description":"Optional idempotency key. Empty or whitespace-only values are treated as having no value at all (no deduplication is performed); otherwise surrounding whitespace is stripped."},"event":{"maxLength":128,"minLength":0,"type":"string"},"attributes":{"type":"object","additionalProperties":{"type":"object","description":"Reserved key sc_assigned_user_id: a Saleschat user ID that assigns the lead to that user on handover, applied when the triggered automation's SEND_TEMPLATE_MESSAGE action has assignment override option set on it."},"description":"Reserved key sc_assigned_user_id: a Saleschat user ID that assigns the lead to that user on handover, applied when the triggered automation's SEND_TEMPLATE_MESSAGE action has assignment override option set on it."}}},"ErrorRespDto":{"type":"object","properties":{"error_code":{"type":"integer"},"error_message":{"type":"string"},"error_description":{"type":"string"},"payload":{"type":"object"}}}}},"paths":{"/v4/orgs/{orgId}/leads/{leadId}/events":{"put":{"tags":["Leads"],"summary":"Add an event for a lead","description":"Records a custom event for the specified lead. If the event type matches a known automation trigger it will be enqueued for processing. Uses distinct_id for idempotency — duplicate requests with the same distinct_id are silently accepted.","operationId":"createLeadEvent","parameters":[{"name":"orgId","in":"path","required":true,"schema":{"type":"string"}},{"name":"leadId","in":"path","description":"Saleschat-generated lead ID (UUID) or the lead's CRM ID — both are resolved.","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLeadEventRequest"}}},"required":true},"responses":{"202":{"description":"Event accepted"},"401":{"description":"Unauthorized - Authentication is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"403":{"description":"Forbidden - You don't have permission to access this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"404":{"description":"Org or lead not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"422":{"description":"Invalid request payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"500":{"description":"Failed to process event","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}}}}}}}
```

## Look up a lead by CRM ID

> Translates a CRM ID into the Saleschat lead ID, returning the lead\_id/crm\_id pair. Responds 404 when no live lead or contact exists for the CRM ID, including when the matched contact has been expired. Note: a matched legacy contact is promoted to a lead on first access, so this endpoint is not side-effect-free and must not be cached.

```json
{"openapi":"3.0.1","info":{"title":"Saleschat API","version":"v0"},"servers":[{"url":"https://apis.saleschat.pro"}],"security":[{"bearer-key":[]},{}],"components":{"securitySchemes":{"bearer-key":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"LeadCrmLookupResponse":{"type":"object","properties":{"lead_id":{"type":"string"},"crm_id":{"type":"string"}}},"ErrorRespDto":{"type":"object","properties":{"error_code":{"type":"integer"},"error_message":{"type":"string"},"error_description":{"type":"string"},"payload":{"type":"object"}}}}},"paths":{"/v4/orgs/{orgId}/leads/lookup":{"get":{"tags":["Leads"],"summary":"Look up a lead by CRM ID","description":"Translates a CRM ID into the Saleschat lead ID, returning the lead_id/crm_id pair. Responds 404 when no live lead or contact exists for the CRM ID, including when the matched contact has been expired. Note: a matched legacy contact is promoted to a lead on first access, so this endpoint is not side-effect-free and must not be cached.","operationId":"lookupLeadByCrmId","parameters":[{"name":"orgId","in":"path","required":true,"schema":{"type":"string"}},{"name":"crm_id","in":"query","description":"The lead's CRM ID. A Saleschat lead ID (UUID) also resolves. Percent-encode reserved characters — in particular a leading '+' on an E.164 phone number should be sent as %2B (a raw '+' decodes to a space in a query string, though that common case is recovered server-side).","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Lead found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadCrmLookupResponse"}}}},"401":{"description":"Unauthorized - Authentication is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"403":{"description":"Forbidden - You don't have permission to access this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"404":{"description":"Org not found, or no live lead for crm_id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"422":{"description":"Missing or invalid crm_id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"500":{"description":"Failed to look up lead","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}}}}}}}
```

## Lead lifecycle

Activate, deactivate, or expire a lead by hand. Lifecycle rules usually decide which lead is active; use these endpoints for exceptions. See [Lead Lifecycle](/principles/lead-lifecycle.md).

## Activate a lead

> Activates the lead's chatroom. With force\_deactivate=true, every other lead on the same phone number is deactivated first, and this lead is activated even if it means taking over the number; if this lead has no chatroom the related leads are still deactivated. With force\_deactivate=false only this lead is activated and a conflicting active lead on the number yields 422 (no sweep). Async (202).

```json
{"openapi":"3.0.1","info":{"title":"Saleschat API","version":"v0"},"servers":[{"url":"https://apis.saleschat.pro"}],"security":[{"bearer-key":[]},{}],"components":{"securitySchemes":{"bearer-key":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"ErrorRespDto":{"type":"object","properties":{"error_code":{"type":"integer"},"error_message":{"type":"string"},"error_description":{"type":"string"},"payload":{"type":"object"}}}}},"paths":{"/v4/orgs/{orgId}/leads/{leadId}/activate":{"put":{"tags":["Leads"],"summary":"Activate a lead","description":"Activates the lead's chatroom. With force_deactivate=true, every other lead on the same phone number is deactivated first, and this lead is activated even if it means taking over the number; if this lead has no chatroom the related leads are still deactivated. With force_deactivate=false only this lead is activated and a conflicting active lead on the number yields 422 (no sweep). Async (202).","operationId":"activate","parameters":[{"name":"orgId","in":"path","required":true,"schema":{"type":"string"}},{"name":"leadId","in":"path","description":"Saleschat-generated lead ID (UUID) or the lead's CRM ID — both are resolved.","required":true,"schema":{"type":"string"}},{"name":"force_deactivate","in":"query","required":false,"schema":{"type":"boolean","default":false}}],"responses":{"202":{"description":"Activation accepted"},"401":{"description":"Unauthorized - Authentication is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"403":{"description":"Forbidden - You don't have permission to access this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"404":{"description":"Org or lead not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"422":{"description":"A conflicting active lead exists on the phone number (force_deactivate=false)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"500":{"description":"Failed to activate lead","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}}}}}}}
```

## Deactivate a lead

> Deactivates the lead's chatroom. With include\_related=true every other lead on the same phone number is deactivated too, leaving nothing active on that number. Idempotent — an already-inactive lead is accepted and its stored status re-synced. A lead that is expired, was never given a WhatsApp channel, or has no chatroom reports self\_deactivated=false while the related sweep still runs. Async (202): the response counts deactivations that were initiated, and the WABA bridge completes them shortly after. Note this does not block the number — the next inbound message creates a new chatroom.

```json
{"openapi":"3.0.1","info":{"title":"Saleschat API","version":"v0"},"servers":[{"url":"https://apis.saleschat.pro"}],"security":[{"bearer-key":[]},{}],"components":{"securitySchemes":{"bearer-key":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"DeactivateLeadResponse":{"type":"object","properties":{"self_deactivated":{"type":"boolean"},"related_found":{"type":"integer","format":"int32"},"deactivated":{"type":"integer","format":"int32"},"failed":{"type":"integer","format":"int32"}}},"ErrorRespDto":{"type":"object","properties":{"error_code":{"type":"integer"},"error_message":{"type":"string"},"error_description":{"type":"string"},"payload":{"type":"object"}}}}},"paths":{"/v4/orgs/{orgId}/leads/{leadId}/deactivate":{"put":{"tags":["Leads"],"summary":"Deactivate a lead","description":"Deactivates the lead's chatroom. With include_related=true every other lead on the same phone number is deactivated too, leaving nothing active on that number. Idempotent — an already-inactive lead is accepted and its stored status re-synced. A lead that is expired, was never given a WhatsApp channel, or has no chatroom reports self_deactivated=false while the related sweep still runs. Async (202): the response counts deactivations that were initiated, and the WABA bridge completes them shortly after. Note this does not block the number — the next inbound message creates a new chatroom.","operationId":"deactivate","parameters":[{"name":"orgId","in":"path","required":true,"schema":{"type":"string"}},{"name":"leadId","in":"path","description":"Saleschat-generated lead ID (UUID) or the lead's CRM ID — both are resolved.","required":true,"schema":{"type":"string"}},{"name":"include_related","in":"query","description":"Also deactivate every other lead sharing this lead's phone number. Default false deactivates only this lead.","required":false,"schema":{"type":"boolean","default":false}}],"responses":{"202":{"description":"Deactivation accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeactivateLeadResponse"}}}},"401":{"description":"Unauthorized - Authentication is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"403":{"description":"Forbidden - You don't have permission to access this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"404":{"description":"Org or lead not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"500":{"description":"Failed to deactivate lead","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}}}}}}}
```

## Expire a lead

> Expires the lead permanently, closing its chatroom. This is terminal — an expired lead cannot be reactivated. Accepts a dormant lead: expiry is a lifecycle transition, not an action on the record, so an already-inactive lead is still expirable. Idempotent — expiring an already-expired lead is accepted and does nothing. A lead with no WhatsApp pairing (mock or another channel only) has nothing to expire and is also accepted. Async (202): the WABA bridge closes the chatroom shortly after.

```json
{"openapi":"3.0.1","info":{"title":"Saleschat API","version":"v0"},"servers":[{"url":"https://apis.saleschat.pro"}],"security":[{"bearer-key":[]},{}],"components":{"securitySchemes":{"bearer-key":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"ErrorRespDto":{"type":"object","properties":{"error_code":{"type":"integer"},"error_message":{"type":"string"},"error_description":{"type":"string"},"payload":{"type":"object"}}}}},"paths":{"/v4/orgs/{orgId}/leads/{leadId}/expire":{"put":{"tags":["Leads"],"summary":"Expire a lead","description":"Expires the lead permanently, closing its chatroom. This is terminal — an expired lead cannot be reactivated. Accepts a dormant lead: expiry is a lifecycle transition, not an action on the record, so an already-inactive lead is still expirable. Idempotent — expiring an already-expired lead is accepted and does nothing. A lead with no WhatsApp pairing (mock or another channel only) has nothing to expire and is also accepted. Async (202): the WABA bridge closes the chatroom shortly after.","operationId":"expire","parameters":[{"name":"orgId","in":"path","required":true,"schema":{"type":"string"}},{"name":"leadId","in":"path","description":"Saleschat-generated lead ID (UUID) or the lead's CRM ID — both are resolved.","required":true,"schema":{"type":"string"}},{"name":"skip_threshold_check","in":"query","description":"Skip the org's expiry-threshold check. Default false applies the threshold, as the Contact-side expire does.","required":false,"schema":{"type":"boolean","default":false}}],"responses":{"202":{"description":"Expiry accepted"},"401":{"description":"Unauthorized - Authentication is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"403":{"description":"Forbidden - You don't have permission to access this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"404":{"description":"Org or lead not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}},"500":{"description":"Failed to expire lead","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorRespDto"}}}}}}}}}
```
