Rilla
Custom CRM APIData Export APIWebhooksDeep Links

Custom CRM API (importing into Rilla)

Push appointments and recordings into Rilla from your scheduling system.

Overview

When a person is scheduled for an appointment in your system, send a POST request to the Rilla API. Rilla creates the appointment record and links it for analysis and coaching — either when the user submits a recording through the app, or automatically when you include a recording URL in the request. If a recording and a calendar event were created separately, you can link them after the fact with POST /custom/appointment/match.

Base URL

https://api.apirilla.com

How it works

Obtain your API key from your Rilla account manager or customer success manager and store it securely.

POST appointment data (event ID, user email, times, customer info) when events are created or updated in your system.

Include a media_url in the payload to have Rilla automatically ingest a recording for that appointment.

Send a DELETE request with the appointment ID if an event is cancelled so Rilla stays in sync.

Authentication

All requests to the Custom CRM API must include a valid API key in the x-api-key request header.

POST /custom/appointment HTTP/1.1
Host: api.apirilla.com
x-api-key: YOUR_API_KEY
Content-Type: application/json

Request Headers

HeaderTypeRequiredDescription
x-api-keystringYesAPI key given to you by Rilla.
Content-TypestringYesMust be application/json.
AcceptstringNoCustomize response type. Supported: text/plain (default), 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 422 Unprocessable Entity.

Keep your key secure

API keys grant access to your organization's data. Do not expose them in client-side code, public repositories, or logs. Contact support@rilla.com immediately if a key is ever compromised.

POST /custom/appointment

Creates a new appointment or updates an existing one. Rilla uses event_id to determine whether to insert or update.

Request Headers

HeaderTypeRequiredDescription
x-api-keystringYesYour Rilla API key.
Content-TypestringYesMust be application/json.
AcceptstringNotext/plain (default) or application/json.

Request Body

FieldTypeRequiredDescription
event_idstringYesID for the event.
user_emailstringYesEmail of the rep who has the appointment. Used to match to the correct Rilla user.
start_timestringYesStart of the event (UTC): "yyyy-mm-dd hh:mm:ss".
end_timestringYesEnd of the event (UTC): "yyyy-mm-dd hh:mm:ss".
titlestringYesTitle of the event. Recommend including the customer name.
customerobjectYesCustomer/contact info. See Customer Object.
resultstringNoOutcome of the appointment (e.g. "won", "lost").
typestringNoThe type of appointment.
pricefloatNoThe price quoted in the appointment.
media_urlstringNoURL of a hosted audio file. If provided, Rilla streams and processes the recording automatically.
recording_typestringNoRequired when media_url is provided. One of: CALL_AUDIO, APPOINTMENT_AUDIO, CALL_AUDIO_WITH_LOCATION. See Recording Types.
locationstringNoRequired when recording_type is CALL_AUDIO_WITH_LOCATION. Determines Voice-ID assignment group.
lead_sourcestringNoSource of the lead (e.g. "Salesforce").
custom_fieldsobjectNoAny additional fields to store in Rilla for this appointment.

start_time and end_time must be in UTC. If not sent in UTC, appointments will not match and users will receive notifications at the wrong time.

Example — Create

{
  "event_id": "appt-1234",
  "user_email": "rep@yourcompany.com",
  "start_time": "2024-06-15 14:00:00",
  "end_time": "2024-06-15 15:00:00",
  "title": "Home Estimate - Jane Smith",
  "customer": {
    "id": "cust-567",
    "name": "Jane Smith",
    "email": "jane@example.com",
    "phone": "555-867-5309"
  },
  "result": "won",
  "price": 4500.00,
  "lead_source": "Facebook"
}

Updating an Appointment

To update an event, use the same POST endpoint. Only event_id and user_email are required. Any other included field will be updated; omitted fields remain unchanged.

{
  "event_id": "appt-1234",
  "user_email": "rep@yourcompany.com",
  "result": "lost"
}

Responses

