Contacts
A contact is a person in your CRM. All contact endpoints require the crm.contacts.read or crm.contacts.write scope.
Endpoints
/api/workspace/v1/contacts/api/workspace/v1/contacts/{id}/api/workspace/v1/contacts/api/workspace/v1/contacts/{id}The contact object
| Field | Type | Description |
|---|---|---|
| first_name | string | Given name |
| last_name | string | Family name |
| string | Primary email (normalised to lowercase) | |
| phone | string | Primary phone (E.164 recommended, we normalise) |
| job_title | string | Free-form job title |
| crm_company_id | integer | Link to an existing CRM company |
| lifecycle_stage | enum | One of lead | customer | opportunity | other (default: lead) |
| timezone | string | IANA zone e.g. Europe/Amsterdam |
| preferred_language | string(2) | ISO 639-1 code, e.g. nl or en |
| country | string(2) | ISO 3166-1 alpha-2, e.g. NL |
| notes | string | Free-form internal notes (max 5000 chars) |
| custom_fields | object | Merged with existing custom fields on update |
On create, at least one of email, phone, or (first_name + last_name) is required.
List contacts
Supports cursor pagination (limit, starting_after) and filters: email, phone, search, updated_after, created_after, archived.
curl "https://app.staffifyai.com/api/workspace/v1/contacts?limit=50&updated_after=2026-09-01T00:00:00Z" \ -H "Authorization: Bearer sfy_wsp_live_YOUR_KEY"
Retrieve a contact
curl "https://app.staffifyai.com/api/workspace/v1/contacts/1893" \ -H "Authorization: Bearer sfy_wsp_live_YOUR_KEY"
Create a contact
Idempotent when you pass an Idempotency-Key. Returns 201 with the new contact.
curl "https://app.staffifyai.com/api/workspace/v1/contacts" \
-X POST \
-H "Authorization: Bearer sfy_wsp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 1c1a-4a8f-9b2e" \
-d '{
"first_name": "Jan",
"last_name": "de Vries",
"email": "[email protected]",
"lifecycle_stage": "lead"
}'Update a contact
Only fields present in the body are updated. Pass is_archived: true to soft-delete (there is no hard DELETE endpoint).
curl "https://app.staffifyai.com/api/workspace/v1/contacts/1893" \
-X PATCH \
-H "Authorization: Bearer sfy_wsp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"job_title": "CTO",
"custom_fields": { "source": "website" }
}'Delete a contact
Soft-delete places the contact in a 30-day recycle bin. It disappears from default list queries and returns 404 on retrieve. Use ?deleted=true on list to see recycled contacts, or ?deleted=any for both live + deleted. Requires the crm.contacts.delete scope (separate from write).
curl -X DELETE "https://app.staffifyai.com/api/workspace/v1/contacts/1893" \ -H "Authorization: Bearer sfy_wsp_live_YOUR_KEY"
Restore a contact
Within the 30-day window you can restore a soft-deleted contact. After the window a nightly purge cron hard-deletes the row for good — restore returns 404 then.
curl -X POST "https://app.staffifyai.com/api/workspace/v1/contacts/1893/restore" \ -H "Authorization: Bearer sfy_wsp_live_YOUR_KEY"
Bulk-delete contacts
Soft-delete up to 500 contacts in one call. Response reports how many rows matched (a missing id is silently skipped, not an error). Idempotent — re-sending the same ids keeps the same deleted_at.
curl -X POST "https://app.staffifyai.com/api/workspace/v1/contacts/bulk-delete" \
-H "Authorization: Bearer sfy_wsp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "ids": [1893, 1894, 1895] }'