> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usefini.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sync conversations

> Import external conversations and events into Fini with repeatable external IDs, event tags, and conversation metadata.

Import conversation history without generating a Fini reply or sending a message to the source provider. Use [Generate answer](https://docs.usefini.com/en/api-reference/generate-answer.md) when you want Fini to respond instead.

The API key needs `write` scope. The workspace is derived from the key; do not supply a workspace ID.

## Request

**Authorization** `string` *required*

`Bearer fini_your_api_key`.

**source** `string` *required*

Source shared by every conversation in the batch. Accepted values: `ui`, `widget`, `standalone`, `testsuite`, `replay`, `api`, `voice`, `jira`, `intercom`, `zendesk`, `salesforce`, `gorgias`, `front`, `hubspot`, `livechat`, `slack`, `discord`, `freshdesk`, `freshchat`, `deskpro`, `microsoft365`, `facebook`, `instagram`, `whatsapp`, `email`.

**interactions** `array` *required*

Between 1 and 50 conversations. Each agent/external-ID pair must be unique within the batch. Across all conversations, include at most 500 events. The serialized JSON payload must not exceed 2 MiB.

**Conversation fields**

**externalId** `string` *required*

Stable conversation ID in your source system, at most 255 characters. Must contain a non-whitespace character; NUL and unpaired surrogate characters are rejected.

**botId** `string` *required*

UUID of an agent in the authenticated workspace. UUID casing is normalized.

**subject** `string`

Conversation subject, at most 1,000 characters. Omit to retain the existing value.

**url** `string`

Source conversation link or identifier, at most 2,048 characters. This field accepts a string without URL-format validation.

**externalCreatedAt** `number`

Source timestamp in Unix milliseconds, independent of Fini’s ingestion timestamp. Omit to preserve the existing value; new conversations default to null.

**userAttributes** `object`

Replaces the conversation’s user attributes when supplied; omitted values are preserved. Also stored under conversation metadata `user_attributes`.

**metadata** `object`

Source metadata stored under `metadata.external_sync.details`. Supplying it replaces that details object, while unrelated existing metadata is preserved.

**statusTagId** `string`

UUID of a configured Conversation Status tag accessible to the workspace. Omit to preserve the existing status. A status locked by a human agent is not overwritten.

**events** `array` *required*

Events to import. An empty array is allowed for a metadata-only sync. Event external IDs must be unique within this conversation. Omitting previously imported events does not delete them.

**Event fields**

**externalId** `string` *required*

Stable event ID within the conversation, at most 255 characters, with the same character restrictions as the conversation external ID.

**role** `string` *required*

One of `user`, `agent`, `finibot`, or `otherbot`.

**content** `string` *required*

Event content, at most 100,000 characters. For `message` and `internalnote`, content must remain nonblank after sanitization.

**type** `string`

Defaults to `message`. Also accepts `internalnote`, `no_reply`, `silent_escalation`, `debounce`, and `widget_form`.

**externalCreatedAt** `number`

Source event timestamp in Unix milliseconds. Fini assigns its own ingestion `createdAt`; this field does not backdate it.

**tagIds** `array`

Up to 50 unique tag UUIDs accessible to the workspace. Adds missing event/tag associations; does not remove existing tags. May be supplied on a retry of an otherwise unchanged event.

**performKnowledgeSearch** `boolean`

Stored knowledge-search flag. Importing it does not execute a search.

**planningReasoning** `string`

Stored planning explanation.

**knowledgeSearchSelectionReasoning** `string`

Stored knowledge-search selection explanation.

**inputTagSelectionReasoning** `string`

Stored input-tag selection explanation.

**outputTagSelectionReasoning** `string`

Stored output-tag selection explanation.

**answerReasoning** `array`

Stored answer-reasoning objects. Each item must be an object.

**matchedArticles** `array`

Stored matched-article objects. Each item must be an object; supplying this field does not retrieve articles.

**executedToolIds** `array`

Stored tool identifiers, each a string. Does not execute tools.

**selectedRuleId** `string`

Stored selected-rule UUID. Does not evaluate the rule.

**selectedRuleVersionId** `string`

Stored selected-rule-version UUID.

**relevantMemoryIds** `array`

Stored relevant-memory UUIDs.

**userAttributes** `object`

Stored event-level user attributes.

**approved** `boolean`

Stored approval value.

**feedback** `string`

Stored feedback text.

**resolved** `boolean`

Stored resolution value.

**csatRating** `number`

Integer satisfaction rating. Defaults to 0 for newly imported events when omitted; the request validator imposes no rating range.

**escalationActive** `boolean`

Stored escalation flag; does not initiate an escalation.

**mlModels** `object`

Stored model metadata.

**replyPipeline** `object`

Stored reply-pipeline metadata.

**decisionProbabilities** `object`

Stored decision probabilities.

## Matching and retries

Conversations match by workspace, source, agent ID, and conversation external ID. The same external ID can be used for different agents. Events match by external ID within the matched conversation.

New events are inserted; existing events are not overwritten. A retry must keep the event’s role, type, and sanitized content unchanged. Any supplied optional event details or external timestamp must match the stored value; optional details can be omitted on retry. A mismatch fails the request. New event tags can still be added.

Conversation fields are updated separately from immutable event content. Sync refreshes conversation summaries and marks imported conversations as Fini-touched. Event `createdAt` and message summaries use Fini ingestion time, not `externalCreatedAt`. See [List conversations](https://docs.usefini.com/en/api-reference/list-conversations.md) for export timestamp filters.

> [!WARNING]
>
> Sync is not transactional. A failed request can leave conversations, events, or tags already written, including writes from other conversations in the batch. Retry with the same external IDs and unchanged event data to complete missing writes. Do not assume failure means nothing was imported, or send overlapping sync requests for the same conversation concurrently.

## Response

Returns HTTP `200` with a `results` array in request order. This is a completed sync response, not a queued job ID. Failed requests do not return per-item success/error results.

**results** `array`

One result per conversation on success.

**Result fields**

**externalId** `string`

The supplied conversation external ID.

**interactionId** `string`

The Fini conversation UUID, usable with [Get conversation](https://docs.usefini.com/en/api-reference/get-conversation.md).

**status** `string`

`created`, `updated`, or `unchanged`. New events, new tag associations, metadata changes, or repaired summaries can produce `updated`.

**tagsAdded** `number`

Number of newly inserted event/tag associations, not distinct tags across the batch.

**events** `array`

Results for the submitted events, in their request order. Empty for a metadata-only sync.

**Event result fields**

**externalId** `string`

The supplied event external ID.

**eventId** `string`

The Fini event UUID.

**status** `string`

`created` or `unchanged`.

## Errors

Invalid request fields, duplicate IDs within a batch, and more than 500 total events are rejected with HTTP `400`. The sync service rejects serialized payloads larger than 2 MiB with HTTP `413`. All agents and referenced tags must be accessible to the authenticated workspace.

> [!NOTE]
>
> Currently, unavailable agents/tags, invalid status tags, blank message content after sanitization, and immutable-event conflicts surface as HTTP `500` rather than typed `400` or `409` responses. Correct the input when one of these conditions is reported; do not repeatedly retry an unchanged conflicting payload. An error response is not a rollback guarantee.

Replace the example `botId` with an agent UUID from your workspace. IDs and content below are synthetic.

```bash cURL theme={null}
curl --request POST \
  --url 'https://api-prod.usefini.com/v2/hc-interactions/sync/public' \
  --header 'Authorization: Bearer fini_your_api_key' \
  --header 'Content-Type: application/json' \
  --data '{
  "source": "api",
  "interactions": [
    {
      "externalId": "support-thread-1001",
      "botId": "11111111-1111-4111-8111-111111111111",
      "subject": "Delivery question",
      "externalCreatedAt": 1793696400000,
      "events": [
        {
          "externalId": "message-1001",
          "role": "user",
          "content": "When will my order arrive?",
          "externalCreatedAt": 1793696400000
        }
      ]
    }
  ]
}'
```

```javascript Node.js theme={null}
const payload = {
  "source": "api",
  "interactions": [
    {
      "externalId": "support-thread-1001",
      "botId": "11111111-1111-4111-8111-111111111111",
      "subject": "Delivery question",
      "externalCreatedAt": 1793696400000,
      "events": [
        {
          "externalId": "message-1001",
          "role": "user",
          "content": "When will my order arrive?",
          "externalCreatedAt": 1793696400000
        }
      ]
    }
  ]
};
const response = await fetch('https://api-prod.usefini.com/v2/hc-interactions/sync/public', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.FINI_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(payload),
});
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());
```

```python Python theme={null}
import os
import requests

payload = {
  "source": "api",
  "interactions": [
    {
      "externalId": "support-thread-1001",
      "botId": "11111111-1111-4111-8111-111111111111",
      "subject": "Delivery question",
      "externalCreatedAt": 1793696400000,
      "events": [
        {
          "externalId": "message-1001",
          "role": "user",
          "content": "When will my order arrive?",
          "externalCreatedAt": 1793696400000
        }
      ]
    }
  ]
}
response = requests.post(
    "https://api-prod.usefini.com/v2/hc-interactions/sync/public",
    headers={"Authorization": f"Bearer {os.environ['FINI_API_KEY']}"},
    json=payload,
    timeout=60,
)
response.raise_for_status()
print(response.json())
```

```json 200 OK theme={null}
{
  "results": [
    {
      "externalId": "support-thread-1001",
      "interactionId": "22222222-2222-4222-8222-222222222222",
      "status": "created",
      "events": [
        {
          "externalId": "message-1001",
          "eventId": "1c2560cb-ad54-5ae8-8dd1-0fbbb4d81fa7",
          "status": "created"
        }
      ],
      "tagsAdded": 0
    }
  ]
}
```


## Related topics

- [Overview](https://docs.usefini.com/en/api-reference/conversations.md)
- [Intercom](https://docs.usefini.com/en/deploy/intercom.md)
- [LiveChat](https://docs.usefini.com/en/deploy/livechat.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.