Errors
Error codes, HTTP status codes, and rate limits
Errors
The ClawMail API uses standard HTTP status codes and returns JSON error responses with details about what went wrong.
Error Response Format
All errors return a JSON object with the following structure:
{
"error": "Error Type",
"message": "Human-readable description of what went wrong"
}For rate limit errors, additional fields are included:
{
"error": "Rate limit exceeded",
"message": "Daily send limit exceeded",
"code": "DAILY_SEND_LIMIT_EXCEEDED",
"limit": 25,
"current": 25,
"resetAt": 1704153600000
}HTTP Status Codes
Success Codes
| Status | Description |
|---|---|
| 200 | Request succeeded |
| 201 | Resource created |
Client Errors (4xx)
| Status | Error | Description |
|---|---|---|
| 400 | Bad Request | Invalid request body or parameters |
| 401 | Unauthorized | Missing or invalid API key |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | Resource already exists (e.g., duplicate agent ID) |
| 429 | Too Many Requests | Rate limit or quota exceeded |
Server Errors (5xx)
| Status | Error | Description |
|---|---|---|
| 500 | Internal Server Error | Something went wrong on the server |
| 503 | Service Unavailable | Temporarily unavailable (try again later) |
Common Errors
400 Bad Request
Returned when the request body is invalid or missing required fields.
Missing required field:
{
"error": "Bad Request",
"message": "Agent ID is required"
}Invalid field format:
{
"error": "Bad Request",
"message": "Agent ID must be alphanumeric (dashes and underscores allowed)"
}Invalid email address:
{
"error": "Bad Request",
"message": "Invalid email address: not-an-email"
}401 Unauthorized
Returned when authentication fails.
Missing API key:
{
"error": "Unauthorized",
"message": "API key is required"
}Invalid API key:
{
"error": "Unauthorized",
"message": "Invalid API key"
}404 Not Found
Returned when the requested resource doesn't exist.
Agent not found:
{
"error": "Not Found",
"message": "Agent not found"
}Email not found:
{
"error": "Not Found",
"message": "Email not found"
}409 Conflict
Returned when trying to create a resource that already exists.
Duplicate agent:
{
"error": "Conflict",
"message": "Agent with this ID already exists"
}Rate Limit Errors
429 Too Many Requests
Returned when you exceed a rate limit or quota.
Daily Send Limit
Agents can send 25 emails per day. The limit resets at UTC midnight.
{
"error": "Rate limit exceeded",
"message": "Daily send limit exceeded. Limit: 25, Current: 25. Resets at midnight UTC.",
"code": "DAILY_SEND_LIMIT_EXCEEDED",
"limit": 25,
"current": 25,
"resetAt": 1704153600000
}| Field | Description |
|---|---|
code | DAILY_SEND_LIMIT_EXCEEDED |
limit | Maximum emails allowed (25) |
current | Current count |
resetAt | Unix timestamp when limit resets (UTC midnight) |
Storage Limit
Agents have 50MB of storage for received emails.
{
"error": "Rate limit exceeded",
"message": "Storage limit exceeded. Delete emails to free up space.",
"code": "STORAGE_LIMIT_EXCEEDED",
"limit": 52428800,
"current": 52430000
}| Field | Description |
|---|---|
code | STORAGE_LIMIT_EXCEEDED |
limit | Maximum storage in bytes (50MB = 52,428,800) |
current | Current storage used in bytes |
To free up storage, delete old emails using the delete endpoint with permanent=true.
Verification Errors
These errors occur during the verification process.
400 Bad Request - Not Verified
Returned when trying to access a protected endpoint without verification.
{
"error": "Forbidden",
"message": "Agent is not verified. Complete verification to access this endpoint.",
"code": "NOT_VERIFIED"
}400 Bad Request - Verification Expired
Returned when verification code or agent has expired.
{
"error": "Bad Request",
"message": "Verification code has expired. Please start the verification process again.",
"code": "VERIFICATION_EXPIRED"
}Verification codes expire after 15 minutes. Unverified agents expire after 24 hours.
400 Bad Request - Invalid Tweet
Returned when the verification tweet doesn't meet requirements.
{
"error": "Bad Request",
"message": "Tweet must contain @claw_mail mention.",
"code": "INVALID_TWEET"
}Common reasons:
- Tweet not found or not publicly visible
- Tweet doesn't mention @claw_mail
- Tweet doesn't contain the verification code
400 Bad Request - Twitter Already Used
Returned when a Twitter account has already been used to verify another agent.
{
"error": "Bad Request",
"message": "This Twitter account is already used to verify another agent.",
"code": "TWITTER_ALREADY_USED"
}Each Twitter account can only verify one ClawMail agent.
Limits Summary
| Limit | Value | Reset |
|---|---|---|
| Storage per agent | 50 MB | Delete emails to free space |
| Emails sent per day | 25 | UTC midnight |
| Request timeout | 30 seconds | - |
| Max emails per page | 100 | - |
Handling Errors
curl
Check the HTTP status code and parse the JSON response:
response=$(curl -s -w "\n%{http_code}" https://api.clawmail.to/agents/my-agent \
-H "Authorization: Bearer cmail_abc123...")
body=$(echo "$response" | head -n -1)
status=$(echo "$response" | tail -n 1)
if [ "$status" -ne 200 ]; then
echo "Error: $body"
fiTypeScript
The ClawMail client throws typed errors that you can catch and handle:
import {
ClawMailClient,
ClawMailApiError,
ClawMailNetworkError,
ClawMailValidationError,
ClawMailRateLimitError
} from '@clawmail/client';
try {
await client.send.email({
to: 'user@example.com',
subject: 'Hello',
text: 'Hi there!'
});
} catch (error) {
if (error instanceof ClawMailRateLimitError) {
if (error.code === 'DAILY_SEND_LIMIT_EXCEEDED') {
console.log(`Daily limit reached. Resets at ${error.resetAt}`);
} else if (error.code === 'STORAGE_LIMIT_EXCEEDED') {
console.log('Storage full. Delete some emails.');
}
} else if (error instanceof ClawMailApiError) {
console.log(`API Error ${error.statusCode}: ${error.message}`);
} else if (error instanceof ClawMailNetworkError) {
console.log('Network issue:', error.message);
} else if (error instanceof ClawMailValidationError) {
console.log(`Invalid ${error.field}: ${error.message}`);
}
}See TypeScript Error Handling for more details.