Prospect contacts

Create, match, read, update and delete prospect contacts through the /prospects endpoints.

A prospect contact is a person you're prospecting who isn't yet a Contact at one of your Accounts. In the API they live at /prospects: every /prospects endpoint reads or writes prospect contacts. A prospect contact can be linked to a Prospect Company.

POST /prospects is built for capturing prospect contacts from forms and other tools: it matches on email, so sending the same person twice updates them instead of creating a duplicate.

The prospect contact object#

Field Type Notes
id string Opaque string ID.
first_name string Can be empty.
last_name string Can be empty.
email string or null Stored in lowercase.
phone string or null
job_title string or null
linkedin_url string or null
stage_id string Prospect stage. See Stage IDs.
owner_id string or null User ID of the person in Assigned To.
lead_company_id string or null The linked Prospect Company.
converted_at string or null When the prospect contact was converted. Read-only.
archived_at string or null When it was archived. Read-only.
created_at string ISO 8601 timestamp.
updated_at string ISO 8601 timestamp.
custom_fields object Your custom fields for prospect contacts, keyed by internal name. See Custom fields.

source_id (where the prospect contact came from) can be set on create and update but isn't returned in responses.

JSON
{
  "id": "e4b7c1d9-2f6a-4b3e-9c8d-5a1f7e2b4c63",
  "first_name": "Sam",
  "last_name": "Lee",
  "email": "sam.lee@fabrikam.example",
  "phone": "+1 646 555 0123",
  "job_title": "Operations Director",
  "linkedin_url": null,
  "stage_id": "rps_new",
  "owner_id": "5b8d1f3a-7e2c-4a9b-b6d4-1c3e5f7a9b20",
  "lead_company_id": "cm3k9x2p10004qz8f7h2d1a6b",
  "converted_at": null,
  "archived_at": null,
  "created_at": "2026-11-12T09:30:00.000Z",
  "updated_at": "2026-11-12T09:30:00.000Z",
  "custom_fields": {
    "budget_band": "50k-100k",
    "wants_demo": true
  }
}

Stage IDs#

stage_id Stage
rps_new New (the default for new prospect contacts)
rps_contacted Contacted
rps_qualified Qualified
rps_converted Converted
rps_disqualified Disqualified

List prospect contacts#

GET /prospects · Scope: prospects:read

Returns prospect contacts newest first, with their custom fields. Archived prospect contacts aren't listed.

Query parameters#

Parameter Type Required Notes
limit integer No 1 to 100. Default 20.
cursor string No meta.cursor from the previous page.

Example#

curl "https://crm.empiraa.app/api/v1/prospects?limit=100" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response 200#

An array of prospect contact objects in data. meta has cursor, hasMore and total (the number of prospect contacts in the workspace).

JSON
{
  "data": [ { "id": "e4b7c1d9-2f6a-4b3e-9c8d-5a1f7e2b4c63", "first_name": "Sam", "last_name": "Lee", "email": "sam.lee@fabrikam.example", "stage_id": "rps_new", "custom_fields": {} } ],
  "meta": { "cursor": null, "total": 1, "hasMore": false },
  "error": null
}

(Shortened: each item is a full prospect contact object.)


Create or update a prospect contact#

POST /prospects · Scope: prospects:write · Supports Idempotency-Key

If a prospect contact with the same email already exists in the workspace, it's updated with the fields you send and the response is 200 with "_action": "updated". Otherwise a new one is created and the response is 201 with "_action": "created".

Request body#

Field Type Required Notes
email string or null No Used to find an existing prospect contact. Trimmed and lowercased.
first_name string No
last_name string No
username string No Used as first_name when neither first_name nor last_name is sent. Handy for form tools that only send one name field.
phone string or null No
job_title string or null No
linkedin_url string or null No
stage_id string No See Stage IDs. New prospect contacts default to rps_new.
source_id string or null No An active prospect source.
owner_id string or null No Assigned To: an active user in the workspace.
lead_company_id string or null No A Prospect Company in the workspace. null unlinks.
notes string No Added as a new note on the prospect contact. Blank values are ignored, and existing notes are never removed.
custom_fields object No Custom field values by internal name.
any other field any No Treated as a custom field when its name matches a custom field's internal name.

All fields are optional, but send at least an email or a name.

Email from other fields. If email is missing or empty, the first other field whose name contains "email" and whose value contains "@" is used as the email. This lets form tools that name the field differently (such as work_email) still match.

