Data Export API (exporting from Rilla)
Export your organization's conversation, team, and user analytics data programmatically.
Overview
Authenticate with your API key and POST a date range to any export endpoint. Rilla returns a structured payload of analytics data you can load into a database, spreadsheet, or BI tool.
Base URL
https://customer.rillavoice.comAuthentication
Learn how to authenticate your requests with an API key.
Endpoints
Explore the available export endpoints.
Code Examples
Copy-paste examples in Python, JavaScript, and cURL.
How it works
Obtain your API key from your Rilla account manager or customer success manager and store it securely.
Include your API key in the Authorization header of every request: Authorization: YOUR_API_KEY.
POST a date range to /export/conversations, /export/teams, or /export/users.
The conversations endpoint is paginated. Use totalPages in the response to loop through all results.
Authentication
All requests to the Data Export API must include a valid API key passed in the Authorization header.
POST /export/conversations HTTP/1.1
Host: customer.rillavoice.com
Authorization: YOUR_API_KEY
Content-Type: application/jsonRequest Headers
| Header | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | API key. Format: YOUR_API_KEY. |
Content-Type | string | Yes | Must be application/json. |
Obtaining an API Key
Reach out to your Rilla account manager or customer success manager to get an API key provisioned for your organization. Each key is scoped to a single Rilla organization.
On every request, Rilla validates that the API key exists and maps to an active organization. If the key is missing or unrecognized, the API returns 401 Unauthorized.
Keep your key secure
API keys grant read access to your organization's analytics data. Do not expose them in client-side code, public repositories, or logs. Contact support@rilla.com immediately if a key is ever compromised.
GET /export/conversations/{conversationId}
Fetches a single conversation by its ID. Returns the same conversation object as the list endpoint below, but as a bare object rather than inside a paginated wrapper.
Use this when you already know a conversation's ID — for example, a conversation_id received from a webhook — and want to pull its full export record without specifying a date range.
Request Headers
| Header | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | API key. Format: YOUR_API_KEY. |
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
conversationId | string (UUID) | Yes | ID of the conversation to fetch. Must be a valid UUID. |
Response
Returns a single ConversationsExport object. Unlike the list endpoint, there is no pagination wrapper.
Returns 404 Not Found if the conversation does not exist, or if it falls outside the scope of your API key. Team-scoped keys receive a 404 (rather than 403) for conversations they cannot access, so existence is never leaked.
Example Request
GET /export/conversations/f1a3e9d8-2b46-4c1a-9c7e-7e4a18d2c93f HTTP/1.1
Host: customer.rillavoice.com
Authorization: YOUR_API_KEYExample Response
{
"conversationId": "f1a3e9d8-2b46-4c1a-9c7e-7e4a18d2c93f",
"recordingId": "rec-7c2f4a90",
"date": "2024-03-05T14:00:00Z",
"processedDate": "2024-03-05T15:12:00Z",
"title": "Home Estimate - John Doe",
"duration": 3240,
"crmEventID": "evt-90817",
"user": {
"id": "user-001",
"name": "Jane Smith",
"email": "rep@yourcompany.com"
},
"jobNumber": "JOB-4471",
"stLink": "https://go.servicetitan.com/jobs/4471",
"totalSold": 12500,
"outcome": "Sold",
"jobSummary": "Rep walked the customer through the premium package and scheduled install.",
"customSummary": "Customer expressed interest in premium package...",
"repSpeedWPM": 148,
"repTalkRatio": 0.54,
"longestRepMonologue": 120,
"longestCustomerMonologue": 64,
"totalComments": 3,
"rillaUrl": "https://app.rillavoice.com/conversations/single?id=f1a3e9d8-2b46-4c1a-9c7e-7e4a18d2c93f",
"viewers": [
{
"userId": "user-014",
"name": "Manager Mike",
"viewCount": 2,
"totalViewTimeMs": 540000
}
],
"checklists": [
{
"name": "Discovery",
"checklistName": "Discovery",
"score": 3,
"checklistScore": 3,
"denominator": 5,
"checklistDenominator": 5,
"trackerData": [
{
"name": "Asked about budget",
"trackerName": "Asked about budget",
"isHit": true,
"trackerIsHit": true,
"aiScore": 0.92,
"trackerAiScore": 0.92
}
]
}
],
"aiTrackers": [
{
"checklistName": "Discovery",
"trackerName": "Asked about budget",
"isHit": true,
"aiScore": 0.92
}
],
"customFields": { "leadSource": "Facebook" },
"surveyResults": [],
"audioUrl": "<presigned-s3-url>",
"transcriptUrl": "<presigned-s3-url>"
}POST /export/conversations
Exports data for all conversations recorded during the provided time range. Results are paginated — use page and limit to iterate.
Request Headers
| Header | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | API key. Format: YOUR_API_KEY. |
Content-Type | string | Yes | Must be application/json. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
fromDate | string | Yes | Beginning of the time range (ISO 8601). |
toDate | string | Yes | End of the time range (ISO 8601). |
dateType | string | No | timeOfRecording (default) or processedDate. |
page | number | No | 1-based page index. Defaults to 1. |
limit | number | No | Conversations per page. Max 50. Defaults to 50. |
users | string[] | No | Filter by user emails. If omitted, all users are returned. |
Response
| Field | Type | Description |
|---|---|---|
currentPage | number | The current page number. |
totalPages | number | Total number of pages. |
totalConversations | number | Total conversations for the date range. |
conversations | array | Conversation objects. See Data Models. |
Example Request
{
"fromDate": "2024-03-01T00:00:00Z",
"toDate": "2024-04-01T00:00:00Z",
"dateType": "timeOfRecording",
"page": 1,
"limit": 50
}Example Response
{
"currentPage": 1,
"totalPages": 4,
"totalConversations": 187,
"conversations": [
{
"conversationId": "f1a3e9d8-2b46-4c1a-9c7e-7e4a18d2c93f",
"recordingId": "rec-7c2f4a90",
"date": "2024-03-05T14:00:00Z",
"processedDate": "2024-03-05T15:12:00Z",
"title": "Home Estimate - John Doe",
"duration": 3240,
"crmEventID": "evt-90817",
"user": {
"id": "user-001",
"name": "Jane Smith",
"email": "rep@yourcompany.com"
},
"jobNumber": "JOB-4471",
"stLink": "https://go.servicetitan.com/jobs/4471",
"totalSold": 12500,
"outcome": "Sold",
"jobSummary": "Rep walked the customer through the premium package and scheduled install.",
"customSummary": "Customer expressed interest in premium package...",
"repSpeedWPM": 148,
"repTalkRatio": 0.54,
"longestRepMonologue": 120,
"longestCustomerMonologue": 64,
"totalComments": 3,
"rillaUrl": "https://app.rillavoice.com/conversations/single?id=f1a3e9d8-2b46-4c1a-9c7e-7e4a18d2c93f",
"viewers": [
{
"userId": "user-014",
"name": "Manager Mike",
"viewCount": 2,
"totalViewTimeMs": 540000
}
],
"checklists": [
{
"name": "Discovery",
"checklistName": "Discovery",
"score": 3,
"checklistScore": 3,
"denominator": 5,
"checklistDenominator": 5,
"trackerData": [
{
"name": "Asked about budget",
"trackerName": "Asked about budget",
"isHit": true,
"trackerIsHit": true,
"aiScore": 0.92,
"trackerAiScore": 0.92
}
]
}
],
"aiTrackers": [
{
"checklistName": "Discovery",
"trackerName": "Asked about budget",
"isHit": true,
"aiScore": 0.92
}
],
"customFields": { "leadSource": "Facebook" },
"surveyResults": [],
"audioUrl": "<presigned-s3-url>",
"transcriptUrl": "<presigned-s3-url>"
}
]
}POST /export/teams
Returns all teams in your organization along with their analytics data.
Request Headers
| Header | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | API key. Format: YOUR_API_KEY. |
Content-Type | string | Yes | Must be application/json. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
fromDate | string | Yes | Beginning of the time range (ISO 8601). |
toDate | string | Yes | End of the time range (ISO 8601). |
includeSubteams | boolean | No | Whether to include sub-teams. Defaults to false. |
Response
| Field | Type | Description |
|---|---|---|
teams | array | Array of team objects. See Data Models. |
Example Request
{
"fromDate": "2024-03-01T00:00:00Z",
"toDate": "2024-04-01T00:00:00Z",
"includeSubteams": true
}Example Response
{
"teams": [
{
"name": "West Region",
"teamId": "team-42",
"externalTeamId": "ST-WEST",
"parentTeamId": null,
"parentTeamName": null,
"analyticsViewed": 12,
"appointmentsRecorded": 88,
"averageConversationDuration": 2980,
"averageConversationLength": 3120,
"clipCommentsGiven": 7,
"clipsCreated": 14,
"clipViewDuration": 86400,
"commentsGiven": 41,
"commentsRead": 33,
"commentsReceived": 52,
"conversationViewDuration": 172800,
"conversationsCommentedOn": 29,
"conversationsRecorded": 95,
"conversationsViewed": 140,
"longestCustomerMonologueAverage": 58,
"longestMonologueAverage": 102,
"patienceAverage": 0.71,
"recordingCompliance": 0.92,
"ridealongsReceived": 4,
"scorecardsGiven": 18,
"scorecardsReceived": 22,
"talkRatioAverage": 0.52,
"totalAppointments": 96,
"totalUsersWhoRecorded": 9,
"totalUsers": 11
}
]
}POST /export/users
Returns all users in your organization along with their analytics data.
Request Headers
| Header | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | API key. Format: YOUR_API_KEY. |
Content-Type | string | Yes | Must be application/json. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
fromDate | string | Yes | Beginning of the time range (ISO 8601). |
toDate | string | Yes | End of the time range (ISO 8601). |
users | string[] | No | Filter by user emails. If omitted, all users are returned. |
Response
| Field | Type | Description |
|---|---|---|
users | array | Array of user objects. See Data Models. |
Example Request
{
"fromDate": "2024-03-01T00:00:00Z",
"toDate": "2024-04-01T00:00:00Z",
"users": ["rep1@yourcompany.com", "rep2@yourcompany.com"]
}Example Response
{
"users": [
{
"userId": "user-001",
"name": "Jane Smith",
"email": "rep1@yourcompany.com",
"accountSetUp": true,
"isRemoved": false,
"role": "rep",
"teams": [{ "teamId": "team-42", "name": "West Region" }],
"timeOfFirstRecording": "2023-11-02T16:20:00Z",
"hasVoiceId": true,
"analyticsViewed": 5,
"appointmentsRecorded": 46,
"averageConversationDuration": 3150,
"averageConversationLength": 3260,
"averageScriptCompliance": 0.81,
"averageTimePerRidealong": 1800,
"clipCommentsGiven": 3,
"clipsCreated": 6,
"clipViewDuration": 43200,
"commentsReceived": 28,
"commentsRead": 21,
"commentsGiven": 12,
"conversationsCommentedOn": 15,
"conversationsRecorded": 48,
"conversationsViewed": 70,
"conversationViewDuration": 86400,
"lastRidealongAt": "2024-03-20T13:00:00Z",
"longestMonologueAverage": 115,
"longestCustomerMonologueAverage": 52,
"patienceAverage": 0.68,
"percentageOfRepsWithCommentsGiven": null,
"recordingCompliance": 0.9,
"ridealongsReceived": 2,
"scorecardsReceived": 9,
"scorecardsGiven": 4,
"talkRatioAverage": 0.53,
"totalAppointments": 51,
"totalEndOfRidealongsReached": 1,
"totalRidealongsCompleted": 3,
"viewedRecordedRatio": 1.46,
"liveCoaching": {
"sessionsHosted": 2,
"viewEventsReceived": 18,
"uniqueViewers": 5,
"viewDurationMinutes": 64,
"commentsReceived": 7,
"uniqueCommenters": 3,
"moneySaved": 1200,
"lastCoachedAt": "2024-03-18T10:30:00Z"
}
}
]
}Data Models
ConversationsExport
| Field | Type | Description |
|---|---|---|
conversationId | string | ID of the conversation. |
recordingId | string | ID of the underlying recording. |
date | string | Date/time the conversation was recorded (ISO 8601). |
processedDate | string | Date/time the conversation finished processing (ISO 8601). |
title | string | Title of the conversation / appointment. |
duration | number | Duration in seconds. |
crmEventID | string | ID of the associated CRM / calendar event. |
user | object | The rep who recorded the conversation: { id, name, email }. |
jobNumber | string | Job number from the CRM / calendar event. |
stLink | string | Deep link to the job in the connected CRM (e.g. ServiceTitan). |
totalSold | number | Total amount sold on the job. |
outcome | string | Outcome of the appointment. |
jobSummary | string | AI-generated summary of the job. |
customSummary | string | Admin summary / custom insights in your organization's format. |
repSpeedWPM | number | Rep speaking speed, in words per minute. |
repTalkRatio | number | Fraction of time the rep was talking (0–1). |
longestRepMonologue | number | Longest uninterrupted rep monologue, in seconds. |
longestCustomerMonologue | number | Longest uninterrupted customer monologue, in seconds. |
totalComments | number | Number of comments left on the conversation. |
rillaUrl | string | Link to view the conversation in the Rilla web app. |
viewers | array | Users who viewed the conversation. See Viewer. |
checklists | array | Coaching checklists scored for the conversation. Each checklist contains its trackers. See Checklist. |
aiTrackers | array | Flattened list of every tracker across all checklists. See AiTracker. |
customFields | object | null | Custom fields from the calendar event. Keys and values are customer-defined. null if none are set. |
surveyResults | array | Survey results associated with the conversation. Empty array if the conversation has none. |
audioUrl | string | Temporary presigned S3 URL for the conversation's audio recording. Expires 6 hours after the response is issued — download or persist the file rather than storing the URL. |
transcriptUrl | string | Temporary presigned S3 URL for the conversation's transcript. Expires 6 hours after the response is issued — download or persist the file rather than storing the URL. |
Viewer
A user who viewed the conversation. Returned in the viewers array of each ConversationsExport.
| Field | Type | Description |
|---|---|---|
userId | string | Rilla user ID of the viewer. |
name | string | Name of the viewer. |
viewCount | number | Number of times this user viewed the conversation. |
totalViewTimeMs | number | Total time this user spent viewing, in milliseconds. |
Checklist
A coaching checklist scored against the conversation. Returned in the checklists array of each ConversationsExport.
| Field | Type | Description |
|---|---|---|
checklistName | string | Name of the checklist. |
checklistScore | number | Number of trackers hit on this checklist. |
checklistDenominator | number | Total number of trackers in the checklist. |
trackerData | array | The individual trackers evaluated for this checklist. See Tracker. |
Each checklist is also returned with the unprefixed aliases name, score, and denominator, which carry the same values as checklistName, checklistScore, and checklistDenominator. Prefer the prefixed fields; the aliases are retained for backward compatibility.
Tracker
A single tracker within a Checklist. Returned in the trackerData array.
| Field | Type | Description |
|---|---|---|
trackerName | string | Name of the tracker. |
trackerIsHit | boolean | Whether the tracker was hit during the conversation. |
trackerAiScore | number | AI-generated score for the tracker. |
Each tracker is also returned with the unprefixed aliases name, isHit, and aiScore, which carry the same values as trackerName, trackerIsHit, and trackerAiScore. Prefer the prefixed fields; the aliases are retained for backward compatibility.
AiTracker
A single tracker in the flattened aiTrackers array of each ConversationsExport. Unlike trackerData, these are not nested under a checklist — each entry carries its own checklistName instead.
| Field | Type | Description |
|---|---|---|
checklistName | string | Name of the checklist this tracker belongs to. |
trackerName | string | Name of the tracker. |
isHit | boolean | Whether the tracker was hit during the conversation. |
aiScore | number | AI-generated score for the tracker. |
Team
Returned in the teams array. All usage metrics are calculated for the date range provided in the request.
| Field | Type | Description |
|---|---|---|
name | string | Name of the team. |
teamId | string | Rilla team ID. |
externalTeamId | string | null | ID of the team in the connected CRM. null if not linked. |
parentTeamId | string | null | ID of the parent team. null for top-level teams. |
parentTeamName | string | null | Name of the parent team. null for top-level teams. |
analyticsViewed | number | Number of analytics views by team members. |
appointmentsRecorded | number | Appointments that were recorded. |
averageConversationDuration | number | Average conversation duration, in seconds. |
averageConversationLength | number | Average conversation length, in seconds. |
clipCommentsGiven | number | Comments given on clips. |
clipsCreated | number | Clips created. |
clipViewDuration | number | Total clip view duration, in seconds. |
commentsGiven | number | Comments given by team members. |
commentsRead | number | Comments read by team members. |
commentsReceived | number | Comments received by team members. |
conversationViewDuration | number | Total conversation view duration, in seconds. |
conversationsCommentedOn | number | Conversations that received at least one comment. |
conversationsRecorded | number | Conversations recorded by the team. |
conversationsViewed | number | Conversations viewed by team members. |
longestCustomerMonologueAverage | number | Average longest customer monologue, in seconds. |
longestMonologueAverage | number | Average longest rep monologue, in seconds. |
patienceAverage | number | Average patience score. |
recordingCompliance | number | Fraction of appointments that were recorded (0–1). |
ridealongsReceived | number | Ride-alongs received. |
scorecardsGiven | number | Scorecards given. |
scorecardsReceived | number | Scorecards received. |
talkRatioAverage | number | Average rep talk ratio (0–1). |
totalAppointments | number | Total appointments in the range. |
totalUsersWhoRecorded | number | Number of team members who recorded at least one conversation. |
totalUsers | number | Total number of users in the team. |
User
Returned in the users array. Usage metrics are calculated for the date range provided in the request, and may be null when no data exists for the user in that range.
| Field | Type | Description |
|---|---|---|
userId | string | Rilla user ID. |
name | string | Full name. |
email | string | Email address. |
accountSetUp | boolean | Whether the user has completed account setup. |
isRemoved | boolean | Whether the user has been removed/deactivated. |
role | string | The user's role. |
teams | array | Teams the user belongs to: { teamId, name }[]. |
timeOfFirstRecording | string | null | Timestamp of the user's first recording (ISO 8601), or null. |
hasVoiceId | boolean | Whether the user has an enrolled voice ID. |
analyticsViewed | number | Number of analytics views. |
appointmentsRecorded | number | null | Appointments recorded. |
averageConversationDuration | number | null | Average conversation duration, in seconds. |
averageConversationLength | number | null | Average conversation length, in seconds. |
averageScriptCompliance | number | null | Average script compliance (0–1). |
averageTimePerRidealong | number | null | Average time per ride-along, in seconds. |
clipCommentsGiven | number | Comments given on clips. |
clipsCreated | number | Clips created. |
clipViewDuration | number | Total clip view duration, in seconds. |
commentsReceived | number | Comments received. |
commentsRead | number | Comments read. |
commentsGiven | number | Comments given. |
conversationsCommentedOn | number | Conversations the user commented on. |
conversationsRecorded | number | Conversations recorded. |
conversationsViewed | number | Conversations viewed. |
conversationViewDuration | number | Total conversation view duration, in seconds. |
lastRidealongAt | string | null | Timestamp of the user's last ride-along (ISO 8601), or null. |
longestMonologueAverage | number | null | Average longest rep monologue, in seconds. |
longestCustomerMonologueAverage | number | null | Average longest customer monologue, in seconds. |
patienceAverage | number | null | Average patience score. |
percentageOfRepsWithCommentsGiven | number | null | For managers: fraction of reps they gave comments to. |
recordingCompliance | number | null | Fraction of appointments recorded (0–1). |
ridealongsReceived | number | Ride-alongs received. |
scorecardsReceived | number | Scorecards received. |
scorecardsGiven | number | Scorecards given. |
talkRatioAverage | number | null | Average talk ratio (0–1). |
totalAppointments | number | Total appointments in the range. |
totalEndOfRidealongsReached | number | Ride-alongs completed through to the end. |
totalRidealongsCompleted | number | Ride-alongs completed. |
viewedRecordedRatio | number | null | Ratio of conversations viewed to recorded. |
liveCoaching | object | Live coaching metrics. See LiveCoaching. |
LiveCoaching
Live coaching metrics for a User, returned in the liveCoaching object.
| Field | Type | Description |
|---|---|---|
sessionsHosted | number | Live coaching sessions hosted. |
viewEventsReceived | number | View events received on hosted sessions. |
uniqueViewers | number | Unique viewers across hosted sessions. |
viewDurationMinutes | number | Total view duration, in minutes. |
commentsReceived | number | Comments received during live coaching. |
uniqueCommenters | number | Unique commenters during live coaching. |
moneySaved | number | Estimated money saved through live coaching. |
lastCoachedAt | string | null | Timestamp of the last live coaching session (ISO 8601), or null. |
Analytics and usage metrics are calculated for the date range provided in the request.
Code Examples
Fetch all conversations (paginated)
import requests
def fetch_all_conversations(from_date, to_date, api_key):
url = "https://customer.rillavoice.com/export/conversations"
headers = {
"Authorization": api_key,
"Content-Type": "application/json"
}
conversations = []
page = 1
total_pages = 1
while page <= total_pages:
payload = {"fromDate": from_date, "toDate": to_date, "page": page, "limit": 50}
response = requests.post(url, json=payload, headers=headers)
data = response.json()
conversations.extend(data["conversations"])
total_pages = data["totalPages"]
page += 1
return conversationsasync function fetchAllConversations(fromDate, toDate, apiKey) {
const conversations = []
let page = 1
let totalPages = 1
do {
const res = await fetch('https://customer.rillavoice.com/export/conversations', {
method: 'POST',
headers: {
Authorization: apiKey,
'Content-Type': 'application/json',
},
body: JSON.stringify({ fromDate, toDate, page, limit: 50 }),
})
const data = await res.json()
conversations.push(...data.conversations)
totalPages = data.totalPages
page++
} while (page <= totalPages)
return conversations
}curl -X POST https://customer.rillavoice.com/export/conversations \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"fromDate": "2024-03-01T00:00:00Z", "toDate": "2024-04-01T00:00:00Z", "page": 1, "limit": 50}'Fetch a single conversation by ID
import requests
def fetch_conversation(conversation_id, api_key):
url = f"https://customer.rillavoice.com/export/conversations/{conversation_id}"
headers = {"Authorization": api_key}
response = requests.get(url, headers=headers)
if response.status_code == 404:
return None
response.raise_for_status()
return response.json()async function fetchConversation(conversationId, apiKey) {
const res = await fetch(
`https://customer.rillavoice.com/export/conversations/${conversationId}`,
{ headers: { Authorization: apiKey } },
)
if (res.status === 404) return null
if (!res.ok) throw new Error(`Request failed: ${res.status}`)
return res.json()
}curl https://customer.rillavoice.com/export/conversations/f1a3e9d8-2b46-4c1a-9c7e-7e4a18d2c93f \
-H "Authorization: YOUR_API_KEY"Fetch teams
import requests
url = "https://customer.rillavoice.com/export/teams"
headers = {
"Authorization": "YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"fromDate": "2024-03-01T00:00:00Z",
"toDate": "2024-04-01T00:00:00Z",
"includeSubteams": True
}
response = requests.post(url, json=payload, headers=headers)
print(response.status_code, response.json())const response = await fetch('https://customer.rillavoice.com/export/teams', {
method: 'POST',
headers: {
Authorization: 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
fromDate: '2024-03-01T00:00:00Z',
toDate: '2024-04-01T00:00:00Z',
includeSubteams: true,
}),
})curl -X POST https://customer.rillavoice.com/export/teams \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"fromDate": "2024-03-01T00:00:00Z", "toDate": "2024-04-01T00:00:00Z", "includeSubteams": true}'Fetch users
import requests
url = "https://customer.rillavoice.com/export/users"
headers = {
"Authorization": "YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"fromDate": "2024-03-01T00:00:00Z",
"toDate": "2024-04-01T00:00:00Z"
}
response = requests.post(url, json=payload, headers=headers)
print(response.status_code, response.json())const response = await fetch('https://customer.rillavoice.com/export/users', {
method: 'POST',
headers: {
Authorization: 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
fromDate: '2024-03-01T00:00:00Z',
toDate: '2024-04-01T00:00:00Z',
}),
})curl -X POST https://customer.rillavoice.com/export/users \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"fromDate": "2024-03-01T00:00:00Z", "toDate": "2024-04-01T00:00:00Z"}'Error Codes
The API returns standard HTTP status codes. On error, the response body is a plain string describing the issue.
| Code | Status | Description |
|---|---|---|
200 | OK | The request was processed successfully. |
400 | Bad Request | Malformed request or missing required fields. Common causes: fromDate or toDate missing; invalid date format; page or limit not a positive integer; limit exceeds 50; users array contains an invalid email; body is not valid JSON. |
401 | Unauthorized | Authorization header missing or API key not recognized. |
404 | Not Found | The requested conversation does not exist, or is outside the scope of your API key. Returned by GET /export/conversations/{conversationId}. |
500 | Internal Server Error | Unexpected server error. |
400 and 404 errors are permanent — retrying the same request will not help. 401 errors indicate auth problems — verify the Authorization header is set to your raw API key (no prefix). 500 errors may be transient — retry with exponential backoff.
Rate Limits
The Data Export API does not enforce application-level rate limits. There is no per-key or per-IP throttling built into the API itself.
Infrastructure-level Limits
Requests pass through AWS API Gateway. The following defaults apply:
- Steady-state requests: 10,000 req/s per account (regional)
- Burst limit: 5,000 requests across all APIs
High-volume Usage
If your integration requires high-throughput or bulk export operations, reach out to support@rilla.com before going live.
Best Practices
- Retry with exponential backoff on
429or5xxresponses. - Page through results incrementally rather than requesting all data at once.
- Narrow your date ranges to reduce response size and processing time.
Pagination
The /export/conversations endpoint returns results one page at a time. Use page and limit to control which slice of results you receive, and totalPages to know when to stop.
Request Parameters
| Parameter | Default | Max | Description |
|---|---|---|---|
page | 1 | — | 1-based page index. |
limit | 50 | 50 | Conversations per page. |
Response Fields
| Field | Description |
|---|---|
currentPage | The page number of the current response. |
totalPages | Total number of pages for the date range. |
totalConversations | Total conversations across all pages. |
conversations | Array of conversation objects on this page. |
Fetching all pages
Loop from page 1 to totalPages, incrementing page each iteration.
async function fetchAllConversations(fromDate, toDate, apiKey) {
const conversations = []
let page = 1
let totalPages = 1
do {
const res = await fetch('https://customer.rillavoice.com/export/conversations', {
method: 'POST',
headers: {
Authorization: apiKey,
'Content-Type': 'application/json',
},
body: JSON.stringify({ fromDate, toDate, page, limit: 50 }),
})
const data = await res.json()
conversations.push(...data.conversations)
totalPages = data.totalPages
page++
} while (page <= totalPages)
return conversations
}Only /export/conversations is paginated. /export/teams and /export/users return all results in a single response.