StatusDescription
200 OKThe appointment was created or updated successfully.
400 Bad RequestMalformed request or missing required fields.
422 Unprocessable EntityValid JSON but cannot be processed (e.g. unrecognized API key or user email).
500 Internal Server ErrorUnexpected server error.

DELETE /custom/appointment/{id}

Deletes an appointment from Rilla. No request body is needed. Use this when an appointment is cancelled in your system to keep data in sync.

Path Parameters

ParameterTypeRequiredDescription
idstringYesThe event_id used when the appointment was originally created.

Request Headers

HeaderTypeRequiredDescription
x-api-keystringYesYour Rilla API key.

Example Request

DELETE /custom/appointment/appt-1234 HTTP/1.1
Host: api.apirilla.com
x-api-key: YOUR_API_KEY

Responses

StatusDescription
200 OKThe appointment was deleted successfully.
404 Not FoundNo appointment with that ID exists for your organization.
422 Unprocessable Entityx-api-key missing or unrecognized.
500 Internal Server ErrorUnexpected server error.

POST /custom/appointment/match

Links a calendar event Rilla already has on file for your organization to an existing Rilla conversation. Use this when a recording and a calendar event were created separately — for example, the rep recorded through the app before the appointment was pushed — and you want to associate them after the fact.

Both records must already exist. This endpoint creates and updates nothing else: it only sets the matched conversation's recording appointment_id to the calendar event. To create or update the appointment itself, use POST /custom/appointment.

Matching is idempotent — re-matching a conversation overwrites any previous link, so it's safe to retry. All lookups run before anything is written, so a request that fails validation changes nothing.

Request Headers

HeaderTypeRequiredDescription
x-api-keystringYesYour Rilla API key.
Content-TypestringYesMust be application/json.
AcceptstringNotext/plain (default) or application/json.

Request Body

FieldTypeRequiredDescription
event_idstringYesThe external ID of a calendar event Rilla already has on file for your organization — typically one you sent via POST /custom/appointment.
conversation_idstring (UUID)YesID of an existing Rilla conversation to link — for example, a conversation_id received from a webhook or the Data Export API.

Example Request

POST /custom/appointment/match HTTP/1.1
Host: api.apirilla.com
x-api-key: YOUR_API_KEY
Content-Type: application/json
{
  "event_id": "appt-1234",
  "conversation_id": "f1a3e9d8-2b46-4c1a-9c7e-7e4a18d2c93f"
}

Responses

On success the response body is the plain string Successfully matched conversation to event.

StatusBodyWhen
200 OKSuccessfully matched conversation to eventThe conversation's recording was linked to the event.
400 Bad RequestInvalid JSON dataThe request body is not valid JSON.
400 Bad RequestMissing some required parameters in the bodyevent_id or conversation_id is missing.
404 Not FoundEvent not foundNo calendar event with that event_id exists for your organization.
404 Not FoundConversation not foundNo conversation with that conversation_id exists in your organization.
422 Unprocessable EntityAPI key is not in Rillax-api-key is missing or unrecognized.
422 Unprocessable EntityConversation has no recording to linkThe conversation exists but has no recording attached.
422 Unprocessable EntityConversation's recording could not be found to linkThe conversation's recording could not be found while linking.
500 Internal Server ErrorUnexpected server error.

Cross-org lookups return 404

A conversation_id that belongs to a different organization returns the same Conversation not found response as one that doesn't exist. Rilla never reveals whether a conversation exists outside your organization.

Data Models

Appointment Object

