curl --request POST \
--url https://api.usesimple.ai/api/v1/journeys/{key}/enrollments \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"idempotencyKey": "appt-APPT02984416",
"contact": {
"phoneNumber": "+14155550100",
"name": "Dana Reyes"
},
"subject": {
"appointment_number": "APPT02984416",
"status": "Scheduled"
},
"params": {
"store_name": "Market Street"
},
"anchorAt": "2026-10-22T14:00:00-04:00"
}
'import requests
url = "https://api.usesimple.ai/api/v1/journeys/{key}/enrollments"
payload = {
"idempotencyKey": "appt-APPT02984416",
"contact": {
"phoneNumber": "+14155550100",
"name": "Dana Reyes"
},
"subject": {
"appointment_number": "APPT02984416",
"status": "Scheduled"
},
"params": { "store_name": "Market Street" },
"anchorAt": "2026-10-22T14:00:00-04:00"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
idempotencyKey: 'appt-APPT02984416',
contact: {phoneNumber: '+14155550100', name: 'Dana Reyes'},
subject: {appointment_number: 'APPT02984416', status: 'Scheduled'},
params: {store_name: 'Market Street'},
anchorAt: '2026-10-22T14:00:00-04:00'
})
};
fetch('https://api.usesimple.ai/api/v1/journeys/{key}/enrollments', 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://api.usesimple.ai/api/v1/journeys/{key}/enrollments",
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([
'idempotencyKey' => 'appt-APPT02984416',
'contact' => [
'phoneNumber' => '+14155550100',
'name' => 'Dana Reyes'
],
'subject' => [
'appointment_number' => 'APPT02984416',
'status' => 'Scheduled'
],
'params' => [
'store_name' => 'Market Street'
],
'anchorAt' => '2026-10-22T14:00:00-04:00'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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://api.usesimple.ai/api/v1/journeys/{key}/enrollments"
payload := strings.NewReader("{\n \"idempotencyKey\": \"appt-APPT02984416\",\n \"contact\": {\n \"phoneNumber\": \"+14155550100\",\n \"name\": \"Dana Reyes\"\n },\n \"subject\": {\n \"appointment_number\": \"APPT02984416\",\n \"status\": \"Scheduled\"\n },\n \"params\": {\n \"store_name\": \"Market Street\"\n },\n \"anchorAt\": \"2026-10-22T14:00:00-04:00\"\n}")
req, _ := http.NewRequest("POST", url, payload)
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://api.usesimple.ai/api/v1/journeys/{key}/enrollments")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"idempotencyKey\": \"appt-APPT02984416\",\n \"contact\": {\n \"phoneNumber\": \"+14155550100\",\n \"name\": \"Dana Reyes\"\n },\n \"subject\": {\n \"appointment_number\": \"APPT02984416\",\n \"status\": \"Scheduled\"\n },\n \"params\": {\n \"store_name\": \"Market Street\"\n },\n \"anchorAt\": \"2026-10-22T14:00:00-04:00\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.usesimple.ai/api/v1/journeys/{key}/enrollments")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"idempotencyKey\": \"appt-APPT02984416\",\n \"contact\": {\n \"phoneNumber\": \"+14155550100\",\n \"name\": \"Dana Reyes\"\n },\n \"subject\": {\n \"appointment_number\": \"APPT02984416\",\n \"status\": \"Scheduled\"\n },\n \"params\": {\n \"store_name\": \"Market Street\"\n },\n \"anchorAt\": \"2026-10-22T14:00:00-04:00\"\n}"
response = http.request(request)
puts response.read_body{
"enrollmentId": "<string>",
"status": "active",
"endedReason": "<string>",
"skippedReason": "<string>",
"created": true,
"nextTouchAt": "2023-11-07T05:31:56Z",
"contact": {
"timezone": "<string>",
"timezoneSource": "<string>"
}
}{
"enrollmentId": "<string>",
"status": "active",
"endedReason": "<string>",
"skippedReason": "<string>",
"created": true,
"nextTouchAt": "2023-11-07T05:31:56Z",
"contact": {
"timezone": "<string>",
"timezoneSource": "<string>"
}
}{
"status": "error",
"success": false,
"error": "<string>",
"errors": [
"<string>"
]
}{
"status": "error",
"success": false,
"error": "<string>",
"errors": [
"<string>"
]
}{
"status": "error",
"success": false,
"error": "<string>",
"errors": [
"<string>"
]
}Enroll a Contact in a Journey with the API
Enroll a contact in an active Simple AI journey by its key, with the record, anchor date and call parameters, using an idempotency key for safe retries.
curl --request POST \
--url https://api.usesimple.ai/api/v1/journeys/{key}/enrollments \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"idempotencyKey": "appt-APPT02984416",
"contact": {
"phoneNumber": "+14155550100",
"name": "Dana Reyes"
},
"subject": {
"appointment_number": "APPT02984416",
"status": "Scheduled"
},
"params": {
"store_name": "Market Street"
},
"anchorAt": "2026-10-22T14:00:00-04:00"
}
'import requests
url = "https://api.usesimple.ai/api/v1/journeys/{key}/enrollments"
payload = {
"idempotencyKey": "appt-APPT02984416",
"contact": {
"phoneNumber": "+14155550100",
"name": "Dana Reyes"
},
"subject": {
"appointment_number": "APPT02984416",
"status": "Scheduled"
},
"params": { "store_name": "Market Street" },
"anchorAt": "2026-10-22T14:00:00-04:00"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
idempotencyKey: 'appt-APPT02984416',
contact: {phoneNumber: '+14155550100', name: 'Dana Reyes'},
subject: {appointment_number: 'APPT02984416', status: 'Scheduled'},
params: {store_name: 'Market Street'},
anchorAt: '2026-10-22T14:00:00-04:00'
})
};
fetch('https://api.usesimple.ai/api/v1/journeys/{key}/enrollments', 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://api.usesimple.ai/api/v1/journeys/{key}/enrollments",
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([
'idempotencyKey' => 'appt-APPT02984416',
'contact' => [
'phoneNumber' => '+14155550100',
'name' => 'Dana Reyes'
],
'subject' => [
'appointment_number' => 'APPT02984416',
'status' => 'Scheduled'
],
'params' => [
'store_name' => 'Market Street'
],
'anchorAt' => '2026-10-22T14:00:00-04:00'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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://api.usesimple.ai/api/v1/journeys/{key}/enrollments"
payload := strings.NewReader("{\n \"idempotencyKey\": \"appt-APPT02984416\",\n \"contact\": {\n \"phoneNumber\": \"+14155550100\",\n \"name\": \"Dana Reyes\"\n },\n \"subject\": {\n \"appointment_number\": \"APPT02984416\",\n \"status\": \"Scheduled\"\n },\n \"params\": {\n \"store_name\": \"Market Street\"\n },\n \"anchorAt\": \"2026-10-22T14:00:00-04:00\"\n}")
req, _ := http.NewRequest("POST", url, payload)
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://api.usesimple.ai/api/v1/journeys/{key}/enrollments")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"idempotencyKey\": \"appt-APPT02984416\",\n \"contact\": {\n \"phoneNumber\": \"+14155550100\",\n \"name\": \"Dana Reyes\"\n },\n \"subject\": {\n \"appointment_number\": \"APPT02984416\",\n \"status\": \"Scheduled\"\n },\n \"params\": {\n \"store_name\": \"Market Street\"\n },\n \"anchorAt\": \"2026-10-22T14:00:00-04:00\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.usesimple.ai/api/v1/journeys/{key}/enrollments")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"idempotencyKey\": \"appt-APPT02984416\",\n \"contact\": {\n \"phoneNumber\": \"+14155550100\",\n \"name\": \"Dana Reyes\"\n },\n \"subject\": {\n \"appointment_number\": \"APPT02984416\",\n \"status\": \"Scheduled\"\n },\n \"params\": {\n \"store_name\": \"Market Street\"\n },\n \"anchorAt\": \"2026-10-22T14:00:00-04:00\"\n}"
response = http.request(request)
puts response.read_body{
"enrollmentId": "<string>",
"status": "active",
"endedReason": "<string>",
"skippedReason": "<string>",
"created": true,
"nextTouchAt": "2023-11-07T05:31:56Z",
"contact": {
"timezone": "<string>",
"timezoneSource": "<string>"
}
}{
"enrollmentId": "<string>",
"status": "active",
"endedReason": "<string>",
"skippedReason": "<string>",
"created": true,
"nextTouchAt": "2023-11-07T05:31:56Z",
"contact": {
"timezone": "<string>",
"timezoneSource": "<string>"
}
}{
"status": "error",
"success": false,
"error": "<string>",
"errors": [
"<string>"
]
}{
"status": "error",
"success": false,
"error": "<string>",
"errors": [
"<string>"
]
}{
"status": "error",
"success": false,
"error": "<string>",
"errors": [
"<string>"
]
}idempotencyKey returns the existing enrollment with 200 instead of creating a second one. A new enrollment returns 201.
A contact the journey can’t take, such as one already active in another journey or without consent, is returned with 200, status: "skipped" and the reason in skippedReason.
See Enroll contacts from your systems for a walkthrough.Authorizations
Your API key, sent as Authorization: Bearer YOUR_API_KEY
Path Parameters
The journey's key, such as appointment-confirmations. It is shown on the journey's Enrollment tab.
Body
Your key for this enrollment, such as a lead or appointment id. Sending it again returns the same enrollment.
255An existing contact by id, or contact details that are created or updated by phone number.
- Existing contact
- Contact details
Show child attributes
Show child attributes
Another id to cancel by later. Defaults to idempotencyKey. It is also used as the contact's external id when the contact is created or updated.
255The record this enrollment is about, such as an appointment. The journey's conditions and texts can read these fields, and calls receive them.
Extra parameters passed to every call the journey places for this enrollment. They are also merged into subject.
Identifies the subject. Defaults to idempotencyKey.
255The date the journey's steps are timed from, in ISO 8601 with an offset. Overrides the anchor the journey would read from subject.
The earliest time the first call or text may go out. Null means as soon as calling hours allow.
Response
The enrollment already existed for this idempotencyKey, or the contact was skipped.
The enrollment's id. Empty when the contact was skipped.
active while the journey is working the contact, ended once it finished, skipped when the contact could not be enrolled.
active, ended, skipped Why the enrollment ended, such as goal_met, opted_out, cancelled, total_cap or exhausted.
Why the contact was not enrolled, in words, such as Active in another journey.
True when this request created the enrollment.
When a call or text is going out right away. Null when the next step is later; it is planned when it comes due.
The contact's time zone, when known.
Show child attributes
Show child attributes