Contacts API Reference
Search, read and update Chatfuel contacts: attributes, names, notes, assignees and sales stages, segments, CSV import and export, and contact events.
Last updated on
A contact is a person who has talked to the bot on WhatsApp, Instagram, Facebook, TikTok or the website widget. Through the Public API you can search contacts with segments, read their attributes, change names, attributes and notes, assign them to teammates or Fuely AI, move them between sales stages, and import or export them as CSV. Reading contacts works for Agent virtual users; editing a contact's data needs Editor.
Contacts are reached through bot(id:). A contact's ID is also the ID of its conversation, as described in messaging.
How to search and read contacts
type Bot {
# Agent. One contact by ID.
contact(id: ContactID!): Contact!
# Agent. Paginated search, up to 500 per page, optionally filtered by a segment and sorted by an attribute.
contactsConnection(
platforms: [Platform!]! # whatsapp, instagram, facebook, tiktok, widget
first: Int!
before: ContactSearchCursor
after: ContactSearchCursor
segment: SegmentInput
orderBy: ContactSearchOrderByInput # { orderBy: <attribute name>, direction: Asc | Desc }
): ContactConnection!
# Agent. Number of contacts matching the platforms and segment.
contactsCount(platforms: [Platform!]!, segment: SegmentInput): Int!
contactsTotalCount(platforms: [Platform!]!, segment: SegmentInput): Int!
}Contact is an interface; WhatsApp contacts are WhatsappContact with an extra phone field, and there are similar types for the other channels. Every contact has:
query Contact($botID: BotID!, $contactID: ContactID!) {
bot(id: $botID) {
contact(id: $contactID) {
id
name
note
updatedAt
salesStageV2 # New, Sorting, Ready, WorkingOn, Won, Lost
lastConversationMessageTime
unreadMessagesCount
unhandledSwitchToHuman # handed to a human and not opened yet
assignee {
... on PublicUserAccount { id name accountType }
... on FuelyAIAssignee { __typename }
}
attributes(names: ["email", "city"]) {
attr { name type }
value {
... on BotAttributeValueString { stringValue }
... on BotAttributeValueDouble { doubleValue }
... on BotAttributeValueBoolean { booleanValue }
... on BotAttributeValueDatetime { datetimeValue }
}
}
... on WhatsappContact { phone }
}
}
}How to filter contacts with segments
A segment is a set of filters joined with AND or OR. Segment and filter IDs are UUIDs that you generate, or call segmentNew to get an empty segment with an ID:
query Leads($botID: BotID!) {
bot(id: $botID) {
contactsConnection(
platforms: [whatsapp]
first: 100
segment: {
id: "2b0c6a0e-6f0a-4a39-9d63-0b1f0d4f7a10"
resultOperator: AND
filters: [{
id: "8f6d2a4e-1c3b-4f5a-9e7d-2a1b3c4d5e6f"
byAttribute: { name: "city", defaultStrategy: { operator: IS, comparableValues: ["Lisbon"] } }
}]
}
) {
edges { node { id name } }
pageInfo { hasNextPage endCursor }
}
}
}Attribute filters support the operators IS, IS_NOT, STARTS_WITH, CONTAINS, LT, GT, IS_EMPTY and IS_NOT_EMPTY; date attributes use dateStrategy. bot.botAttributes(...) lists the system and custom attributes a bot has, with their data types (Agent).
How to update a contact
type Mutation {
# Editor. Errors: ContactDoesNotExist, ContactNameTooLong, ContactNameRequired
contactUpdateName(id: ContactID!, name: String!): Contact!
# Editor. Creates or updates a custom attribute. System attributes can't be changed (SystemAttributeUpdateNotAllowed).
contactAttributeUpdate(id: ContactID!, attrName: AttributeName!, attrValue: String!): Contact!
# Editor. Deletes a custom attribute value from the contact.
contactAttributeDelete(id: ContactID!, attrName: AttributeName!): Contact!
# Editor. A free-text note shown on the contact card and in bookings. Errors: ContactNoteTooLong
contactSetNote(id: ContactID!, note: String): Contact!
# Agent. The person must have access to the bot's contacts (AssigneeHasNoAccess).
contactSetAssignee(id: ContactID!, assigneeID: UserAccountID!): Contact!
# Agent. Hands the contact to Fuely AI.
contactSetFuelyAIAssignee(id: ContactID!): Contact!
# Agent.
contactRemoveAssignee(id: ContactID!): Contact!
# Agent. Moves the contact on the Leads board.
contactSetSalesStage(id: ContactID!, salesStageV2: SalesStageV2!): Contact!
# Editor. Creates a WhatsApp contact by phone number for a calendar booking (source: CalendarBooking).
whatsappContactCreateV2(botID: BotID!, data: WhatsappContactCreateInput!): Contact!
}A virtual user can assign a contact to itself: pass its own currentUser.id as assigneeID.
Default values of bot attributes apply to every contact that has no value of its own (Editor):
type Mutation {
botAttributeCreateDefaultVal(botID: BotID!, attributeName: AttributeName!, defaultValue: String!): Bot!
botAttributeUpdateDefaultVal(botID: BotID!, attributeName: AttributeName!, defaultValue: String!): Bot!
botAttributeDeleteDefaultVal(botID: BotID!, attributeName: AttributeName!): Bot!
}How to read deals by sales stage
The Leads board groups contacts by sales stage. Both queries work for Agent:
type Bot {
# Contacts in one stage, filtered by assignee (Any, Unassigned, FuelyAI or a specific AssigneeID).
contactDealsConnection(
first: Int!
before: ContactSearchCursor
after: ContactSearchCursor
assigneeFilter: ContactAssigneeFilter!
salesStageV2Filter: SalesStageV2!
): ContactConnection!
# Number of contacts in each stage, optionally limited by the time of the last stage change.
contactDealsByStages(filter: DealsByStagesFilter!): TotalsByStages!
}How to export and import contacts as CSV
Exports and imports run in the background and report progress through a task or a subscription.
type Mutation {
# Agent. Export by segment; pass an empty attributes list to export all attributes.
# Errors: CSVContactExportAlreadyInProgress
csvContactExportStartBySegment(botID: BotID!, platforms: [Platform!]!, segment: SegmentInput, attributes: [AttributeName!]!): Task!
# Agent. Export a list of contacts. Errors: CSVContactExportInvalidContactIDsCount
csvContactExportStartByIDsList(botID: BotID!, contactIDs: [ContactID!]!, attributes: [AttributeName!]!): Task!
# Agent. Cancels an export; the task status changes to cancelled shortly after.
csvContactExportCancel(botID: BotID!, id: String!): Bot!
# Editor. 1) upload the CSV file, 2) create the import, 3) map columns, 4) start it.
csvContactImportCreate(botID: BotID!, fileID: FileID!, platform: Platform!, locale: DashboardLocale!): CSVContactImport!
csvContactImportUpdateFile(botID: BotID!, id: CSVContactImportID!, fileID: FileID!): CSVContactImport!
csvContactImportUpdateColumns(botID: BotID!, id: CSVContactImportID!, request: CSVContactImportColumnsUpdate!): CSVContactImport!
# Errors: ContactScopeNotConnected if the channel, for example the WhatsApp number, is not connected.
csvContactImportStart(botID: BotID!, id: CSVContactImportID!): CSVContactImport!
}When an export task reaches the Finished status, its data is a CSVContactsExport whose file { url } is the CSV to download. bot.lastActiveCSVContactsExportTask (Agent) returns a running export, and bot.latestCSVContactsImport(platform:) (Editor) the last import with its counters and errors.
Contact subscriptions
type Subscription {
# Agent. Any change of one contact.
contactUpdated(botID: BotID!, contactID: ContactID!): Contact
# Agent. Changes on the Leads board for the given assignee filter.
contactsDealUpdates(botID: BotID!, assigneeFilter: ContactAssigneeFilter!): ContactsDealUpdate
contactsDealsPageIndicatorUpdates(botID: BotID!): DealsPageIndicatorUpdate
# Editor. Progress of a CSV import.
csvContactImportUpdated(botID: BotID!, id: CSVContactImportID!): CSVContactImport!
}Common issues
"NotEnoughPermissions" when an Agent edits a contact
Agents can assign contacts and change sales stages, but changing names, attributes and notes needs an Editor. If an Editor also gets this error, the bot's role settings may limit it to contacts assigned to it, as described in team and roles.
"SystemAttributeUpdateNotAllowed"
System attributes such as the phone number or the channel's profile data are set by Chatfuel. Store your own data in custom attributes.
"ContactDoesNotExist"
The contact ID is wrong or belongs to another bot. Contact IDs are bot-specific; read them from contactsConnection of the same bot.