FieldTypeDescription
event_idstringID for the event.
user_emailstringEmail of the rep who has the appointment.
start_timestringStart of the event (UTC): "yyyy-mm-dd hh:mm:ss".
end_timestringEnd of the event (UTC): "yyyy-mm-dd hh:mm:ss".
titlestringTitle of the event.
customerobjectCustomer/contact info.
customer.idstringID for the customer.
customer.namestringFull name of the customer.
customer.emailstringEmail of the customer.
customer.phonestringPhone number of the customer.
customer.addressstringAddress of the customer.
resultstringOutcome of the appointment (e.g. "won", "lost").
typestringThe type of appointment.
pricefloatPrice quoted in the appointment.
media_urlstringURL of a hosted audio file.
recording_typestringOne of: CALL_AUDIO, APPOINTMENT_AUDIO, CALL_AUDIO_WITH_LOCATION.
locationstringVoice-ID assignment group (used with CALL_AUDIO_WITH_LOCATION).
lead_sourcestringSource of the lead.
custom_fieldsobjectAdditional custom fields.

Customer Object

FieldTypeRequiredDescription
idstringYesID for the customer.
namestringYesFull name of the customer.
emailstringNoEmail of the customer.
phonestringNoPhone number of the customer.
addressstringNoAddress of the customer.

Recording Types

TypeDescription
CALL_AUDIOThe recording is a dialer call.
APPOINTMENT_AUDIOThe recording is an in-person appointment.
CALL_AUDIO_WITH_LOCATIONDialer call with Voice-ID assignment via location.

Code Examples

Create an Appointment

import requests

url = "https://api.apirilla.com/custom/appointment"
headers = {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json"
}
payload = {
    "event_id": "appt-1234",
    "user_email": "rep@yourcompany.com",
    "start_time": "2024-06-15 14:00:00",
    "end_time": "2024-06-15 15:00:00",
    "title": "Home Estimate - Jane Smith",
    "customer": {
        "id": "cust-567",
        "name": "Jane Smith",
        "email": "jane@example.com",
        "phone": "555-867-5309"
    },
    "result": "won",
    "price": 4500.00,
    "lead_source": "Facebook"
}
response = requests.post(url, json=payload, headers=headers)
print(response.status_code, response.text)
const response = await fetch('https://api.apirilla.com/custom/appointment', {
  method: 'POST',
  headers: {
    'x-api-key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    event_id: 'appt-1234',
    user_email: 'rep@yourcompany.com',
    start_time: '2024-06-15 14:00:00',
    end_time: '2024-06-15 15:00:00',
    title: 'Home Estimate - Jane Smith',
    customer: { id: 'cust-567', name: 'Jane Smith' },
    result: 'won',
    price: 4500.00,
  }),
})
curl -X POST https://api.apirilla.com/custom/appointment \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "event_id": "appt-1234",
    "user_email": "rep@yourcompany.com",
    "start_time": "2024-06-15 14:00:00",
    "end_time": "2024-06-15 15:00:00",
    "title": "Home Estimate - Jane Smith",
    "customer": {"id": "cust-567", "name": "Jane Smith"},
    "result": "won"
  }'

Update an Appointment

POST to the same endpoint with event_id, user_email, and only the fields you want to change. Omitted fields remain unchanged.

import requests

url = "https://api.apirilla.com/custom/appointment"
headers = {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json"
}
payload = {
    "event_id": "appt-1234",
    "user_email": "rep@yourcompany.com",
    "result": "lost"
}
response = requests.post(url, json=payload, headers=headers)
print(response.status_code, response.text)
const response = await fetch('https://api.apirilla.com/custom/appointment', {
  method: 'POST',
  headers: {
    'x-api-key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    event_id: 'appt-1234',
    user_email: 'rep@yourcompany.com',
    result: 'lost',
  }),
})
curl -X POST https://api.apirilla.com/custom/appointment \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"event_id": "appt-1234", "user_email": "rep@yourcompany.com", "result": "lost"}'

Delete an Appointment

import requests

event_id = "appt-1234"
url = f"https://api.apirilla.com/custom/appointment/{event_id}"
headers = {"x-api-key": "YOUR_API_KEY"}
response = requests.delete(url, headers=headers)
print(response.status_code, response.text)
const eventId = 'appt-1234'
const response = await fetch(
  `https://api.apirilla.com/custom/appointment/${eventId}`,
  {
    method: 'DELETE',
    headers: { 'x-api-key': 'YOUR_API_KEY' },
  }
)
curl -X DELETE https://api.apirilla.com/custom/appointment/appt-1234 \
  -H "x-api-key: YOUR_API_KEY"

