Create or update a contact
Creates a new contact or updates an existing one.
If a contact with the given email or userId already exists, it will be updated.
Otherwise, a new contact will be created.
At least one of email or userId must be provided for identification.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
email | string or null | One of email/userId | Contact email address. Send null with userId to remove the current email. |
userId | string or null | One of email/userId | External user ID. Send null with email to remove it. |
name | string or null | No | Contact display name. null resets it to the system fallback. |
profilePicture | string or null | No | Profile picture URL. null removes it. |
companies | array | No | Replacement company list. [] removes all memberships. |
customFields | object | No | Values merge by key. A key with null is removed. |
subscribedToChangelog | boolean | No | Whether subscribed to changelog |
locale | string or null | No | Contact locale/language. null removes it. |
phone | string or null | No | Contact phone number. null removes it. |
roles | array | No | Replacement role list. [] removes all roles. |
userHash | string | No | HMAC hash for identity verification |
createdAt | string | No | When the contact was created (ISO 8601) |
Orbit Field Update Semantics
- Omit a field to keep its current value.
- Send a non-null scalar value to add or replace that value.
- Send
nullforemail,userId,name,profilePicture,phone, orlocaleto clear or reset it. - A contact must keep at least one identifier. Removing
emailrequiresuserId. RemovinguserIdrequiresemail. - Send an array to replace the stored list. Send
[]to clearcompaniesorroles. customFieldsis merged by key. Omitted keys stay unchanged. A key withnullis removed.createdAtandsubscribedToChangelogdo not acceptnull. Usefalseto turn off changelog subscription.- Empty strings are not deletion values for typed contact fields.
Company Object
Each company in the companies array can have:
id(required) - External company ID from your systemname(required) - Company namemonthlySpend- Monthly spend/revenuecustomFields- Custom field valuesindustry- Industrywebsite- Company website URLplan- Current plan/subscriptioncompanySize- Number of employeescreatedAt- When the company was created
Response
Returns the created or updated contact object.
- 201 Created - A new contact was created
- 200 OK - An existing contact was updated
Example Request
{
"email": "john@example.com",
"name": "John Doe",
"userId": "usr_12345",
"companies": [
{
"id": "company_123",
"name": "Acme Inc",
"monthlySpend": 500,
"plan": "enterprise"
}
],
"customFields": {
"plan": "pro",
"signupSource": "website"
},
"subscribedToChangelog": true
}
Example: Remove an Email
{
"userId": "usr_12345",
"email": null
}
Example Response
{
"object": "contact",
"id": "676f0f6765bdaa7d7d760f88",
"email": "john@example.com",
"name": "John Doe",
"userId": "usr_12345",
"type": "customer",
"companies": [...],
"customFields": {...},
...
}
Version Availability
This endpoint is available in API version 2026-01-01.nova and newer. The Orbit field update rules, including null removal and empty-array replacement, require API version 2026-08-19.orbit or newer.
Body ParametersJSON
When the contact was created in your system (ISO 8601). This field cannot be null.
Contact email address. Omit to preserve it, or pass null with userId to remove the stored email.
Contact locale/language preference. Pass null to remove it.
Contact display name. Pass null to reset it to the system fallback.
Profile picture URL. Pass null to remove the stored profile picture.
Create or update a contact
curl https://do.featurebase.app/v2/contacts \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $FEATUREBASE_API_KEY" \
-d '{
"createdAt": "2024-01-15T10:30:00Z",
"customFields": {
"plan": "pro",
"signupSource": "website",
"accountType": "string"
},
"email": "john@example.com",
"locale": "en",
"name": "John Doe",
"phone": "+1234567890",
"profilePicture": "https://example.com/avatar.png",
"roles": [
"app",
"role_vip",
"role_beta",
"Internal User"
],
"subscribedToChangelog": true,
"userHash": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6",
"userId": "usr_12345"
}'{
"id": "676f0f6765bdaa7d7d760f88",
"name": "John Steezy",
"object": "contact",
"type": "customer",
"commentsCreated": 0,
"companies": [
{
"id": "507f1f77bcf86cd799439011",
"companyId": "comp_12345",
"companySize": 250,
"createdAt": "2025-01-01T12:00:00.000Z",
"industry": "Technology",
"lastActivity": "2025-01-15T00:00:00.000Z",
"linkedUsers": 15,
"monthlySpend": 5000,
"name": "Acme Inc",
"object": "company",
"plan": "enterprise",
"updatedAt": "2025-01-10T15:30:00.000Z",
"website": "https://acme.com",
"customFields": {
"location": "bar",
"priority": "bar"
}
}
],
"customFields": {
"foo": "bar"
},
"description": "",
"email": "john@example.com",
"lastActivity": "2025-01-03T21:42:30.181Z",
"locale": "en",
"manuallyOptedOutFromChangelog": false,
"organizationId": "5febde12dc56d60012d47db6",
"postsCreated": 0,
"profilePicture": "https://fb-usercontent.fra1.cdn.digitaloceanspaces.com/anon_23.png",
"roles": [
"string"
],
"subscribedToChangelog": true,
"userId": "676f0f673dbb299c8a4f3057",
"verified": true
}Returns Examples
{
"id": "676f0f6765bdaa7d7d760f88",
"name": "John Steezy",
"object": "contact",
"type": "customer",
"commentsCreated": 0,
"companies": [
{
"id": "507f1f77bcf86cd799439011",
"companyId": "comp_12345",
"companySize": 250,
"createdAt": "2025-01-01T12:00:00.000Z",
"industry": "Technology",
"lastActivity": "2025-01-15T00:00:00.000Z",
"linkedUsers": 15,
"monthlySpend": 5000,
"name": "Acme Inc",
"object": "company",
"plan": "enterprise",
"updatedAt": "2025-01-10T15:30:00.000Z",
"website": "https://acme.com",
"customFields": {
"location": "bar",
"priority": "bar"
}
}
],
"customFields": {
"foo": "bar"
},
"description": "",
"email": "john@example.com",
"lastActivity": "2025-01-03T21:42:30.181Z",
"locale": "en",
"manuallyOptedOutFromChangelog": false,
"organizationId": "5febde12dc56d60012d47db6",
"postsCreated": 0,
"profilePicture": "https://fb-usercontent.fra1.cdn.digitaloceanspaces.com/anon_23.png",
"roles": [
"string"
],
"subscribedToChangelog": true,
"userId": "676f0f673dbb299c8a4f3057",
"verified": true
}