All Vilna API errors follow the RFC 7807 Problem Details format, returned as application/problem+json.
Every error response contains at least type, title, and status:
{
"type": "https://docs.vilna.io/apis/problems/not-found",
"title": "Not Found",
"status": 404,
"detail": "Address not found"
}Requests that fail input validation return status 400 with a fields array describing each invalid field:
{
"type": "https://docs.vilna.io/apis/problems/invalid-request",
"title": "Invalid Request",
"status": 400,
"detail": "Validation error",
"fields": [
{ "name": "value", "reason": "must not be empty" },
{ "name": "chainFamily", "reason": "must be one of: evm, bitcoin, solana, tron" }
]
}| Status | Title | When |
|---|---|---|
| 400 | Invalid Request | Invalid or missing request fields |
| 401 | Unauthorized | Missing or invalid API key |
| 403 | Forbidden | Valid key but insufficient permissions |
| 404 | Not Found | Resource does not exist |
| 409 | Conflict | Resource state conflict (e.g., address already exists) |
| 422 | Unprocessable Entity | Business logic precondition failed |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Unexpected server error |
| 502 | Bad Gateway | Upstream service unavailable |
| 503 | Service Unavailable | Server temporarily overloaded |
When you exceed the request rate limit, the API returns 429 with a standard error body:
{
"type": "https://docs.vilna.io/apis/problems/rate-limit",
"title": "Too Many Requests",
"status": 429,
"detail": "Rate limit exceeded"
}Every response includes rate limit headers:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed per window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
When you receive a 429, wait until X-RateLimit-Reset before retrying. If the header is unavailable, use exponential backoff with jitter.
5xx errors indicate a temporary server-side issue. Retry with exponential backoff: wait 1s, 2s, 4s, and so on up to a maximum of 30s, for at most 5 attempts. Add random jitter (e.g., 0-500ms) to each delay to avoid thundering herd effects.
Idempotency note: GET and DELETE requests are safe to retry. POST, PUT, and PATCH requests may not be idempotent - check the endpoint documentation or use an idempotency key if supported before retrying.
The SDK returns { data, error } from every call. Check error before using data:
const { data, error } = await client.POST("/addresses/external", {
body: {
value: "0x...",
chainFamily: "evm",
label: "Treasury",
},
});
if (error) {
switch (error.status) {
case 400:
// Validation error - inspect individual fields
for (const field of error.fields ?? []) {
console.error(`${field.name}: ${field.reason}`);
}
break;
case 404:
console.error("Resource not found:", error.detail);
break;
case 409:
console.error("Conflict:", error.detail);
break;
default:
console.error(`${error.title}: ${error.detail}`);
}
}curl -s -w "\n%{http_code}" "https://api.vilna.io/v1/addresses/invalid" \
-H "X-Api-Key: your-api-key" | jq .A 404 response looks like:
{
"type": "https://docs.vilna.io/apis/problems/not-found",
"title": "Not Found",
"status": 404,
"detail": "Address not found"
}Error: 401 Unauthorized
Verify the X-Api-Key header is present and the key is active. Make sure you are calling the correct base URL (https://api.vilna.io/v1).
Error: 404 Not Found
Check that the address format matches the chain. EVM addresses start with 0x and are 42 characters. TRON addresses start with T and are 34 characters. The address must have been previously registered via the API.
Error: Channel marked as failed after repeated delivery failures
- Verify the webhook URL is publicly accessible from the internet.
- Ensure the endpoint returns an HTTP 2xx status code within 10 seconds.
- Check that the endpoint accepts
Content-Type: application/json.
Vilna uses CAIP standards for chain, account, and asset identifiers.
| Type | Format | Example |
|---|---|---|
| Chain (CAIP-2) | {namespace}:{reference} | eip155:1 |
| Asset (CAIP-19) | {chain_id}/{asset_namespace}:{asset_reference} | eip155:1/erc20:0xa0b8... |
Common mistakes:
- Using a chain ID number instead of CAIP-2 format (
1vseip155:1) - Missing the namespace prefix in asset identifiers