curl --request GET \
--url https://api.reply.io/v3/ai-sdr/learnings/{id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.reply.io/v3/ai-sdr/learnings/{id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.reply.io/v3/ai-sdr/learnings/{id}', 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/learnings/{id}",
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>"
],
]);
$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://api.reply.io/v3/ai-sdr/learnings/{id}"
req, _ := http.NewRequest("GET", url, nil)
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://api.reply.io/v3/ai-sdr/learnings/{id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reply.io/v3/ai-sdr/learnings/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"id": 5498,
"text": "Never open a message with \"Hello\".",
"categories": [
"personalizedMessage"
],
"source": "manual",
"scope": "user",
"sequenceIds": [],
"isEnabled": true,
"createdAt": "2026-09-02T09:14:07Z",
"updatedAt": "2026-09-11T16:41:55Z",
"ownerUserId": 1234,
"isOwn": true,
"conflictState": "takesPrecedence",
"conflicts": [
{
"otherLearningId": 5512,
"otherText": "Always open with a short greeting.",
"categories": [
"personalizedMessage"
],
"state": "takesPrecedence",
"reason": "One learning forbids a greeting the other requires."
}
]
}{
"title": "Validation failed",
"status": 400,
"detail": "The request body contains validation errors.",
"errors": [
{
"pointer": "/id",
"detail": "Value has an invalid format."
}
]
}{
"title": "Unauthorized",
"status": 401,
"detail": "Authentication credentials are missing or invalid."
}{
"title": "Forbidden",
"status": 403,
"detail": "AI Learnings is not available for your team",
"code": "aiLearning.forbidden"
}{
"title": "Not Found",
"status": 404,
"detail": "AI learning '5498' not found",
"code": "aiLearning.notFound"
}{
"title": "Bad Gateway",
"status": 502,
"detail": "The AI Learnings service is temporarily unavailable",
"code": "aiLearning.upstreamFailure"
}Get an AI learning
Coming soon. This endpoint will be available by early October 2026.
ai-sdr:read scope (or a broader one that includes it).
Use this endpoint when you need a single AI learning by its id, including the rules it clashes with. Alongside the text, categories, scope and status you already see in the list, conflicts names every other learning this one contradicts, quoting its text and saying which of the two currently applies: takesPrecedence means this learning wins, overridden means the other one does, and unresolved means neither is applied until somebody settles it. A learning a team or organization admin set for everyone can be read here but not changed unless you hold the matching permission. The AI Learnings feature must be enabled for your team.
curl --request GET \
--url https://api.reply.io/v3/ai-sdr/learnings/{id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.reply.io/v3/ai-sdr/learnings/{id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.reply.io/v3/ai-sdr/learnings/{id}', 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/learnings/{id}",
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>"
],
]);
$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://api.reply.io/v3/ai-sdr/learnings/{id}"
req, _ := http.NewRequest("GET", url, nil)
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://api.reply.io/v3/ai-sdr/learnings/{id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reply.io/v3/ai-sdr/learnings/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"id": 5498,
"text": "Never open a message with \"Hello\".",
"categories": [
"personalizedMessage"
],
"source": "manual",
"scope": "user",
"sequenceIds": [],
"isEnabled": true,
"createdAt": "2026-09-02T09:14:07Z",
"updatedAt": "2026-09-11T16:41:55Z",
"ownerUserId": 1234,
"isOwn": true,
"conflictState": "takesPrecedence",
"conflicts": [
{
"otherLearningId": 5512,
"otherText": "Always open with a short greeting.",
"categories": [
"personalizedMessage"
],
"state": "takesPrecedence",
"reason": "One learning forbids a greeting the other requires."
}
]
}{
"title": "Validation failed",
"status": 400,
"detail": "The request body contains validation errors.",
"errors": [
{
"pointer": "/id",
"detail": "Value has an invalid format."
}
]
}{
"title": "Unauthorized",
"status": 401,
"detail": "Authentication credentials are missing or invalid."
}{
"title": "Forbidden",
"status": 403,
"detail": "AI Learnings is not available for your team",
"code": "aiLearning.forbidden"
}{
"title": "Not Found",
"status": 404,
"detail": "AI learning '5498' not found",
"code": "aiLearning.notFound"
}{
"title": "Bad Gateway",
"status": 502,
"detail": "The AI Learnings service is temporarily unavailable",
"code": "aiLearning.upstreamFailure"
}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.
Path Parameters
AI learning ID
x >= 1Response
The requested learning
A standing rule that shapes how the AI writes, together with the learnings it contradicts.
Unique identifier of the learning
The standing rule the AI follows
Where the rule applies
Where a learning applies. personalizedMessage shapes outbound message drafting, replyHandling
shapes answers to incoming mail. A learning can carry both.
personalizedMessage, replyHandling Whether the AI derived the learning or a person wrote it
aiGenerated, manual Who the learning binds
organization, workspace, user, sequence Sequences the learning is limited to. Empty unless scope is sequence.
Whether the learning is switched on
When the learning was created (UTC)
When the learning was last changed (UTC). null if it has never been changed.
User ID of the learning's owner. null when the owner is no longer a Reply user.
Whether the learning is yours. false for a learning a team or organization admin set for everyone.
How the learning stands against the learnings it contradicts. An unresolved learning is not applied.
none, overridden, takesPrecedence, unresolved Every other learning this one contradicts. Empty when conflictState is none.
Show child attributes
Show child attributes