Build a client with Client::new(Config { ... }). Always pass POLYESTER_TESTNET_ENVIRONMENT on environment, because an unset environment does not target testnet; other defaults suit API-key
trading applications. Unary
ConnectRPC responses are limited to 4 MiB after decompression.
Recommended constructor
use polyester::{Client, Config};
let client = Client::new(Config {
environment: Some(polyester::POLYESTER_TESTNET_ENVIRONMENT.clone()),
api_key_id: Some("ak_...".into()),
api_private_key: Some("...".into()), // 64-char hex from key creation
default_account_id: Some("...".into()), // Profile → Account ID
// api_url / ws_url come from environment (api.testnet.polyester.com)
// hydrate_catalogs: true,
// timeout: Duration::from_secs(10),
..Default::default()
})?;
client.wait_for_catalogs().await?;Config fields
environment: API, WebSocket, RPC, and contract pins. PassSome(POLYESTER_TESTNET_ENVIRONMENT.clone()).api_key_id/api_private_key: Required for private RPCs / private WS. Default:None.api_url: ConnectRPC base override. Default: fromenvironment(https://api.testnet.polyester.com).ws_url: Centrifugo WebSocket override. Default: fromenvironment(wss://api.testnet.polyester.com).default_account_id: Private channel scoping. Default:None.default_sub_account_id: Default trading scope. Default:None.timeout: Connect and realtime-token deadline. Default:10s.wire_format: Transport wire format. Default: binary.hydrate_catalogs: Fail-closed spot + Zipper hydrate. Default:true.allow_insecure_http: Allow remotehttp:///ws://. Default:false.
default_sub_account_id is the client configuration field and must reuse the canonical public
base58 string returned by subaccount APIs. Canonical base58 can be all digits, such as "5", so
never reinterpret the string as decimal. Use a numeric subaccount_id only in request or proto
fields that are actually typed as an integer and only when you already have that typed value. An
explicit sub-account ID of 0 (subaccount_id: Some(0) in any params, options or request, or sub_accounts.get(0, ..)) returns Error::Validation before sending, because 0 on the wire means no
sub-account. Pass None to act on the main account, or on default_sub_account_id where a method
applies the configured default. The root default_account_id is a different string identifier
used for private realtime channels.
Config.api_key_id is the ak_... credential handle used for request signing. It is not the
base58 public ID reported by auth.me().api_key_id; do not compare or substitute those values.
There is no client.candles alias, use client.market_data. Withdraw lives on client.withdraw.
From environment
Client::from_env() loads:
POLYESTER_API_KEY_IDPOLYESTER_API_PRIVATE_KEYPOLYESTER_ACCOUNT_IDPOLYESTER_ENV(always set it totestnet)POLYESTER_API_URL(optional override)POLYESTER_WS_URL(optional override)
Prefer explicit Config in production.
client.wait_for_catalogs().await? before decimal order writes that need symbol
scales. Subscribe helpers that resolve symbols also need hydration. If the client was
constructed outside a Tokio runtime, this call starts hydration on the current runtime. The wait
fails if either required catalog cannot be hydrated or validated.unavailable answer with the same request for about 2 seconds. Retry only transport and rate-limit failures
with backoff and stable idempotency keys. Reconcile mutation outcomes before retrying.