Match a Conversation to an Event

Link an existing conversation to a calendar event Rilla already has for your organization. Both must already exist.

import requests

url = "https://api.apirilla.com/custom/appointment/match"
headers = {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json"
}
payload = {
    "event_id": "appt-1234",
    "conversation_id": "f1a3e9d8-2b46-4c1a-9c7e-7e4a18d2c93f"
}
response = requests.post(url, json=payload, headers=headers)
print(response.status_code, response.text)
const response = await fetch('https://api.apirilla.com/custom/appointment/match', {
  method: 'POST',
  headers: {
    'x-api-key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    event_id: 'appt-1234',
    conversation_id: 'f1a3e9d8-2b46-4c1a-9c7e-7e4a18d2c93f',
  }),
})
curl -X POST https://api.apirilla.com/custom/appointment/match \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"event_id": "appt-1234", "conversation_id": "f1a3e9d8-2b46-4c1a-9c7e-7e4a18d2c93f"}'

Custom API Debugger

Once your integration is sending events, you can verify them inside Rilla's web app. The Custom API Debugger lists every event we received against your API key and shows the full payload exactly as Rilla stored it. Use it to confirm field values, troubleshoot mappings, and check timestamps without needing access to logs.

In the Rilla web app, go to Settings → Account and scroll to the bottom. Click Open in the Custom API Debugger section.

Settings page with the Open button highlighted on the Custom API Debugger row

Paste the same x-api-key you use to call the API, then click Continue. The key is only used in your browser session to fetch the events for your organization. It is not stored.

Custom API Debugger dialog asking for an API key

You'll see every appointment Rilla received with that key, most recent first. Each row shows the rep, client, title, recording status, outcome, and the timestamp Rilla recorded the event.

Table of events received by Rilla through the Custom API

Use the search box to filter by rep name, client name, or appointment title. The Refresh button re-fetches the latest events.

Click any row to open the detail panel. It shows the IDs, appointment fields, rep, client, any custom_fields you sent, and the exact timestamps Rilla recorded — useful for confirming that what you sent matches what we stored.

Detail panel showing the full payload for a single event

If an event isn't here

If you sent a request and don't see the event in the debugger, the API likely rejected it. Check the response status from your POST. A 4xx response means the event never reached storage. See Error Codes for what each status means.

Error Codes

The API returns standard HTTP status codes. On error, the response body is a plain string describing the issue.

CodeStatusDescription
200OKThe request was processed successfully.
400Bad RequestMalformed request or missing required fields. Common causes: event_id, user_email, or title missing; customer object missing or incomplete; timestamp format invalid; media_url provided with CALL_AUDIO_WITH_LOCATION but location missing; body is not valid JSON. On /custom/appointment/match: event_id or conversation_id missing.
404Not FoundA targeted record was not found in your organization. Returned by DELETE /custom/appointment/{id} (appointment ID not found) and POST /custom/appointment/match (event_id or conversation_id not found).
422Unprocessable EntityValid JSON but cannot be processed. Common causes: x-api-key missing or not recognized; user_email doesn't exist in Rilla; user_email belongs to a different organization. On /custom/appointment/match: the conversation has no recording to link.
500Internal Server ErrorUnexpected server error. The event is forwarded to a dead-letter queue for investigation.

400, 404, and 422 errors are permanent — retrying the same payload will not help. Fix the data first. 500 errors may be transient — retry with exponential backoff.

Rate Limits

The Custom CRM 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 operations, reach out to support@rilla.com before going live.

Best Practices

  • Retry with exponential backoff on 429 or 5xx responses.
  • Avoid polling at high frequency.
  • Batch appointment creation on your side before calling the API.