Create a lead
POST /api/leads — create a lead with a per-firm API key.
POST /api/leadsCreates a lead. With a per-firm API key (scope leads:write) the payload is validated, the lead
lands in the firm's first open pipeline stage, and the created lead is returned in full. A
lead.created webhook fires.
Request body
JSON. first_name, last_name, and source are required, plus at least one of email /
phone — a lead has to be reachable.
| Field | Type | Notes |
|---|---|---|
first_name | string | Required. |
last_name | string | Required. |
source | string | Required. Where the lead came from. |
email | string | Required if no phone. |
phone | string | Required if no email. |
assignee_id | string | null | Optional firm member (UUID) to assign. |
data | object | Optional firm-defined fields (case type, etc.). Only the fields your firm defines are stored. |
Idempotency
Send an Idempotency-Key header to make a create safe to retry — a repeat with the same key
returns the original lead instead of creating a second. Use a fresh unique value (e.g. a UUID) per
logical create.
Idempotency-Key: 9d2b7c1e-5a4b-4c3d-8e2f-1a2b3c4d5e6fExample
curl https://app.lawfficient.com/api/leads \
-H "Authorization: Bearer $LAWFFICIENT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 9d2b7c1e-5a4b-4c3d-8e2f-1a2b3c4d5e6f" \
-d '{
"first_name": "Ada",
"last_name": "Lovelace",
"email": "ada@example.com",
"source": "partner_referral",
"data": { "caseType": "Family" }
}'{
"id": "3f8c1e2a-1b2c-4d5e-8f90-abcdef012345",
"first_name": "Ada",
"last_name": "Lovelace",
"email": "ada@example.com",
"phone": "",
"source": "partner_referral",
"status": { "key": "new", "name": "New" },
"assignee_id": null,
"archived": false,
"created_at": "2026-06-24T10:00:00.000Z",
"last_activity_at": "2026-06-24T10:00:00.000Z",
"data": { "caseType": "Family" }
}Errors use the error envelope: 422 invalid_request (e.g. no contact method, or an
unknown data value), 403 insufficient_scope (the key lacks leads:write), 409 no_open_stage
(the firm has no open pipeline stage configured).
Inbound ingestion shares this path. Authenticate with a per-source ingestion key instead of
an API key and POST /api/leads is the inbound webhook: it takes the source's mapped fields,
dedupes on externalId, and returns { status, leadId }. See the
lead-ingestion spec.