Help
Errors and rate limits
Errors come as JSON with a stable error code and a message written for a person:
{ "error": "auth_required", "message": "This tool needs a TerraLab account. Connect TerraLab in your assistant's settings; see https://terra-lab.ai/mcp." }
Branch on error, never on message: the wording can change.
HTTP errors
| Status | error | Meaning | What to do |
|---|---|---|---|
| 400 | invalid_input | The body is not a JSON object of the tool arguments. | Fix the request body. |
| 400 | bad_request | The request could not be read. | Check the JSON and the headers. |
| 401 | auth_required | No key or token was sent. | Send Authorization: Bearer <key>. |
| 401 | invalid_token | The key or token is invalid, revoked or expired. | Create a new key, or let the agent sign in again. |
| 401 | access_revoked | The app was disconnected from the dashboard. | Reconnect the agent. |
| 402 | balance_required | The free calls of the month are used, or the operation is paid, and the balance is empty. | Add funds; the answer carries hint and account_url. |
| 404 | not_found | There is no such API path. | Check the URL. |
| 404 | unknown_tool | No tool has that name. | List tools with GET /v1/tools. |
| 405 | method_not_allowed | Tools are called with POST. | Use POST. |
| 413 | too_large | The request body is too large. | Send a smaller file or fewer features. |
| 429 | rate_limited | Too many requests in the last minute. | Wait for Retry-After seconds, then retry. |
| 429 | daily_limit | The account reached its daily safety ceiling. | Retry the next day (UTC) or write to support. |
| 503 | unavailable | The account service did not answer. | Retry after Retry-After seconds. |
Tool errors
A tool that runs but cannot answer returns 200 with isError: true. Its structuredContent then carries code, message and, most of the time, a hint saying what to change: a place it could not find, an area too large, a country it does not cover.
{
"structuredContent": { "code": "...", "message": "...", "hint": "..." },
"content": [{ "type": "text", "text": "..." }],
"isError": true
}
What is counted
A call that fails or finds nothing is not counted: the free call or the amount taken from the balance is given back. Only answers with a result count.
Rate limits
Every account can make 60 calls a minute. Past it, the API answers 429 with Retry-After: 60. Spread batch jobs over time, and retry with a growing delay:
import time
import requests
def call(url, headers, body, attempts=5):
for attempt in range(attempts):
response = requests.post(url, headers=headers, json=body, timeout=120)
if response.status_code not in (429, 503):
return response
time.sleep(int(response.headers.get("Retry-After", 2 ** attempt)))
return response
Retry only 429 and 503. A 401 or 402 will not pass on a second try.
Updated 2026-10-27