# Tickets ## List tickets **get** `/v2/tickets` Returns a list of tickets in your organization using cursor-based pagination. ### Query Parameters | Parameter | Type | Description | | ------------------- | -------- | ---------------------------------------------------------------- | | `limit` | number | Number of tickets to return (1-100, default 10) | | `cursor` | string | Cursor from previous response for pagination | | `ticketCategoryIds` | string[] | Filter by ticket category IDs | | `statusIds` | string[] | Filter by status IDs | | `q` | string | Search query | | `assigneeId` | string | Filter by assignee ID | | `categoryType` | string | Filter by category type: "customer", "tracker", or "back-office" | | `sortBy` | string | Sort field: "date" (default), "recent", or "ticketNumber" | | `sortOrder` | string | Sort direction: "asc" or "desc" (default) | ### Response Returns a list object with `data` (array of ticket objects) and `nextCursor`. ### Query Parameters - `assigneeId: optional string` - `categoryType: optional "customer" or "tracker" or "back-office"` - `"customer"` - `"tracker"` - `"back-office"` - `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` - `q: optional string` - `sortBy: optional "date" or "recent" or "ticketNumber"` - `"date"` - `"recent"` - `"ticketNumber"` - `sortOrder: optional "asc" or "desc"` - `"asc"` - `"desc"` - `statusIds: optional array of string` - `ticketCategoryIds: optional array of string` ### 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 Ticket` Array of tickets - `id: string` Unique identifier (MongoDB ID) - `assigneeId: string` Assigned admin ID - `author: object { id, email, name, 2 more }` Contact who created the ticket - `id: string` Author unique identifier - `email: string` Author email - `name: string` Author display name - `profilePicture: string` Author profile picture URL - `type: "admin" or "customer" or "guest" or 3 more` Type of user - `"admin"` - `"customer"` - `"guest"` - `"integration"` - `"bot"` - `"lead"` - `categoryType: "customer" or "tracker" or "back-office"` Ticket category type - `"customer"` - `"tracker"` - `"back-office"` - `companyId: string` Associated company ID - `content: string` Ticket content/description (HTML) - `createdAt: string` ISO 8601 creation timestamp - `customFields: map[unknown]` Custom field values keyed by field ID. File-type fields contain a JSON string of { key, name, url } with a signed download URL (1 hour expiry). For allowMultiple file fields, the value is a JSON string of an array of these objects. - `integrations: object { clickup, devops, github, 3 more }` Third-party integration links - `clickup: array of object { id, title, url }` - `id: string` ClickUp task ID - `title: string` ClickUp task title - `url: string` URL to the ClickUp task - `devops: array of object { id, projectId, projectName, 2 more }` - `id: number` Azure DevOps work item ID - `projectId: string` Azure DevOps project ID - `projectName: string` Azure DevOps project name - `title: string` Work item title - `url: string` URL to the work item - `github: array of object { id, number, repositoryFullName, 3 more }` - `id: string` GitHub issue ID - `number: string` GitHub issue number - `repositoryFullName: string` Full repository name (owner/repo) - `repositoryName: string` Repository name - `title: string` GitHub issue title - `url: string` URL to the GitHub issue - `hubspot: array of object { dealAmount, dealClosed, objectId, type }` - `dealAmount: number` Deal amount (for DEAL type) - `dealClosed: boolean` Whether the deal is closed (for DEAL type) - `objectId: number` HubSpot object ID - `type: "TICKET" or "DEAL" or "CONTACT"` HubSpot object type - `"TICKET"` - `"DEAL"` - `"CONTACT"` - `jira: array of object { issueId, issueUrl }` - `issueId: string` Jira issue ID - `issueUrl: string` URL to the Jira issue - `linear: array of object { issueId, issueUrl }` - `issueId: string` Linear issue ID - `issueUrl: string` URL to the Linear issue - `linkedConversations: array of object { id, role }` Linked conversations - `id: string` Conversation ID - `role: "customer" or "tracker" or "back-office"` Link role - `"customer"` - `"tracker"` - `"back-office"` - `object: "ticket"` Object type identifier - `"ticket"` - `open: boolean` Whether the ticket is open - `snoozedUntil: string` ISO 8601 timestamp until snoozed (from linked conversation) - `status: PostStatus` Current ticket status - `id: string` Unique identifier - `color: string` Color for UI display - `isDefault: boolean` Whether this is the default status for new posts - `name: string` Display name - `object: "post_status"` Object type identifier - `"post_status"` - `type: "reviewing" or "unstarted" or "active" or 2 more` The workflow stage this status represents - `"reviewing"` - `"unstarted"` - `"active"` - `"completed"` - `"canceled"` - `teamAssigneeId: string` Assigned team ID (from linked conversation) - `ticketCategoryId: string` Ticket category ID - `ticketNumber: number` Sequential display ID (e.g. TK-42) - `ticketUrl: string` Full URL to view the ticket - `title: string` Ticket title - `updatedAt: string` ISO 8601 last updated timestamp - `conversationParts: optional array of ConversationPart` Conversation message history. Only included when fetching a single ticket by ID. - `UserMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Message from a customer or lead - `id: string` Unique part identifier - `bodyHtml: string` Message body content as HTML with signed image URLs - `bodyMarkdown: string` Message body content as markdown - `channel: "unknown" or "desktop" or "android" or 2 more` Channel through which the message was sent - `"unknown"` - `"desktop"` - `"android"` - `"ios"` - `"email"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "user_msg"` User message type - `"user_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `id: string` Author ID - `type: "customer" or "lead" or "admin" or 3 more` Type of author - `"customer"` - `"lead"` - `"admin"` - `"bot"` - `"guest"` - `"integration"` - `email: optional string` Author email address - `name: optional string` Author display name - `profilePicture: optional string` Author profile picture URL - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `type: "admin" or "customer" or "lead" or 4 more` Actor that caused the tag mutation - `"admin"` - `"customer"` - `"lead"` - `"bot"` - `"integration"` - `"system"` - `"workflow"` - `id: optional string` Actor identifier when available - `name: optional string` Actor display name when available - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `id: string` Unique tag identifier - `name: string` Current tag name - `type: "tag"` Object type identifier for a tag - `"tag"` - `AdminMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Message from an admin or support agent - `id: string` Unique part identifier - `bodyHtml: string` Message body content as HTML with signed image URLs - `bodyMarkdown: string` Message body content as markdown - `channel: "unknown" or "desktop" or "android" or 2 more` Channel through which the message was sent - `"unknown"` - `"desktop"` - `"android"` - `"ios"` - `"email"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "admin_msg"` Admin message type - `"admin_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `AdminNote object { id, bodyHtml, bodyMarkdown, 7 more }` Internal note visible only to admins - `id: string` Unique part identifier - `bodyHtml: string` Note body content as HTML with signed image URLs - `bodyMarkdown: string` Note body content as markdown - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "admin_note"` Admin internal note type - `"admin_note"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `EmailMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Message sent via email - `id: string` Unique part identifier - `bodyHtml: string` Email body content as HTML with signed image URLs - `bodyMarkdown: string` Email body content as markdown - `channel: "email"` Email channel - `"email"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "email_msg"` Email message type - `"email_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `BotMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Automated message from AI or bot - `id: string` Unique part identifier - `bodyHtml: string` Bot message body content as HTML with signed image URLs - `bodyMarkdown: string` Bot message body content as markdown - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "bot_msg"` Bot message type - `"bot_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `channel: optional "unknown" or "desktop" or "android" or 2 more` Channel through which the message was sent - `"unknown"` - `"desktop"` - `"android"` - `"ios"` - `"email"` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `QuickReplyOpts object { id, createdAt, object, 6 more }` Presents options for user to choose from - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "quick_reply_opts"` Quick reply options type - `"quick_reply_opts"` - `replyOptions: array of object { id, text }` Available reply options - `id: string` Option ID - `text: string` Option text - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `QuickReplyResp object { id, bodyHtml, bodyMarkdown, 8 more }` User's selection from quick reply options - `id: string` Unique part identifier - `bodyHtml: string` The selected option text as HTML - `bodyMarkdown: string` The selected option text as markdown - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "quick_reply_resp"` Quick reply response type - `"quick_reply_resp"` - `selectedOptionId: string` ID of the selected option - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `RatingRequested object { id, createdAt, csat, 3 more }` Represents a persisted CSAT request in the conversation thread - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `csat: object { channel, requestedAt, requestId, 7 more }` Canonical CSAT request payload for this thread event - `channel: "desktop" or "email"` Channel used for the CSAT request - `"desktop"` - `"email"` - `requestedAt: string` ISO timestamp when the request was created - `requestId: string` Canonical CSAT request ID - `requestSource: "workflow"` Source that created the CSAT request - `"workflow"` - `status: "pending" or "rated" or "canceled" or "expired"` Status of the CSAT request represented by this part - `"pending"` - `"rated"` - `"canceled"` - `"expired"` - `changeLockWindowEndsAt: optional string` ISO timestamp after which changing the rating is no longer allowed - `expiredAt: optional string` ISO timestamp when the request expired, when applicable - `lateSubmitWindowEndsAt: optional string` ISO timestamp after which late submission is no longer allowed - `ratedAgent: optional CsatRatedAgent` - `type: "teammate" or "fibi" or "chatbot"` Type of agent the CSAT request is attributed to - `"teammate"` - `"fibi"` - `"chatbot"` - `id: optional string` Identifier of the rated agent when applicable - `workflow: optional CsatWorkflowLink` - `workflowActionId: optional string` Workflow action ID associated with the CSAT request - `workflowId: optional string` Workflow ID associated with the CSAT request - `workflowRunId: optional string` Workflow run ID associated with the CSAT request - `workflowStepId: optional string` Workflow step ID associated with the CSAT request - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "rating_requested"` CSAT rating requested part type - `"rating_requested"` - `updatedAt: string` ISO timestamp when the part was last updated - `RatingSubmitted object { id, createdAt, csat, 3 more }` Represents a persisted CSAT submission in the conversation thread - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `csat: object { channel, ratedAt, requestId, 7 more }` Canonical CSAT submission payload for this thread event - `channel: "desktop" or "email"` Channel used for the CSAT request - `"desktop"` - `"email"` - `ratedAt: string` ISO timestamp when the customer submitted the rating - `requestId: string` Canonical CSAT request ID - `requestSource: "workflow"` Source that created the CSAT request - `"workflow"` - `score: number` CSAT score from 1 to 5 - `status: "rated"` Submitted ratings are always in the rated state - `"rated"` - `ratedAgent: optional CsatRatedAgent` - `remark: optional string` Optional remark left with the rating - `requestedAt: optional string` ISO timestamp when the request was created - `workflow: optional CsatWorkflowLink` - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "rating_submitted"` CSAT rating submitted part type - `"rating_submitted"` - `updatedAt: string` ISO timestamp when the part was last updated - `AttrPrompt object { id, createdAt, form, 6 more }` Requests information from user via form - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `form: object { id, attributes }` Form configuration - `id: string` Form ID - `attributes: array of object { identifier, name, type }` Form fields - `identifier: string` Field identifier - `name: string` Field display name - `type: string` Field type - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "attr_prompt"` Attribute collection prompt type - `"attr_prompt"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `AttrComplete object { id, createdAt, object, 2 more }` Indicates form was completed - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "attr_complete"` Attribute collection complete type - `"attr_complete"` - `updatedAt: string` ISO timestamp when the part was last updated - `Assign object { id, createdAt, object, 5 more }` Conversation assigned to admin or team - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "assign"` Assignment type - `"assign"` - `updatedAt: string` ISO timestamp when the part was last updated - `adminAssigneeId: optional string` ID of the admin assigned to the conversation - `adminAssignerId: optional string` ID of the admin who made the assignment - `teamAssigneeId: optional string` ID of the team assigned to the conversation - `Status object { id, createdAt, object, 4 more }` Conversation state changed (open/closed/snoozed) - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "status"` Status change type - `"status"` - `status: "open" or "closed" or "snoozed"` New conversation status - `"open"` - `"closed"` - `"snoozed"` - `updatedAt: string` ISO timestamp when the part was last updated - `snoozedUntil: optional string` ISO timestamp until conversation is snoozed (if snoozed) - `Tags object { id, action, createdAt, 8 more }` A tag was added to or removed from a specific reply - `id: string` Unique part identifier - `action: "added" or "removed"` Whether the tag was added or removed - `"added"` - `"removed"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `occurredAt: string` ISO timestamp when the tag mutation occurred - `partType: "tags"` Tag update type - `"tags"` - `tagId: string` Identifier of the affected tag - `updatedAt: string` ISO timestamp when the part was last updated - `actor: optional ConversationTagMutationActor` Actor that applied the tag - `tagName: optional string` Tag name at the time of the event or the best available current display name - `targetPartId: optional string` Conversation part that the tag mutation targeted - `WorkflowWait object { id, createdAt, object, 3 more }` Represents a workflow wait start, finish, or interruption in the conversation thread - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "workflow_wait"` Workflow wait event part type - `"workflow_wait"` - `updatedAt: string` ISO timestamp when the part was last updated - `workflowWait: object { eventType, occurredAt, interruptedByUserType, 3 more }` Workflow wait event payload for this thread event - `eventType: "started" or "finished" or "interrupted"` Lifecycle stage of the workflow wait event - `"started"` - `"finished"` - `"interrupted"` - `occurredAt: string` ISO timestamp when the wait event occurred - `interruptedByUserType: optional "admin" or "customer" or "lead"` User type that interrupted the wait when applicable - `"admin"` - `"customer"` - `"lead"` - `waitLabel: optional string` Human-readable wait duration or preset label - `workflowId: optional string` Workflow ID associated with the wait event - `workflowName: optional string` Workflow display name at the time of the wait event - `Priority object { id, createdAt, isPriority, 3 more }` Conversation priority was updated - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `isPriority: boolean` Whether the conversation is now marked as priority - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "priority"` Priority change type - `"priority"` - `updatedAt: string` ISO timestamp when the part was last updated - `PartAdd object { id, createdAt, object, 3 more }` New participant joined the conversation - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `participant: object { id, type }` The added participant - `id: string` Participant ID - `type: "customer" or "lead" or "admin"` Participant type - `"customer"` - `"lead"` - `"admin"` - `partType: "part_add"` Participant added type - `"part_add"` - `updatedAt: string` ISO timestamp when the part was last updated - `nextCursor: string` Cursor for fetching the next page - `object: "list"` Object type identifier - `"list"` ### Example ```http curl https://do.featurebase.app/v2/tickets \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "data": [ { "id": "507f1f77bcf86cd799439011", "assigneeId": "507f1f77bcf86cd799439013", "author": { "id": "507f1f77bcf86cd799439011", "email": "john@example.com", "name": "John Doe", "profilePicture": "https://cdn.example.com/avatars/john.png", "type": "customer" }, "categoryType": "customer", "companyId": "507f1f77bcf86cd799439015", "content": "
I get a 403 error when logging in.
", "createdAt": "2025-01-15T10:30:00.000Z", "customFields": { "priority": "bar", "507f1f77bcf86cd799439099": "bar" }, "integrations": { "clickup": [ { "id": "86a1b2c3d", "title": "Fix login bug", "url": "https://app.clickup.com/t/86a1b2c3d" } ], "devops": [ { "id": 789, "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "projectName": "My Project", "title": "Implement SSO", "url": "https://dev.azure.com/org/project/_workitems/edit/789" } ], "github": [ { "id": "1234567890", "number": "42", "repositoryFullName": "acme/frontend", "repositoryName": "frontend", "title": "Login page returns 403", "url": "https://github.com/acme/frontend/issues/42" } ], "hubspot": [ { "dealAmount": 5000, "dealClosed": false, "objectId": 12345, "type": "DEAL" } ], "jira": [ { "issueId": "PROJ-456", "issueUrl": "https://company.atlassian.net/browse/PROJ-456" } ], "linear": [ { "issueId": "LIN-123", "issueUrl": "https://linear.app/team/issue/LIN-123" } ] }, "linkedConversations": [ { "id": "507f1f77bcf86cd799439011", "role": "customer" } ], "object": "ticket", "open": true, "snoozedUntil": "2025-01-16T09:00:00.000Z", "status": { "id": "507f1f77bcf86cd799439011", "color": "Blue", "isDefault": false, "name": "In Progress", "object": "post_status", "type": "active" }, "teamAssigneeId": "507f1f77bcf86cd799439014", "ticketCategoryId": "507f1f77bcf86cd799439011", "ticketNumber": 42, "ticketUrl": "https://feedback.example.com/p/cannot-login", "title": "Cannot login to dashboard", "updatedAt": "2025-01-15T12:30:00.000Z", "conversationParts": [ { "id": "1", "bodyHtml": "Hello, I have a question about your product.
", "bodyMarkdown": "Hello, I have a question about your product.", "channel": "desktop", "createdAt": "2025-01-15T10:30:00.000Z", "object": "conversation_part", "partType": "user_msg", "updatedAt": "2025-01-15T10:30:00.000Z", "author": { "id": "676f0f6765bdaa7d7d760f88", "type": "customer", "email": "john@example.com", "name": "John Doe", "profilePicture": "https://cdn.example.com/avatars/user.png" }, "redacted": false, "tagApplications": [ { "appliedAt": "2025-01-15T10:30:00.000Z", "tagId": "67ec1234abcd5678ef901234", "appliedBy": { "type": "admin", "id": "507f1f77bcf86cd799439011", "name": "John Doe" }, "removedAt": "2025-01-15T11:00:00.000Z", "removedBy": { "type": "admin", "id": "507f1f77bcf86cd799439011", "name": "John Doe" }, "tag": { "id": "67ec1234abcd5678ef901234", "name": "Churn", "type": "tag" } } ] } ] } ], "nextCursor": "eyJpZCI6IjUwN2YxZjc3YmNmODZjZDc5OTQzOTAxMSJ9", "object": "list" } ``` ## Create a ticket **post** `/v2/tickets` Creates a new ticket. ### Required Fields | Field | Type | Description | | ------------------ | ------ | ------------------------------------------------------------- | | `ticketCategoryId` | string | Ticket category ID | | `title` | string | Ticket title (min 2 characters) | | `author` | object | Author/contact info (id, userId, email, name, profilePicture) | ### Optional Fields | Field | Type | Description | | ---------------------- | ------- | ------------------------------------------ | | `content` | string | Ticket description (HTML) | | `customFields` | object | Custom field values | | `companyId` | string | Company to associate | | `linkedConversationId` | string | Conversation to link | | `assigneeId` | string | Admin to assign | | `statusId` | string | Initial status | | `createdAt` | string | ISO 8601 timestamp for backdating | | `skipNotifications` | boolean | Skip sending notifications (default false) | ### File Custom Fields File-type custom fields can be provided in two ways: **Method 1: Multipart upload** — Send the request as `multipart/form-data`. Put the JSON body in a field named `data`, and attach files with field names like `customFields.I get a 403 error when logging in.
", "createdAt": "2025-01-15T10:30:00.000Z", "linkedConversationId": "507f1f77bcf86cd799439012", "statusId": "507f1f77bcf86cd799439016" }' ``` #### Response ```json { "id": "507f1f77bcf86cd799439011", "assigneeId": "507f1f77bcf86cd799439013", "author": { "id": "507f1f77bcf86cd799439011", "email": "john@example.com", "name": "John Doe", "profilePicture": "https://cdn.example.com/avatars/john.png", "type": "customer" }, "categoryType": "customer", "companyId": "507f1f77bcf86cd799439015", "content": "I get a 403 error when logging in.
", "createdAt": "2025-01-15T10:30:00.000Z", "customFields": { "priority": "bar", "507f1f77bcf86cd799439099": "bar" }, "integrations": { "clickup": [ { "id": "86a1b2c3d", "title": "Fix login bug", "url": "https://app.clickup.com/t/86a1b2c3d" } ], "devops": [ { "id": 789, "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "projectName": "My Project", "title": "Implement SSO", "url": "https://dev.azure.com/org/project/_workitems/edit/789" } ], "github": [ { "id": "1234567890", "number": "42", "repositoryFullName": "acme/frontend", "repositoryName": "frontend", "title": "Login page returns 403", "url": "https://github.com/acme/frontend/issues/42" } ], "hubspot": [ { "dealAmount": 5000, "dealClosed": false, "objectId": 12345, "type": "DEAL" } ], "jira": [ { "issueId": "PROJ-456", "issueUrl": "https://company.atlassian.net/browse/PROJ-456" } ], "linear": [ { "issueId": "LIN-123", "issueUrl": "https://linear.app/team/issue/LIN-123" } ] }, "linkedConversations": [ { "id": "507f1f77bcf86cd799439011", "role": "customer" } ], "object": "ticket", "open": true, "snoozedUntil": "2025-01-16T09:00:00.000Z", "status": { "id": "507f1f77bcf86cd799439011", "color": "Blue", "isDefault": false, "name": "In Progress", "object": "post_status", "type": "active" }, "teamAssigneeId": "507f1f77bcf86cd799439014", "ticketCategoryId": "507f1f77bcf86cd799439011", "ticketNumber": 42, "ticketUrl": "https://feedback.example.com/p/cannot-login", "title": "Cannot login to dashboard", "updatedAt": "2025-01-15T12:30:00.000Z", "conversationParts": [ { "id": "1", "bodyHtml": "Hello, I have a question about your product.
", "bodyMarkdown": "Hello, I have a question about your product.", "channel": "desktop", "createdAt": "2025-01-15T10:30:00.000Z", "object": "conversation_part", "partType": "user_msg", "updatedAt": "2025-01-15T10:30:00.000Z", "author": { "id": "676f0f6765bdaa7d7d760f88", "type": "customer", "email": "john@example.com", "name": "John Doe", "profilePicture": "https://cdn.example.com/avatars/user.png" }, "redacted": false, "tagApplications": [ { "appliedAt": "2025-01-15T10:30:00.000Z", "tagId": "67ec1234abcd5678ef901234", "appliedBy": { "type": "admin", "id": "507f1f77bcf86cd799439011", "name": "John Doe" }, "removedAt": "2025-01-15T11:00:00.000Z", "removedBy": { "type": "admin", "id": "507f1f77bcf86cd799439011", "name": "John Doe" }, "tag": { "id": "67ec1234abcd5678ef901234", "name": "Churn", "type": "tag" } } ] } ] } ``` ## Get a ticket **get** `/v2/tickets/{id}` Retrieves a single ticket by its ticket number. ### Path Parameters - `id` - The ticket number (e.g. 42 from TK-42) ### Response Returns the ticket object, including `conversationParts` from the linked conversation (message history). ### Path Parameters - `id: number` ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `Ticket object { id, assigneeId, author, 18 more }` - `id: string` Unique identifier (MongoDB ID) - `assigneeId: string` Assigned admin ID - `author: object { id, email, name, 2 more }` Contact who created the ticket - `id: string` Author unique identifier - `email: string` Author email - `name: string` Author display name - `profilePicture: string` Author profile picture URL - `type: "admin" or "customer" or "guest" or 3 more` Type of user - `"admin"` - `"customer"` - `"guest"` - `"integration"` - `"bot"` - `"lead"` - `categoryType: "customer" or "tracker" or "back-office"` Ticket category type - `"customer"` - `"tracker"` - `"back-office"` - `companyId: string` Associated company ID - `content: string` Ticket content/description (HTML) - `createdAt: string` ISO 8601 creation timestamp - `customFields: map[unknown]` Custom field values keyed by field ID. File-type fields contain a JSON string of { key, name, url } with a signed download URL (1 hour expiry). For allowMultiple file fields, the value is a JSON string of an array of these objects. - `integrations: object { clickup, devops, github, 3 more }` Third-party integration links - `clickup: array of object { id, title, url }` - `id: string` ClickUp task ID - `title: string` ClickUp task title - `url: string` URL to the ClickUp task - `devops: array of object { id, projectId, projectName, 2 more }` - `id: number` Azure DevOps work item ID - `projectId: string` Azure DevOps project ID - `projectName: string` Azure DevOps project name - `title: string` Work item title - `url: string` URL to the work item - `github: array of object { id, number, repositoryFullName, 3 more }` - `id: string` GitHub issue ID - `number: string` GitHub issue number - `repositoryFullName: string` Full repository name (owner/repo) - `repositoryName: string` Repository name - `title: string` GitHub issue title - `url: string` URL to the GitHub issue - `hubspot: array of object { dealAmount, dealClosed, objectId, type }` - `dealAmount: number` Deal amount (for DEAL type) - `dealClosed: boolean` Whether the deal is closed (for DEAL type) - `objectId: number` HubSpot object ID - `type: "TICKET" or "DEAL" or "CONTACT"` HubSpot object type - `"TICKET"` - `"DEAL"` - `"CONTACT"` - `jira: array of object { issueId, issueUrl }` - `issueId: string` Jira issue ID - `issueUrl: string` URL to the Jira issue - `linear: array of object { issueId, issueUrl }` - `issueId: string` Linear issue ID - `issueUrl: string` URL to the Linear issue - `linkedConversations: array of object { id, role }` Linked conversations - `id: string` Conversation ID - `role: "customer" or "tracker" or "back-office"` Link role - `"customer"` - `"tracker"` - `"back-office"` - `object: "ticket"` Object type identifier - `"ticket"` - `open: boolean` Whether the ticket is open - `snoozedUntil: string` ISO 8601 timestamp until snoozed (from linked conversation) - `status: PostStatus` Current ticket status - `id: string` Unique identifier - `color: string` Color for UI display - `isDefault: boolean` Whether this is the default status for new posts - `name: string` Display name - `object: "post_status"` Object type identifier - `"post_status"` - `type: "reviewing" or "unstarted" or "active" or 2 more` The workflow stage this status represents - `"reviewing"` - `"unstarted"` - `"active"` - `"completed"` - `"canceled"` - `teamAssigneeId: string` Assigned team ID (from linked conversation) - `ticketCategoryId: string` Ticket category ID - `ticketNumber: number` Sequential display ID (e.g. TK-42) - `ticketUrl: string` Full URL to view the ticket - `title: string` Ticket title - `updatedAt: string` ISO 8601 last updated timestamp - `conversationParts: optional array of ConversationPart` Conversation message history. Only included when fetching a single ticket by ID. - `UserMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Message from a customer or lead - `id: string` Unique part identifier - `bodyHtml: string` Message body content as HTML with signed image URLs - `bodyMarkdown: string` Message body content as markdown - `channel: "unknown" or "desktop" or "android" or 2 more` Channel through which the message was sent - `"unknown"` - `"desktop"` - `"android"` - `"ios"` - `"email"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "user_msg"` User message type - `"user_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `id: string` Author ID - `type: "customer" or "lead" or "admin" or 3 more` Type of author - `"customer"` - `"lead"` - `"admin"` - `"bot"` - `"guest"` - `"integration"` - `email: optional string` Author email address - `name: optional string` Author display name - `profilePicture: optional string` Author profile picture URL - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `type: "admin" or "customer" or "lead" or 4 more` Actor that caused the tag mutation - `"admin"` - `"customer"` - `"lead"` - `"bot"` - `"integration"` - `"system"` - `"workflow"` - `id: optional string` Actor identifier when available - `name: optional string` Actor display name when available - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `id: string` Unique tag identifier - `name: string` Current tag name - `type: "tag"` Object type identifier for a tag - `"tag"` - `AdminMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Message from an admin or support agent - `id: string` Unique part identifier - `bodyHtml: string` Message body content as HTML with signed image URLs - `bodyMarkdown: string` Message body content as markdown - `channel: "unknown" or "desktop" or "android" or 2 more` Channel through which the message was sent - `"unknown"` - `"desktop"` - `"android"` - `"ios"` - `"email"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "admin_msg"` Admin message type - `"admin_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `AdminNote object { id, bodyHtml, bodyMarkdown, 7 more }` Internal note visible only to admins - `id: string` Unique part identifier - `bodyHtml: string` Note body content as HTML with signed image URLs - `bodyMarkdown: string` Note body content as markdown - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "admin_note"` Admin internal note type - `"admin_note"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `EmailMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Message sent via email - `id: string` Unique part identifier - `bodyHtml: string` Email body content as HTML with signed image URLs - `bodyMarkdown: string` Email body content as markdown - `channel: "email"` Email channel - `"email"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "email_msg"` Email message type - `"email_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `BotMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Automated message from AI or bot - `id: string` Unique part identifier - `bodyHtml: string` Bot message body content as HTML with signed image URLs - `bodyMarkdown: string` Bot message body content as markdown - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "bot_msg"` Bot message type - `"bot_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `channel: optional "unknown" or "desktop" or "android" or 2 more` Channel through which the message was sent - `"unknown"` - `"desktop"` - `"android"` - `"ios"` - `"email"` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `QuickReplyOpts object { id, createdAt, object, 6 more }` Presents options for user to choose from - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "quick_reply_opts"` Quick reply options type - `"quick_reply_opts"` - `replyOptions: array of object { id, text }` Available reply options - `id: string` Option ID - `text: string` Option text - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `QuickReplyResp object { id, bodyHtml, bodyMarkdown, 8 more }` User's selection from quick reply options - `id: string` Unique part identifier - `bodyHtml: string` The selected option text as HTML - `bodyMarkdown: string` The selected option text as markdown - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "quick_reply_resp"` Quick reply response type - `"quick_reply_resp"` - `selectedOptionId: string` ID of the selected option - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `RatingRequested object { id, createdAt, csat, 3 more }` Represents a persisted CSAT request in the conversation thread - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `csat: object { channel, requestedAt, requestId, 7 more }` Canonical CSAT request payload for this thread event - `channel: "desktop" or "email"` Channel used for the CSAT request - `"desktop"` - `"email"` - `requestedAt: string` ISO timestamp when the request was created - `requestId: string` Canonical CSAT request ID - `requestSource: "workflow"` Source that created the CSAT request - `"workflow"` - `status: "pending" or "rated" or "canceled" or "expired"` Status of the CSAT request represented by this part - `"pending"` - `"rated"` - `"canceled"` - `"expired"` - `changeLockWindowEndsAt: optional string` ISO timestamp after which changing the rating is no longer allowed - `expiredAt: optional string` ISO timestamp when the request expired, when applicable - `lateSubmitWindowEndsAt: optional string` ISO timestamp after which late submission is no longer allowed - `ratedAgent: optional CsatRatedAgent` - `type: "teammate" or "fibi" or "chatbot"` Type of agent the CSAT request is attributed to - `"teammate"` - `"fibi"` - `"chatbot"` - `id: optional string` Identifier of the rated agent when applicable - `workflow: optional CsatWorkflowLink` - `workflowActionId: optional string` Workflow action ID associated with the CSAT request - `workflowId: optional string` Workflow ID associated with the CSAT request - `workflowRunId: optional string` Workflow run ID associated with the CSAT request - `workflowStepId: optional string` Workflow step ID associated with the CSAT request - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "rating_requested"` CSAT rating requested part type - `"rating_requested"` - `updatedAt: string` ISO timestamp when the part was last updated - `RatingSubmitted object { id, createdAt, csat, 3 more }` Represents a persisted CSAT submission in the conversation thread - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `csat: object { channel, ratedAt, requestId, 7 more }` Canonical CSAT submission payload for this thread event - `channel: "desktop" or "email"` Channel used for the CSAT request - `"desktop"` - `"email"` - `ratedAt: string` ISO timestamp when the customer submitted the rating - `requestId: string` Canonical CSAT request ID - `requestSource: "workflow"` Source that created the CSAT request - `"workflow"` - `score: number` CSAT score from 1 to 5 - `status: "rated"` Submitted ratings are always in the rated state - `"rated"` - `ratedAgent: optional CsatRatedAgent` - `remark: optional string` Optional remark left with the rating - `requestedAt: optional string` ISO timestamp when the request was created - `workflow: optional CsatWorkflowLink` - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "rating_submitted"` CSAT rating submitted part type - `"rating_submitted"` - `updatedAt: string` ISO timestamp when the part was last updated - `AttrPrompt object { id, createdAt, form, 6 more }` Requests information from user via form - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `form: object { id, attributes }` Form configuration - `id: string` Form ID - `attributes: array of object { identifier, name, type }` Form fields - `identifier: string` Field identifier - `name: string` Field display name - `type: string` Field type - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "attr_prompt"` Attribute collection prompt type - `"attr_prompt"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `AttrComplete object { id, createdAt, object, 2 more }` Indicates form was completed - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "attr_complete"` Attribute collection complete type - `"attr_complete"` - `updatedAt: string` ISO timestamp when the part was last updated - `Assign object { id, createdAt, object, 5 more }` Conversation assigned to admin or team - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "assign"` Assignment type - `"assign"` - `updatedAt: string` ISO timestamp when the part was last updated - `adminAssigneeId: optional string` ID of the admin assigned to the conversation - `adminAssignerId: optional string` ID of the admin who made the assignment - `teamAssigneeId: optional string` ID of the team assigned to the conversation - `Status object { id, createdAt, object, 4 more }` Conversation state changed (open/closed/snoozed) - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "status"` Status change type - `"status"` - `status: "open" or "closed" or "snoozed"` New conversation status - `"open"` - `"closed"` - `"snoozed"` - `updatedAt: string` ISO timestamp when the part was last updated - `snoozedUntil: optional string` ISO timestamp until conversation is snoozed (if snoozed) - `Tags object { id, action, createdAt, 8 more }` A tag was added to or removed from a specific reply - `id: string` Unique part identifier - `action: "added" or "removed"` Whether the tag was added or removed - `"added"` - `"removed"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `occurredAt: string` ISO timestamp when the tag mutation occurred - `partType: "tags"` Tag update type - `"tags"` - `tagId: string` Identifier of the affected tag - `updatedAt: string` ISO timestamp when the part was last updated - `actor: optional ConversationTagMutationActor` Actor that applied the tag - `tagName: optional string` Tag name at the time of the event or the best available current display name - `targetPartId: optional string` Conversation part that the tag mutation targeted - `WorkflowWait object { id, createdAt, object, 3 more }` Represents a workflow wait start, finish, or interruption in the conversation thread - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "workflow_wait"` Workflow wait event part type - `"workflow_wait"` - `updatedAt: string` ISO timestamp when the part was last updated - `workflowWait: object { eventType, occurredAt, interruptedByUserType, 3 more }` Workflow wait event payload for this thread event - `eventType: "started" or "finished" or "interrupted"` Lifecycle stage of the workflow wait event - `"started"` - `"finished"` - `"interrupted"` - `occurredAt: string` ISO timestamp when the wait event occurred - `interruptedByUserType: optional "admin" or "customer" or "lead"` User type that interrupted the wait when applicable - `"admin"` - `"customer"` - `"lead"` - `waitLabel: optional string` Human-readable wait duration or preset label - `workflowId: optional string` Workflow ID associated with the wait event - `workflowName: optional string` Workflow display name at the time of the wait event - `Priority object { id, createdAt, isPriority, 3 more }` Conversation priority was updated - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `isPriority: boolean` Whether the conversation is now marked as priority - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "priority"` Priority change type - `"priority"` - `updatedAt: string` ISO timestamp when the part was last updated - `PartAdd object { id, createdAt, object, 3 more }` New participant joined the conversation - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `participant: object { id, type }` The added participant - `id: string` Participant ID - `type: "customer" or "lead" or "admin"` Participant type - `"customer"` - `"lead"` - `"admin"` - `partType: "part_add"` Participant added type - `"part_add"` - `updatedAt: string` ISO timestamp when the part was last updated ### Example ```http curl https://do.featurebase.app/v2/tickets/$ID \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "id": "507f1f77bcf86cd799439011", "assigneeId": "507f1f77bcf86cd799439013", "author": { "id": "507f1f77bcf86cd799439011", "email": "john@example.com", "name": "John Doe", "profilePicture": "https://cdn.example.com/avatars/john.png", "type": "customer" }, "categoryType": "customer", "companyId": "507f1f77bcf86cd799439015", "content": "I get a 403 error when logging in.
", "createdAt": "2025-01-15T10:30:00.000Z", "customFields": { "priority": "bar", "507f1f77bcf86cd799439099": "bar" }, "integrations": { "clickup": [ { "id": "86a1b2c3d", "title": "Fix login bug", "url": "https://app.clickup.com/t/86a1b2c3d" } ], "devops": [ { "id": 789, "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "projectName": "My Project", "title": "Implement SSO", "url": "https://dev.azure.com/org/project/_workitems/edit/789" } ], "github": [ { "id": "1234567890", "number": "42", "repositoryFullName": "acme/frontend", "repositoryName": "frontend", "title": "Login page returns 403", "url": "https://github.com/acme/frontend/issues/42" } ], "hubspot": [ { "dealAmount": 5000, "dealClosed": false, "objectId": 12345, "type": "DEAL" } ], "jira": [ { "issueId": "PROJ-456", "issueUrl": "https://company.atlassian.net/browse/PROJ-456" } ], "linear": [ { "issueId": "LIN-123", "issueUrl": "https://linear.app/team/issue/LIN-123" } ] }, "linkedConversations": [ { "id": "507f1f77bcf86cd799439011", "role": "customer" } ], "object": "ticket", "open": true, "snoozedUntil": "2025-01-16T09:00:00.000Z", "status": { "id": "507f1f77bcf86cd799439011", "color": "Blue", "isDefault": false, "name": "In Progress", "object": "post_status", "type": "active" }, "teamAssigneeId": "507f1f77bcf86cd799439014", "ticketCategoryId": "507f1f77bcf86cd799439011", "ticketNumber": 42, "ticketUrl": "https://feedback.example.com/p/cannot-login", "title": "Cannot login to dashboard", "updatedAt": "2025-01-15T12:30:00.000Z", "conversationParts": [ { "id": "1", "bodyHtml": "Hello, I have a question about your product.
", "bodyMarkdown": "Hello, I have a question about your product.", "channel": "desktop", "createdAt": "2025-01-15T10:30:00.000Z", "object": "conversation_part", "partType": "user_msg", "updatedAt": "2025-01-15T10:30:00.000Z", "author": { "id": "676f0f6765bdaa7d7d760f88", "type": "customer", "email": "john@example.com", "name": "John Doe", "profilePicture": "https://cdn.example.com/avatars/user.png" }, "redacted": false, "tagApplications": [ { "appliedAt": "2025-01-15T10:30:00.000Z", "tagId": "67ec1234abcd5678ef901234", "appliedBy": { "type": "admin", "id": "507f1f77bcf86cd799439011", "name": "John Doe" }, "removedAt": "2025-01-15T11:00:00.000Z", "removedBy": { "type": "admin", "id": "507f1f77bcf86cd799439011", "name": "John Doe" }, "tag": { "id": "67ec1234abcd5678ef901234", "name": "Churn", "type": "tag" } } ] } ] } ``` ## Update a ticket **patch** `/v2/tickets/{id}` Updates a ticket's properties. Only provided fields will be updated. ### Path Parameters - `id` - The ticket number ### Request Body All fields are optional. | Field | Type | Description | | ------------------- | ----------- | -------------------------------------------------- | | `title` | string | Update title | | `content` | string | Update description (HTML) | | `statusId` | string | Set status by ID | | `open` | boolean | Close (false) or reopen (true) the ticket | | `assigneeId` | string/null | Assign/unassign admin | | `companyId` | string/null | Update company association | | `customFields` | object | Update custom field values | | `snoozedUntil` | string/null | Snooze until ISO 8601 timestamp (null to unsnooze) | | `skipNotifications` | boolean | Skip notifications (default false) | ### Closing a Ticket Set `open: false` to close the ticket. Closing a ticket will also unsnooze it. The status is not changed automatically — use `statusId` to change the status explicitly. ### File Custom Fields File-type custom fields support the same two upload methods as ticket creation: multipart upload (`customFields.Updated description.
", "snoozedUntil": "2025-01-16T09:00:00.000Z", "statusId": "507f1f77bcf86cd799439016", "title": "Updated ticket title" }' ``` #### Response ```json { "id": "507f1f77bcf86cd799439011", "assigneeId": "507f1f77bcf86cd799439013", "author": { "id": "507f1f77bcf86cd799439011", "email": "john@example.com", "name": "John Doe", "profilePicture": "https://cdn.example.com/avatars/john.png", "type": "customer" }, "categoryType": "customer", "companyId": "507f1f77bcf86cd799439015", "content": "I get a 403 error when logging in.
", "createdAt": "2025-01-15T10:30:00.000Z", "customFields": { "priority": "bar", "507f1f77bcf86cd799439099": "bar" }, "integrations": { "clickup": [ { "id": "86a1b2c3d", "title": "Fix login bug", "url": "https://app.clickup.com/t/86a1b2c3d" } ], "devops": [ { "id": 789, "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "projectName": "My Project", "title": "Implement SSO", "url": "https://dev.azure.com/org/project/_workitems/edit/789" } ], "github": [ { "id": "1234567890", "number": "42", "repositoryFullName": "acme/frontend", "repositoryName": "frontend", "title": "Login page returns 403", "url": "https://github.com/acme/frontend/issues/42" } ], "hubspot": [ { "dealAmount": 5000, "dealClosed": false, "objectId": 12345, "type": "DEAL" } ], "jira": [ { "issueId": "PROJ-456", "issueUrl": "https://company.atlassian.net/browse/PROJ-456" } ], "linear": [ { "issueId": "LIN-123", "issueUrl": "https://linear.app/team/issue/LIN-123" } ] }, "linkedConversations": [ { "id": "507f1f77bcf86cd799439011", "role": "customer" } ], "object": "ticket", "open": true, "snoozedUntil": "2025-01-16T09:00:00.000Z", "status": { "id": "507f1f77bcf86cd799439011", "color": "Blue", "isDefault": false, "name": "In Progress", "object": "post_status", "type": "active" }, "teamAssigneeId": "507f1f77bcf86cd799439014", "ticketCategoryId": "507f1f77bcf86cd799439011", "ticketNumber": 42, "ticketUrl": "https://feedback.example.com/p/cannot-login", "title": "Cannot login to dashboard", "updatedAt": "2025-01-15T12:30:00.000Z", "conversationParts": [ { "id": "1", "bodyHtml": "Hello, I have a question about your product.
", "bodyMarkdown": "Hello, I have a question about your product.", "channel": "desktop", "createdAt": "2025-01-15T10:30:00.000Z", "object": "conversation_part", "partType": "user_msg", "updatedAt": "2025-01-15T10:30:00.000Z", "author": { "id": "676f0f6765bdaa7d7d760f88", "type": "customer", "email": "john@example.com", "name": "John Doe", "profilePicture": "https://cdn.example.com/avatars/user.png" }, "redacted": false, "tagApplications": [ { "appliedAt": "2025-01-15T10:30:00.000Z", "tagId": "67ec1234abcd5678ef901234", "appliedBy": { "type": "admin", "id": "507f1f77bcf86cd799439011", "name": "John Doe" }, "removedAt": "2025-01-15T11:00:00.000Z", "removedBy": { "type": "admin", "id": "507f1f77bcf86cd799439011", "name": "John Doe" }, "tag": { "id": "67ec1234abcd5678ef901234", "name": "Churn", "type": "tag" } } ] } ] } ``` ## Delete a ticket **delete** `/v2/tickets/{id}` Permanently deletes a ticket by its ticket number. ### Path Parameters - `id` - The ticket number ### Response Returns a deletion confirmation: ```json { "id": "507f1f77bcf86cd799439011", "object": "ticket", "deleted": true } ``` ### Behavior - **Customer-facing tickets**: Deletes the ticket and its linked conversation. - **Back-office / tracker tickets**: Deletes the ticket and unlinks it from the conversation (conversation is preserved). ### Caution This operation is **irreversible**. ### Path Parameters - `id: number` ### 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 deleted ticket - `deleted: true` Indicates the resource was deleted - `true` - `object: "ticket"` Object type identifier - `"ticket"` ### Example ```http curl https://do.featurebase.app/v2/tickets/$ID \ -X DELETE \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "id": "507f1f77bcf86cd799439011", "deleted": true, "object": "ticket" } ``` ## Reply to a ticket **post** `/v2/tickets/{id}/reply` Adds a reply to a ticket's linked conversation. Supports both contact and admin replies. ### Path Parameters - `id` - The ticket number ### Contact Reply | Field | Type | Required | Description | | ------------------- | -------- | -------- | ---------------------------------------- | | `type` | string | Yes | Must be "contact" | | `contactId` | string | No* | Featurebase contact ID | | `contactEmail` | string | No* | Contact email | | `body` | string | Yes | Message content (HTML) | | `messageType` | string | No | Always "comment" for contacts | | `attachmentUrls` | string[] | No | Attachment URLs (max 10) | | `skipNotifications` | boolean | No | Skip notifications (default false) | | `createdAt` | string | No | ISO 8601 timestamp to backdate the reply | \*At least one of `contactId` or `contactEmail` is required. ### Admin Reply | Field | Type | Required | Description | | ------------------- | -------- | -------- | ------------------------------------------------ | | `type` | string | Yes | Must be "admin" | | `adminId` | string | Yes | ID of the admin authoring the reply | | `body` | string | Yes | Message content (HTML) | | `messageType` | string | No | "comment" (default) or "note" for internal notes | | `attachmentUrls` | string[] | No | Attachment URLs (max 10) | | `skipNotifications` | boolean | No | Skip notifications (default false) | | `createdAt` | string | No | ISO 8601 timestamp to backdate the reply | ### Response Returns a reply confirmation object. ### Path Parameters - `id: number` ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Body Parameters - `body: object { body, type, attachmentUrls, 5 more } or object { adminId, body, type, 4 more }` - `object { body, type, attachmentUrls, 5 more }` - `body: string` - `type: "contact"` - `"contact"` - `attachmentUrls: optional array of string` - `contactEmail: optional string` - `contactId: optional string` - `createdAt: optional string` - `messageType: optional "comment"` - `"comment"` - `skipNotifications: optional boolean` - `object { adminId, body, type, 4 more }` - `adminId: string` - `body: string` - `type: "admin"` - `"admin"` - `attachmentUrls: optional array of string` - `createdAt: optional string` - `messageType: optional "comment" or "note"` - `"comment"` - `"note"` - `skipNotifications: optional boolean` ### Returns - `Ticket object { id, assigneeId, author, 18 more }` - `id: string` Unique identifier (MongoDB ID) - `assigneeId: string` Assigned admin ID - `author: object { id, email, name, 2 more }` Contact who created the ticket - `id: string` Author unique identifier - `email: string` Author email - `name: string` Author display name - `profilePicture: string` Author profile picture URL - `type: "admin" or "customer" or "guest" or 3 more` Type of user - `"admin"` - `"customer"` - `"guest"` - `"integration"` - `"bot"` - `"lead"` - `categoryType: "customer" or "tracker" or "back-office"` Ticket category type - `"customer"` - `"tracker"` - `"back-office"` - `companyId: string` Associated company ID - `content: string` Ticket content/description (HTML) - `createdAt: string` ISO 8601 creation timestamp - `customFields: map[unknown]` Custom field values keyed by field ID. File-type fields contain a JSON string of { key, name, url } with a signed download URL (1 hour expiry). For allowMultiple file fields, the value is a JSON string of an array of these objects. - `integrations: object { clickup, devops, github, 3 more }` Third-party integration links - `clickup: array of object { id, title, url }` - `id: string` ClickUp task ID - `title: string` ClickUp task title - `url: string` URL to the ClickUp task - `devops: array of object { id, projectId, projectName, 2 more }` - `id: number` Azure DevOps work item ID - `projectId: string` Azure DevOps project ID - `projectName: string` Azure DevOps project name - `title: string` Work item title - `url: string` URL to the work item - `github: array of object { id, number, repositoryFullName, 3 more }` - `id: string` GitHub issue ID - `number: string` GitHub issue number - `repositoryFullName: string` Full repository name (owner/repo) - `repositoryName: string` Repository name - `title: string` GitHub issue title - `url: string` URL to the GitHub issue - `hubspot: array of object { dealAmount, dealClosed, objectId, type }` - `dealAmount: number` Deal amount (for DEAL type) - `dealClosed: boolean` Whether the deal is closed (for DEAL type) - `objectId: number` HubSpot object ID - `type: "TICKET" or "DEAL" or "CONTACT"` HubSpot object type - `"TICKET"` - `"DEAL"` - `"CONTACT"` - `jira: array of object { issueId, issueUrl }` - `issueId: string` Jira issue ID - `issueUrl: string` URL to the Jira issue - `linear: array of object { issueId, issueUrl }` - `issueId: string` Linear issue ID - `issueUrl: string` URL to the Linear issue - `linkedConversations: array of object { id, role }` Linked conversations - `id: string` Conversation ID - `role: "customer" or "tracker" or "back-office"` Link role - `"customer"` - `"tracker"` - `"back-office"` - `object: "ticket"` Object type identifier - `"ticket"` - `open: boolean` Whether the ticket is open - `snoozedUntil: string` ISO 8601 timestamp until snoozed (from linked conversation) - `status: PostStatus` Current ticket status - `id: string` Unique identifier - `color: string` Color for UI display - `isDefault: boolean` Whether this is the default status for new posts - `name: string` Display name - `object: "post_status"` Object type identifier - `"post_status"` - `type: "reviewing" or "unstarted" or "active" or 2 more` The workflow stage this status represents - `"reviewing"` - `"unstarted"` - `"active"` - `"completed"` - `"canceled"` - `teamAssigneeId: string` Assigned team ID (from linked conversation) - `ticketCategoryId: string` Ticket category ID - `ticketNumber: number` Sequential display ID (e.g. TK-42) - `ticketUrl: string` Full URL to view the ticket - `title: string` Ticket title - `updatedAt: string` ISO 8601 last updated timestamp - `conversationParts: optional array of ConversationPart` Conversation message history. Only included when fetching a single ticket by ID. - `UserMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Message from a customer or lead - `id: string` Unique part identifier - `bodyHtml: string` Message body content as HTML with signed image URLs - `bodyMarkdown: string` Message body content as markdown - `channel: "unknown" or "desktop" or "android" or 2 more` Channel through which the message was sent - `"unknown"` - `"desktop"` - `"android"` - `"ios"` - `"email"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "user_msg"` User message type - `"user_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `id: string` Author ID - `type: "customer" or "lead" or "admin" or 3 more` Type of author - `"customer"` - `"lead"` - `"admin"` - `"bot"` - `"guest"` - `"integration"` - `email: optional string` Author email address - `name: optional string` Author display name - `profilePicture: optional string` Author profile picture URL - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `type: "admin" or "customer" or "lead" or 4 more` Actor that caused the tag mutation - `"admin"` - `"customer"` - `"lead"` - `"bot"` - `"integration"` - `"system"` - `"workflow"` - `id: optional string` Actor identifier when available - `name: optional string` Actor display name when available - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `id: string` Unique tag identifier - `name: string` Current tag name - `type: "tag"` Object type identifier for a tag - `"tag"` - `AdminMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Message from an admin or support agent - `id: string` Unique part identifier - `bodyHtml: string` Message body content as HTML with signed image URLs - `bodyMarkdown: string` Message body content as markdown - `channel: "unknown" or "desktop" or "android" or 2 more` Channel through which the message was sent - `"unknown"` - `"desktop"` - `"android"` - `"ios"` - `"email"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "admin_msg"` Admin message type - `"admin_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `AdminNote object { id, bodyHtml, bodyMarkdown, 7 more }` Internal note visible only to admins - `id: string` Unique part identifier - `bodyHtml: string` Note body content as HTML with signed image URLs - `bodyMarkdown: string` Note body content as markdown - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "admin_note"` Admin internal note type - `"admin_note"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `EmailMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Message sent via email - `id: string` Unique part identifier - `bodyHtml: string` Email body content as HTML with signed image URLs - `bodyMarkdown: string` Email body content as markdown - `channel: "email"` Email channel - `"email"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "email_msg"` Email message type - `"email_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `BotMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Automated message from AI or bot - `id: string` Unique part identifier - `bodyHtml: string` Bot message body content as HTML with signed image URLs - `bodyMarkdown: string` Bot message body content as markdown - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "bot_msg"` Bot message type - `"bot_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `channel: optional "unknown" or "desktop" or "android" or 2 more` Channel through which the message was sent - `"unknown"` - `"desktop"` - `"android"` - `"ios"` - `"email"` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `QuickReplyOpts object { id, createdAt, object, 6 more }` Presents options for user to choose from - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "quick_reply_opts"` Quick reply options type - `"quick_reply_opts"` - `replyOptions: array of object { id, text }` Available reply options - `id: string` Option ID - `text: string` Option text - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `QuickReplyResp object { id, bodyHtml, bodyMarkdown, 8 more }` User's selection from quick reply options - `id: string` Unique part identifier - `bodyHtml: string` The selected option text as HTML - `bodyMarkdown: string` The selected option text as markdown - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "quick_reply_resp"` Quick reply response type - `"quick_reply_resp"` - `selectedOptionId: string` ID of the selected option - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `RatingRequested object { id, createdAt, csat, 3 more }` Represents a persisted CSAT request in the conversation thread - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `csat: object { channel, requestedAt, requestId, 7 more }` Canonical CSAT request payload for this thread event - `channel: "desktop" or "email"` Channel used for the CSAT request - `"desktop"` - `"email"` - `requestedAt: string` ISO timestamp when the request was created - `requestId: string` Canonical CSAT request ID - `requestSource: "workflow"` Source that created the CSAT request - `"workflow"` - `status: "pending" or "rated" or "canceled" or "expired"` Status of the CSAT request represented by this part - `"pending"` - `"rated"` - `"canceled"` - `"expired"` - `changeLockWindowEndsAt: optional string` ISO timestamp after which changing the rating is no longer allowed - `expiredAt: optional string` ISO timestamp when the request expired, when applicable - `lateSubmitWindowEndsAt: optional string` ISO timestamp after which late submission is no longer allowed - `ratedAgent: optional CsatRatedAgent` - `type: "teammate" or "fibi" or "chatbot"` Type of agent the CSAT request is attributed to - `"teammate"` - `"fibi"` - `"chatbot"` - `id: optional string` Identifier of the rated agent when applicable - `workflow: optional CsatWorkflowLink` - `workflowActionId: optional string` Workflow action ID associated with the CSAT request - `workflowId: optional string` Workflow ID associated with the CSAT request - `workflowRunId: optional string` Workflow run ID associated with the CSAT request - `workflowStepId: optional string` Workflow step ID associated with the CSAT request - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "rating_requested"` CSAT rating requested part type - `"rating_requested"` - `updatedAt: string` ISO timestamp when the part was last updated - `RatingSubmitted object { id, createdAt, csat, 3 more }` Represents a persisted CSAT submission in the conversation thread - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `csat: object { channel, ratedAt, requestId, 7 more }` Canonical CSAT submission payload for this thread event - `channel: "desktop" or "email"` Channel used for the CSAT request - `"desktop"` - `"email"` - `ratedAt: string` ISO timestamp when the customer submitted the rating - `requestId: string` Canonical CSAT request ID - `requestSource: "workflow"` Source that created the CSAT request - `"workflow"` - `score: number` CSAT score from 1 to 5 - `status: "rated"` Submitted ratings are always in the rated state - `"rated"` - `ratedAgent: optional CsatRatedAgent` - `remark: optional string` Optional remark left with the rating - `requestedAt: optional string` ISO timestamp when the request was created - `workflow: optional CsatWorkflowLink` - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "rating_submitted"` CSAT rating submitted part type - `"rating_submitted"` - `updatedAt: string` ISO timestamp when the part was last updated - `AttrPrompt object { id, createdAt, form, 6 more }` Requests information from user via form - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `form: object { id, attributes }` Form configuration - `id: string` Form ID - `attributes: array of object { identifier, name, type }` Form fields - `identifier: string` Field identifier - `name: string` Field display name - `type: string` Field type - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "attr_prompt"` Attribute collection prompt type - `"attr_prompt"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `AttrComplete object { id, createdAt, object, 2 more }` Indicates form was completed - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "attr_complete"` Attribute collection complete type - `"attr_complete"` - `updatedAt: string` ISO timestamp when the part was last updated - `Assign object { id, createdAt, object, 5 more }` Conversation assigned to admin or team - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "assign"` Assignment type - `"assign"` - `updatedAt: string` ISO timestamp when the part was last updated - `adminAssigneeId: optional string` ID of the admin assigned to the conversation - `adminAssignerId: optional string` ID of the admin who made the assignment - `teamAssigneeId: optional string` ID of the team assigned to the conversation - `Status object { id, createdAt, object, 4 more }` Conversation state changed (open/closed/snoozed) - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "status"` Status change type - `"status"` - `status: "open" or "closed" or "snoozed"` New conversation status - `"open"` - `"closed"` - `"snoozed"` - `updatedAt: string` ISO timestamp when the part was last updated - `snoozedUntil: optional string` ISO timestamp until conversation is snoozed (if snoozed) - `Tags object { id, action, createdAt, 8 more }` A tag was added to or removed from a specific reply - `id: string` Unique part identifier - `action: "added" or "removed"` Whether the tag was added or removed - `"added"` - `"removed"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `occurredAt: string` ISO timestamp when the tag mutation occurred - `partType: "tags"` Tag update type - `"tags"` - `tagId: string` Identifier of the affected tag - `updatedAt: string` ISO timestamp when the part was last updated - `actor: optional ConversationTagMutationActor` Actor that applied the tag - `tagName: optional string` Tag name at the time of the event or the best available current display name - `targetPartId: optional string` Conversation part that the tag mutation targeted - `WorkflowWait object { id, createdAt, object, 3 more }` Represents a workflow wait start, finish, or interruption in the conversation thread - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "workflow_wait"` Workflow wait event part type - `"workflow_wait"` - `updatedAt: string` ISO timestamp when the part was last updated - `workflowWait: object { eventType, occurredAt, interruptedByUserType, 3 more }` Workflow wait event payload for this thread event - `eventType: "started" or "finished" or "interrupted"` Lifecycle stage of the workflow wait event - `"started"` - `"finished"` - `"interrupted"` - `occurredAt: string` ISO timestamp when the wait event occurred - `interruptedByUserType: optional "admin" or "customer" or "lead"` User type that interrupted the wait when applicable - `"admin"` - `"customer"` - `"lead"` - `waitLabel: optional string` Human-readable wait duration or preset label - `workflowId: optional string` Workflow ID associated with the wait event - `workflowName: optional string` Workflow display name at the time of the wait event - `Priority object { id, createdAt, isPriority, 3 more }` Conversation priority was updated - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `isPriority: boolean` Whether the conversation is now marked as priority - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "priority"` Priority change type - `"priority"` - `updatedAt: string` ISO timestamp when the part was last updated - `PartAdd object { id, createdAt, object, 3 more }` New participant joined the conversation - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `participant: object { id, type }` The added participant - `id: string` Participant ID - `type: "customer" or "lead" or "admin"` Participant type - `"customer"` - `"lead"` - `"admin"` - `partType: "part_add"` Participant added type - `"part_add"` - `updatedAt: string` ISO timestamp when the part was last updated ### Example ```http curl https://do.featurebase.app/v2/tickets/$ID/reply \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" \ -d '{ "body": "Thank you for your help!
", "type": "contact", "contactEmail": "john@example.com", "contactId": "507f1f77bcf86cd799439011", "createdAt": "2025-01-15T10:30:00.000Z", "messageType": "comment" }' ``` #### Response ```json { "id": "507f1f77bcf86cd799439011", "assigneeId": "507f1f77bcf86cd799439013", "author": { "id": "507f1f77bcf86cd799439011", "email": "john@example.com", "name": "John Doe", "profilePicture": "https://cdn.example.com/avatars/john.png", "type": "customer" }, "categoryType": "customer", "companyId": "507f1f77bcf86cd799439015", "content": "I get a 403 error when logging in.
", "createdAt": "2025-01-15T10:30:00.000Z", "customFields": { "priority": "bar", "507f1f77bcf86cd799439099": "bar" }, "integrations": { "clickup": [ { "id": "86a1b2c3d", "title": "Fix login bug", "url": "https://app.clickup.com/t/86a1b2c3d" } ], "devops": [ { "id": 789, "projectId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "projectName": "My Project", "title": "Implement SSO", "url": "https://dev.azure.com/org/project/_workitems/edit/789" } ], "github": [ { "id": "1234567890", "number": "42", "repositoryFullName": "acme/frontend", "repositoryName": "frontend", "title": "Login page returns 403", "url": "https://github.com/acme/frontend/issues/42" } ], "hubspot": [ { "dealAmount": 5000, "dealClosed": false, "objectId": 12345, "type": "DEAL" } ], "jira": [ { "issueId": "PROJ-456", "issueUrl": "https://company.atlassian.net/browse/PROJ-456" } ], "linear": [ { "issueId": "LIN-123", "issueUrl": "https://linear.app/team/issue/LIN-123" } ] }, "linkedConversations": [ { "id": "507f1f77bcf86cd799439011", "role": "customer" } ], "object": "ticket", "open": true, "snoozedUntil": "2025-01-16T09:00:00.000Z", "status": { "id": "507f1f77bcf86cd799439011", "color": "Blue", "isDefault": false, "name": "In Progress", "object": "post_status", "type": "active" }, "teamAssigneeId": "507f1f77bcf86cd799439014", "ticketCategoryId": "507f1f77bcf86cd799439011", "ticketNumber": 42, "ticketUrl": "https://feedback.example.com/p/cannot-login", "title": "Cannot login to dashboard", "updatedAt": "2025-01-15T12:30:00.000Z", "conversationParts": [ { "id": "1", "bodyHtml": "Hello, I have a question about your product.
", "bodyMarkdown": "Hello, I have a question about your product.", "channel": "desktop", "createdAt": "2025-01-15T10:30:00.000Z", "object": "conversation_part", "partType": "user_msg", "updatedAt": "2025-01-15T10:30:00.000Z", "author": { "id": "676f0f6765bdaa7d7d760f88", "type": "customer", "email": "john@example.com", "name": "John Doe", "profilePicture": "https://cdn.example.com/avatars/user.png" }, "redacted": false, "tagApplications": [ { "appliedAt": "2025-01-15T10:30:00.000Z", "tagId": "67ec1234abcd5678ef901234", "appliedBy": { "type": "admin", "id": "507f1f77bcf86cd799439011", "name": "John Doe" }, "removedAt": "2025-01-15T11:00:00.000Z", "removedBy": { "type": "admin", "id": "507f1f77bcf86cd799439011", "name": "John Doe" }, "tag": { "id": "67ec1234abcd5678ef901234", "name": "Churn", "type": "tag" } } ] } ] } ``` ## Domain Types ### Author Input - `AuthorInput object { id, email, name, 2 more }` Author to attribute the post to. If not provided, uses the authenticated user. Supports multiple identification methods: id (Featurebase ID), userId (external SSO ID), or email. - `id: optional string` Featurebase user ID to attribute content to - `email: optional string` Author email (used to find or create user) - `name: optional string` Author display name - `profilePicture: optional string` Author profile picture URL - `userId: optional string` External user ID from your system (matched via SSO) ### Ticket - `Ticket object { id, assigneeId, author, 18 more }` - `id: string` Unique identifier (MongoDB ID) - `assigneeId: string` Assigned admin ID - `author: object { id, email, name, 2 more }` Contact who created the ticket - `id: string` Author unique identifier - `email: string` Author email - `name: string` Author display name - `profilePicture: string` Author profile picture URL - `type: "admin" or "customer" or "guest" or 3 more` Type of user - `"admin"` - `"customer"` - `"guest"` - `"integration"` - `"bot"` - `"lead"` - `categoryType: "customer" or "tracker" or "back-office"` Ticket category type - `"customer"` - `"tracker"` - `"back-office"` - `companyId: string` Associated company ID - `content: string` Ticket content/description (HTML) - `createdAt: string` ISO 8601 creation timestamp - `customFields: map[unknown]` Custom field values keyed by field ID. File-type fields contain a JSON string of { key, name, url } with a signed download URL (1 hour expiry). For allowMultiple file fields, the value is a JSON string of an array of these objects. - `integrations: object { clickup, devops, github, 3 more }` Third-party integration links - `clickup: array of object { id, title, url }` - `id: string` ClickUp task ID - `title: string` ClickUp task title - `url: string` URL to the ClickUp task - `devops: array of object { id, projectId, projectName, 2 more }` - `id: number` Azure DevOps work item ID - `projectId: string` Azure DevOps project ID - `projectName: string` Azure DevOps project name - `title: string` Work item title - `url: string` URL to the work item - `github: array of object { id, number, repositoryFullName, 3 more }` - `id: string` GitHub issue ID - `number: string` GitHub issue number - `repositoryFullName: string` Full repository name (owner/repo) - `repositoryName: string` Repository name - `title: string` GitHub issue title - `url: string` URL to the GitHub issue - `hubspot: array of object { dealAmount, dealClosed, objectId, type }` - `dealAmount: number` Deal amount (for DEAL type) - `dealClosed: boolean` Whether the deal is closed (for DEAL type) - `objectId: number` HubSpot object ID - `type: "TICKET" or "DEAL" or "CONTACT"` HubSpot object type - `"TICKET"` - `"DEAL"` - `"CONTACT"` - `jira: array of object { issueId, issueUrl }` - `issueId: string` Jira issue ID - `issueUrl: string` URL to the Jira issue - `linear: array of object { issueId, issueUrl }` - `issueId: string` Linear issue ID - `issueUrl: string` URL to the Linear issue - `linkedConversations: array of object { id, role }` Linked conversations - `id: string` Conversation ID - `role: "customer" or "tracker" or "back-office"` Link role - `"customer"` - `"tracker"` - `"back-office"` - `object: "ticket"` Object type identifier - `"ticket"` - `open: boolean` Whether the ticket is open - `snoozedUntil: string` ISO 8601 timestamp until snoozed (from linked conversation) - `status: PostStatus` Current ticket status - `id: string` Unique identifier - `color: string` Color for UI display - `isDefault: boolean` Whether this is the default status for new posts - `name: string` Display name - `object: "post_status"` Object type identifier - `"post_status"` - `type: "reviewing" or "unstarted" or "active" or 2 more` The workflow stage this status represents - `"reviewing"` - `"unstarted"` - `"active"` - `"completed"` - `"canceled"` - `teamAssigneeId: string` Assigned team ID (from linked conversation) - `ticketCategoryId: string` Ticket category ID - `ticketNumber: number` Sequential display ID (e.g. TK-42) - `ticketUrl: string` Full URL to view the ticket - `title: string` Ticket title - `updatedAt: string` ISO 8601 last updated timestamp - `conversationParts: optional array of ConversationPart` Conversation message history. Only included when fetching a single ticket by ID. - `UserMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Message from a customer or lead - `id: string` Unique part identifier - `bodyHtml: string` Message body content as HTML with signed image URLs - `bodyMarkdown: string` Message body content as markdown - `channel: "unknown" or "desktop" or "android" or 2 more` Channel through which the message was sent - `"unknown"` - `"desktop"` - `"android"` - `"ios"` - `"email"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "user_msg"` User message type - `"user_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `id: string` Author ID - `type: "customer" or "lead" or "admin" or 3 more` Type of author - `"customer"` - `"lead"` - `"admin"` - `"bot"` - `"guest"` - `"integration"` - `email: optional string` Author email address - `name: optional string` Author display name - `profilePicture: optional string` Author profile picture URL - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `type: "admin" or "customer" or "lead" or 4 more` Actor that caused the tag mutation - `"admin"` - `"customer"` - `"lead"` - `"bot"` - `"integration"` - `"system"` - `"workflow"` - `id: optional string` Actor identifier when available - `name: optional string` Actor display name when available - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `id: string` Unique tag identifier - `name: string` Current tag name - `type: "tag"` Object type identifier for a tag - `"tag"` - `AdminMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Message from an admin or support agent - `id: string` Unique part identifier - `bodyHtml: string` Message body content as HTML with signed image URLs - `bodyMarkdown: string` Message body content as markdown - `channel: "unknown" or "desktop" or "android" or 2 more` Channel through which the message was sent - `"unknown"` - `"desktop"` - `"android"` - `"ios"` - `"email"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "admin_msg"` Admin message type - `"admin_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `AdminNote object { id, bodyHtml, bodyMarkdown, 7 more }` Internal note visible only to admins - `id: string` Unique part identifier - `bodyHtml: string` Note body content as HTML with signed image URLs - `bodyMarkdown: string` Note body content as markdown - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "admin_note"` Admin internal note type - `"admin_note"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `EmailMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Message sent via email - `id: string` Unique part identifier - `bodyHtml: string` Email body content as HTML with signed image URLs - `bodyMarkdown: string` Email body content as markdown - `channel: "email"` Email channel - `"email"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "email_msg"` Email message type - `"email_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `BotMsg object { id, bodyHtml, bodyMarkdown, 8 more }` Automated message from AI or bot - `id: string` Unique part identifier - `bodyHtml: string` Bot message body content as HTML with signed image URLs - `bodyMarkdown: string` Bot message body content as markdown - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "bot_msg"` Bot message type - `"bot_msg"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `channel: optional "unknown" or "desktop" or "android" or 2 more` Channel through which the message was sent - `"unknown"` - `"desktop"` - `"android"` - `"ios"` - `"email"` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `QuickReplyOpts object { id, createdAt, object, 6 more }` Presents options for user to choose from - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "quick_reply_opts"` Quick reply options type - `"quick_reply_opts"` - `replyOptions: array of object { id, text }` Available reply options - `id: string` Option ID - `text: string` Option text - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `QuickReplyResp object { id, bodyHtml, bodyMarkdown, 8 more }` User's selection from quick reply options - `id: string` Unique part identifier - `bodyHtml: string` The selected option text as HTML - `bodyMarkdown: string` The selected option text as markdown - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "quick_reply_resp"` Quick reply response type - `"quick_reply_resp"` - `selectedOptionId: string` ID of the selected option - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `RatingRequested object { id, createdAt, csat, 3 more }` Represents a persisted CSAT request in the conversation thread - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `csat: object { channel, requestedAt, requestId, 7 more }` Canonical CSAT request payload for this thread event - `channel: "desktop" or "email"` Channel used for the CSAT request - `"desktop"` - `"email"` - `requestedAt: string` ISO timestamp when the request was created - `requestId: string` Canonical CSAT request ID - `requestSource: "workflow"` Source that created the CSAT request - `"workflow"` - `status: "pending" or "rated" or "canceled" or "expired"` Status of the CSAT request represented by this part - `"pending"` - `"rated"` - `"canceled"` - `"expired"` - `changeLockWindowEndsAt: optional string` ISO timestamp after which changing the rating is no longer allowed - `expiredAt: optional string` ISO timestamp when the request expired, when applicable - `lateSubmitWindowEndsAt: optional string` ISO timestamp after which late submission is no longer allowed - `ratedAgent: optional CsatRatedAgent` - `type: "teammate" or "fibi" or "chatbot"` Type of agent the CSAT request is attributed to - `"teammate"` - `"fibi"` - `"chatbot"` - `id: optional string` Identifier of the rated agent when applicable - `workflow: optional CsatWorkflowLink` - `workflowActionId: optional string` Workflow action ID associated with the CSAT request - `workflowId: optional string` Workflow ID associated with the CSAT request - `workflowRunId: optional string` Workflow run ID associated with the CSAT request - `workflowStepId: optional string` Workflow step ID associated with the CSAT request - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "rating_requested"` CSAT rating requested part type - `"rating_requested"` - `updatedAt: string` ISO timestamp when the part was last updated - `RatingSubmitted object { id, createdAt, csat, 3 more }` Represents a persisted CSAT submission in the conversation thread - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `csat: object { channel, ratedAt, requestId, 7 more }` Canonical CSAT submission payload for this thread event - `channel: "desktop" or "email"` Channel used for the CSAT request - `"desktop"` - `"email"` - `ratedAt: string` ISO timestamp when the customer submitted the rating - `requestId: string` Canonical CSAT request ID - `requestSource: "workflow"` Source that created the CSAT request - `"workflow"` - `score: number` CSAT score from 1 to 5 - `status: "rated"` Submitted ratings are always in the rated state - `"rated"` - `ratedAgent: optional CsatRatedAgent` - `remark: optional string` Optional remark left with the rating - `requestedAt: optional string` ISO timestamp when the request was created - `workflow: optional CsatWorkflowLink` - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "rating_submitted"` CSAT rating submitted part type - `"rating_submitted"` - `updatedAt: string` ISO timestamp when the part was last updated - `AttrPrompt object { id, createdAt, form, 6 more }` Requests information from user via form - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `form: object { id, attributes }` Form configuration - `id: string` Form ID - `attributes: array of object { identifier, name, type }` Form fields - `identifier: string` Field identifier - `name: string` Field display name - `type: string` Field type - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "attr_prompt"` Attribute collection prompt type - `"attr_prompt"` - `updatedAt: string` ISO timestamp when the part was last updated - `author: optional ConversationPartAuthor` - `redacted: optional boolean` Whether this message has been redacted - `tagApplications: optional array of ConversationTagApplication` Reply-level tag applications and provenance for this conversation part - `appliedAt: string` ISO timestamp when the tag was applied to this reply - `tagId: string` Identifier of the applied tag - `appliedBy: optional ConversationTagMutationActor` Actor that applied the tag - `removedAt: optional string` ISO timestamp when the tag was removed from this reply, if it was removed - `removedBy: optional ConversationTagMutationActor` Actor that applied the tag - `tag: optional ConversationTag` Resolved tag object when the tag still exists in the shared workspace catalog - `AttrComplete object { id, createdAt, object, 2 more }` Indicates form was completed - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "attr_complete"` Attribute collection complete type - `"attr_complete"` - `updatedAt: string` ISO timestamp when the part was last updated - `Assign object { id, createdAt, object, 5 more }` Conversation assigned to admin or team - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "assign"` Assignment type - `"assign"` - `updatedAt: string` ISO timestamp when the part was last updated - `adminAssigneeId: optional string` ID of the admin assigned to the conversation - `adminAssignerId: optional string` ID of the admin who made the assignment - `teamAssigneeId: optional string` ID of the team assigned to the conversation - `Status object { id, createdAt, object, 4 more }` Conversation state changed (open/closed/snoozed) - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "status"` Status change type - `"status"` - `status: "open" or "closed" or "snoozed"` New conversation status - `"open"` - `"closed"` - `"snoozed"` - `updatedAt: string` ISO timestamp when the part was last updated - `snoozedUntil: optional string` ISO timestamp until conversation is snoozed (if snoozed) - `Tags object { id, action, createdAt, 8 more }` A tag was added to or removed from a specific reply - `id: string` Unique part identifier - `action: "added" or "removed"` Whether the tag was added or removed - `"added"` - `"removed"` - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `occurredAt: string` ISO timestamp when the tag mutation occurred - `partType: "tags"` Tag update type - `"tags"` - `tagId: string` Identifier of the affected tag - `updatedAt: string` ISO timestamp when the part was last updated - `actor: optional ConversationTagMutationActor` Actor that applied the tag - `tagName: optional string` Tag name at the time of the event or the best available current display name - `targetPartId: optional string` Conversation part that the tag mutation targeted - `WorkflowWait object { id, createdAt, object, 3 more }` Represents a workflow wait start, finish, or interruption in the conversation thread - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "workflow_wait"` Workflow wait event part type - `"workflow_wait"` - `updatedAt: string` ISO timestamp when the part was last updated - `workflowWait: object { eventType, occurredAt, interruptedByUserType, 3 more }` Workflow wait event payload for this thread event - `eventType: "started" or "finished" or "interrupted"` Lifecycle stage of the workflow wait event - `"started"` - `"finished"` - `"interrupted"` - `occurredAt: string` ISO timestamp when the wait event occurred - `interruptedByUserType: optional "admin" or "customer" or "lead"` User type that interrupted the wait when applicable - `"admin"` - `"customer"` - `"lead"` - `waitLabel: optional string` Human-readable wait duration or preset label - `workflowId: optional string` Workflow ID associated with the wait event - `workflowName: optional string` Workflow display name at the time of the wait event - `Priority object { id, createdAt, isPriority, 3 more }` Conversation priority was updated - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `isPriority: boolean` Whether the conversation is now marked as priority - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `partType: "priority"` Priority change type - `"priority"` - `updatedAt: string` ISO timestamp when the part was last updated - `PartAdd object { id, createdAt, object, 3 more }` New participant joined the conversation - `id: string` Unique part identifier - `createdAt: string` ISO timestamp when the part was created - `object: "conversation_part"` Object type identifier - `"conversation_part"` - `participant: object { id, type }` The added participant - `id: string` Participant ID - `type: "customer" or "lead" or "admin"` Participant type - `"customer"` - `"lead"` - `"admin"` - `partType: "part_add"` Participant added type - `"part_add"` - `updatedAt: string` ISO timestamp when the part was last updated ### Ticket Delete Response - `TicketDeleteResponse object { id, deleted, object }` - `id: string` Unique identifier of the deleted ticket - `deleted: true` Indicates the resource was deleted - `true` - `object: "ticket"` Object type identifier - `"ticket"` # Custom Fields ## List custom fields **get** `/v2/tickets/custom_fields` Returns all custom fields configured in your organization that can be used on tickets. This endpoint returns all custom fields at once. No pagination is supported. ### Custom Field Object Each custom field includes: - `id` - Unique field identifier - `label` - Field label displayed to users - `type` - Field type (text, number, select, multi-select, checkbox, date, file) - `required` - Whether the field is required - `placeholder` - Placeholder text (for text/number fields) - `public` - Whether the field value is publicly visible - `internal` - Whether the field is for internal use only - `options` - Array of options (for select/multi-select fields) - `allowMultiple` - Whether multiple files can be uploaded (file fields only) ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `CustomFieldList object { data, nextCursor, object, pagination }` - `data: array of CustomField` Array of custom fields - `id: string` Unique identifier - `label: string` Field label displayed to users - `object: "custom_field"` Object type identifier - `"custom_field"` - `type: "text" or "number" or "select" or 4 more` Field type - `"text"` - `"number"` - `"select"` - `"multi-select"` - `"checkbox"` - `"date"` - `"file"` - `allowMultiple: optional boolean` Whether multiple files can be uploaded (file fields only) - `createdAt: optional string` ISO timestamp when created - `internal: optional boolean` Whether the field is for internal use only - `options: optional array of object { id, label }` Options for select/multi-select fields - `id: string` Option unique identifier - `label: string` Option display label - `placeholder: optional string` Placeholder text - `public: optional boolean` Whether the field value is publicly visible - `required: optional boolean` Whether the field is required - `updatedAt: optional string` ISO timestamp when last updated - `nextCursor: string` Cursor for fetching the next page (cursor-based pagination) - `object: "list"` Object type identifier - `"list"` - `pagination: optional object { limit, page, total, totalPages }` Pagination metadata for page-based requests - `limit: number` Items per page - `page: number` Current page number - `total: number` Total number of items - `totalPages: number` Total number of pages ### Example ```http curl https://do.featurebase.app/v2/tickets/custom_fields \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "data": [ { "id": "65d26304b2e65b1e1278170c", "label": "Your @username", "object": "custom_field", "type": "text", "allowMultiple": false, "createdAt": "2025-04-06T14:11:58.141Z", "internal": false, "options": [ { "id": "65d26304b2e65b1e1278170d", "label": "High Priority" } ], "placeholder": "Enter your username", "public": false, "required": true, "updatedAt": "2025-04-06T14:11:58.141Z" } ], "nextCursor": null, "object": "list", "pagination": { "limit": 10, "page": 1, "total": 42, "totalPages": 5 } } ``` ## Get a custom field by ID **get** `/v2/tickets/custom_fields/{id}` Retrieves a single custom field by its unique identifier. ### Response Returns a custom field object with: - `id` - Unique field identifier - `label` - Field label displayed to users - `type` - Field type (text, number, select, multi-select, checkbox, date, file) - `required` - Whether the field is required - `placeholder` - Placeholder text (for text/number fields) - `public` - Whether the field value is publicly visible - `internal` - Whether the field is for internal use only - `options` - Array of options (for select/multi-select fields) - `allowMultiple` - Whether multiple files can be uploaded (file fields only) ### Path Parameters - `id: string` Custom field unique identifier ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `CustomField object { id, label, object, 9 more }` - `id: string` Unique identifier - `label: string` Field label displayed to users - `object: "custom_field"` Object type identifier - `"custom_field"` - `type: "text" or "number" or "select" or 4 more` Field type - `"text"` - `"number"` - `"select"` - `"multi-select"` - `"checkbox"` - `"date"` - `"file"` - `allowMultiple: optional boolean` Whether multiple files can be uploaded (file fields only) - `createdAt: optional string` ISO timestamp when created - `internal: optional boolean` Whether the field is for internal use only - `options: optional array of object { id, label }` Options for select/multi-select fields - `id: string` Option unique identifier - `label: string` Option display label - `placeholder: optional string` Placeholder text - `public: optional boolean` Whether the field value is publicly visible - `required: optional boolean` Whether the field is required - `updatedAt: optional string` ISO timestamp when last updated ### Example ```http curl https://do.featurebase.app/v2/tickets/custom_fields/$ID \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "id": "65d26304b2e65b1e1278170c", "label": "Your @username", "object": "custom_field", "type": "text", "allowMultiple": false, "createdAt": "2025-04-06T14:11:58.141Z", "internal": false, "options": [ { "id": "65d26304b2e65b1e1278170d", "label": "High Priority" } ], "placeholder": "Enter your username", "public": false, "required": true, "updatedAt": "2025-04-06T14:11:58.141Z" } ``` # Categories ## List ticket categories **get** `/v2/tickets/categories` Returns all ticket categories for the authenticated organization. Ticket categories organize tickets into distinct containers. Each category can have different: - Access controls (public, private, segment-restricted) - Feature toggles (comments, posting enabled) - Custom fields Use the `supportBoard` and `supportBoardType` fields to identify ticket categories. This endpoint returns all categories without pagination. ### 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 - `access: object { adminOnly, allowedRoles, deniedRoles, segments }` - `adminOnly: boolean` If true, only admins can see this board - `allowedRoles: array of string` Role IDs allowed access (empty = all) - `deniedRoles: array of string` Role IDs explicitly denied access - `segments: array of string` Segment IDs that can access (empty = all) - `createdAt: string` ISO 8601 timestamp when created - `customFields: array of string` Custom field IDs attached to this board - `features: object { commentsEnabled, createdDatesVisible, postingEnabled }` - `commentsEnabled: boolean` Whether users can comment on posts - `createdDatesVisible: boolean` Whether creation dates are visible on posts - `postingEnabled: boolean` Whether users can create new posts - `icon: object { type, value } or object { type, value } or object { type, value }` The board's icon. Can be one of three types: - **emoji**: A single emoji character (e.g., 💡, 🚀, ⭐) - **icon**: A predefined icon from the built-in library (e.g., lightbulb, bug, star) - **url**: A custom image URL (HTTPS required) Can be `null` if no icon is set. - `EmojiIcon object { type, value }` An emoji character as the board icon - `type: "emoji"` Emoji icon type - `"emoji"` - `value: string` A single emoji character - `PredefinedIcon object { type, value }` A predefined icon from the built-in icon library - `type: "icon"` Predefined icon type - `"icon"` - `value: string` Icon name from the predefined icon set (e.g., lightbulb, bug, star, rocket, flag, heart, check, question, megaphone, gift) - `URLIcon object { type, value }` A custom icon loaded from an external URL - `type: "url"` External URL icon type - `"url"` - `value: string` HTTPS URL to a custom icon image (PNG, SVG, or WebP recommended) - `localization: object { description, formPlaceholder, heroDescription, 3 more }` - `description: map[string]` Localized description - `formPlaceholder: map[string]` Placeholder text in the post creation form - `heroDescription: map[string]` Hero description/subtitle - `heroTitle: map[string]` Hero title shown on the board page - `name: map[string]` Localized board name (language code → text) - `submitButtonText: map[string]` Submit button text - `name: string` Display name in organization's default locale - `object: "board"` Object type identifier - `"board"` - `postDefaults: object { visibility }` - `visibility: "public" or "authorOnly" or "companyOnly"` Default visibility for new posts - `"public"` - `"authorOnly"` - `"companyOnly"` ### Example ```http curl https://do.featurebase.app/v2/tickets/categories \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json [ { "id": "507f1f77bcf86cd799439011", "access": { "adminOnly": false, "allowedRoles": [ "string" ], "deniedRoles": [ "role_blocked" ], "segments": [ "string" ] }, "createdAt": "2023-12-12T00:00:00.000Z", "customFields": [ "cf_priority", "cf_category" ], "features": { "commentsEnabled": true, "createdDatesVisible": true, "postingEnabled": true }, "icon": { "type": "emoji", "value": "💡" }, "localization": { "description": { "en": "Submit and vote on feature ideas" }, "formPlaceholder": { "en": "Describe your feature idea..." }, "heroDescription": { "foo": "string" }, "heroTitle": { "en": "Share your ideas" }, "name": { "en": "Feature Requests", "es": "Solicitudes de funciones" }, "submitButtonText": { "en": "Submit Feedback" } }, "name": "Feature Requests", "object": "board", "postDefaults": { "visibility": "public" } } ] ``` ## Get a ticket category by ID **get** `/v2/tickets/categories/{id}` Retrieves a single ticket category by its unique identifier. Returns the full category object including access controls, feature toggles, and localization settings. ### Path Parameters - `id: string` Board unique identifier ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `Board object { id, access, createdAt, 7 more }` - `id: string` Unique identifier - `access: object { adminOnly, allowedRoles, deniedRoles, segments }` - `adminOnly: boolean` If true, only admins can see this board - `allowedRoles: array of string` Role IDs allowed access (empty = all) - `deniedRoles: array of string` Role IDs explicitly denied access - `segments: array of string` Segment IDs that can access (empty = all) - `createdAt: string` ISO 8601 timestamp when created - `customFields: array of string` Custom field IDs attached to this board - `features: object { commentsEnabled, createdDatesVisible, postingEnabled }` - `commentsEnabled: boolean` Whether users can comment on posts - `createdDatesVisible: boolean` Whether creation dates are visible on posts - `postingEnabled: boolean` Whether users can create new posts - `icon: object { type, value } or object { type, value } or object { type, value }` The board's icon. Can be one of three types: - **emoji**: A single emoji character (e.g., 💡, 🚀, ⭐) - **icon**: A predefined icon from the built-in library (e.g., lightbulb, bug, star) - **url**: A custom image URL (HTTPS required) Can be `null` if no icon is set. - `EmojiIcon object { type, value }` An emoji character as the board icon - `type: "emoji"` Emoji icon type - `"emoji"` - `value: string` A single emoji character - `PredefinedIcon object { type, value }` A predefined icon from the built-in icon library - `type: "icon"` Predefined icon type - `"icon"` - `value: string` Icon name from the predefined icon set (e.g., lightbulb, bug, star, rocket, flag, heart, check, question, megaphone, gift) - `URLIcon object { type, value }` A custom icon loaded from an external URL - `type: "url"` External URL icon type - `"url"` - `value: string` HTTPS URL to a custom icon image (PNG, SVG, or WebP recommended) - `localization: object { description, formPlaceholder, heroDescription, 3 more }` - `description: map[string]` Localized description - `formPlaceholder: map[string]` Placeholder text in the post creation form - `heroDescription: map[string]` Hero description/subtitle - `heroTitle: map[string]` Hero title shown on the board page - `name: map[string]` Localized board name (language code → text) - `submitButtonText: map[string]` Submit button text - `name: string` Display name in organization's default locale - `object: "board"` Object type identifier - `"board"` - `postDefaults: object { visibility }` - `visibility: "public" or "authorOnly" or "companyOnly"` Default visibility for new posts - `"public"` - `"authorOnly"` - `"companyOnly"` ### Example ```http curl https://do.featurebase.app/v2/tickets/categories/$ID \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "id": "507f1f77bcf86cd799439011", "access": { "adminOnly": false, "allowedRoles": [ "string" ], "deniedRoles": [ "role_blocked" ], "segments": [ "string" ] }, "createdAt": "2023-12-12T00:00:00.000Z", "customFields": [ "cf_priority", "cf_category" ], "features": { "commentsEnabled": true, "createdDatesVisible": true, "postingEnabled": true }, "icon": { "type": "emoji", "value": "💡" }, "localization": { "description": { "en": "Submit and vote on feature ideas" }, "formPlaceholder": { "en": "Describe your feature idea..." }, "heroDescription": { "foo": "string" }, "heroTitle": { "en": "Share your ideas" }, "name": { "en": "Feature Requests", "es": "Solicitudes de funciones" }, "submitButtonText": { "en": "Submit Feedback" } }, "name": "Feature Requests", "object": "board", "postDefaults": { "visibility": "public" } } ``` ## Domain Types ### Category List Response - `CategoryListResponse = array of Board` - `id: string` Unique identifier - `access: object { adminOnly, allowedRoles, deniedRoles, segments }` - `adminOnly: boolean` If true, only admins can see this board - `allowedRoles: array of string` Role IDs allowed access (empty = all) - `deniedRoles: array of string` Role IDs explicitly denied access - `segments: array of string` Segment IDs that can access (empty = all) - `createdAt: string` ISO 8601 timestamp when created - `customFields: array of string` Custom field IDs attached to this board - `features: object { commentsEnabled, createdDatesVisible, postingEnabled }` - `commentsEnabled: boolean` Whether users can comment on posts - `createdDatesVisible: boolean` Whether creation dates are visible on posts - `postingEnabled: boolean` Whether users can create new posts - `icon: object { type, value } or object { type, value } or object { type, value }` The board's icon. Can be one of three types: - **emoji**: A single emoji character (e.g., 💡, 🚀, ⭐) - **icon**: A predefined icon from the built-in library (e.g., lightbulb, bug, star) - **url**: A custom image URL (HTTPS required) Can be `null` if no icon is set. - `EmojiIcon object { type, value }` An emoji character as the board icon - `type: "emoji"` Emoji icon type - `"emoji"` - `value: string` A single emoji character - `PredefinedIcon object { type, value }` A predefined icon from the built-in icon library - `type: "icon"` Predefined icon type - `"icon"` - `value: string` Icon name from the predefined icon set (e.g., lightbulb, bug, star, rocket, flag, heart, check, question, megaphone, gift) - `URLIcon object { type, value }` A custom icon loaded from an external URL - `type: "url"` External URL icon type - `"url"` - `value: string` HTTPS URL to a custom icon image (PNG, SVG, or WebP recommended) - `localization: object { description, formPlaceholder, heroDescription, 3 more }` - `description: map[string]` Localized description - `formPlaceholder: map[string]` Placeholder text in the post creation form - `heroDescription: map[string]` Hero description/subtitle - `heroTitle: map[string]` Hero title shown on the board page - `name: map[string]` Localized board name (language code → text) - `submitButtonText: map[string]` Submit button text - `name: string` Display name in organization's default locale - `object: "board"` Object type identifier - `"board"` - `postDefaults: object { visibility }` - `visibility: "public" or "authorOnly" or "companyOnly"` Default visibility for new posts - `"public"` - `"authorOnly"` - `"companyOnly"` # Statuses ## List ticket statuses **get** `/v2/tickets/statuses` Returns all ticket statuses for the authenticated organization. Ticket statuses define workflow stages. Each status has: - A display name and color - A type indicating the workflow stage (reviewing, unstarted, active, completed, canceled) - A flag indicating if it's the default status for new tickets This endpoint returns all statuses without pagination. ### 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 - `color: string` Color for UI display - `isDefault: boolean` Whether this is the default status for new posts - `name: string` Display name - `object: "post_status"` Object type identifier - `"post_status"` - `type: "reviewing" or "unstarted" or "active" or 2 more` The workflow stage this status represents - `"reviewing"` - `"unstarted"` - `"active"` - `"completed"` - `"canceled"` ### Example ```http curl https://do.featurebase.app/v2/tickets/statuses \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json [ { "id": "507f1f77bcf86cd799439011", "color": "Blue", "isDefault": false, "name": "In Progress", "object": "post_status", "type": "active" } ] ``` ## Get a ticket status by ID **get** `/v2/tickets/statuses/{id}` Retrieves a single ticket status by its unique identifier. Returns the status object including name, color, type, and default flag. ### Path Parameters - `id: string` Post status unique identifier ### Header Parameters - `"Featurebase-Version": optional "2026-01-01.nova" or "2025-12-12.clover"` - `"2026-01-01.nova"` - `"2025-12-12.clover"` ### Returns - `PostStatus object { id, color, isDefault, 3 more }` - `id: string` Unique identifier - `color: string` Color for UI display - `isDefault: boolean` Whether this is the default status for new posts - `name: string` Display name - `object: "post_status"` Object type identifier - `"post_status"` - `type: "reviewing" or "unstarted" or "active" or 2 more` The workflow stage this status represents - `"reviewing"` - `"unstarted"` - `"active"` - `"completed"` - `"canceled"` ### Example ```http curl https://do.featurebase.app/v2/tickets/statuses/$ID \ -H "Authorization: Bearer $FEATUREBASE_API_KEY" ``` #### Response ```json { "id": "507f1f77bcf86cd799439011", "color": "Blue", "isDefault": false, "name": "In Progress", "object": "post_status", "type": "active" } ``` ## Domain Types ### Status List Response - `StatusListResponse = array of PostStatus` - `id: string` Unique identifier - `color: string` Color for UI display - `isDefault: boolean` Whether this is the default status for new posts - `name: string` Display name - `object: "post_status"` Object type identifier - `"post_status"` - `type: "reviewing" or "unstarted" or "active" or 2 more` The workflow stage this status represents - `"reviewing"` - `"unstarted"` - `"active"` - `"completed"` - `"canceled"`