Use these APIs to send conversation and voice data directly to Heap Conversational Intelligence to be analyzed. They are intended for organizations using CRM, customer support, or phone systems without a native Heap integration.
Overview
The APIs support the following data types:
| API | Channel | Use case |
|---|---|---|
| Conversation API | Chat, email, SMS, and other text channels | Text-based conversations where you provide the messages. |
| Voice API | Voice calls | Phone calls where Heap transcribes the audio and identifies speakers. |
How it works
The Conversation API follows these steps:
- Send a conversation and its messages to the API.
- Heap accepts and queues the conversation for processing.
- Use the processing status endpoint to check progress.
- Heap analyzes the conversation. Results typically appear in the Heap UI within 2 to 3 hours.
The Voice API follows these steps:
- Send conversation metadata and one or more audio file paths or URLs to the API.
- Heap accepts and queues the conversation for processing.
- Use the processing status endpoint to check progress.
- Heap transcribes the audio, identifies speakers, and analyzes the conversation. Results typically appear in the Heap UI within 3 hours.
Prerequisites
Complete the following steps before using these APIs:
- Complete account setup: Heap configures your integration and provides your API credentials.
- Configure audio file access for voice ingestion: Either provide access to your Amazon S3 bucket or provide publicly accessible URLs for your audio files. Heap provides an S3 bucket policy file when applicable. Share this file with the person who manages your infrastructure.
- Configure customer satisfaction (CSAT), if needed: If you plan to send customer satisfaction ratings, configure CSAT normalization rules using the CSAT configuration API.
API authentication
Heap APIs use OAuth 2.0 with the client credentials grant. Your application exchanges its client credentials for a bearer token and includes that token with every API request.
Get your API credentials
During onboarding, authorized users receive access to the Heap onboarding portal. Use the portal to retrieve your API credentials and, when applicable, the S3 bucket policy file.
Request a bearer token
Send a POST request to the token endpoint:
POST https://live.loris.ai/ci/api/oauth/token/Use the client_credentials grant type with your client ID and secret. The response includes a bearer token. Heap doesn't issue a refresh token.
Include the bearer token in the Authorization header of every API request:
Authorization: Bearer <token>Bearer tokens expire after 24 hours. When a token expires, send another request to the token endpoint with the same client ID and secret.
The API accepts the client_credentials grant type only. Other grant types, including refresh_token, are rejected.
Test requests without writing production data
To send a test conversation without writing data to the database, include this header:
Dry-Run: trueDry-run requests still run through validation, translation, and personally identifiable information (PII) redaction. This lets you test the full processing pipeline without affecting production data.
Endpoints
Use the following endpoints:
| Purpose | Method | URL |
|---|---|---|
| Conversation API | POST | https://live.loris.ai/ci/api/conversation/ |
| Voice API | POST | https://live.loris.ai/ci/api/voice-conversation/ |
| Check processing status | GET | https://live.loris.ai/ci/api/conversation-status/?source_id={source_id} |
| CSAT configuration | POST | https://live.loris.ai/ci/api/settings/csat/ |
| Revoke a token | POST | https://live.loris.ai/ci/api/oauth/revoke_token/ |
| Delete conversation | POST | https://live.loris.ai/ci/api/conversation/delete/ Send the source_id of the conversation. |
Request structure
The Conversation API and Voice API use the same top-level request structure. All conversation fields are nested inside the conversation object.
| Field | Type | Required | Description |
|---|---|---|---|
conversation | Object | Yes | Dictionary containing the conversation fields. |
Common fields
These fields apply to both the Conversation API and the Voice API.
Required fields
| Field | Type | Description |
|---|---|---|
source_id | String | Unique conversation identifier. The maximum length is 63 characters. Use letters, numbers, hyphens, and underscores. The value must be unique for your account. If one ticket contains multiple conversations, append a suffix to identify the channel and conversation. For example: {ticket_id}_{channel}_{index}, such as 123456789_CHAT_0. |
crm_user_id | String | Unique identifier of the customer in your CRM. |
created | String, ISO 8601 | Timestamp when the conversation was created in the source system. Use UTC and include a timezone indicator, such as 2024-01-15T09:00:00Z. |
Optional fields
| Field | Type | Description |
|---|---|---|
related_ticket_id | String | ID of the parent ticket in the source system. The maximum length is 63 characters. This field is optional when one ticket maps to one conversation. It is required when one ticket maps to multiple conversations. Use the original ticket ID to link related conversations. |
csat | String | Customer satisfaction rating as received from the source system, such as 5, good, or satisfied. CSAT normalization rules must be configured during onboarding. |
brand_name | String | Brand associated with the conversation. The maximum length is 60 characters. Heap creates the brand if it doesn't already exist. |
tags | Object | Tags in the format {tag_name: [tag_values]}. Values must be arrays, even when a tag has one value. For example: {"priority": ["high"]}. Tag names can contain up to 80 characters. Tag values can contain up to 150 characters. Tags are available for filtering in the Heap UI. |
custom_fields | Object | Custom fields in the format {field_name: value}. Values must be strings, integers, or floats. Nested objects aren't supported. Custom fields are available for filtering in the Heap UI. |
csq_user_id | String or integer | Identifier of the user in Heap. |
Conversation API
Use the Conversation API for text-based conversations (such as chat, email, and SMS) where you provide the messages.
Heap enriches every ingested conversation. We recommend that if a conversation is ongoing, wait until it is closed or resolved before sending it.
If you send a conversation again with the same source_id, the new version completely replaces the previous version, including previous analysis results. Partial updates, such as metadata-only updates, aren't supported.
Messages must be sorted by created in non-decreasing order. Messages with the same timestamp are allowed and remain in their array order. A request with messages in the wrong order returns a 400 error.
Language support
The Conversation API supports English, French, Spanish, and Arabic. Non-English conversations are translated into English for analysis.
Required fields
| Field | Type | Description |
|---|---|---|
channel | String | Communication channel. See the supported channel values below. |
messages | Array | Array of message objects. See the Message object section below. |
Channel values
| Value | Description |
|---|---|
EMAIL | Email conversations. |
CHAT | Live chat or web chat. |
SMS | SMS or text messaging. |
WHATSAPP | WhatsApp messaging. |
FACEBOOK | Facebook Messenger. |
INSTAGRAM | Instagram direct messages. |
TWITTER | Twitter or X direct messages. |
TIKTOK | TikTok messages. |
MESSAGING | Generic messaging channel. |
WEB | Web-based conversations. |
MOBILE_SDK | Mobile app SDK conversations. |
API | API-initiated conversations. |
Message object
Each message represents one message in the conversation:
| Field | Type | Required | Description |
|---|---|---|---|
message_type | String | Yes | Direction of the message:IN for a customer message.OUT-HUMAN for an agent message.OUT-BOT for an automated bot or AI response.OUT-AUTO-REPLY for a simple automated reply, such as “An agent will be with you shortly.” |
message_body | String | Yes | Message content. Attachments aren't supported. To indicate that a message includes an attachment, include [FILE_UPLOAD] in the message text. |
created | String, ISO 8601 | Yes | Timestamp when the message was sent. Use UTC and include a timezone indicator. |
author_id | String | Conditional | Required for OUT-HUMAN, OUT-BOT, and OUT-AUTO-REPLY messages. |
author_name | String | Conditional | Required for OUT-HUMAN, OUT-BOT, and OUT-AUTO-REPLY messages. |
author_email | String | Conditional | Required for OUT-HUMAN, OUT-BOT, and OUT-AUTO-REPLY messages. |
For OUT-HUMAN, OUT-BOT, and OUT-AUTO-REPLY messages, author_id, author_name, and author_email are all required. Empty values are not accepted.
Conversation request example
{ "conversation": { "source_id": "ticket-98765", "crm_user_id": "customer-123", "channel": "EMAIL", "created": "2024-01-15T09:00:00Z", "csat": "5", "brand_name": "Acme Pro", "tags": { "category": ["billing"], "priority": ["high"] }, "custom_fields": { "account_tier": "premium", "case_type": "billing_inquiry" }, "messages": [ { "message_type": "IN", "message_body": "Hi, I have a question about my recent invoice.", "created": "2024-01-15T09:00:00Z" }, { "message_type": "OUT-HUMAN", "message_body": "Hello John, I'd be happy to help you with your invoice. Could you please provide your account number?", "created": "2024-01-15T09:30:00Z", "author_id": "agent-456", "author_name": "Jane Smith", "author_email": "jane.smith@company.com" }, { "message_type": "IN", "message_body": "Sure, it's ACC-12345.", "created": "2024-01-15T09:35:00Z" }, { "message_type": "OUT-HUMAN", "message_body": "Thank you! I've reviewed your account and corrected the billing issue. You should see the adjustment within 24 hours.", "created": "2024-01-15T14:25:00Z", "author_id": "agent-456", "author_name": "Jane Smith", "author_email": "jane.smith@company.com" } ] } }Conversation API limits
- Text from non-English conversations cannot exceed 100 KB in UTF-8 format.
- A single message cannot exceed 5 KB.
- A request cannot exceed 2.5 MB.
- Each conversation must contain at least one message and no more than 300 messages.
- Heap stores the agent name and email address the first time they are received. You can't update these values through the API.
CSAT configuration
Survey systems use different rating formats, so you must declare your scale before sending any conversation that includes a csat value. Heap converts each raw score into a normalized value between 0.0 and 1.0 so scores are comparable across conversations and channels. This is a one-time setup call, separate from sending conversations.
Send a POST request to https://live.loris.ai/ci/api/settings/csat/ with a csat_config object. Set csat_type to either numerical or binary.
Numerical scale
Use this when your survey produces a number in a fixed range, such as 1–5 or 1–10. Required fields are min_value and max_value, both integers within a 0–100 range, and min_value must be less than max_value. Normalization is (raw_score - min_value) / (max_value - min_value). On a 1–5 scale, 1 becomes 0.00, 3 becomes 0.50, and 5 becomes 1.00. A raw score outside the declared range is ignored, so no CSAT is recorded for that conversation.
{ "csat_config": { "csat_type": "numerical", "min_value": 1, "max_value": 5 } }Binary scale
Use this when your survey produces exactly two outcomes, such as satisfied and unsatisfied. The required field is raw_rating_to_normalized_csat, a mapping of your two raw values to 0.0 and 1.0, and the mapping must contain exactly two values. A raw value that is not in the mapping is ignored, so no CSAT is recorded. Text values must match what your source system sends exactly. Case and spelling matter, and emojis or special characters may not work.
{ "csat_config": { "csat_type": "binary", "raw_rating_to_normalized_csat": { "1": 0.0, "5": 1.0 } } }Voice API
Use the Voice API for voice conversations where Heap transcribes the audio and identifies the speakers.
Required fields
| Field | Type | Description |
|---|---|---|
is_inbound_call | Boolean | Use true when the customer called your organization. Use false when an agent called the customer. |
audio_files | Array | One or more audio file objects. See the Audio files section below. |
Optional timing field
| Field | Type | Description |
|---|---|---|
audio_start_time | String, ISO 8601 | Time when the audio recording started. Heap uses this value to calculate message timestamps in the transcript. Defaults to created. |
Optional call metrics
| Field | Type | Description |
|---|---|---|
audio_duration_seconds | Float | Total duration of the audio recording in seconds. |
call_talk_time | Integer | Conversation time in seconds, excluding hold and wrap-up time. |
call_hold_time | Integer | Total customer hold time in seconds. |
call_wrap_up_time | Integer | Agent after-call work time in seconds. |
call_consultation_time | Integer | Time the agent spent consulting with others in seconds. |
Audio files
A voice conversation can contain one or more audio segments. Heap merges multiple segments into one audio file before transcription and orders messages by their timestamps across all segments.
Agent details must be provided on each object in audio_files. Agent fields sent at the conversation level are ignored.
Stereo files with separate channels are preferred because they improve speaker identification. Use the optional agent_channel field to identify the agent's channel.
| Field | Type | Required | Description |
|---|---|---|---|
file_path | String | Yes | Path to the audio file in Amazon S3, such as recordings/2024/01/call-12345.mp3, or a publicly accessible URL. |
audio_start_time | String, ISO 8601 | Conditional | Time when the audio segment started. Heap uses this value to calculate message timestamps in the transcript. For a single-segment call, this defaults to the conversation-level audio_start_time. For a multi-segment call, audio_start_time is required on every audio-file object. |
agent_id | String | Yes | Identifier of the agent for the segment. |
agent_name | String | Yes | Name of the agent for the segment. |
agent_email | String | Yes | Email address of the agent for the segment. |
agent_channel | Integer | No | Identifies the agent's audio channel:null means Heap performs speaker identification.1 means the agent is on channel 1 and the customer is on channel 2.2 means the agent is on channel 2 and the customer is on channel 1. |
Supported audio formats
The API supports the following audio formats:
- MP3
- WAV
- Other formats supported by FFmpeg
Single audio file example
{ "audio_files": [ { "file_path": "recordings/2024/01/call-12345.mp3", "agent_id": "agent-123", "agent_name": "John Smith", "agent_email": "john.smith@company.com" } ] }Multiple audio segments example
{ "audio_files": [ { "file_path": "recordings/2024/01/call-12345-seg1.mp3", "audio_start_time": "2024-01-15T10:30:00Z", "agent_id": "agent-123", "agent_name": "John Smith", "agent_email": "john.smith@company.com" }, { "file_path": "recordings/2024/01/call-12345-seg2.mp3", "audio_start_time": "2024-01-15T10:33:00Z", "agent_id": "agent-456", "agent_name": "Jane Doe", "agent_email": "jane.doe@company.com" } ] }Voice language support
Voice transcription supports English.
Speaker identification
Heap uses AI to identify speakers and determine whether each speaker is an agent or customer. Stereo files with separate channels improve speaker identification.
The process includes the following steps:
- Transcription: Heap transcribes the audio and identifies speakers.
- Speaker identification: Heap determines speaker roles using pattern matching and language-model-based identification.
Voice processing requirements
The following requirements apply to voice conversations:
- Each audio segment must contain one customer and one agent.
- Calls with only one detected speaker, such as voicemails, are skipped.
- Interactive voice response, conference, and consultation segments aren't supported as standalone segments.
- Processing fails if Heap can't identify an agent, can't identify a customer, or attributes too many words to unknown speakers.
- Processing failures appear in the status response with
"status": "failed"and an error message. - Audio file download failures aren't retried.
Voice audio limits
- Audio must contain one or two channels.
- MP3, WAV, and other FFmpeg-supported formats are supported.
- Very long calls may have transcripts truncated for speaker identification. This can reduce accuracy for calls with more than approximately 30 minutes of continuous speech.
Voice request example
{ "conversation": { "source_id": "call-98765", "crm_user_id": "customer-456", "created": "2024-01-15T10:30:00Z", "is_inbound_call": true, "csat": "5", "tags": { "category": ["billing"], "resolution": ["resolved"] }, "custom_fields": { "call_reason": "billing_inquiry", "account_tier": "premium" }, "audio_files": [ { "file_path": "recordings/2024/01/call-98765.mp3", "agent_id": "agent-456", "agent_name": "Jane Smith", "agent_email": "jane.smith@company.com" } ] } }
Response format
Each request contains one conversation and returns one outcome. The API doesn't return a partial-success list.
| Status | Condition | Meaning | Response body |
|---|---|---|---|
200 | Success | The request was accepted. | Empty body. |
400 | Schema validation failure | The request doesn't match the schema. | {"errors": [{"loc": [...], "msg": "...", "type": "..."}]} |
400 | CSAT is not configured | The request includes a csat value, but CSAT normalization hasn't been configured. | {"error": "<message>"} |
400 | Missing source_id | The status request doesn't include the required query parameter. | {"success": false, "error_message": "source_id query parameter is required"} |
401 | Authentication failure | The bearer token is invalid, missing, or expired. Request a new token from the token endpoint. | |
404 | Conversation not found | No conversation exists for the supplied source_id. | {"success": false, "error_message": "No conversation found for source_id <id>"} |
429 | Rate limit exceeded | Reduce the request rate and try again. | |
500 | Processing failure | Translation or PII redaction failed while processing an otherwise valid request. | {"error": "<message>"} |
400 response example
{ "errors": [ { "loc": ["conversation", "messages", 0, "author_id"], "msg": "Field required", "type": "missing" }, { "loc": ["conversation", "channel"], "msg": "Input should be 'EMAIL', 'CHAT', ...", "type": "enum" } ] }The loc value identifies the field path. Nested fields include the conversation envelope in the path.
Processing status
Use the processing status endpoint to check whether a conversation has finished processing.
Send a GET request to:
GET https://live.loris.ai/ci/api/conversation-status/?source_id={source_id}Error responses
The status endpoint returns the following errors:
| Status | Condition | Response body |
|---|---|---|
400 | Missing source_id | {"success": false, "error_message": "source_id query parameter is required"} |
404 | Conversation not found | {"success": false, "error_message": "No conversation found for source_id <id>"} |
Response example
{ "source_id": "ticket-12345", "status": "complete", "error": null }Status values
| Status | API | Description |
|---|---|---|
pending | Conversation and Voice | Conversation is waiting to be processed or actively being processed. |
transcribing | Voice only | Audio was received. Transcription and PII redaction are in progress. |
complete | Conversation and Voice | Processing is complete, and the conversation is available in the Heap UI. |
failed | Conversation and Voice | Processing failed. Check the error field for details. |
Failed status example
{ "source_id": "call-12345", "status": "failed", "error": "Failed to download audio file: file not found" }Rate limits
Both APIs accept up to 100 requests per minute.
Revoke a token
If a bearer token is compromised, or you're decommissioning an integration, revoke the token instead of waiting for it to expire.
Send a POST request to https://live.loris.ai/ci/api/oauth/revoke_token/.
Send token, client_id, and client_secret as application/x-www-form-urlencoded fields in the request body. The endpoint always returns 200, whether or not the token existed. An application can only revoke tokens issued to itself.