Error Codes
All Agent API errors follow a consistent JSON format. When a request fails, the response body contains success: false and an error object with a machine-readable code and a human-readable message.
Error Response Format
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable description of what went wrong."
}
}
The code field is a stable string identifier that your agent should use for programmatic error handling. The message field may change between releases and is intended for logging and debugging.
Error Code Reference
| HTTP Status | Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR | Request parameters or body are invalid |
| 401 | MISSING_API_KEY | X-API-Key header was not provided |
| 401 | INVALID_API_KEY | API key is invalid, expired, or has been revoked |
| 403 | INSUFFICIENT_SCOPE | API key does not have the required scope for this operation |
| 404 | NOT_FOUND | The requested resource does not exist |
| 429 | RATE_LIMIT_EXCEEDED | Too many requests; check the Retry-After header |
| 500 | INTERNAL_ERROR | An unexpected server error occurred |
Detailed Error Descriptions
MISSING_API_KEY (401)
The request did not include an X-API-Key header.
{
"success": false,
"error": {
"code": "MISSING_API_KEY",
"message": "API key is required. Include it in the X-API-Key header."
}
}
Fix: Add the X-API-Key header to your request:
curl https://home.dobprotocol.com/api/agent/pools \
-H "X-API-Key: dob_ak_your_key_here"
INVALID_API_KEY (401)
The provided API key does not match any active key in the system. This can happen if:
- The key was typed incorrectly
- The key has been revoked
- The key was rotated and the old value is being used
{
"success": false,
"error": {
"code": "INVALID_API_KEY",
"message": "The provided API key is not valid or has been revoked."
}
}
Fix: Verify the key is correct. If it was revoked or rotated, create a new key or use the rotated value. See API Keys.
INSUFFICIENT_SCOPE (403)
The API key is valid but does not have the required scope for the requested operation. For example, using a read-only key to call a marketplace trade endpoint.
{
"success": false,
"error": {
"code": "INSUFFICIENT_SCOPE",
"message": "This operation requires the 'trade' scope. Your key has: ['read']."
}
}
Fix: Create a new API key with the required scopes, or use a key that already has them. See Authentication - Scopes.
| Operation | Required Scope |
|---|---|
| Pool discovery, portfolio, webhooks | read |
| Marketplace buy/list/cancel | trade |
| Crowdfunding contribute | trade |
NOT_FOUND (404)
The requested resource does not exist. This can happen when:
- A pool address is incorrect or does not exist on the specified network
- A listing has been purchased or cancelled
- A webhook ID is incorrect
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Pool not found: CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC on network 10."
}
}
Fix: Verify the resource identifier and network ID. Use the list endpoints to find valid identifiers.
VALIDATION_ERROR (400)
The request body or query parameters failed validation. The message field describes what is wrong, and for requests with multiple fields, an additional details array may be included.
Simple validation error:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Contribution amount must be greater than zero."
}
}
Multiple field validation errors:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed.",
"details": [
{
"field": "page",
"message": "Must be a positive integer."
},
{
"field": "limit",
"message": "Must be between 1 and 100."
}
]
}
}
Common validation errors:
| Scenario | Message |
|---|---|
| Missing required field | "pool_address" is required. |
| Invalid network ID | Invalid network_id. Supported: 1, 9, 10, 137, 8453, 42161, 84532. |
| Invalid sort parameter | Invalid sort value. Supported: created_desc, created_asc, apr_desc, apr_asc. |
| Amount exceeds limit | Amount exceeds remaining target (max: 17500.00). |
| Invalid scopes | Invalid scope "write". Supported scopes: read, trade. |
| Max keys reached | Maximum of 10 API keys per wallet. |
| Expired XDR | Transaction XDR has expired. Prepare a new transaction. |
| Pool not crowdfunding | Pool is not a crowdfunding campaign. |
| Campaign ended | Crowdfunding campaign deadline has passed. |
RATE_LIMIT_EXCEEDED (429)
The API key has exceeded its rate limit. The response includes a Retry-After header indicating how many seconds to wait.
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Retry after 23 seconds."
}
}
Fix: Wait for the Retry-After duration, then retry. See Rate Limiting for implementation patterns.
INTERNAL_ERROR (500)
An unexpected error occurred on the server. This is not caused by your request and typically resolves on its own.
{
"success": false,
"error": {
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred. Please try again later."
}
}
Fix: Retry the request after a short delay. If the error persists, contact DobProtocol support.
Error Handling Example
Python
import time
import requests
API_KEY = "dob_ak_your_key_here"
BASE = "https://home.dobprotocol.com/api/agent"
def api_request(method: str, path: str, max_retries: int = 3, **kwargs) -> dict:
"""Make an API request with comprehensive error handling."""
headers = {"X-API-Key": API_KEY}
if "headers" in kwargs:
headers.update(kwargs.pop("headers"))
for attempt in range(max_retries + 1):
resp = requests.request(method, f"{BASE}{path}", headers=headers, **kwargs)
if resp.status_code == 200 or resp.status_code == 201:
return resp.json()
error_body = resp.json()
error = error_body.get("error", {})
code = error.get("code", "UNKNOWN")
message = error.get("message", "Unknown error")
if code == "RATE_LIMIT_EXCEEDED":
retry_after = int(resp.headers.get("Retry-After", 60))
if attempt < max_retries:
print(f"Rate limited. Waiting {retry_after}s...")
time.sleep(retry_after)
continue
elif code == "INVALID_API_KEY":
raise PermissionError(f"API key is invalid or revoked: {message}")
elif code == "INSUFFICIENT_SCOPE":
raise PermissionError(f"Missing required scope: {message}")
elif code == "MISSING_API_KEY":
raise PermissionError("API key not configured.")
elif code == "NOT_FOUND":
return None # Resource does not exist
elif code == "VALIDATION_ERROR":
details = error.get("details", [])
if details:
field_errors = "; ".join(
f"{d['field']}: {d['message']}" for d in details
)
raise ValueError(f"Validation failed: {field_errors}")
raise ValueError(f"Validation error: {message}")
elif code == "INTERNAL_ERROR":
if attempt < max_retries:
wait = 2 ** attempt # Exponential backoff: 1, 2, 4 seconds
print(f"Server error. Retrying in {wait}s...")
time.sleep(wait)
continue
# If we get here, raise the error
raise Exception(f"API error {resp.status_code} [{code}]: {message}")
raise Exception("Max retries exceeded")
# Usage examples
try:
# Successful request
pools = api_request("GET", "/pools", params={"network_id": 10})
print(f"Found {len(pools['data'])} pools")
# 404 returns None
pool = api_request("GET", "/pools/INVALID_ADDRESS", params={"network_id": 10})
if pool is None:
print("Pool not found")
# Validation error raises ValueError
api_request("POST", "/marketplace/prepare-buy", json={"amount": -1})
except PermissionError as e:
print(f"Auth error: {e}")
except ValueError as e:
print(f"Invalid request: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
curl
# Check the response and handle errors
response=$(curl -s -w "\n%{http_code}" \
-H "X-API-Key: dob_ak_your_key_here" \
"https://home.dobprotocol.com/api/agent/pools/INVALID")
http_code=$(echo "$response" | tail -1)
body=$(echo "$response" | sed '$d')
case $http_code in
200|201)
echo "Success: $body"
;;
401)
echo "Authentication error. Check your API key."
;;
403)
echo "Permission denied. Check your key scopes."
;;
404)
echo "Resource not found."
;;
429)
echo "Rate limited. Check Retry-After header."
;;
500)
echo "Server error. Try again later."
;;
*)
echo "Unexpected status $http_code: $body"
;;
esac
HTTP Status Code Summary
| Status | Meaning | Agent Action |
|---|---|---|
| 200 | Success | Process the response |
| 201 | Created | Resource was created successfully |
| 400 | Bad Request | Fix the request parameters and retry |
| 401 | Unauthorized | Check or recreate API key |
| 403 | Forbidden | Use a key with the required scope |
| 404 | Not Found | Verify the resource identifier |
| 429 | Too Many Requests | Wait Retry-After seconds, then retry |
| 500 | Server Error | Retry with exponential backoff |