curl --request POST \
--url https://api.reply.io/v3/ai-sdr/playbooks \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Outbound playbook v2",
"description": "Tone and pacing for cold outreach",
"body": "## Voice\nFriendly, concise, never desperate.\n\n## Pacing\nTwo touches per week max.",
"type": "team"
}
'import requests
url = "https://api.reply.io/v3/ai-sdr/playbooks"
payload = {
"name": "Outbound playbook v2",
"description": "Tone and pacing for cold outreach",
"body": "## Voice
Friendly, concise, never desperate.
## Pacing
Two touches per week max.",
"type": "team"
}
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({
name: 'Outbound playbook v2',
description: 'Tone and pacing for cold outreach',
body: JSON.stringify('## Voice\nFriendly, concise, never desperate.\n\n## Pacing\nTwo touches per week max.'),
type: 'team'
})
};
fetch('https://api.reply.io/v3/ai-sdr/playbooks', 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.reply.io/v3/ai-sdr/playbooks",
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([
'name' => 'Outbound playbook v2',
'description' => 'Tone and pacing for cold outreach',
'body' => '## Voice
Friendly, concise, never desperate.
## Pacing
Two touches per week max.',
'type' => 'team'
]),
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.reply.io/v3/ai-sdr/playbooks"
payload := strings.NewReader("{\n \"name\": \"Outbound playbook v2\",\n \"description\": \"Tone and pacing for cold outreach\",\n \"body\": \"## Voice\\nFriendly, concise, never desperate.\\n\\n## Pacing\\nTwo touches per week max.\",\n \"type\": \"team\"\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.reply.io/v3/ai-sdr/playbooks")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Outbound playbook v2\",\n \"description\": \"Tone and pacing for cold outreach\",\n \"body\": \"## Voice\\nFriendly, concise, never desperate.\\n\\n## Pacing\\nTwo touches per week max.\",\n \"type\": \"team\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reply.io/v3/ai-sdr/playbooks")
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 \"name\": \"Outbound playbook v2\",\n \"description\": \"Tone and pacing for cold outreach\",\n \"body\": \"## Voice\\nFriendly, concise, never desperate.\\n\\n## Pacing\\nTwo touches per week max.\",\n \"type\": \"team\"\n}"
response = http.request(request)
puts response.read_body{
"id": "t-7",
"name": "Outbound playbook v2",
"description": "Tone and pacing for cold outreach",
"body": "## Voice\nFriendly, concise, never desperate.\n\n## Pacing\nTwo touches per week max.",
"type": "team",
"lastUpdatedAt": "2026-05-10T14:32:11Z",
"authorUserId": 4821,
"styleFiles": [
{
"id": 12345,
"fileName": "tone-guide.pdf"
}
]
}Create a playbook
ai-sdr:write scope (or a broader one that includes it).
Create a playbook holding the tone, voice, and writing guidance your AI SDR follows. Name, description, body, and type are required.
curl --request POST \
--url https://api.reply.io/v3/ai-sdr/playbooks \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Outbound playbook v2",
"description": "Tone and pacing for cold outreach",
"body": "## Voice\nFriendly, concise, never desperate.\n\n## Pacing\nTwo touches per week max.",
"type": "team"
}
'import requests
url = "https://api.reply.io/v3/ai-sdr/playbooks"
payload = {
"name": "Outbound playbook v2",
"description": "Tone and pacing for cold outreach",
"body": "## Voice
Friendly, concise, never desperate.
## Pacing
Two touches per week max.",
"type": "team"
}
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({
name: 'Outbound playbook v2',
description: 'Tone and pacing for cold outreach',
body: JSON.stringify('## Voice\nFriendly, concise, never desperate.\n\n## Pacing\nTwo touches per week max.'),
type: 'team'
})
};
fetch('https://api.reply.io/v3/ai-sdr/playbooks', 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.reply.io/v3/ai-sdr/playbooks",
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([
'name' => 'Outbound playbook v2',
'description' => 'Tone and pacing for cold outreach',
'body' => '## Voice
Friendly, concise, never desperate.
## Pacing
Two touches per week max.',
'type' => 'team'
]),
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.reply.io/v3/ai-sdr/playbooks"
payload := strings.NewReader("{\n \"name\": \"Outbound playbook v2\",\n \"description\": \"Tone and pacing for cold outreach\",\n \"body\": \"## Voice\\nFriendly, concise, never desperate.\\n\\n## Pacing\\nTwo touches per week max.\",\n \"type\": \"team\"\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.reply.io/v3/ai-sdr/playbooks")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Outbound playbook v2\",\n \"description\": \"Tone and pacing for cold outreach\",\n \"body\": \"## Voice\\nFriendly, concise, never desperate.\\n\\n## Pacing\\nTwo touches per week max.\",\n \"type\": \"team\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reply.io/v3/ai-sdr/playbooks")
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 \"name\": \"Outbound playbook v2\",\n \"description\": \"Tone and pacing for cold outreach\",\n \"body\": \"## Voice\\nFriendly, concise, never desperate.\\n\\n## Pacing\\nTwo touches per week max.\",\n \"type\": \"team\"\n}"
response = http.request(request)
puts response.read_body{
"id": "t-7",
"name": "Outbound playbook v2",
"description": "Tone and pacing for cold outreach",
"body": "## Voice\nFriendly, concise, never desperate.\n\n## Pacing\nTwo touches per week max.",
"type": "team",
"lastUpdatedAt": "2026-05-10T14:32:11Z",
"authorUserId": 4821,
"styleFiles": [
{
"id": 12345,
"fileName": "tone-guide.pdf"
}
]
}Authorizations
Authenticate every request with a Bearer token. Pass your Reply API key in the
Authorization header:
Authorization: Bearer <your-api-key>
Get your API key from the Reply dashboard: Settings → API Key.
Body
Request body for creating a new playbook.
Display name of the playbook
1 - 128Short description of the playbook's purpose. Empty string allowed.
1000Full playbook body — typically Markdown or plain text instructions the AI SDR follows when this playbook is applied. Empty string allowed.
Visibility scope for the new playbook. Only organization and team are accepted —
global playbooks are Reply-curated and cannot be created via the API.
global, organization, team Response
Playbook created successfully
Detailed representation of a playbook, returned by get/create/update responses.
Composite identifier formatted as {prefix}-{numericId} where the prefix encodes the playbook scope:
g for global, o for organization, t for team (e.g. g-1, o-42, t-7).
Display name of the playbook
Short description of the playbook's purpose
Full playbook body — typically Markdown or plain text instructions the AI SDR follows when this playbook is applied.
Visibility scope of the playbook. Set on create and immutable thereafter.
global, organization, team Timestamp of the last modification
User ID of the playbook author. null for global playbooks and when the original author is no longer a team member.
Style files attached to the playbook. Managed via the /style-files sub-resource — uploads are immediate, deletes are immediate; the field is read-only on the playbook payload.
Show child attributes
Show child attributes