curl --request POST \
--url https://partner-api.getoliver.com/services/core/open_api/v1/ai_outbound/requests \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'X-Client-Id: <x-client-id>' \
--data '
{
"contact_number": "<string>",
"channel": "sms",
"client_id": "<string>",
"client_name": "<string>",
"patient_id": "<string>",
"patient_name": "<string>",
"patients": [
{
"patient_id": "<string>",
"patient_name": "<string>",
"services_due": [
"<string>"
]
}
],
"context": "<string>",
"initial_message_script": "<string>",
"partner_request_id": "<string>",
"callback_url": "<string>"
}
'import requests
url = "https://partner-api.getoliver.com/services/core/open_api/v1/ai_outbound/requests"
payload = {
"contact_number": "<string>",
"channel": "sms",
"client_id": "<string>",
"client_name": "<string>",
"patient_id": "<string>",
"patient_name": "<string>",
"patients": [
{
"patient_id": "<string>",
"patient_name": "<string>",
"services_due": ["<string>"]
}
],
"context": "<string>",
"initial_message_script": "<string>",
"partner_request_id": "<string>",
"callback_url": "<string>"
}
headers = {
"X-Client-Id": "<x-client-id>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Client-Id': '<x-client-id>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
contact_number: '<string>',
channel: 'sms',
client_id: '<string>',
client_name: '<string>',
patient_id: '<string>',
patient_name: '<string>',
patients: [{patient_id: '<string>', patient_name: '<string>', services_due: ['<string>']}],
context: '<string>',
initial_message_script: '<string>',
partner_request_id: '<string>',
callback_url: '<string>'
})
};
fetch('https://partner-api.getoliver.com/services/core/open_api/v1/ai_outbound/requests', 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/ai_outbound/requests",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'contact_number' => '<string>',
'channel' => 'sms',
'client_id' => '<string>',
'client_name' => '<string>',
'patient_id' => '<string>',
'patient_name' => '<string>',
'patients' => [
[
'patient_id' => '<string>',
'patient_name' => '<string>',
'services_due' => [
'<string>'
]
]
],
'context' => '<string>',
'initial_message_script' => '<string>',
'partner_request_id' => '<string>',
'callback_url' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://partner-api.getoliver.com/services/core/open_api/v1/ai_outbound/requests"
payload := strings.NewReader("{\n \"contact_number\": \"<string>\",\n \"channel\": \"sms\",\n \"client_id\": \"<string>\",\n \"client_name\": \"<string>\",\n \"patient_id\": \"<string>\",\n \"patient_name\": \"<string>\",\n \"patients\": [\n {\n \"patient_id\": \"<string>\",\n \"patient_name\": \"<string>\",\n \"services_due\": [\n \"<string>\"\n ]\n }\n ],\n \"context\": \"<string>\",\n \"initial_message_script\": \"<string>\",\n \"partner_request_id\": \"<string>\",\n \"callback_url\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Client-Id", "<x-client-id>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://partner-api.getoliver.com/services/core/open_api/v1/ai_outbound/requests")
.header("X-Client-Id", "<x-client-id>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"contact_number\": \"<string>\",\n \"channel\": \"sms\",\n \"client_id\": \"<string>\",\n \"client_name\": \"<string>\",\n \"patient_id\": \"<string>\",\n \"patient_name\": \"<string>\",\n \"patients\": [\n {\n \"patient_id\": \"<string>\",\n \"patient_name\": \"<string>\",\n \"services_due\": [\n \"<string>\"\n ]\n }\n ],\n \"context\": \"<string>\",\n \"initial_message_script\": \"<string>\",\n \"partner_request_id\": \"<string>\",\n \"callback_url\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://partner-api.getoliver.com/services/core/open_api/v1/ai_outbound/requests")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Client-Id"] = '<x-client-id>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"contact_number\": \"<string>\",\n \"channel\": \"sms\",\n \"client_id\": \"<string>\",\n \"client_name\": \"<string>\",\n \"patient_id\": \"<string>\",\n \"patient_name\": \"<string>\",\n \"patients\": [\n {\n \"patient_id\": \"<string>\",\n \"patient_name\": \"<string>\",\n \"services_due\": [\n \"<string>\"\n ]\n }\n ],\n \"context\": \"<string>\",\n \"initial_message_script\": \"<string>\",\n \"partner_request_id\": \"<string>\",\n \"callback_url\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "<string>",
"partner_request_id": "<string>",
"channel": "sms",
"purpose": "scheduling",
"status": "received",
"outcome": "booked",
"suppression_reason": "<string>",
"error_message": "<string>",
"client_id": "<string>",
"patient_id": "<string>",
"contact_number": "<string>",
"context": "<string>",
"contacted_at": "2023-11-07T05:31:56Z",
"completed_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z",
"opener_channel": "rcs"
},
"message": "<string>"
}{
"success": true,
"data": {
"id": "<string>",
"partner_request_id": "<string>",
"channel": "sms",
"purpose": "scheduling",
"status": "received",
"outcome": "booked",
"suppression_reason": "<string>",
"error_message": "<string>",
"client_id": "<string>",
"patient_id": "<string>",
"contact_number": "<string>",
"context": "<string>",
"contacted_at": "2023-11-07T05:31:56Z",
"completed_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z",
"opener_channel": "rcs"
},
"message": "<string>"
}{
"success": true,
"message": "<string>",
"data": {}
}{
"success": true,
"message": "<string>",
"data": {}
}{
"success": true,
"message": "<string>",
"data": {}
}{
"success": true,
"message": "<string>",
"data": {}
}Trigger AI Outbound Contact
Trigger an AI outbound contact flow (SMS today) for a single client. Intake is synchronous — Oliver validates the request, resolves the target client, and runs suppression checks before responding. The actual outreach is dispatched asynchronously; the final outcome is delivered to your callback_url webhook, if provided.
A suppressed request is not an error: it returns 200 OK with status: "suppressed" and a suppression_reason. Only malformed or unresolvable input returns a 400.
Identify the target with contact_number (always required); optionally supply client_id to resolve the client directly. Set partner_request_id to make the call idempotent — re-submitting the same value returns the existing request instead of creating a new one.
curl --request POST \
--url https://partner-api.getoliver.com/services/core/open_api/v1/ai_outbound/requests \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'X-Client-Id: <x-client-id>' \
--data '
{
"contact_number": "<string>",
"channel": "sms",
"client_id": "<string>",
"client_name": "<string>",
"patient_id": "<string>",
"patient_name": "<string>",
"patients": [
{
"patient_id": "<string>",
"patient_name": "<string>",
"services_due": [
"<string>"
]
}
],
"context": "<string>",
"initial_message_script": "<string>",
"partner_request_id": "<string>",
"callback_url": "<string>"
}
'import requests
url = "https://partner-api.getoliver.com/services/core/open_api/v1/ai_outbound/requests"
payload = {
"contact_number": "<string>",
"channel": "sms",
"client_id": "<string>",
"client_name": "<string>",
"patient_id": "<string>",
"patient_name": "<string>",
"patients": [
{
"patient_id": "<string>",
"patient_name": "<string>",
"services_due": ["<string>"]
}
],
"context": "<string>",
"initial_message_script": "<string>",
"partner_request_id": "<string>",
"callback_url": "<string>"
}
headers = {
"X-Client-Id": "<x-client-id>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Client-Id': '<x-client-id>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
contact_number: '<string>',
channel: 'sms',
client_id: '<string>',
client_name: '<string>',
patient_id: '<string>',
patient_name: '<string>',
patients: [{patient_id: '<string>', patient_name: '<string>', services_due: ['<string>']}],
context: '<string>',
initial_message_script: '<string>',
partner_request_id: '<string>',
callback_url: '<string>'
})
};
fetch('https://partner-api.getoliver.com/services/core/open_api/v1/ai_outbound/requests', 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/ai_outbound/requests",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'contact_number' => '<string>',
'channel' => 'sms',
'client_id' => '<string>',
'client_name' => '<string>',
'patient_id' => '<string>',
'patient_name' => '<string>',
'patients' => [
[
'patient_id' => '<string>',
'patient_name' => '<string>',
'services_due' => [
'<string>'
]
]
],
'context' => '<string>',
'initial_message_script' => '<string>',
'partner_request_id' => '<string>',
'callback_url' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://partner-api.getoliver.com/services/core/open_api/v1/ai_outbound/requests"
payload := strings.NewReader("{\n \"contact_number\": \"<string>\",\n \"channel\": \"sms\",\n \"client_id\": \"<string>\",\n \"client_name\": \"<string>\",\n \"patient_id\": \"<string>\",\n \"patient_name\": \"<string>\",\n \"patients\": [\n {\n \"patient_id\": \"<string>\",\n \"patient_name\": \"<string>\",\n \"services_due\": [\n \"<string>\"\n ]\n }\n ],\n \"context\": \"<string>\",\n \"initial_message_script\": \"<string>\",\n \"partner_request_id\": \"<string>\",\n \"callback_url\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Client-Id", "<x-client-id>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://partner-api.getoliver.com/services/core/open_api/v1/ai_outbound/requests")
.header("X-Client-Id", "<x-client-id>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"contact_number\": \"<string>\",\n \"channel\": \"sms\",\n \"client_id\": \"<string>\",\n \"client_name\": \"<string>\",\n \"patient_id\": \"<string>\",\n \"patient_name\": \"<string>\",\n \"patients\": [\n {\n \"patient_id\": \"<string>\",\n \"patient_name\": \"<string>\",\n \"services_due\": [\n \"<string>\"\n ]\n }\n ],\n \"context\": \"<string>\",\n \"initial_message_script\": \"<string>\",\n \"partner_request_id\": \"<string>\",\n \"callback_url\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://partner-api.getoliver.com/services/core/open_api/v1/ai_outbound/requests")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Client-Id"] = '<x-client-id>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"contact_number\": \"<string>\",\n \"channel\": \"sms\",\n \"client_id\": \"<string>\",\n \"client_name\": \"<string>\",\n \"patient_id\": \"<string>\",\n \"patient_name\": \"<string>\",\n \"patients\": [\n {\n \"patient_id\": \"<string>\",\n \"patient_name\": \"<string>\",\n \"services_due\": [\n \"<string>\"\n ]\n }\n ],\n \"context\": \"<string>\",\n \"initial_message_script\": \"<string>\",\n \"partner_request_id\": \"<string>\",\n \"callback_url\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "<string>",
"partner_request_id": "<string>",
"channel": "sms",
"purpose": "scheduling",
"status": "received",
"outcome": "booked",
"suppression_reason": "<string>",
"error_message": "<string>",
"client_id": "<string>",
"patient_id": "<string>",
"contact_number": "<string>",
"context": "<string>",
"contacted_at": "2023-11-07T05:31:56Z",
"completed_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z",
"opener_channel": "rcs"
},
"message": "<string>"
}{
"success": true,
"data": {
"id": "<string>",
"partner_request_id": "<string>",
"channel": "sms",
"purpose": "scheduling",
"status": "received",
"outcome": "booked",
"suppression_reason": "<string>",
"error_message": "<string>",
"client_id": "<string>",
"patient_id": "<string>",
"contact_number": "<string>",
"context": "<string>",
"contacted_at": "2023-11-07T05:31:56Z",
"completed_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z",
"opener_channel": "rcs"
},
"message": "<string>"
}{
"success": true,
"message": "<string>",
"data": {}
}{
"success": true,
"message": "<string>",
"data": {}
}{
"success": true,
"message": "<string>",
"data": {}
}{
"success": true,
"message": "<string>",
"data": {}
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Headers
The location id of the practice
Body
The AI outbound contact to trigger
Provide contact_number to identify the target client. client_id may also be supplied to resolve the client directly.
The reason for the outreach. Required.
scheduling, callback_followup, refill, general The client's phone number in E.164 or local format. Required.
The outreach channel. Only sms can be supplied here, which covers SMS and RCS, when available. To configure rich RCS content, see content below.
sms Oliver's identifier for the target client. Optional; resolves the client directly.
Client name used to disambiguate when a contact_number is shared across multiple client records (e.g. a household).
Oliver's identifier for the patient the outreach concerns, if applicable. To name several pets, use patients instead.
Patient name, used to match a patient within the resolved client. To name several pets, use patients instead.
The pets the outreach is about, up to 10, each with what it is due for. The opener and the whole conversation use them, so one message can cover several pets and the AI books them together. Each pet must be one of the client's active pets, or the request returns 400 naming it (e.g. patients[1]). The first pet is the request's patient_id. Don't combine with patient_id or patient_name.
1 - 10 elementsShow child attributes
Show child attributes
Free-text context that guides the AI opener (e.g. "overdue for annual wellness exam").
The exact opening text message, sent verbatim. If you omit it, Oliver writes the opener from the purpose, context and patients. With content, this is the plain text: the SMS a client without RCS receives, and the bubble of type: text content. At most 1,600 characters when content is sent.
Optional rich opener: a card, carousel, image or reply buttons, the same shape and limits as the messages endpoint. See Writing card text for how each layout looks on a phone. Clients whose phone supports RCS see it; everyone else gets initial_message_script as an SMS, or the opener Oliver writes if you omit it. Every reply, including a reply-button tap, goes to Oliver's AI, which continues the conversation. For type: text, the bubble is that same text, so you can send only reply buttons. Requires channel: sms.
Show child attributes
Show child attributes
Your idempotency key. Re-submitting the same value returns the existing request instead of creating a new one.
HTTPS URL that receives the outcome webhook when the request reaches a terminal status (completed, suppressed, or failed). Exactly one webhook is delivered per request. Must begin with https://.

