Check iMessage Availability (Round-Robin)
curl --request POST \
--url https://app.tuco.ai/api/check-availability-rr \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"phones": [
"<string>"
],
"emails": [
"<string>"
]
}
'import requests
url = "https://app.tuco.ai/api/check-availability-rr"
payload = {
"phones": ["<string>"],
"emails": ["<string>"]
}
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({phones: ['<string>'], emails: ['<string>']})
};
fetch('https://app.tuco.ai/api/check-availability-rr', 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://app.tuco.ai/api/check-availability-rr",
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([
'phones' => [
'<string>'
],
'emails' => [
'<string>'
]
]),
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://app.tuco.ai/api/check-availability-rr"
payload := strings.NewReader("{\n \"phones\": [\n \"<string>\"\n ],\n \"emails\": [\n \"<string>\"\n ]\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://app.tuco.ai/api/check-availability-rr")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"phones\": [\n \"<string>\"\n ],\n \"emails\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.tuco.ai/api/check-availability-rr")
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 \"phones\": [\n \"<string>\"\n ],\n \"emails\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_bodyiMessage Availability
Check iMessage Availability (Round-Robin)
Check if a phone or email has iMessage, using round-robin across your lines. REST endpoint in the Tuco AI iMessage API — bearer-token auth, JSON.
POST
/
api
/
check-availability-rr
Check iMessage Availability (Round-Robin)
curl --request POST \
--url https://app.tuco.ai/api/check-availability-rr \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"phones": [
"<string>"
],
"emails": [
"<string>"
]
}
'import requests
url = "https://app.tuco.ai/api/check-availability-rr"
payload = {
"phones": ["<string>"],
"emails": ["<string>"]
}
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({phones: ['<string>'], emails: ['<string>']})
};
fetch('https://app.tuco.ai/api/check-availability-rr', 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://app.tuco.ai/api/check-availability-rr",
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([
'phones' => [
'<string>'
],
'emails' => [
'<string>'
]
]),
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://app.tuco.ai/api/check-availability-rr"
payload := strings.NewReader("{\n \"phones\": [\n \"<string>\"\n ],\n \"emails\": [\n \"<string>\"\n ]\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://app.tuco.ai/api/check-availability-rr")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"phones\": [\n \"<string>\"\n ],\n \"emails\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.tuco.ai/api/check-availability-rr")
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 \"phones\": [\n \"<string>\"\n ],\n \"emails\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_bodyOverview
Round-robin iMessage availability check across your workspace’s eligible lines. Returns whether any of the provided phone numbers or emails are registered on iMessage.70 checks/day per line (hard cap). Each line can perform up to 70 availability
checks per day. With 3 lines you get 210 total. When all lines are exhausted,
you receive a
429 with Retry-After: 3600.Recommended: Skip this endpoint entirely. Instead, call POST /api/messages
directly and listen for the message.fallback webhook to trigger your SMS/WhatsApp
fallback. This avoids burning your daily availability quota. See
Integration Patterns below.Request
string[]
Array of phone numbers to check (checked first, in order).
string[]
Array of email addresses to check (checked after phones).
curl -X POST https://app.tuco.ai/api/check-availability-rr \
-H "Authorization: Bearer tuco_sk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"phones": ["+14155551234"],
"emails": ["frank@example.com"]
}'
Response
Available
{
"available": true
}
Not Available
{
"available": false,
"reason": "Contact not available on iMessage"
}
Quota Exhausted (429)
{
"available": false,
"reason": "Daily availability check quota exhausted"
}
Rate Limits
| Limit | Value |
|---|---|
| API rate limit | 200 req/min per workspace |
| Daily cap | 70 checks/day per line |
| Device gap | 3 seconds between checks on the same physical device |
Availability checks do not consume your daily send quota. Send limits and
availability limits are tracked separately in Redis.
Recommended Pattern: Send + Fallback Webhook
Instead of checking availability first, just send viaPOST /api/messages and
handle the message.fallback webhook to trigger your SMS or WhatsApp fallback.
Why this is better:
- No availability quota consumed (saves your 70/day/line cap)
- One API call instead of two
- Webhook-driven fallback is reliable and async
- Works even when availability quota is exhausted
# Step 1: Just send. Don't check availability first.
resp = requests.post("https://app.tuco.ai/api/messages", headers=headers, json={
"message": "Hey, quick question about your demo.",
"recipientPhone": "+14155551234",
"recipientName": "Frank"
})
# Step 2: Handle webhooks on your server
@app.post("/tuco-webhook")
def handle(request):
event = request.json["event"]
if event == "message.sent":
pass # iMessage delivered
elif event == "message.fallback":
# No iMessage — trigger WhatsApp/SMS fallback
phone = request.json["message"]["recipientPhone"]
send_whatsapp(phone)
elif event == "message.reply":
reply_text = request.json["message"] # string
notify_team(request.json["leadId"], reply_text)
return {"ok": True}
Error Codes
| Code | When | Body |
|---|---|---|
| 400 | No phones or emails provided | { "available": false, "reason": "No phone or email addresses provided" } |
| 401 | Bad API key | { "error": "Unauthorized" } |
| 429 | API rate limit hit | { "error": "Rate limit exceeded" } |
| 429 | Daily cap exhausted | { "available": false, "reason": "Daily availability check quota exhausted" } |
| 500 | Server error | { "error": "Internal server error" } |