Please reach out to your accounts team to discuss access and tailored, hands-on support.
Fin can be accessed programmatically via an API. Integration is centered around two endpoints (/fin/start and /fin/reply) and a set of events that notify the client of Fin’s status and responses.
Once Fin is initialized, it progresses through a series of statuses such as thinking, awaiting_user_reply, or resolved before ending its workflow with a status of complete . During this workflow, the client should allow Fin to continue uninterrupted until a final complete status is returned, at which point control of the conversation passes back to the client.
Endpoint: /fin/start
Initialise Fin by passing it the user’s message along with some conversation history and user details. These additional pieces of context will be used by Fin to provide a better and more contextual answer to the user.
| KEY | TYPE | Required | DESCRIPTION |
|---|---|---|---|
message | Message | true | The message that the user is sending to Fin. |
conversation_id | String | true | The ID of the conversation that is calling Fin via this API. |
user | Object<User> | true | A user object that identifies the user making the query |
attachments | Array<Attachment> | false | An array of attachments to include with the message. Note: Maximum of 10 attachments. |
conversation_metadata | Object | false | Metadata about the conversation, including history and attributes. |
conversation_metadata.history | Array<Message> | false | An array of previous messages of the conversation before Fin is initialised. This data provides context to Fin on the history of the conversation and helps generate a better answer. Note: Limit to the last 10 messages. |
conversation_metadata.attributes | Hash<String,Object> | false | A Hash of attributes associated with the conversation. These attributes can be used by Fin to provide more contextual responses. Note: Limit to 10 attributes. |
Request Payload Example
{
"conversation_id": "ext-123",
"message": {
"author": "user",
"body": "How can I see my account details?",
"timestamp": "2025-01-24T10:01:20.000Z"
},
"user": {
"id": "123456",
"name": "John Doe",
"email": "john.doe@example.com",
"attributes": {
"plan_type": "Pro",
"subscription_status": "active"
}
},
"attachments": [
{
"type": "url",
"url": "https://example.com/document.pdf"
},
{
"type": "file",
"name": "screenshot.png",
"content_type": "image/png",
"data": "<base64 encoded file data>"
}
],
"conversation_metadata": {
"history": [
{
"author": "user",
"body": "I need help",
"timestamp": "2025-01-24T10:00:01Z"
},
{
"author": "agent",
"body": "What do you need help with?",
"timestamp": "2025-01-24T10:01:00Z"
}
],
"attributes": {
"priority_level": "high",
"department": "sales"
}
}
}| KEY | TYPE | DESCRIPTION |
|---|---|---|
conversation_id | String | The ID of the conversation. |
user_id | String | The ID of the user |
status | Enum<String> | Fin's status. |
created_at_ms | String | The timestamp the response was created at, with millisecond precision. Example: 2025-01-24T10:00:00.123Z |
errors | Object | Optional. Contains error details if any user or conversation attribute updates failed. |
errors.user.attributes | Hash<String,String> | Optional. Map of user attribute names to error messages. |
errors.conversation.attributes | Hash<String,String> | Optional. Map of conversation attribute names to error messages. |
Response Example
{
"conversation_id": "ext-123",
"user_id": "user-456",
"status": "thinking",
"created_at_ms": "2025-01-24T10:00:00.123Z",
"errors": {
"user": {
"attributes": {
"invalid_attr": "User attribute 'invalid_attr' does not exist"
}
},
"conversation": {
"attributes": {
"bad_attr": "Conversation attribute 'bad_attr' does not exist",
"priority_level": "'1234' is not a valid value for attribute 'priority_level' of type 'string'"
}
}
}
}Endpoint: /fin/reply
Once Fin has returned a response to a user’s message, its status will be awaiting_user_reply. If a user replies, use this endpoint to send this response to Fin.
| KEY | TYPE | Required | DESCRIPTION |
|---|---|---|---|
message | Message | true | The user's message. |
conversation_id | String | true | The ID of the conversation. |
user | Object<User> | true | A user object that identifies the user replying to Fin. |
attachments | Array<Attachment> | false | An array of attachments to include with the message. Note: Maximum of 10 attachments. |
Request Payload Example
{
"message": {
"author": "user",
"body": "Here's the information you requested.",
"timestamp": "2025-01-24T09:01:00.000Z"
},
"conversation_id": "123456",
"user": {
"id": "123456",
"name": "John Doe",
"email": "john.doe@example.com",
"attributes": {
"plan_type": "Pro",
"subscription_status": "active"
}
},
"attachments": [
{
"type": "url",
"url": "https://example.com/invoice.pdf"
}
]
}| KEY | TYPE | DESCRIPTION |
|---|---|---|
conversation_id | String | The ID of the conversation. |
user_id | String | The ID of the user |
status | Enum<String> | Fin's status. |
created_at_ms | String | The timestamp the response was created at, with millisecond precision. Example: 2025-01-24T10:00:00.123Z |
errors | Object | Optional. Contains error details if any user attribute updates failed. |
errors.user.attributes | Hash<String,String> | Optional. Map of user attribute names to error messages. |
Response Example
{
"conversation_id": "ext-123",
"user_id": "user-456",
"status": "thinking",
"created_at_ms": "2025-01-24T10:00:00.123Z",
"errors": {
"user": {
"attributes": {
"invalid_attr": "User attribute 'invalid_attr' does not exist"
}
}
}
}Fin will fire a number of different events during its workflow to convey its status and also deliver replies to the user. These events are sent via a Webhook, which can be configured in the Fin Agent API settings.
A webhook endpoint can be configured in the Fin Agent API settings. The client can then listen for Fin events sent to this webhook and handle them accordingly.
All webhook requests will include an X-Fin-Agent-API-Webhook-Signature header containing an HMAC-SHA256 signature of the request body. Validation can be done by generating a signature using the request body and the signing secret from the settings, and comparing it with the aforementioned header value.
Fin will report its status to the client via this event.
| KEY | TYPE | DESCRIPTION |
|---|---|---|
event_name | String | The name of the event. Value: fin_status_updated |
conversation_id | String | The ID of the conversation. |
user_id | String | The ID of the user. |
status | Enum<String> | Fin's current status. Supported values: escalated resolved complete |
reason | String | Optional. A human-readable explanation of why the conversation was escalated. Only present when status is escalated. See Escalation Reasons for possible values. |
created_at_ms | String | The timestamp the event was created at, with millisecond precision. Example: 2025-01-24T10:00:00.123Z |
Status Update Example (Escalated)
{
"event_name": "fin_status_updated",
"conversation_id": "123456",
"user_id": "7891",
"status": "escalated",
"reason": "Escalation requested by user",
"created_at_ms": "2025-01-24T10:00:00.123Z"
}Status Update Example (Resolved)
{
"event_name": "fin_status_updated",
"conversation_id": "123456",
"user_id": "7891",
"status": "resolved",
"created_at_ms": "2025-01-24T10:00:00.123Z"
}Fin will reply to a user via this event. The content of the response will be contained in the Message object and Fin's status will update to awaiting_user_reply.
| KEY | TYPE | DESCRIPTION |
|---|---|---|
event_name | String | The name of the event. Value: fin_replied |
conversation_id | String | The ID of the conversation. |
user_id | String | The ID of the user. |
message | Message | Fin's answer to the user's query. Includes timestamp_ms for millisecond precision timing. |
status | Enum<String> | Fin's current status. Value: awaiting_user_reply |
created_at_ms | String | The timestamp the event was created at, with millisecond precision. Example: 2025-01-24T10:00:00.123Z |
Fin Answer Example
{
"event_name": "fin_replied",
"conversation_id": "123456",
"user_id": "7891",
"message": {
"author": "fin",
"body": "<p>You can see your account details by clicking on the <em>Account</em> tab in the top right corner of the screen.</p>",
"timestamp_ms": "2025-01-24T09:01:00.456Z"
},
"status": "awaiting_user_reply",
"created_at_ms": "2025-01-24T10:00:00.123Z"
}The Message object defines the schema for all messages exchanged within a conversation. It encapsulates the complete content required to represent a message.
| KEY | TYPE | Required | DESCRIPTION |
|---|---|---|---|
author | Enum<String> | true | The author that created the message. Allowed values: agent user fin |
body | String | HTML | true | This attribute contains the body of the message. It accepts both String and HTML format. When sending a message to Fin, this should contain the user's message. Fin's response will be returned as HTML. This attribute is required when sending a message to Fin. |
timestamp | String | true | The timestamp the message was created at. Important: We use this timestamp to deduplicate messages sent within a 5 minute window. So please ensure that message timestamps are unique per conversation. Ideally this should include milliseconds for higher precision. Example: 2025-01-01T09:01:45.123Z |
timestamp_ms | String | false | The timestamp the message was created at, with millisecond precision. Only present in webhook event responses (fin_replied). Example: 2025-01-01T09:01:45.123Z |
A user object represents the user in the conversation.
| KEY | TYPE | Required | DESCRIPTION |
|---|---|---|---|
id | String | true | The ID of the user. This value will be used to uniquely identify the user during a conversation with Fin. |
name | String | false | The name of the user. |
email | String | false | The email of the user. |
attributes | Hash<String,Object> | false | A Hash of attributes associated with a user. Attributes can be added to the user and used by Fin to target content and responses to users who match specific attributes. Note: Limit to 10 attributes. |
An attachment object represents a file or URL attachment included with a message. Attachments can be used to provide additional context to Fin, such as screenshots, documents, or links to relevant resources.
| KEY | TYPE | Required | DESCRIPTION |
|---|---|---|---|
type | Enum<String> | true | The type of attachment. Allowed values: url file |
url | String | true* | The URL of the attachment. Required when type is url. The URL must be publicly accessible. |
name | String | true** | The name of the file. Required when type is file. |
content_type | String | true** | The MIME type of the file (e.g., application/pdf, image/jpeg, image/png). Required when type is file. |
data | String | true** | Base64-encoded file data. Required when type is file. |
Notes:
- Maximum of 10 attachments per request
- *Required only when
typeisurl - **Required only when
typeisfile
Attachment Example (URL)
{
"type": "url",
"url": "https://example.com/document.pdf"
}Attachment Example (File)
{
"type": "file",
"name": "screenshot.png",
"content_type": "image/png",
"data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
}During a conversation, Fin goes through a number of statuses as it progresses through a workflow. The client that is calling Fin will need to listen to these statuses via a Webhook and react accordingly.

