Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.tuco.ai/llms.txt

Use this file to discover all available pages before exploring further.

Error format

All error responses return a JSON body with an error field. Some include a machine-readable code for programmatic handling.
{
  "error": "Human-readable description of the problem",
  "code": "MACHINE_READABLE_CODE"
}

HTTP status codes

CodeMeaning
200Request succeeded
201Resource created (e.g. message, lead)
400Validation error — check the error field for details
401Authentication failed — invalid or missing API key
402Workspace is read-only (e.g. subscription past due)
404Resource not found (e.g. lead, line, campaign)
429Rate limit exceeded — wait and retry
500Internal server error — retry or contact support

Send Message errors (POST /api/messages)

These are the specific errors you may encounter when sending a message.
Pre-send checks like line limits, time windows, device gaps, and contact gaps never return errors. The message is accepted with 201 and the status field indicates the outcome (pending, scheduled, etc.).
Neither message nor attachmentUrls was provided (or both were empty).
{ "error": "Message and attachmentUrls cannot both be empty" }
Fix: Include at least one of: a non-empty message string, or an attachmentUrls array with up to 2 URLs.
The messageType value is not one of the accepted values.
{ "error": "Invalid messageType. Must be email, sms, or imessage" }
Fix: Use "imessage", "sms", or "email". Or omit it entirely to default to "imessage".
No fromLineId was provided and the workspace has no active lines to round-robin from.
{ "error": "No active lines in workspace..." }
Fix: Provision at least one line in your workspace, or pass fromLineId explicitly.
No recipientPhone, recipientEmail, or leadId was provided, and the resolved lead (if any) has no contact details.
{ "error": "Either recipientEmail or recipientPhone is required..." }
Fix: Provide at least one of recipientPhone, recipientEmail, or a leadId that has stored contact details.
sendFallbackSmsOnFailed was set to true but the workspace doesn’t have Twilio fallback configured.
{ "error": "...", "code": "FALLBACK_NOT_CONFIGURED" }
Fix: Configure Twilio on your workspace via PATCH /api/workspace/fallback-config, or set sendFallbackSmsOnFailed to false.
The API key is missing, invalid, or expired.
{ "error": "Unauthorized" }
Fix: Check your Authorization: Bearer <key> header. Generate a new key from your workspace settings if needed.
The workspace subscription is past due and write operations are blocked.
{ "error": "READ_ONLY", "code": "READ_ONLY", "reason": "past_due" }
Fix: Update your billing in the Tuco dashboard.
A leadId was provided but no matching lead exists in the workspace.
{ "error": "Lead not found or access denied" }
Fix: Verify the leadId exists and belongs to the same workspace as the API key.

Status vs error — key distinction

A 201 response with status: "pending" or status: "scheduled" is not an error. It means the message was accepted and Tuco will send it when conditions are met (time window, line limits, device gap, etc.).Only 4xx and 5xx responses indicate actual errors.
You receivedWhat it meansAction
201 + "pending"Message accepted, sending soonNo action needed
201 + "scheduled"Message accepted, will send at scheduled timeNo action needed
201 + "sent"Message sent immediatelyNo action needed
201 + "fallback"Recipient has no iMessage, fallback may fireOptional: send via another channel
400Validation errorFix the request and retry
401Auth errorCheck API key
402Billing issueUpdate payment
404Resource not foundCheck IDs

Rate limits

Tuco applies per-workspace rate limits to protect the platform. When you hit a limit:
  • You receive a 429 response.
  • The Retry-After header tells you how many seconds to wait before retrying.
  • No data is modified — safe to retry.
Endpoint groupAPI rate limitDaily cap
Send message (/api/messages)60 req/minPer-line (see GET /api/lines/by-user for your limits)
Check iMessage availability (/api/check-availability-rr, /api/leads/check-availability)200 req/min70 checks/day per line
Get replies (/api/replies)120 req/min
Create campaign (/api/campaigns)200 req/min
Campaign add lead (/api/campaigns/{id}/leads)200 req/min
Unibox reply (/api/unibox/send-reply)30 req/min
Fallback SMS (/api/fallback-sms)200 req/min
All limits are per workspace (organization), regardless of how many API keys or users are calling the endpoint.
Availability checks have two limits:
  1. 200 req/min API rate limit (token bucket, per workspace)
  2. 70 checks/day per line hard cap (each check hits a real device). With 3 lines = 210/day total.
When the daily cap is exhausted, you get 429 with Retry-After: 3600.Availability checks do not consume your daily send quota — they use separate counters.
For API integrators: Skip availability checking entirely. Just call POST /api/messages and listen for the message.fallback webhook to trigger your SMS/WhatsApp fallback. This avoids burning your 70/day availability quota. See the check-availability-rr endpoint for the recommended pattern.
For high-volume sends, use campaigns instead of individual API calls. Campaigns handle pacing, line rotation, and retry logic automatically — and are not subject to per-request rate limits.