curl --request GET \
--url https://partner-api.getoliver.com/services/core/open_api/v1/phone_calls \
--header 'Authorization: Bearer <token>' \
--header 'X-Client-Id: <x-client-id>'import requests
url = "https://partner-api.getoliver.com/services/core/open_api/v1/phone_calls"
headers = {
"X-Client-Id": "<x-client-id>",
"Authorization": "Bearer <token>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'X-Client-Id': '<x-client-id>', Authorization: 'Bearer <token>'}
};
fetch('https://partner-api.getoliver.com/services/core/open_api/v1/phone_calls', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://partner-api.getoliver.com/services/core/open_api/v1/phone_calls",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"X-Client-Id: <x-client-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://partner-api.getoliver.com/services/core/open_api/v1/phone_calls"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Client-Id", "<x-client-id>")
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://partner-api.getoliver.com/services/core/open_api/v1/phone_calls")
.header("X-Client-Id", "<x-client-id>")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://partner-api.getoliver.com/services/core/open_api/v1/phone_calls")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Client-Id"] = '<x-client-id>'
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"page": 0,
"per_page": 50,
"total_pages": 3,
"total_count": 122,
"content": [
{
"id": "5f0f4ca5-9e4a-44ad-b26e-cf13cb1bf922",
"created_at": "2026-04-10T18:00:00Z",
"practice_name": "Alpha Veterinary Clinic",
"direction": "inbound",
"state": "completed",
"caller_type": "new",
"client_id": "8a4b1c2d-3e5f-4a6b-8c7d-9e0f1a2b3c4d",
"remote_client_id": "1234-56",
"client_name": "Dana Reed",
"patient_id": "b7c8d9e0-f1a2-4b3c-8d5e-6f7a8b9c0d1e",
"remote_patient_id": "7890-56",
"patient_name": "Rufus",
"phone_number": "+15125550123",
"call_classification": "scheduling",
"summary": "Booked a wellness exam",
"customer_sentiment": "happy",
"outcome": "appointment_booked",
"booked": true,
"booking_intent": true,
"duration_seconds": 125
}
]
},
"message": null
}{
"success": true,
"message": "<string>",
"data": {}
}{
"success": true,
"message": "<string>",
"data": {}
}{
"success": true,
"message": "<string>",
"data": {}
}List Phone Calls
List AI voice agent call records for a practice. Returns JSON by default; pass format=csv for a CSV batch download with the same rows.
curl --request GET \
--url https://partner-api.getoliver.com/services/core/open_api/v1/phone_calls \
--header 'Authorization: Bearer <token>' \
--header 'X-Client-Id: <x-client-id>'import requests
url = "https://partner-api.getoliver.com/services/core/open_api/v1/phone_calls"
headers = {
"X-Client-Id": "<x-client-id>",
"Authorization": "Bearer <token>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'X-Client-Id': '<x-client-id>', Authorization: 'Bearer <token>'}
};
fetch('https://partner-api.getoliver.com/services/core/open_api/v1/phone_calls', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://partner-api.getoliver.com/services/core/open_api/v1/phone_calls",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"X-Client-Id: <x-client-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://partner-api.getoliver.com/services/core/open_api/v1/phone_calls"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Client-Id", "<x-client-id>")
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://partner-api.getoliver.com/services/core/open_api/v1/phone_calls")
.header("X-Client-Id", "<x-client-id>")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://partner-api.getoliver.com/services/core/open_api/v1/phone_calls")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Client-Id"] = '<x-client-id>'
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"page": 0,
"per_page": 50,
"total_pages": 3,
"total_count": 122,
"content": [
{
"id": "5f0f4ca5-9e4a-44ad-b26e-cf13cb1bf922",
"created_at": "2026-04-10T18:00:00Z",
"practice_name": "Alpha Veterinary Clinic",
"direction": "inbound",
"state": "completed",
"caller_type": "new",
"client_id": "8a4b1c2d-3e5f-4a6b-8c7d-9e0f1a2b3c4d",
"remote_client_id": "1234-56",
"client_name": "Dana Reed",
"patient_id": "b7c8d9e0-f1a2-4b3c-8d5e-6f7a8b9c0d1e",
"remote_patient_id": "7890-56",
"patient_name": "Rufus",
"phone_number": "+15125550123",
"call_classification": "scheduling",
"summary": "Booked a wellness exam",
"customer_sentiment": "happy",
"outcome": "appointment_booked",
"booked": true,
"booking_intent": true,
"duration_seconds": 125
}
]
},
"message": null
}{
"success": true,
"message": "<string>",
"data": {}
}{
"success": true,
"message": "<string>",
"data": {}
}{
"success": true,
"message": "<string>",
"data": {}
}format=csv.
Filtering
Dates areYYYY-MM-DD and inclusive on both ends — start_date=2026-04-01&end_date=2026-04-30
returns the whole month. Any other date format returns a 400.
Unknown values for direction, state, or call_classification return a 400 rather than
silently matching nothing. Pass outcome more than once (outcome[]=appointment_booked&outcome[]=task_created)
to match any of several outcomes.
Field definitions
caller_type—existingif the matched client (or one of their patients) had a visit before this call,newif the caller matched a client with no prior visit,unknownif the call was never matched to a client.booked— the call ended in a scheduling outcome (appointment_booked,appointment_rescheduled,appointment_confirmed).booking_intent— the caller wanted to book or change an appointment. True when any of: the call was classified asscheduling, the outcome was a scheduling outcome, or the AI invoked a scheduling tool (book, reschedule, cancel, or confirm an appointment) during the call. The last two conditions catch calls the classifier filed under a different intent. It is derived at read time, so it is populated for historical calls too.summary— the AI’s one-line summary of the call.remote_client_id/remote_patient_id— the client’s and patient’s ids in your practice management system, qualified with the practice’s server id when it has one. These are the same values returned by the appointments endpoints, so records line up across both.
CSV download
Addformat=csv (or send Accept: text/csv) to get the same rows as a CSV attachment:
curl -L 'https://partner-api.getoliver.com/services/core/open_api/v1/phone_calls?start_date=2026-04-01&end_date=2026-04-30&format=csv&per_page=5000' \
-H 'Authorization: Bearer <token>' \
-H 'X-Client-Id: <location id>' \
-o phone_calls_april.csv
Date, Practice, Direction, Status, Caller Type, Client, Patient, Phone Number,
Intent, Booking Intent, Summary, Sentiment, Outcome, Booked, Duration
Date is rendered in the practice timezone as YYYY-MM-DD HH:MM, Duration as m:ss, and the
yes/no columns as Yes/No. The Intent, Sentiment, and Outcome columns contain humanized
labels of the JSON enum values — Scheduling for call_classification: scheduling,
Appointment booked for outcome: appointment_booked, and so on — so lowercase and replace
spaces with underscores to map a CSV value back to its JSON enum.
per_page defaults to 1000 and allows up to 5000. The
paging metadata comes back in response headers (X-Total-Count, X-Page, X-Per-Page,
X-Total-Pages) so you can page through a wide date range without guessing how many pages there
are. page is zero-based in both formats.Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Headers
The location id of the practice
Query Parameters
Only return calls created on or after this date, inclusive. Interpreted as a whole day in the practice timezone.
"2026-04-01"
Only return calls created on or before this date, inclusive. Interpreted as a whole day in the practice timezone.
"2026-04-30"
Filter by call direction.
inbound, outbound Filter by the call's lifecycle state.
pending, queued, ringing, in_progress, completed, failed, no_answer, busy, voicemail, canceled Filter by call outcome. Repeat the parameter (outcome[]=a&outcome[]=b) to match any of several outcomes.
appointment_booked, appointment_rescheduled, appointment_confirmed, appointment_canceled, callback_requested, declined, do_not_call, no_answer, voicemail, forwarded, transferred, quick_abandoned, abandoned, abandoned_after_transfer, dropped, transfer_completed, transfer_no_human, transfer_caller_abandoned, task_created, resolved Filter by the AI's classification of why the caller called.
scheduling, prescription_refill, medical_question, billing, records_request, emergency, callback, general_inquiry, price_shopping, other Filter to calls where the caller did (true) or did not (false) want to book or change an appointment. See the endpoint page for how this is derived.
Only return calls matched to this Oliver client.
Page number (0-based)
Number of results per page. JSON: default 50, max 100. CSV: default 1000, max 5000.
Set to 'csv' to download the same rows as a CSV attachment instead of JSON. Sending 'Accept: text/csv' has the same effect.
csv Response
Phone calls response. Returns JSON by default, or a CSV attachment when format=csv. The CSV response also carries X-Total-Count, X-Page (0-based), X-Per-Page and X-Total-Pages headers so a wide date range can be paged through without guessing.

