Errors & retries
How the Blueticks API reports failures and how your client should respond.
All error responses use a single envelope shape, regardless of endpoint
or status code. success is always false, and the details live under error:
{
"success": false,
"error": {
"code": "authentication_required",
"message": "API key required or invalid.",
"request_id": "req_1a2b3c4d5e"
}
}Status codes
| Code | Meaning | Retry? |
|---|---|---|
400 | Bad request — payload shape is invalid | No |
401 | Authentication required — missing / invalid key | No |
403 | Permission denied — key lacks required scope | No |
404 | Not found — resource doesn't exist or isn't visible | No |
409 | Conflict — e.g. an Idempotency-Key reused with a different body | No |
422 | Unprocessable entity — semantically invalid | No |
429 | Rate limited — honor Retry-After header | Yes |
5xx | Server error | Yes, with exponential backoff |
Error codes
Current error codes (locked as of v1.0.0):
authentication_requiredpermission_deniednot_foundinvalid_requestrate_limitedinternal_error
The SDK maps each code to a typed exception class so you can
catch (RateLimitError) vs catch (AuthenticationError) without
string-matching.
Validation details
When a request body fails validation (400/422), the envelope carries
an additional error.details array with one entry per offending field:
{
"success": false,
"error": {
"code": "invalid_request",
"message": "Request body failed validation.",
"request_id": "req_1a2b3c4d5e",
"details": [
{ "path": "pollOptions", "code": "too_small", "message": "Array must contain at least 2 element(s)" }
]
}
}Retry guidance
The official SDKs retry automatically on 429, 502, 503, 504, and
network errors. Defaults:
- Base delay: 500 ms, doubling each attempt, capped at 8 s.
- Jitter: random fraction of the current backoff window.
- Max retries: 2 (3 total attempts).
- POST idempotency: POST without an
Idempotency-Keyheader is not retried on HTTP errors (only on network failures). SupplyIdempotency-Key: <your-uuid>to opt in.
Retry-After
On 429, the server returns a Retry-After header (seconds or
HTTP-date). The SDK waits that long before the next attempt. On other
retryable statuses, the SDK uses its own exponential backoff.
Request IDs
Every response (success or error) includes a X-Request-Id header.
Error envelopes echo it in error.request_id for convenience. Include
request IDs in any support inquiry.
Example: handle 429 manually
from blueticks import Blueticks, RateLimitError
client = Blueticks()
try:
account = client.account.retrieve()
except RateLimitError as e:
print(f"throttled, retry after {e.retry_after}s")import { Blueticks, RateLimitError } from "blueticks";
const client = new Blueticks();
try {
const account = await client.account.retrieve();
} catch (err) {
if (err instanceof RateLimitError) {
console.log(`throttled, retry after ${err.retryAfter}s`);
}
}use Blueticks\Blueticks;
use Blueticks\Errors\RateLimitError;
$client = new Blueticks();
try {
$account = $client->account->retrieve();
} catch (RateLimitError $e) {
echo "throttled, retry after {$e->retryAfter}s\n";
}require "blueticks"
client = Blueticks::Client.new
begin
account = client.account.retrieve
rescue Blueticks::Errors::RateLimitError => e
puts "throttled, retry after #{e.retry_after}s"
endimport (
"context"
"errors"
"fmt"
blueticks "github.com/serenix-com/blueticks-go"
)
c, _ := blueticks.NewClient()
_, err := c.Account.Retrieve(context.Background())
var apiErr *blueticks.APIError
if errors.Is(err, blueticks.ErrRateLimit) && errors.As(err, &apiErr) {
fmt.Printf("throttled, retry after %.0fs\n", apiErr.RetryAfter)
}