Blueticks

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

CodeMeaningRetry?
400Bad request — payload shape is invalidNo
401Authentication required — missing / invalid keyNo
403Permission denied — key lacks required scopeNo
404Not found — resource doesn't exist or isn't visibleNo
409Conflict — e.g. an Idempotency-Key reused with a different bodyNo
422Unprocessable entity — semantically invalidNo
429Rate limited — honor Retry-After headerYes
5xxServer errorYes, with exponential backoff

Error codes

Current error codes (locked as of v1.0.0):

  • authentication_required
  • permission_denied
  • not_found
  • invalid_request
  • rate_limited
  • internal_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-Key header is not retried on HTTP errors (only on network failures). Supply Idempotency-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"
end
import (
	"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)
}