When a prospect contact is matched, only the fields you send are changed. An empty first_name or last_name doesn't overwrite an existing name.

Example#

curl -X POST https://crm.empiraa.app/api/v1/prospects \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 2c7e4a90-6b1d-4f3e-8a5c-0d9b7e3f1a26" \
  -d '{
    "email": "sam.lee@fabrikam.example",
    "first_name": "Sam",
    "last_name": "Lee",
    "job_title": "Operations Director",
    "source_id": "rls_website",
    "notes": "Requested a demo from the pricing page.",
    "custom_fields": { "budget_band": "50k-100k" }
  }'

Response 201 or 200#

JSON
{
  "data": {
    "id": "e4b7c1d9-2f6a-4b3e-9c8d-5a1f7e2b4c63",
    "first_name": "Sam",
    "last_name": "Lee",
    "email": "sam.lee@fabrikam.example",
    "phone": null,
    "job_title": "Operations Director",
    "linkedin_url": null,
    "stage_id": "rps_new",
    "owner_id": null,
    "lead_company_id": null,
    "converted_at": null,
    "archived_at": null,
    "created_at": "2026-11-12T09:30:00.000Z",
    "updated_at": "2026-11-12T09:30:00.000Z",
    "custom_fields": { "budget_band": "50k-100k", "wants_demo": null },
    "_action": "created"
  },
  "meta": { "cursor": null },
  "error": null
}

Errors#

Status Code When
400 INVALID_REQUEST owner_id, source_id or lead_company_id isn't a string or null.
404 NOT_FOUND owner_id isn't an active user in the workspace ("User not found"), lead_company_id isn't a Prospect Company in the workspace, or source_id isn't an active prospect source.

Webhook events: prospect.created for a new prospect contact, prospect.updated for a matched one. Also starts any Autopilot workflows that run when a prospect contact is created, updated or changes stage.


Get a prospect contact#

GET /prospects/{id} · Scope: prospects:read

Path parameters#

Parameter Type Notes
id string Prospect contact ID.

Example#

curl https://crm.empiraa.app/api/v1/prospects/e4b7c1d9-2f6a-4b3e-9c8d-5a1f7e2b4c63 \
  -H "Authorization: Bearer YOUR_API_KEY"

Response 200#

The prospect contact object in data.

Errors#

Status Code When
404 NOT_FOUND No prospect contact with that ID in this workspace.

Update a prospect contact#

PATCH /prospects/{id} · Scope: prospects:write

Send only the fields you want to change.

Request body#

Field Type Notes
first_name string
last_name string
email string or null
phone string or null
job_title string or null
linkedin_url string or null
stage_id string See Stage IDs.
source_id string or null An active prospect source, or null to clear.
owner_id string or null Assigned To: an active user in the workspace, or null for nobody.
lead_company_id string or null A Prospect Company in the workspace, or null to unlink.
notes string Added as a new note. Blank values are ignored.
custom_fields object Custom field values by internal name. Other unrecognized top-level fields are also treated as custom fields.

Example#

curl -X PATCH https://crm.empiraa.app/api/v1/prospects/e4b7c1d9-2f6a-4b3e-9c8d-5a1f7e2b4c63 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"stage_id": "rps_qualified", "owner_id": "5b8d1f3a-7e2c-4a9b-b6d4-1c3e5f7a9b20"}'

Response 200#

The updated prospect contact object in data.

Errors#

Status Code When
400 INVALID_REQUEST owner_id, source_id or lead_company_id isn't a string or null.
404 NOT_FOUND The prospect contact, user, Prospect Company or prospect source doesn't exist in this workspace.

Webhook events: prospect.updated.


Delete a prospect contact#

DELETE /prospects/{id} · Scope: prospects:write

Moves the prospect contact to Recently deleted in Signal. It stays there for 30 days, during which it can be restored from Settings → Recently deleted. After 30 days it's removed for good.

Example#

curl -X DELETE https://crm.empiraa.app/api/v1/prospects/e4b7c1d9-2f6a-4b3e-9c8d-5a1f7e2b4c63 \
  -H "Authorization: Bearer YOUR_API_KEY"

Response 204#

No body.

Errors#

Status Code When
404 NOT_FOUND No prospect contact with that ID in this workspace.

Webhook events: prospect.deleted.