| STATUS | DESCRIPTION |
|---|---|
thinking | Fin is currently thinking about a response. When Fin is thinking, the client should consider indicating to the user that Fin is working on an answer. |
awaiting_user_reply | Fin is waiting for a user to reply. Fin enters this status when it has delivered an answer or a reply and is waiting for the user to respond. |
escalated | The conversation has been escalated by the user or Fin. This status means that the Fin has determined or the user has requested that the conversation be escalated to a human. The client should respond accordingly. |
resolved | The user’s query has been resolved. The user has indicated to Fin that it has successfully answered their query. |
complete | Fin has completed its workflow and the conversation is over. Control of the conversation is now back with the client. |
When Fin escalates a conversation and reports an escalated status via the fin_status_updated event, it includes a reason field that provides context for why the conversation was escalated. This helps you understand the path the conversation took and respond appropriately.
The following reasons may be provided:
| REASON | DESCRIPTION |
|---|---|
Escalation requested by user | The user explicitly requested to speak with a human agent during the conversation. |
Escalation rule: {rule_name} | An escalation rule was triggered based on conversation attributes or conditions. The {rule_name} will be replaced with the actual name of the matched rule. |
Escalation rule matched | A generic escalation rule was triggered, but no specific rule name is available. |
Routed to team | The conversation was routed to a specific team based on your routing configuration. |
Conversation finished without resolution | The conversation ended without being resolved or explicitly escalated through one of the above paths. |
Note: The reason field is optional and may not be present in all escalated status update events. Legacy implementations or certain edge cases may not include this field.
All requests to this API require an API key in the HTTP header. You can obtain an API key after completing the Fin Agent API setup.
For general authentication guidelines, see Intercom authentication.
Your API key grants access to the Fin Agent API on behalf of your workspace. Do not share it publicly or expose it in client-side code.
The Fin Agent API access token is created with the write_conversations OAuth scope, which provides the minimum permissions needed for Fin Agent API operations. This follows security best practices by limiting what an access token can do if compromised.
For more information about OAuth scopes and token security, see the OAuth Scopes & Permissions section in the setup guide.
When you provide a User object to the Fin Agent API, the following behavior applies:
User role only: The Fin Agent API only supports the User role. Leads and Visitors are not supported.
User lookup: The
idfield is used to look up existing users in Intercom. This value maps to theuser_idfield on the Intercom User object.User creation: If no user is found with the provided
id, a new user will be created with the given parameters.Email updates: If an
emailis provided and differs from the existing user's email, the user's email will be updated.Attribute updates: If
attributesare provided, they will be merged with the user's existing attributes. New attributes are added and existing attributes with the same key are overwritten.User data update considerationsIf your users interact with Intercom across multiple channels (e.g., Messenger and the Fin Agent API), updating the email or attributes via this API will affect the user record across all channels. Ensure that the data you provide is authoritative and consistent with your other integrations to avoid unintended changes to user data.
Below is a basic example of the flow of API requests and webhooks when a client passes a message to Fin.
