# Users # Contacts ## List contacts **get** `/v2/contacts` Returns a list of contacts (customers and leads) in your organization using cursor-based pagination. ### Query Parameters - `limit` - Number of contacts to return (1-100, default 10) - `cursor` - Cursor from previous response for pagination - `contactType` - Filter by contact type: "customer" (default), "lead", or "all" ### Response Format Returns a list object with: - `object` - Always "list" - `data` - Array of contact objects - `nextCursor` - Cursor for the next page, or null if no more results ### Contact Object Each contact includes: - `id` - Unique contact identifier - `userId` - External user ID from SSO (if set) - `email` - Contact email address - `name` - Contact display name - `profilePicture` - Profile picture URL - `type` - Contact type ("customer" or "lead") - `companies` - Array of companies the contact belongs to - `customFields` - Custom field values - `postsCreated` - Number of posts created - `commentsCreated` - Number of comments created - `lastActivity` - Last activity timestamp ### Example ```json { "object": "list", "data": [ { "object": "contact", "id": "676f0f6765bdaa7d7d760f88", "email": "john@example.com", "name": "John Doe", "type": "customer", ... } ], "nextCursor": "eyJpZCI6IjUwN2YxZjc3YmNmODZjZDc5OTQzOTAxMSJ9" } ``` ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Query Parameters - `contactType: optional "customer" or "lead" or "all"` Filter contacts by type. Defaults to "customer". - `"customer"` - `"lead"` - `"all"` - `cursor: optional string` An opaque cursor for pagination. Use the nextCursor value from a previous response to fetch the next page of results. - `limit: optional number` A limit on the number of objects to be returned, between 1 and 100. ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `ContactList object { data, nextCursor, object }` - `data: array of Contact` Array of contacts - `nextCursor: string` Cursor for fetching the next page (cursor-based pagination) - `object: "list"` Object type identifier - `"list"` ### Example ```http curl https://do.featurebase.app/v2/contacts \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "data": [ { "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 } ], "nextCursor": "eyJpZCI6IjUwN2YxZjc3YmNmODZjZDc5OTQzOTAxMSJ9", "object": "list" } ``` ## Create or update a contact **post** `/v2/contacts` 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 | One of email/userId | Contact email address | | `userId` | string | One of email/userId | External user ID from your system | | `name` | string | No | Contact display name | | `profilePicture` | string | No | Profile picture URL | | `companies` | array | No | Companies the contact belongs to | | `customFields` | object | No | Custom field values | | `subscribedToChangelog` | boolean | No | Whether subscribed to changelog | | `locale` | string | No | Contact locale/language | | `phone` | string | No | Contact phone number | | `roles` | array | No | Role IDs to assign | | `userHash` | string | No | HMAC hash for identity verification | | `createdAt` | string | No | When the contact was created (ISO 8601) | ### Company Object Each company in the `companies` array can have: - `id` (required) - External company ID from your system - `name` (required) - Company name - `monthlySpend` - Monthly spend/revenue - `customFields` - Custom field values - `industry` - Industry - `website` - Company website URL - `plan` - Current plan/subscription - `companySize` - Number of employees - `createdAt` - 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 ```json { "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 Response ```json { "object": "contact", "id": "676f0f6765bdaa7d7d760f88", "email": "john@example.com", "name": "John Doe", "userId": "usr_12345", "type": "customer", "companies": [...], "customFields": {...}, ... } ``` ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Body Parameters - `companies: optional array of object { id, name, companyHash, 7 more }` Companies the contact belongs to - `id: string` External company ID from your system - `name: string` Company name - `companyHash: optional string` HMAC-SHA256 hash of company ID for identity verification - `companySize: optional number` Number of employees in the company - `createdAt: optional string` When the company was created (ISO 8601) - `customFields: optional object { industry, plan, priority }` Custom field values on the company. Values can be string, number, boolean, null, or array of primitives. - `industry: optional string` - `plan: optional string` - `priority: optional string` - `industry: optional string` Industry the company operates in - `monthlySpend: optional number` Monthly spend/revenue from this company - `plan: optional string` Current plan/subscription name - `website: optional string` Company website URL - `createdAt: optional string` When the contact was created in your system (ISO 8601) - `customFields: optional object { accountType, plan, signupSource }` Custom field values on the contact. Values can be string, number, boolean, null, or array of primitives. - `accountType: optional string` - `plan: optional string` - `signupSource: optional string` - `email: optional string` Contact email address. Used for identification if userId is not provided. - `locale: optional string` Contact locale/language preference - `name: optional string` Contact display name - `phone: optional string` Contact phone number - `profilePicture: optional string` Profile picture URL - `roles: optional array of string` Array of role IDs to assign to the contact - `subscribedToChangelog: optional boolean` Whether the contact is subscribed to changelog updates - `userHash: optional string` HMAC-SHA256 hash of userId or email for identity verification - `userId: optional string` External user ID from your system. Takes precedence over email for identification. ### Example ```http 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", "email": "john@example.com", "locale": "en", "name": "John Doe", "phone": "+1234567890", "profilePicture": "https://example.com/avatar.png", "roles": [ "role_vip", "role_beta" ], "subscribedToChangelog": true, "userHash": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6", "userId": "usr_12345" }' ``` #### Response ```json { "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 } ``` ## Get contact by ID **get** `/v2/contacts/{id}` Retrieves a single contact by their Featurebase ID. Returns both customers and leads. ### Path Parameters - `id` - The Featurebase contact ID (24-character ObjectId) ### Response Format Returns a single contact object with: - `object` - Always "contact" - `id` - Unique contact identifier - `userId` - External user ID from SSO (if set) - `email` - Contact email address - `name` - Contact display name - `profilePicture` - Profile picture URL - `type` - Contact type ("customer" or "lead") - `companies` - Array of companies the contact belongs to - `customFields` - Custom field values - `postsCreated` - Number of posts created - `commentsCreated` - Number of comments created - `lastActivity` - Last activity timestamp ### Example ```json { "object": "contact", "id": "676f0f6765bdaa7d7d760f88", "email": "john@example.com", "name": "John Doe", "type": "customer", ... } ``` ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Path Parameters - `id: string` Featurebase contact ID ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Example ```http curl https://do.featurebase.app/v2/contacts/$ID \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "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 } ``` ## Delete contact by ID **delete** `/v2/contacts/{id}` Permanently deletes a contact by their Featurebase ID. Supports deleting both customers and leads. ### Path Parameters - `id` - The Featurebase contact ID (24-character ObjectId) ### Deletion Behavior When a contact is deleted: - The contact record is permanently removed - Associated data cleanup is triggered asynchronously - Comments and posts created by the contact are handled according to retention policies ### Response Returns a deletion confirmation object: - `id` - The ID of the deleted contact - `object` - Always "contact" - `deleted` - Always `true` ### Example Response ```json { "id": "676f0f6765bdaa7d7d760f88", "object": "contact", "deleted": true } ``` ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Path Parameters - `id: string` Featurebase contact ID ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `DeletedContact object { id, deleted, object }` - `id: string` Unique identifier of the deleted contact - `deleted: true` Indicates the resource was deleted - `true` - `object: "contact"` Object type identifier - `"contact"` ### Example ```http curl https://do.featurebase.app/v2/contacts/$ID \ -X DELETE \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "id": "507f1f77bcf86cd799439011", "deleted": true, "object": "contact" } ``` ## Block a contact **post** `/v2/contacts/{id}/block` Blocks a contact by their Featurebase ID from the messenger/inbox. ### Path Parameters - `id` - The Featurebase internal ID of the contact (MongoDB ObjectId) ### Supported Contact Types This endpoint blocks both: - **Customers** - Users with registered accounts - **Leads** - Anonymous or unregistered visitors ### Blocking Behavior When a contact is blocked: - The contact cannot send new messages via messenger - Existing conversations are not deleted but no new messages can be added by the blocked user - The block can be removed by unblocking the contact ### Response Returns a block confirmation object: - `id` - The ID of the blocked contact - `object` - Always "contact" - `blocked` - Always `true` ### Example Response ```json { "id": "507f1f77bcf86cd799439011", "object": "contact", "blocked": true } ``` ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Path Parameters - `id: string` Featurebase contact ID ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `id: string` Unique identifier of the blocked contact - `blocked: true` Indicates the contact was blocked - `true` - `object: "contact"` Object type identifier - `"contact"` ### Example ```http curl https://do.featurebase.app/v2/contacts/$ID/block \ -X POST \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "id": "507f1f77bcf86cd799439011", "blocked": true, "object": "contact" } ``` ## Unblock a contact **post** `/v2/contacts/{id}/unblock` Unblocks a contact by their Featurebase ID from the messenger/inbox. ### Path Parameters - `id` - The Featurebase internal ID of the contact (MongoDB ObjectId) ### Supported Contact Types This endpoint unblocks both: - **Customers** - Users with registered accounts - **Leads** - Anonymous or unregistered visitors ### Unblocking Behavior When a contact is unblocked: - The contact can resume sending messages via messenger - Previously blocked conversations remain intact - The contact regains full messenger functionality ### Response Returns an unblock confirmation object: - `id` - The ID of the unblocked contact - `object` - Always "contact" - `unblocked` - Always `true` ### Example Response ```json { "id": "507f1f77bcf86cd799439011", "object": "contact", "unblocked": true } ``` ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Path Parameters - `id: string` Featurebase contact ID ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `id: string` Unique identifier of the unblocked contact - `object: "contact"` Object type identifier - `"contact"` - `unblocked: true` Indicates the contact was unblocked - `true` ### Example ```http curl https://do.featurebase.app/v2/contacts/$ID/unblock \ -X POST \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "id": "507f1f77bcf86cd799439011", "object": "contact", "unblocked": true } ``` ## Domain Types ### Contact - `Contact object { id, name, object, 16 more }` User who submitted the response - `id: string` Unique identifier - `name: string` Contact display name - `object: "contact"` Object type identifier - `"contact"` - `type: "customer" or "lead"` Type of contact - `"customer"` - `"lead"` - `commentsCreated: optional number` Number of comments created - `companies: optional array of Company` Companies the contact belongs to - `id: string` Featurebase internal ID - `companyId: string` External company ID from your system - `companySize: number` Company employee headcount - `createdAt: string` ISO date when company was created - `industry: string` Industry - `lastActivity: string` ISO date of last activity - `linkedUsers: number` Number of users linked to this company - `monthlySpend: number` Monthly spend - `name: string` Company name - `object: "company"` Object type identifier - `"company"` - `plan: string` Plan or tier name - `updatedAt: string` ISO date when company was last updated - `website: string` Company website URL - `customFields: optional map[unknown]` Custom field values - `customFields: optional map[unknown]` Custom field values on the contact - `description: optional string` Contact description/bio - `email: optional string` Contact email - `lastActivity: optional string` Last activity ISO timestamp - `locale: optional string` Contact locale - `manuallyOptedOutFromChangelog: optional boolean` Whether manually opted out from changelog - `organizationId: optional string` Organization ID the contact belongs to - `postsCreated: optional number` Number of posts created - `profilePicture: optional string` Profile picture URL - `roles: optional array of string` Contact roles - `subscribedToChangelog: optional boolean` Whether subscribed to changelog - `userId: optional string` External user ID from SSO - `verified: optional boolean` Whether email is verified ### Contact List - `ContactList object { data, nextCursor, object }` - `data: array of Contact` Array of contacts - `nextCursor: string` Cursor for fetching the next page (cursor-based pagination) - `object: "list"` Object type identifier - `"list"` ### Deleted Contact - `DeletedContact object { id, deleted, object }` - `id: string` Unique identifier of the deleted contact - `deleted: true` Indicates the resource was deleted - `true` - `object: "contact"` Object type identifier - `"contact"` ### Contact Create Or Update Response - `ContactCreateOrUpdateResponse = Contact` User who submitted the response ### Contact Retrieve Response - `ContactRetrieveResponse = Contact` User who submitted the response ### Contact Block Response - `ContactBlockResponse object { id, blocked, object }` - `id: string` Unique identifier of the blocked contact - `blocked: true` Indicates the contact was blocked - `true` - `object: "contact"` Object type identifier - `"contact"` ### Contact Unblock Response - `ContactUnblockResponse object { id, object, unblocked }` - `id: string` Unique identifier of the unblocked contact - `object: "contact"` Object type identifier - `"contact"` - `unblocked: true` Indicates the contact was unblocked - `true` # By User ID ## Get contact by external user ID **get** `/v2/contacts/by-user-id/{userId}` Retrieves a single contact by their external user ID (from your system via SSO). **Important:** This endpoint only returns customers (type: "customer"). Leads are not returned. ### Path Parameters - `userId` - The external user ID from your system (matched via SSO integration) ### Response Format Returns a single contact object with: - `object` - Always "contact" - `id` - Unique contact identifier - `userId` - External user ID from SSO - `email` - Contact email address - `name` - Contact display name - `profilePicture` - Profile picture URL - `type` - Always "customer" for this endpoint - `companies` - Array of companies the contact belongs to - `customFields` - Custom field values - `postsCreated` - Number of posts created - `commentsCreated` - Number of comments created - `lastActivity` - Last activity timestamp ### Example ```json { "object": "contact", "id": "676f0f6765bdaa7d7d760f88", "userId": "usr_12345", "email": "john@example.com", "name": "John Doe", "type": "customer", ... } ``` ### Use Case This endpoint is useful when you need to look up a contact using your own system's user identifier, such as when displaying Featurebase data alongside your user's information in your own application. ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Path Parameters - `userId: string` External user ID from your system ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Example ```http curl https://do.featurebase.app/v2/contacts/by-user-id/$USER_ID \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "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 } ``` ## Delete contact by external user ID **delete** `/v2/contacts/by-user-id/{userId}` Permanently deletes a contact by their external user ID. **Important:** This endpoint only deletes customers (type: "customer"). Leads cannot be deleted using this endpoint. ### Path Parameters - `userId` - The external user ID from your system ### Deletion Behavior When a contact is deleted: - The contact record is permanently removed - Associated data cleanup is triggered asynchronously - Comments and posts created by the contact are handled according to retention policies ### Response Returns a deletion confirmation object: - `id` - The ID of the deleted contact - `object` - Always "contact" - `deleted` - Always `true` ### Example Response ```json { "id": "676f0f6765bdaa7d7d760f88", "object": "contact", "deleted": true } ``` ### Use Case Use this endpoint when you need to delete a contact using your own system's user identifier, such as when a user deletes their account in your application. ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Path Parameters - `userId: string` External user ID from your system ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `DeletedContact object { id, deleted, object }` - `id: string` Unique identifier of the deleted contact - `deleted: true` Indicates the resource was deleted - `true` - `object: "contact"` Object type identifier - `"contact"` ### Example ```http curl https://do.featurebase.app/v2/contacts/by-user-id/$USER_ID \ -X DELETE \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "id": "507f1f77bcf86cd799439011", "deleted": true, "object": "contact" } ``` ## Domain Types ### By User ID Retrieve Response - `ByUserIDRetrieveResponse = Contact` User who submitted the response # Email Preferences ## Get contact email preferences by external user ID **get** `/v2/contacts/by-user-id/{userId}/email-preferences` Retrieves the email preference state for a customer contact by their external user ID. This endpoint only supports customer contacts and mirrors the existing `by-user-id` lookup pattern used across the contact API. ### Path Parameters - `userId` - The external user ID from your system ### Example Response ```json { "object": "contact_email_preferences", "contactId": "676f0f6765bdaa7d7d760f88", "userId": "usr_12345", "email": "john@example.com", "preferences": { "all": { "status": "unsubscribed", "effectiveStatus": "unsubscribed" }, "postUpdates": { "status": "subscribed", "effectiveStatus": "unsubscribed" }, "postComments": { "status": "subscribed", "effectiveStatus": "unsubscribed" }, "commentReplies": { "status": "subscribed", "effectiveStatus": "unsubscribed" }, "changelog": { "status": "subscribed", "effectiveStatus": "unsubscribed" } } } ``` ### Path Parameters - `userId: string` External user ID from your system ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `PreferencesOutput object { contactId, object, preferences, 2 more }` - `contactId: string` Featurebase contact ID - `object: "contact_email_preferences"` Object type identifier - `"contact_email_preferences"` - `preferences: object { all, changelog, commentReplies, 2 more }` Email preference state for this contact, including both stored status and final effective status. - `all: PreferenceState` Global email preference state for all email notifications. - `effectiveStatus: "subscribed" or "unsubscribed"` Final effective status after applying global preference overrides - `"subscribed"` - `"unsubscribed"` - `status: "subscribed" or "unsubscribed"` Stored preference status for this category - `"subscribed"` - `"unsubscribed"` - `changelog: PreferenceState` Global email preference state for all email notifications. - `commentReplies: PreferenceState` Global email preference state for all email notifications. - `postComments: PreferenceState` Global email preference state for all email notifications. - `postUpdates: PreferenceState` Global email preference state for all email notifications. - `email: optional string` Contact email address, if available - `userId: optional string` External user ID from your system, if available ### Example ```http curl https://do.featurebase.app/v2/contacts/by-user-id/$USER_ID/email-preferences \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "contactId": "676f0f6765bdaa7d7d760f88", "object": "contact_email_preferences", "preferences": { "all": { "effectiveStatus": "unsubscribed", "status": "unsubscribed" }, "changelog": { "effectiveStatus": "unsubscribed", "status": "subscribed" }, "commentReplies": { "effectiveStatus": "unsubscribed", "status": "subscribed" }, "postComments": { "effectiveStatus": "unsubscribed", "status": "subscribed" }, "postUpdates": { "effectiveStatus": "unsubscribed", "status": "subscribed" } }, "email": "john@example.com", "userId": "usr_12345" } ``` ## Update contact email preferences by external user ID **patch** `/v2/contacts/by-user-id/{userId}/email-preferences` Updates one or more email preferences for a customer contact by their external user ID. This endpoint only supports customer contacts and mirrors the existing `by-user-id` lookup pattern used across the contact API. ### Path Parameters - `userId` - The external user ID from your system ### Request Body - `preferences` - A partial map of preference keys to their desired stored status. Only the preferences included in the request are updated; any preferences omitted are left unchanged. At least one preference must be provided. See `PATCH /v2/contacts/{id}/email-preferences` for the full list of supported preference keys and per-key values, the `all` delivery-gate semantics, and details on combining `all` with per-category keys in a single request. ### Example Request (partial update) ```json { "preferences": { "postUpdates": "unsubscribed", "changelog": "subscribed" } } ``` ### Example Request (full preference-center submit) ```json { "preferences": { "all": "subscribed", "postUpdates": "subscribed", "postComments": "unsubscribed", "commentReplies": "unsubscribed", "changelog": "unsubscribed" } } ``` ### Example Response ```json { "object": "contact_email_preferences", "contactId": "676f0f6765bdaa7d7d760f88", "userId": "usr_12345", "email": "john@example.com", "preferences": { "all": { "status": "subscribed", "effectiveStatus": "subscribed" }, "postUpdates": { "status": "subscribed", "effectiveStatus": "subscribed" }, "postComments": { "status": "unsubscribed", "effectiveStatus": "unsubscribed" }, "commentReplies": { "status": "unsubscribed", "effectiveStatus": "unsubscribed" }, "changelog": { "status": "unsubscribed", "effectiveStatus": "unsubscribed" } } } ``` ### Path Parameters - `userId: string` External user ID from your system ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Body Parameters - `preferences: object { all, changelog, commentReplies, 2 more }` - `all: optional "subscribed" or "unsubscribed"` Master delivery gate. When `unsubscribed`, the contact receives no emails regardless of the per-category values. Per-category values are preserved. - `"subscribed"` - `"unsubscribed"` - `changelog: optional "subscribed" or "unsubscribed"` Stored status for new changelog release notifications. - `"subscribed"` - `"unsubscribed"` - `commentReplies: optional "subscribed" or "unsubscribed"` Stored status for replies to the contact’s own comments. - `"subscribed"` - `"unsubscribed"` - `postComments: optional "subscribed" or "unsubscribed"` Stored status for new comments on posts the contact follows. - `"subscribed"` - `"unsubscribed"` - `postUpdates: optional "subscribed" or "unsubscribed"` Stored status for post status changes and updates on posts the contact follows. - `"subscribed"` - `"unsubscribed"` ### Returns - `PreferencesOutput object { contactId, object, preferences, 2 more }` - `contactId: string` Featurebase contact ID - `object: "contact_email_preferences"` Object type identifier - `"contact_email_preferences"` - `preferences: object { all, changelog, commentReplies, 2 more }` Email preference state for this contact, including both stored status and final effective status. - `all: PreferenceState` Global email preference state for all email notifications. - `effectiveStatus: "subscribed" or "unsubscribed"` Final effective status after applying global preference overrides - `"subscribed"` - `"unsubscribed"` - `status: "subscribed" or "unsubscribed"` Stored preference status for this category - `"subscribed"` - `"unsubscribed"` - `changelog: PreferenceState` Global email preference state for all email notifications. - `commentReplies: PreferenceState` Global email preference state for all email notifications. - `postComments: PreferenceState` Global email preference state for all email notifications. - `postUpdates: PreferenceState` Global email preference state for all email notifications. - `email: optional string` Contact email address, if available - `userId: optional string` External user ID from your system, if available ### Example ```http curl https://do.featurebase.app/v2/contacts/by-user-id/$USER_ID/email-preferences \ -X PATCH \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" \ -d '{ "preferences": {} }' ``` #### Response ```json { "contactId": "676f0f6765bdaa7d7d760f88", "object": "contact_email_preferences", "preferences": { "all": { "effectiveStatus": "unsubscribed", "status": "unsubscribed" }, "changelog": { "effectiveStatus": "unsubscribed", "status": "subscribed" }, "commentReplies": { "effectiveStatus": "unsubscribed", "status": "subscribed" }, "postComments": { "effectiveStatus": "unsubscribed", "status": "subscribed" }, "postUpdates": { "effectiveStatus": "unsubscribed", "status": "subscribed" } }, "email": "john@example.com", "userId": "usr_12345" } ``` # Email Preferences ## Get contact email preferences by ID **get** `/v2/contacts/{id}/email-preferences` Retrieves the email preference state for a customer contact by their Featurebase ID. **Important:** This endpoint only supports customer contacts. Leads do not have a customer email preference surface in the public API. ### Path Parameters - `id` - The Featurebase contact ID (24-character ObjectId) ### Response Format Returns a contact email preferences object with: - `object` - Always "contact_email_preferences" - `contactId` - Featurebase contact ID - `userId` - External user ID, if available - `email` - Contact email address, if available - `preferences` - Current email preference state ### Preference Semantics Each preference includes: - `status` - The stored preference state for that category - `effectiveStatus` - The final state after applying the global `all` preference override ### Example Response ```json { "object": "contact_email_preferences", "contactId": "676f0f6765bdaa7d7d760f88", "userId": "usr_12345", "email": "john@example.com", "preferences": { "all": { "status": "unsubscribed", "effectiveStatus": "unsubscribed" }, "postUpdates": { "status": "subscribed", "effectiveStatus": "unsubscribed" }, "postComments": { "status": "subscribed", "effectiveStatus": "unsubscribed" }, "commentReplies": { "status": "subscribed", "effectiveStatus": "unsubscribed" }, "changelog": { "status": "subscribed", "effectiveStatus": "unsubscribed" } } } ``` ### Path Parameters - `id: string` Featurebase contact ID ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `PreferencesOutput object { contactId, object, preferences, 2 more }` - `contactId: string` Featurebase contact ID - `object: "contact_email_preferences"` Object type identifier - `"contact_email_preferences"` - `preferences: object { all, changelog, commentReplies, 2 more }` Email preference state for this contact, including both stored status and final effective status. - `all: PreferenceState` Global email preference state for all email notifications. - `effectiveStatus: "subscribed" or "unsubscribed"` Final effective status after applying global preference overrides - `"subscribed"` - `"unsubscribed"` - `status: "subscribed" or "unsubscribed"` Stored preference status for this category - `"subscribed"` - `"unsubscribed"` - `changelog: PreferenceState` Global email preference state for all email notifications. - `commentReplies: PreferenceState` Global email preference state for all email notifications. - `postComments: PreferenceState` Global email preference state for all email notifications. - `postUpdates: PreferenceState` Global email preference state for all email notifications. - `email: optional string` Contact email address, if available - `userId: optional string` External user ID from your system, if available ### Example ```http curl https://do.featurebase.app/v2/contacts/$ID/email-preferences \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "contactId": "676f0f6765bdaa7d7d760f88", "object": "contact_email_preferences", "preferences": { "all": { "effectiveStatus": "unsubscribed", "status": "unsubscribed" }, "changelog": { "effectiveStatus": "unsubscribed", "status": "subscribed" }, "commentReplies": { "effectiveStatus": "unsubscribed", "status": "subscribed" }, "postComments": { "effectiveStatus": "unsubscribed", "status": "subscribed" }, "postUpdates": { "effectiveStatus": "unsubscribed", "status": "subscribed" } }, "email": "john@example.com", "userId": "usr_12345" } ``` ## Update contact email preferences by ID **patch** `/v2/contacts/{id}/email-preferences` Updates one or more email preferences for a customer contact by their Featurebase ID. **Important:** This endpoint only supports customer contacts. Leads do not have a customer email preference surface in the public API. ### Path Parameters - `id` - The Featurebase contact ID (24-character ObjectId) ### Request Body - `preferences` - A partial map of preference keys to their desired stored status. Only the preferences included in the request are updated; any preferences omitted are left unchanged. At least one preference must be provided. ### Supported Preference Keys - `all` - Master delivery gate. When `unsubscribed`, the contact will not receive any emails regardless of the per-category values. Per-category values are still persisted, so flipping `all` back to `subscribed` restores the contact's previous granular preferences. - `postUpdates` - Status changes and updates on posts the contact interacts with. - `postComments` - New comments on posts the contact follows. - `commentReplies` - Replies to the contact's own comments. - `changelog` - New changelog releases. ### Per-key Values - `subscribed` - The contact will receive this email category (subject to the `all` gate). - `unsubscribed` - The contact will not receive this email category. ### Combining `all` with per-category keys You can send `all` together with any per-category keys in the same request. The full map is applied atomically as the contact's new stored state — there is no implicit reset of the other keys. This makes the endpoint safe for preference-center UIs that POST the entire form state on submit. The computed per-category result (after applying the `all` gate) is surfaced as `effectiveStatus` in the response, while `status` reflects the value actually stored for that key. ### Example Request (partial update) ```json { "preferences": { "postUpdates": "unsubscribed", "changelog": "subscribed" } } ``` ### Example Request (full preference-center submit) ```json { "preferences": { "all": "subscribed", "postUpdates": "subscribed", "postComments": "unsubscribed", "commentReplies": "unsubscribed", "changelog": "unsubscribed" } } ``` ### Example Response ```json { "object": "contact_email_preferences", "contactId": "676f0f6765bdaa7d7d760f88", "userId": "usr_12345", "email": "john@example.com", "preferences": { "all": { "status": "subscribed", "effectiveStatus": "subscribed" }, "postUpdates": { "status": "subscribed", "effectiveStatus": "subscribed" }, "postComments": { "status": "unsubscribed", "effectiveStatus": "unsubscribed" }, "commentReplies": { "status": "unsubscribed", "effectiveStatus": "unsubscribed" }, "changelog": { "status": "unsubscribed", "effectiveStatus": "unsubscribed" } } } ``` ### Path Parameters - `id: string` Featurebase contact ID ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Body Parameters - `preferences: object { all, changelog, commentReplies, 2 more }` - `all: optional "subscribed" or "unsubscribed"` Master delivery gate. When `unsubscribed`, the contact receives no emails regardless of the per-category values. Per-category values are preserved. - `"subscribed"` - `"unsubscribed"` - `changelog: optional "subscribed" or "unsubscribed"` Stored status for new changelog release notifications. - `"subscribed"` - `"unsubscribed"` - `commentReplies: optional "subscribed" or "unsubscribed"` Stored status for replies to the contact’s own comments. - `"subscribed"` - `"unsubscribed"` - `postComments: optional "subscribed" or "unsubscribed"` Stored status for new comments on posts the contact follows. - `"subscribed"` - `"unsubscribed"` - `postUpdates: optional "subscribed" or "unsubscribed"` Stored status for post status changes and updates on posts the contact follows. - `"subscribed"` - `"unsubscribed"` ### Returns - `PreferencesOutput object { contactId, object, preferences, 2 more }` - `contactId: string` Featurebase contact ID - `object: "contact_email_preferences"` Object type identifier - `"contact_email_preferences"` - `preferences: object { all, changelog, commentReplies, 2 more }` Email preference state for this contact, including both stored status and final effective status. - `all: PreferenceState` Global email preference state for all email notifications. - `effectiveStatus: "subscribed" or "unsubscribed"` Final effective status after applying global preference overrides - `"subscribed"` - `"unsubscribed"` - `status: "subscribed" or "unsubscribed"` Stored preference status for this category - `"subscribed"` - `"unsubscribed"` - `changelog: PreferenceState` Global email preference state for all email notifications. - `commentReplies: PreferenceState` Global email preference state for all email notifications. - `postComments: PreferenceState` Global email preference state for all email notifications. - `postUpdates: PreferenceState` Global email preference state for all email notifications. - `email: optional string` Contact email address, if available - `userId: optional string` External user ID from your system, if available ### Example ```http curl https://do.featurebase.app/v2/contacts/$ID/email-preferences \ -X PATCH \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" \ -d '{ "preferences": {} }' ``` #### Response ```json { "contactId": "676f0f6765bdaa7d7d760f88", "object": "contact_email_preferences", "preferences": { "all": { "effectiveStatus": "unsubscribed", "status": "unsubscribed" }, "changelog": { "effectiveStatus": "unsubscribed", "status": "subscribed" }, "commentReplies": { "effectiveStatus": "unsubscribed", "status": "subscribed" }, "postComments": { "effectiveStatus": "unsubscribed", "status": "subscribed" }, "postUpdates": { "effectiveStatus": "unsubscribed", "status": "subscribed" } }, "email": "john@example.com", "userId": "usr_12345" } ``` ## Domain Types ### Preference State - `PreferenceState object { effectiveStatus, status }` Global email preference state for all email notifications. - `effectiveStatus: "subscribed" or "unsubscribed"` Final effective status after applying global preference overrides - `"subscribed"` - `"unsubscribed"` - `status: "subscribed" or "unsubscribed"` Stored preference status for this category - `"subscribed"` - `"unsubscribed"` ### Preferences Output - `PreferencesOutput object { contactId, object, preferences, 2 more }` - `contactId: string` Featurebase contact ID - `object: "contact_email_preferences"` Object type identifier - `"contact_email_preferences"` - `preferences: object { all, changelog, commentReplies, 2 more }` Email preference state for this contact, including both stored status and final effective status. - `all: PreferenceState` Global email preference state for all email notifications. - `effectiveStatus: "subscribed" or "unsubscribed"` Final effective status after applying global preference overrides - `"subscribed"` - `"unsubscribed"` - `status: "subscribed" or "unsubscribed"` Stored preference status for this category - `"subscribed"` - `"unsubscribed"` - `changelog: PreferenceState` Global email preference state for all email notifications. - `commentReplies: PreferenceState` Global email preference state for all email notifications. - `postComments: PreferenceState` Global email preference state for all email notifications. - `postUpdates: PreferenceState` Global email preference state for all email notifications. - `email: optional string` Contact email address, if available - `userId: optional string` External user ID from your system, if available ### Update Preference Body - `UpdatePreferenceBody object { preferences }` - `preferences: object { all, changelog, commentReplies, 2 more }` - `all: optional "subscribed" or "unsubscribed"` Master delivery gate. When `unsubscribed`, the contact receives no emails regardless of the per-category values. Per-category values are preserved. - `"subscribed"` - `"unsubscribed"` - `changelog: optional "subscribed" or "unsubscribed"` Stored status for new changelog release notifications. - `"subscribed"` - `"unsubscribed"` - `commentReplies: optional "subscribed" or "unsubscribed"` Stored status for replies to the contact’s own comments. - `"subscribed"` - `"unsubscribed"` - `postComments: optional "subscribed" or "unsubscribed"` Stored status for new comments on posts the contact follows. - `"subscribed"` - `"unsubscribed"` - `postUpdates: optional "subscribed" or "unsubscribed"` Stored status for post status changes and updates on posts the contact follows. - `"subscribed"` - `"unsubscribed"` # Companies ## List all companies **get** `/v2/companies` Returns all companies in your organization with cursor-based pagination. ### Query Parameters - `limit` - Number of companies to return (1-100, default: 10) - `cursor` - Opaque cursor from a previous response for pagination ### Response Structure The response includes: - `object` - Always "list" - `data` - Array of company objects - `nextCursor` - Cursor for the next page (null if no more results) ### Company Object Each company includes: - `id` - Featurebase internal ID (MongoDB ObjectId) - `companyId` - External company ID from your system - `name` - Company name - `monthlySpend` - Monthly spend/revenue - `industry` - Industry - `website` - Company website URL - `plan` - Plan/tier name - `linkedUsers` - Number of users linked to this company - `companySize` - Employee headcount - `lastActivity` - Last activity timestamp - `customFields` - Custom field values - `createdAt` - Creation timestamp - `updatedAt` - Last update timestamp ### Example Response ```json { "object": "list", "data": [ { "object": "company", "id": "507f1f77bcf86cd799439011", "companyId": "comp_12345", "name": "Acme Inc", "monthlySpend": 5000, "industry": "Technology", "website": "https://acme.com", "plan": "enterprise", "linkedUsers": 15, "companySize": 250, "lastActivity": "2025-01-15T00:00:00.000Z", "customFields": { "location": "Europe" }, "createdAt": "2025-01-01T12:00:00.000Z", "updatedAt": "2025-01-10T15:30:00.000Z" } ], "nextCursor": "eyJpZCI6IjUwN2YxZjc3YmNmODZjZDc5OTQzOTAxMSJ9" } ``` ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Query Parameters - `cursor: optional string` An opaque cursor for pagination. Use the nextCursor value from a previous response to fetch the next page of results. - `limit: optional number` A limit on the number of companies to be returned, between 1 and 100. ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `data: array of Company` Array of companies - `id: string` Featurebase internal ID - `companyId: string` External company ID from your system - `companySize: number` Company employee headcount - `createdAt: string` ISO date when company was created - `industry: string` Industry - `lastActivity: string` ISO date of last activity - `linkedUsers: number` Number of users linked to this company - `monthlySpend: number` Monthly spend - `name: string` Company name - `object: "company"` Object type identifier - `"company"` - `plan: string` Plan or tier name - `updatedAt: string` ISO date when company was last updated - `website: string` Company website URL - `customFields: optional map[unknown]` Custom field values - `nextCursor: string` Cursor for fetching the next page (cursor-based pagination) - `object: "list"` Object type identifier - `"list"` ### Example ```http curl https://do.featurebase.app/v2/companies \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "data": [ { "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" } } ], "nextCursor": "eyJpZCI6IjUwN2YxZjc3YmNmODZjZDc5OTQzOTAxMSJ9", "object": "list" } ``` ## Create or update a company **post** `/v2/companies` Creates a new company or updates an existing one. Uses the external `companyId` as the unique identifier for upsert matching. If a company with the given `companyId` already exists, it will be updated. Otherwise, a new company will be created. ### Request Body | Field | Type | Required | Description | | -------------- | ------ | -------- | -------------------------------------------------------- | | `companyId` | string | Yes | External company ID from your system (unique identifier) | | `name` | string | Yes | Company name | | `monthlySpend` | number | No | Monthly spend/revenue from this company | | `industry` | string | No | Industry the company operates in | | `website` | string | No | Company website URL | | `plan` | string | No | Current plan/subscription name | | `companySize` | number | No | Number of employees | | `createdAt` | string | No | When the company was created (ISO 8601) | | `customFields` | object | No | Custom field values | ### Example Request ```json { "companyId": "comp_12345", "name": "Acme Inc", "monthlySpend": 5000, "industry": "Technology", "website": "https://acme.com", "plan": "enterprise", "companySize": 250, "customFields": { "region": "EMEA", "tier": "gold" } } ``` ### Example Response ```json { "object": "company", "id": "507f1f77bcf86cd799439011", "companyId": "comp_12345", "name": "Acme Inc", "monthlySpend": 5000, "industry": "Technology", "website": "https://acme.com", "plan": "enterprise", "linkedUsers": 1, "companySize": 250, "lastActivity": "2025-01-15T00:00:00.000Z", "customFields": { "region": "EMEA", "tier": "gold" }, "createdAt": "2025-01-01T12:00:00.000Z", "updatedAt": "2025-01-15T10:30:00.000Z" } ``` ### Error Responses - **400 Bad Request** - Invalid company data ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Body Parameters - `companyId: string` External company ID from your system. Used as the unique identifier for upsert matching. - `name: string` Company name - `companySize: optional number` Number of employees in the company - `createdAt: optional string` When the company was created in your system (ISO 8601) - `customFields: optional object { priority, region, tier }` Custom field values on the company. Values can be string, number, boolean, null, or array of primitives. - `priority: optional string` - `region: optional string` - `tier: optional string` - `industry: optional string` Industry the company operates in - `monthlySpend: optional number` Monthly spend/revenue from this company - `plan: optional string` Current plan/subscription name - `website: optional string` Company website URL ### Returns - `Company object { id, companyId, companySize, 11 more }` - `id: string` Featurebase internal ID - `companyId: string` External company ID from your system - `companySize: number` Company employee headcount - `createdAt: string` ISO date when company was created - `industry: string` Industry - `lastActivity: string` ISO date of last activity - `linkedUsers: number` Number of users linked to this company - `monthlySpend: number` Monthly spend - `name: string` Company name - `object: "company"` Object type identifier - `"company"` - `plan: string` Plan or tier name - `updatedAt: string` ISO date when company was last updated - `website: string` Company website URL - `customFields: optional map[unknown]` Custom field values ### Example ```http curl https://do.featurebase.app/v2/companies \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" \ -d '{ "companyId": "comp_12345", "name": "Acme Inc", "companySize": 250, "createdAt": "2024-01-15T10:30:00Z", "industry": "Technology", "monthlySpend": 5000, "plan": "enterprise", "website": "https://acme.com" }' ``` #### Response ```json { "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" } } ``` ## Get company by ID **get** `/v2/companies/{id}` Retrieves a single company by its Featurebase ID. ### Path Parameters - `id` - The Featurebase internal ID of the company (MongoDB ObjectId) ### Response Returns a company object with: - `id` - Featurebase internal ID - `companyId` - External company ID from your system - `name` - Company name - `monthlySpend` - Monthly spend/revenue - `industry` - Industry - `website` - Company website URL - `plan` - Plan/tier name - `linkedUsers` - Number of users linked to this company - `companySize` - Employee headcount - `lastActivity` - Last activity timestamp - `customFields` - Custom field values - `createdAt` - Creation timestamp - `updatedAt` - Last update timestamp ### Example Response ```json { "object": "company", "id": "507f1f77bcf86cd799439011", "companyId": "comp_12345", "name": "Acme Inc", "monthlySpend": 5000, "industry": "Technology", "website": "https://acme.com", "plan": "enterprise", "linkedUsers": 15, "companySize": 250, "lastActivity": "2025-01-15T00:00:00.000Z", "customFields": { "location": "Europe" }, "createdAt": "2025-01-01T12:00:00.000Z", "updatedAt": "2025-01-10T15:30:00.000Z" } ``` ### Error Responses - **404 Not Found** - Company with the specified ID does not exist ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Path Parameters - `id: string` The Featurebase internal ID of the company (MongoDB ObjectId) ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `Company object { id, companyId, companySize, 11 more }` - `id: string` Featurebase internal ID - `companyId: string` External company ID from your system - `companySize: number` Company employee headcount - `createdAt: string` ISO date when company was created - `industry: string` Industry - `lastActivity: string` ISO date of last activity - `linkedUsers: number` Number of users linked to this company - `monthlySpend: number` Monthly spend - `name: string` Company name - `object: "company"` Object type identifier - `"company"` - `plan: string` Plan or tier name - `updatedAt: string` ISO date when company was last updated - `website: string` Company website URL - `customFields: optional map[unknown]` Custom field values ### Example ```http curl https://do.featurebase.app/v2/companies/$ID \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "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" } } ``` ## Delete a company **delete** `/v2/companies/{id}` Deletes a company by its Featurebase ID. This will also remove the company from all linked users' associations. ### Path Parameters - `id` - The Featurebase internal ID of the company (MongoDB ObjectId) ### Response Returns a deletion confirmation object: ```json { "id": "507f1f77bcf86cd799439011", "object": "company", "deleted": true } ``` ### Error Responses - **404 Not Found** - Company with the specified ID does not exist ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Path Parameters - `id: string` The Featurebase internal ID of the company (MongoDB ObjectId) ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `DeletedCompany object { id, deleted, object }` - `id: string` Unique identifier of the deleted company - `deleted: true` Indicates the resource was deleted - `true` - `object: "company"` Object type identifier - `"company"` ### Example ```http curl https://do.featurebase.app/v2/companies/$ID \ -X DELETE \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "id": "507f1f77bcf86cd799439011", "deleted": true, "object": "company" } ``` ## Delete a company by external company ID **delete** `/v2/companies/by-company-id/{companyId}` Permanently deletes a company by its external company ID (the `companyId` from your system). This will also remove the company from all linked users' associations. ### Path Parameters - `companyId` - The external company ID from your system ### Deletion Behavior When a company is deleted: - The company record is permanently removed - The company is removed from all linked users' `companyIds` and `companies` arrays ### Response Returns a deletion confirmation object: - `id` - The Featurebase internal ID of the deleted company - `object` - Always "company" - `deleted` - Always `true` ### Example Response ```json { "id": "507f1f77bcf86cd799439011", "object": "company", "deleted": true } ``` ### Use Case Use this endpoint when you need to delete a company using your own system's company identifier, such as when a company is removed from your application. ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Path Parameters - `companyId: string` The external company ID from your system ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `DeletedCompany object { id, deleted, object }` - `id: string` Unique identifier of the deleted company - `deleted: true` Indicates the resource was deleted - `true` - `object: "company"` Object type identifier - `"company"` ### Example ```http curl https://do.featurebase.app/v2/companies/by-company-id/$COMPANY_ID \ -X DELETE \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "id": "507f1f77bcf86cd799439011", "deleted": true, "object": "company" } ``` ## Domain Types ### Company - `Company object { id, companyId, companySize, 11 more }` - `id: string` Featurebase internal ID - `companyId: string` External company ID from your system - `companySize: number` Company employee headcount - `createdAt: string` ISO date when company was created - `industry: string` Industry - `lastActivity: string` ISO date of last activity - `linkedUsers: number` Number of users linked to this company - `monthlySpend: number` Monthly spend - `name: string` Company name - `object: "company"` Object type identifier - `"company"` - `plan: string` Plan or tier name - `updatedAt: string` ISO date when company was last updated - `website: string` Company website URL - `customFields: optional map[unknown]` Custom field values ### Deleted Company - `DeletedCompany object { id, deleted, object }` - `id: string` Unique identifier of the deleted company - `deleted: true` Indicates the resource was deleted - `true` - `object: "company"` Object type identifier - `"company"` # Contacts ## List contacts attached to a company **get** `/v2/companies/{id}/contacts` Returns all contacts (customers) attached to a specific company. Only returns contacts with type "customer" that have the company in their `companyIds` array. Uses cursor-based pagination. ### Path Parameters - `id` - The Featurebase internal ID of the company (MongoDB ObjectId) ### Query Parameters - `limit` - Number of contacts to return (1-100, default: 10) - `cursor` - Opaque cursor from a previous response for pagination ### Response Structure The response includes: - `object` - Always "list" - `data` - Array of contact objects - `nextCursor` - Cursor for the next page (null if no more results) ### Example Response ```json { "object": "list", "data": [ { "object": "contact", "id": "507f1f77bcf86cd799439011", "userId": "usr_12345", "email": "john@acme.com", "name": "John Doe", "type": "customer", "companies": [...], "createdAt": "2025-01-01T12:00:00.000Z" } ], "nextCursor": "eyJpZCI6IjUwN2YxZjc3YmNmODZjZDc5OTQzOTAxMSJ9" } ``` ### Error Responses - **404 Not Found** - Company with the specified ID does not exist ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Path Parameters - `id: string` The Featurebase internal ID of the company (MongoDB ObjectId) ### Query Parameters - `cursor: optional string` An opaque cursor for pagination. Use the nextCursor value from a previous response to fetch the next page of results. - `limit: optional number` A limit on the number of contacts to be returned, between 1 and 100. ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `ContactList object { data, nextCursor, object }` - `data: array of Contact` Array of contacts - `nextCursor: string` Cursor for fetching the next page (cursor-based pagination) - `object: "list"` Object type identifier - `"list"` ### Example ```http curl https://do.featurebase.app/v2/companies/$ID/contacts \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "data": [ { "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 } ], "nextCursor": "eyJpZCI6IjUwN2YxZjc3YmNmODZjZDc5OTQzOTAxMSJ9", "object": "list" } ``` ## Attach a contact to a company **post** `/v2/companies/{id}/contacts` Attaches a contact (customer) to a company. Adds the company to the contact's `companyIds` array and embedded `companies` array. This operation is **additive** - existing company associations are preserved. Also increments the `linkedUsers` count on the company. ### Path Parameters - `id` - The Featurebase internal ID of the company (MongoDB ObjectId) ### Request Body | Field | Type | Required | Description | | ----------- | ------ | -------- | ----------------------------------------------------------------------- | | `contactId` | string | Yes | The Featurebase internal ID of the contact to attach (MongoDB ObjectId) | ### Example Request ```json { "contactId": "507f1f77bcf86cd799439012" } ``` ### Response Returns the updated contact object with the new company association. ### Example Response ```json { "object": "contact", "id": "507f1f77bcf86cd799439012", "userId": "usr_12345", "email": "john@acme.com", "name": "John Doe", "type": "customer", "companies": [ { "object": "company", "id": "507f1f77bcf86cd799439011", "companyId": "comp_12345", "name": "Acme Inc" } ] } ``` ### Error Responses - **404 Not Found** - Company or contact does not exist ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Path Parameters - `id: string` The Featurebase internal ID of the company (MongoDB ObjectId) ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Body Parameters - `contactId: string` The Featurebase internal ID of the contact to attach (MongoDB ObjectId) ### Example ```http curl https://do.featurebase.app/v2/companies/$ID/contacts \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" \ -d '{ "contactId": "507f1f77bcf86cd799439012" }' ``` #### Response ```json { "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 } ``` ## Remove a contact from a company **delete** `/v2/companies/{id}/contacts/{contactId}` Removes a contact (customer) from a company. Removes the company from the contact's `companyIds` array and embedded `companies` array. Also decrements the `linkedUsers` count on the company. ### Path Parameters - `id` - The Featurebase internal ID of the company (MongoDB ObjectId) - `contactId` - The Featurebase internal ID of the contact to remove (MongoDB ObjectId) ### Response Returns the updated contact object with the company removed. ### Example Response ```json { "object": "contact", "id": "507f1f77bcf86cd799439012", "userId": "usr_12345", "email": "john@acme.com", "name": "John Doe", "type": "customer", "companies": [] } ``` ### Error Responses - **400 Bad Request** - Contact is not attached to this company - **404 Not Found** - Company or contact does not exist ### Version Availability This endpoint is only available in API version 2026-01-01.nova and newer. ### Path Parameters - `id: string` The Featurebase internal ID of the company (MongoDB ObjectId) - `contactId: string` The Featurebase internal ID of the contact to remove (MongoDB ObjectId) ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Example ```http curl https://do.featurebase.app/v2/companies/$ID/contacts/$CONTACT_ID \ -X DELETE \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "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 } ``` ## Domain Types ### Contact Attach Response - `ContactAttachResponse = Contact` User who submitted the response ### Contact Remove Response - `ContactRemoveResponse = Contact` User who submitted the response