AI reply sorting
With reply sorting on, Ready reads each reply a contact sends and labels it, such as interested, not interested or question. The label is reply_category on the reply in List messages and Get a message . Each sorted reply costs 0.2 × your per-segment rate.
Without your own labels, Ready uses these: interested, not interested, question, callback requested, wrong number, opt-out, contact info, complaint, auto-reply and other. To use your own, list them after a colon in default_prompt, for example Sort each reply into: hot, warm, cold. A reply that fits none of your labels is uncategorized.
The guide and corrections further down teach the reply check automations use when they start or branch on a reply (positive, negative or neither). They don’t change reply_category, and default_prompt doesn’t change that check.
Automations that start or branch on a reply check it whether reply sorting is on or off, so you don’t need to turn it on for them. While it’s off, those checks are free. While it’s on, each one costs the same as a sorted reply.
# Get the reply sorting setting
Whether reply sorting is on, and the instruction it follows.
Returns
data.enabledboolean true when every reply on the account is sorted.
data.default_promptstring Your instruction to the sorter for reply_category only, "" when you haven’t set one. Automations read the guide below instead.
Legacy fields (1)
data.apply_allboolean Kept for older clients. It changes nothing.
Errors
HTTP Code When
500 INTENT_SETTING_LOAD_FAILEDWe couldn’t read the setting. Retry.
curl "https://api.tryready.com/settings/intent-classification" \
-H "X-API-Key: $READY_API_KEY"
const res = await fetch('https://api.tryready.com/settings/intent-classification', {
headers: {
'X-API-Key': process.env.READY_API_KEY,
},
});
const json = await res.json().catch(() => ({}));
if (!res.ok || json.success === false) {
throw new Error(`${res.status}${json.error_code || json.code ? ' ' + (json.error_code || json.code) : ''}: ${json.error || json.message || res.statusText}`);
}
import os, requests
r = requests.get(
"https://api.tryready.com/settings/intent-classification",
headers={"X-API-Key": os.environ["READY_API_KEY"]},
timeout=30,
)
data = r.json() if r.headers.get("content-type", "").startswith("application/json") else {}
if not r.ok or data.get("success") is False:
raise RuntimeError(f'{r.status_code} {data.get("error_code") or data.get("code") or ""}: {data.get("error") or data.get("message") or r.reason}')
Returns:
{
"success": true,
"data": {
"enabled": true,
"default_prompt": "Sort each reply into: hot, warm, cold",
"apply_all": false
}
}
# Turn reply sorting on or off
Turning it on starts the per-reply charge, for every reply in your inbox and for each reply an automation checks. Sending the same body again changes nothing. Needs the manage_campaigns permission.
Parameters
enabledboolean Required true or false. Left out, the request is refused with a 400 so sorting is not turned off by accident.
default_promptstring Your instruction to the sorter. Up to 2000 characters; longer text is cut. Left out, the saved one stays. "" or null clears it.
Returns
The setting as saved, the same object as Get the reply sorting setting .
Errors
HTTP Code When
400 none enabled isn’t true or false.
500 INTENT_SETTING_NOT_SAVEDNothing changed. Retry.
503 INTENT_SETTING_OUTCOME_UNKNOWNWe couldn’t confirm the save. Read the setting before you send it again.
curl -X PUT "https://api.tryready.com/settings/intent-classification" \
-H "X-API-Key: $READY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"default_prompt": "Sort each reply into: hot, warm, cold"
}'
const res = await fetch('https://api.tryready.com/settings/intent-classification', {
method: 'PUT',
headers: {
'X-API-Key': process.env.READY_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"enabled": true,
"default_prompt": "Sort each reply into: hot, warm, cold"
}),
});
const json = await res.json().catch(() => ({}));
if (!res.ok || json.success === false) {
throw new Error(`${res.status}${json.error_code || json.code ? ' ' + (json.error_code || json.code) : ''}: ${json.error || json.message || res.statusText}`);
}
import os, requests
r = requests.put(
"https://api.tryready.com/settings/intent-classification",
headers={"X-API-Key": os.environ["READY_API_KEY"]},
json={
"enabled": True,
"default_prompt": "Sort each reply into: hot, warm, cold"
},
timeout=30,
)
data = r.json() if r.headers.get("content-type", "").startswith("application/json") else {}
if not r.ok or data.get("success") is False:
raise RuntimeError(f'{r.status_code} {data.get("error_code") or data.get("code") or ""}: {data.get("error") or data.get("message") or r.reason}')
Returns:
{
"success": true,
"data": {
"enabled": true,
"default_prompt": "Sort each reply into: hot, warm, cold",
"apply_all": false
}
}
# Get the sorting guide
The description of your business that automations read before they decide if a reply is positive or negative (the Last reply intent branch and the reply intent trigger). It does not change reply_category. Needs the manage_campaigns permission.
Returns
data.guidestring The guide, "" when none is saved.
Errors
HTTP Code When
500 INTENT_TRAINING_LOAD_FAILEDWe couldn’t read the guide. Retry.
curl "https://api.tryready.com/automations/intent-training" \
-H "X-API-Key: $READY_API_KEY"
const res = await fetch('https://api.tryready.com/automations/intent-training', {
headers: {
'X-API-Key': process.env.READY_API_KEY,
},
});
const json = await res.json().catch(() => ({}));
if (!res.ok || json.success === false) {
throw new Error(`${res.status}${json.error_code || json.code ? ' ' + (json.error_code || json.code) : ''}: ${json.error || json.message || res.statusText}`);
}
import os, requests
r = requests.get(
"https://api.tryready.com/automations/intent-training",
headers={"X-API-Key": os.environ["READY_API_KEY"]},
timeout=30,
)
data = r.json() if r.headers.get("content-type", "").startswith("application/json") else {}
if not r.ok or data.get("success") is False:
raise RuntimeError(f'{r.status_code} {data.get("error_code") or data.get("code") or ""}: {data.get("error") or data.get("message") or r.reason}')
Returns:
{
"success": true,
"data": {
"guide": "We sell solar panels. A reply asking for a price is positive."
}
}
# Save the sorting guide
Replaces the guide. Sending it again changes nothing. Needs the manage_campaigns permission.
Parameters
guidestring Up to 600 characters. "" or left out clears it.
Returns
data.guidestring The guide as saved.
Errors
HTTP Code When
400 invalid_fieldguide is over 600 characters or isn’t text.
500 INTENT_GUIDE_SAVE_FAILEDNothing changed. Retry.
curl -X PUT "https://api.tryready.com/automations/intent-training/guide" \
-H "X-API-Key: $READY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"guide": "We sell solar panels. A reply asking for a price is positive."
}'
const res = await fetch('https://api.tryready.com/automations/intent-training/guide', {
method: 'PUT',
headers: {
'X-API-Key': process.env.READY_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"guide": "We sell solar panels. A reply asking for a price is positive."
}),
});
const json = await res.json().catch(() => ({}));
if (!res.ok || json.success === false) {
throw new Error(`${res.status}${json.error_code || json.code ? ' ' + (json.error_code || json.code) : ''}: ${json.error || json.message || res.statusText}`);
}
import os, requests
r = requests.put(
"https://api.tryready.com/automations/intent-training/guide",
headers={"X-API-Key": os.environ["READY_API_KEY"]},
json={
"guide": "We sell solar panels. A reply asking for a price is positive."
},
timeout=30,
)
data = r.json() if r.headers.get("content-type", "").startswith("application/json") else {}
if not r.ok or data.get("success") is False:
raise RuntimeError(f'{r.status_code} {data.get("error_code") or data.get("code") or ""}: {data.get("error") or data.get("message") or r.reason}')
Returns:
{
"success": true,
"data": {
"guide": "We sell solar panels. A reply asking for a price is positive."
}
}
# Correct a sorted reply
Tells automations how they should have read one reply. Later replies are sorted for automations with your corrections as examples. reply_category on the reply is not changed. Sending it again for the same reply replaces the first correction. Needs the manage_campaigns permission.
Parameters
message_idinteger Required Ready’s numeric id of the reply: message_id in the inbound_reply webhook.
labelenum Required positive, negative or other.
Returns
data.sorted_asenum How the sorter had read it: positive, negative or other.
Errors
HTTP Code When
400 invalid_fieldmessage_id isn’t a whole number, or label isn’t one of the three.
404 REPLY_NOT_FOUNDNo reply with this id on your account, or the reply has no text.
500 INTENT_CORRECTION_FAILEDNothing saved. Retry.
curl -X POST "https://api.tryready.com/automations/intent-training/corrections" \
-H "X-API-Key: $READY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message_id": 19408828,
"label": "positive"
}'
const res = await fetch('https://api.tryready.com/automations/intent-training/corrections', {
method: 'POST',
headers: {
'X-API-Key': process.env.READY_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"message_id": 19408828,
"label": "positive"
}),
});
const json = await res.json().catch(() => ({}));
if (!res.ok || json.success === false) {
throw new Error(`${res.status}${json.error_code || json.code ? ' ' + (json.error_code || json.code) : ''}: ${json.error || json.message || res.statusText}`);
}
import os, requests
r = requests.post(
"https://api.tryready.com/automations/intent-training/corrections",
headers={"X-API-Key": os.environ["READY_API_KEY"]},
json={
"message_id": 19408828,
"label": "positive"
},
timeout=30,
)
data = r.json() if r.headers.get("content-type", "").startswith("application/json") else {}
if not r.ok or data.get("success") is False:
raise RuntimeError(f'{r.status_code} {data.get("error_code") or data.get("code") or ""}: {data.get("error") or data.get("message") or r.reason}')
Returns:
{
"success": true,
"data": {
"sorted_as": "other"
}
}