Repository navigation
Releases
v0.7.2
Package version: 0.7.2. Git tag: v0.7.2. Released 2026-11-06.
- REST errors that say an order or trigger outcome is unknown now use the
same non-retryable API error as Connect. Read the order or trigger back
before retrying: the first request may still apply. A gateway timeout
without a recognised outcome code remains a retryable transport/server
failure with an unknown outcome; reconcile before retrying a mutation.
v0.7.1
Package version: 0.7.1. Git tag: v0.7.1. Released 2026-11-06.
- Service-unavailable responses now raise retryable server errors on Connect
for orders, withdrawals and internal transfers, matching REST. This includes
policy and fee lookups, backlogs, operations in progress and temporarily
unavailable dependencies. Policy denials and permanent precondition failures
remain non-retryable. Rate-limit errors keep their retry delay, and unknown
mutation outcomes remain non-retryable even on an unavailable response. - These failures now use the existing server error, which does not expose
the structured service code previously available on API errors.
v0.7.0
Built on public contract 748066a, the contract of backend 9.2.5. Breaking changes are marked Breaking below; read them before upgrading.
Package version: 0.7.0. Git tag: v0.7.0. Released 2026-11-05. Built on
public contract 748066a.
- Breaking: a trailing stop created with an activation price already
reached now endsFAILEDwith
TRIGGER_FAILURE_REASON_TRIGGER_WOULD_TRIGGER_IMMEDIATELY(244).
ModifyTriggerand order modifies that would make a trailing stop act at
once are refused withERROR_CODE_TRIGGER_WOULD_TRIGGER_IMMEDIATELY(302),
leaving the existing state unchanged. To start trailing from the market,
clear the activation price with a present zero. - Breaking: remove the public holds-list method, hold models and decoders.
Read aggregate held trading funds from each asset'sreservedbalance in
the balances API. Individual hold IDs and expiry times have no replacement. - Breaking: listing events for an unreadable trigger now returns the same
not-found error as reading that trigger, instead of an empty history.
Events reads retry a catching-upUNAVAILABLEwith the trigger-read policy. - Breaking:
SpotFeeRategains public fields, so exhaustive struct literals
must initialize them.SpotFeeRateandSpotFeeRatesListno longer implementEq. - Expose reserve fee rates, the next scheduled change and the full fee
breakdown. Omitted optional components remain absent and omitted account
discounts decode as an empty list. - Breaking:
Error::PermissionDenied,Error::ApiKeyRejected,
Error::TimestampSkewandError::SessionRequiredgain
optional problem metadata. Include..in variant patterns when ignoring it. - Preserve REST problem status, code, detail and canonical type on realtime
authorization and early gateway authentication errors. - Pin execution-history continuation pages to the returned exchange order ID
so reuse of a client order ID cannot change generations between pages.
Attached-exit self-trade prevention, sub-account balances (contract
54dc59d). Breaking for code that builds Order, GetSubaccountResult or
GetSubaccountOpts with a struct literal naming every field.
GetSubaccountOpts::include_balancesasks a sub-account read for the
sub-account's balances, andGetSubaccountResult.balancesreturns them as a
BalancesList, the shape ofbalances.list.Noneunless asked for; an
empty list when the sub-account holds none. It needs theREAD_BALANCES
action on the sub-account, or the read fails withPermissionDenied; a
root-scoped API key cannot read a sub-account's balances. A read that
cannot reach the balances right now fails with the retryable
AUTH_TEMPORARILY_UNAVAILABLE.Order.self_trade_prevention_modereports the order's mode
(expire_taker,expire_maker,expire_both,UNKNOWN(<n>)for a newer
one). The order's attached take-profit, stop-loss and trailing-stop exits
use it; set it withCreateOrderParams.self_trade_prevention.- An attached exit never trades with the order it protects. When it fires
while that order still rests, the order's unfilled rest is canceled first
and the order ends withcancel_reasonCANCEL_REASON_ATTACHED_EXIT_FIRED
(on reads and on the private order stream). - A self-trade prevention block of an attached exit is a refused fire, not an
end: afire_refusedtrigger event withfire_refusal_reason
self_trade_prevented, whosechild_seqnames the child order self-trade
prevention expired. The leg stays armed. Reject reason
ERROR_CODE_SELF_TRADE_PREVENTEDdecodes too; no request is answered with
it. - A trigger a halted market refuses now reads
market_haltedas its
failure_reasonorfire_refusal_reason, never the unnamed
UNKNOWN_TRIGGER_FAILURE_REASON(212). Unknown reasons still decode with
their number. - A buy sized by a quote amount can carry attached exits; the server checks
the legs against the pair's minimums. - Docs:
Order.cum_notional,cum_quote()andquote_used()are exactly the
settled quote when the pair'sbase_quantity_scaleis at most 9; above
that they can exceed it by less than 1e-18 per fill.
Exact order totals, refused trigger fires, API-key refusal reasons
(contract e96897c). Breaking for code that builds these types with struct
literals or matches Error exhaustively.
Order::avg_price()is the exact average execution price from the new
Order.avg_price_e18(18 decimals;avg_pxstays rounded down to 1e-9).
Order.cum_notional/Order::cum_quote(base_quantity_scale)is the exact
quote amount of the fills before fees, andOrder.fee_total
(OrderFeeTotal:amount_e18/amount(),is_rebate,qty) their fee
net of rebates.Order::quote_used(base_scale)and
Order::quote_unspent(base_scale, quote_scale)tell how much of a
quote-sized buy's amount the fills used;Noneuntil the fee total covers
every fill. All exactDecimals, zero with no fills, andNonerather
than a rounded value when a result needs more digits than aDecimal
holds.- Trigger events:
fire_refused(also alist_eventsfilter) for a fire
refused while the trigger stays live, with the new
TriggerEvent.fire_refusal_reason(rate_limited,account_repairing,
market_halted,min_notional, ...). It is not terminal. The failure reason
account_repairingis named. Unknown event types and reasons still read as
UNKNOWN(<n>)/UNKNOWN_TRIGGER_FAILURE_REASON(<n>). Error::auth_code()returns the typedauth.v1.AuthErrorCodeof a refusal
on ConnectRPC (AuthErrorDetail) and REST (codewithAUTH_added,
UNAUTHENTICATEDasAUTH_AUTHENTICATION_REQUIRED);
errors::auth_codes::from_rest_codemaps a REST code, andauth_codesnames
the seven new values (SIGNATURE_INVALID,MISSING_HEADERS,KEY_EXPIRED,
KEY_DISABLED,IP_NOT_ALLOWED,API_KEY_NOT_ACCEPTED, plus the existing
TIMESTAMP_SKEW).- Changed: a ConnectRPC
AUTH_TIMESTAMP_SKEWdetail is the retryable
Error::TimestampSkew, and the other API-key reasons are
Error::ApiKeyRejectedwith the REST form of the code (SIGNATURE_INVALID),
the same errors the API gateway's answers map to. They wereError::Api. - New
Error::SessionRequired(is_session_required()) for
AUTH_SESSION_KIND_NOT_ALLOWED: a session-only method called with an
account API key, read from the Connectpermission_denieddetail and the
REST 403codealike. It wasError::Apion Connect and
Error::ApiKeyRejectedon REST. Error::Apigainsviolations(Error::violations()): the request fields
an order refusal names, with ConnectRPC field paths. A missing or wrong
attached trailing-stop maximum on create, preview or batch create is now
refused before sending with the server's code, rule ID and field path
(ERROR_CODE_BAD_PRICE/sell_unsetorbuy_at_least_activation,
ERROR_CODE_TRIGGER_BUY_REQUIRES_LIMIT/buy_required) asError::Api
instead ofError::Validation; a modify namesnew_attached_risk...and
a batch replace itemitems[N].new_attached_risk....Error::is_order_already_terminal()and
order_codes::ORDER_ALREADY_TERMINAL/ORDER_UNKNOWN: a cancel of an order
that has already ended, a repeat of the cancel that ended it included, is
now always refused withERROR_CODE_ORDER_ALREADY_TERMINAL. Treat it as
"already done".client.stop_all_trading(scope)cancels every live trigger, then every open
order. Cancel-all and the dead-man switch cancel orders only, never
triggers;cancel_all,cancel_all_afterandcanceldocument it.- Fixed: with
WireFormat::Json, a response naming an enum value newer than
this SDK (a new changelog surface, for example) failed the whole call with
a retryableError::Server. The value now reads as unset (and is dropped
from a repeated field), as protojson'sDiscardUnknowndoes; binary
responses keep the value's number. - Changelog: surface labels
market_data,quickswapandrewards;
ChangelogSection.surfacenames the product area a section covers;
list_changesrefuses more than 10surfacesbefore sending. - Docs: an API key's
permission_deniedmessage names the missing policy
action and reaches the caller as is; a quote-sized buy that spent its amount
endsfilled; a ladder whose levels were all canceled before any filled
endscancelled.
New: public product changelog (client.changelog). Read the changelog of
the environment you call without an API key. It is available on
devnet now and on testnet with its next release.
list_posts,get_postandlist_changeswrap
changelog.v1.ChangelogService;postsandchangesstream every page.breaking_changes_since(t)andaction_required_since(t)collect the
matching changes published sincet.- Typed models
ChangelogPostSummary,ChangelogPost,ChangelogSection,
ChangelogChangeandChangelogChangeEntry. Enums are lowercase labels and
unknown values read asunknown(<n>); change ids are base58. - The generated module tree now compiles
changelog.v1.
Batch replace refusals, trigger read-your-writes, owner role lock.
orders.wait_batch_replace(batch_request_id, subaccount_id, timeout)polls
get_batch_replace_statuswith a short backoff until no item is
admitted, polling through thenot_foundandunavailableanswers of the
first seconds after admission. It stops at the 60-second status window (or
an earliertimeout) withError::Transport: reconcile through the orders
then.BatchReplaceStatusItem::error_code()turns an item'scode
(POST_ONLY_CROSS) into the orders error code (ERROR_CODE_POST_ONLY_CROSS),
keeping a code this SDK does not know unchanged;
errors::order_codes::from_status_codedoes the same for any string.- Fixed:
get_batch_replace_statusfailed with `Error::ResponseContrac...
v0.6.0
Package version: 0.6.0. Git tag: v0.6.0. Released 2026-11-02.
What a trading bot gains. A sell order can carry an attached trailing stop
again. That trailing stop buys back, and the server now requires the most its
exit pays; 0.5.0 could not send it, so every sell order with an attached
trailing stop was rejected. Set it with TrailingStop::with_limit_price.
This is a minor release because input structs changed shape. The order and
trigger inputs that grow optional fields are now #[non_exhaustive] with
constructors, so future optional fields arrive in compatible releases. The Go
and Python SDKs ship the same fix as 0.5.1, without breaking changes.
An environment requires the limit price once it runs the 0.5.0 contract:
devnet first, then testnet after its next upgrade.
Breaking changes
CreateOrderParams,PreviewOrderParams,CreateTriggerParams,RiskLeg
andTrailingStopare#[non_exhaustive]: code outside the crate can no
longer build them with a struct literal. UseCreateOrderParams::new(symbol, side, order_type),PreviewOrderParams::new(symbol, side, order_type),
CreateTriggerParams::new(symbol, trigger_type, side, order_type, qty),
RiskLeg::market(trigger_price)/RiskLeg::limit(trigger_price, limit_price)orTrailingStop::new(distance), then set optional fields
(params.price = Some(..)) or chain the leg setters
(.with_activation_price(..),.with_limit_price(..),
.with_trigger_price_source(..),.with_max_slippage(..)).
OrdersService::create_paramsis unchanged. Inputs that deriveDefault
(AttachedRiskand the list and read options) are unchanged: keep
..Default::default().TrailingStophas a new public field,limit_price: Option<Price>.- Creating a sell order whose attached trailing stop has no
limit_pricenow
fails locally withError::Validation; the server rejected it already.
Fixed
- Attached trailing stops send
TrailingStop::limit_price(or
TrailingStop::with_limit_price) as the trailing stop's maximum buy-back
price. On order create, preview and batch create, a sell order's trailing
stop requires it and a buy order's trailing stop rejects it. On every path
it must be positive and at leastactivation_pricewhen that is set. A
modify or batch replace does not carry the order's side, so the server
checks the side rule there. Order reads do not return the limit price yet.
v0.5.0
Package version: 0.5.0. Git tag: v0.5.0. Released 2026-11-02.
What a trading bot gains. An attached take-profit, stop-loss or trailing
stop now says when it starts protecting the position: its trigger events
include armed, once, when the parent order's first fill makes the leg live.
A bot can wait for it instead of polling the leg's status. Three new error
codes are final refusals: the request did not apply, so do not resend it
unchanged.
An environment reports armed events and the new codes once it runs this
contract: devnet first, then testnet after its next upgrade.
Breaking changes
- None in the SDK API.
Added
- Trigger events decode the new
armedevent type: an attached take-profit,
stop-loss or trailing-stop leg reports it once, when its parent order's
first fill makes the leg live (or when a leg paused before that fill
resumes). It is not terminal.trigger_event_type_from_labelaccepts
"armed"for the event filter. Attached trailing stops still report
activatedwhen they start tracking. - Error codes
AUTH_SUBACCOUNT_OWNER_ROLE_LOCKED(the sub-account's owner
cannot be invited, re-roled or removed),
ERROR_CODE_TRIGGER_SYMBOL_MISMATCH(modify, pause or resume named a listed
pair other than the trigger's own; name the trigger's pair or omit it) and
the balance reads'ERROR_CODE_INVALID_SUBACCOUNT_ID(a zero or malformed
sub-account ID). - Generated messages add
Subaccount.removed(real-time sub-account updates
only: the caller lost access, so drop the sub-account),
TrailingStopPolicy.limit_price_ticks,Checkpoint.opening_value_usd,
ListMyRewardAwardsResponse.awards_may_changeand the Swap reason
MAX_ORDER_QUANTITY, and the trade WebSocket protobufs follow binary schema
34.
Server behaviour on this contract
- Batch replace amends an order in place, keeping its order ID and queue
priority, when an item keeps the price, does not raise the total quantity
and keeps the client order ID. Otherwise it replaces the order under a new
order ID. - An attached trailing stop on a selling order buys back, and the server now
requires its maximum buy-back price. This SDK's
AttachedRisk::trailing_stopdoes not send that price yet, so place a
selling order with only take-profit and stop-loss legs until a later release
adds it. A buying order's attached trailing stop is unchanged. - Ladder outcomes: a ladder is completed once no child order remains open and
at least one reached the book; it is failed only when every child order was
rejected before reaching the book.
v0.4.0
Package version: 0.4.0. Git tag: v0.4.0. Released 2026-11-02.
What a trading bot gains. An order now says why it ended, in the same
words everywhere. A rejected order's reject_reason is the error code the
Orders API returns for the same refusal, and a canceled order's
cancel_reason says why it was canceled, on order reads and on the private
order stream alike. Before, the numeric reason used the matching engine's own
numbering, which clashed with the API's error codes. OrderbookData::available
tells a bot when a book's levels are unknown rather than empty, so it does not
quote into a book that is being rebuilt. Trigger::version picks out the
newest copy of a trigger, and nine new error codes are final refusals: the
request did not apply, so do not resend it unchanged.
This release works on devnet now, and on testnet after testnet's next upgrade.
Reason labels in this SDK. Both reasons are full proto enum names.
reject_reason is the orders.v1.ErrorCode name, the same string as
Error::Api's code, for example ERROR_CODE_POST_ONLY_CROSS.
cancel_reason is the orders.v1.CancelReason name, for example
CANCEL_REASON_USER_REQUEST. The Go and Python SDKs format these labels
differently.
Breaking changes
Client::whiteboard,Client::polychartandClient::layoutare removed.- The generated
orders.v1.Orderlosesterminal_reason_codeand
terminal_reason, and the private order stream'sOrderEventloses
reason_code. Readreject_reasonandcancel_reasoninstead. OrderStreamEvent::reason_codeis replaced byreject_reasonand
cancel_reason, bothOption<String>.GetSubaccountOpts::include_balancesis removed.orderbook::build_orderbook_datatakes the book's availability as a new
last argument.
Breaking
Client::whiteboard,Client::polychartandClient::layoutare removed,
because those APIs are no longer part of the public API.- The order terminal reason fields are removed: the generated
orders.v1.Orderno longer hasterminal_reason_codeorterminal_reason,
and the private order stream'sOrderEventno longer hasreason_code.
Read the typedreject_reasonandcancel_reasoninstead, and replace any
matching onterminal_reasontext with them. OrderStreamEvent::reason_codeis replaced byreject_reasonand
cancel_reason, bothOption<String>. A rejected order's event names its
refusal with the order error code the Orders API returns (for example
ERROR_CODE_POST_ONLY_CROSS). A canceled order's event names why it ended
(for exampleCANCEL_REASON_USER_REQUEST), and so does the replaced event
of the order a replace ended (CANCEL_REASON_REPLACED). Both areNone
otherwise.GetSubaccountOpts::include_balancesis removed: a sub-account read no
longer returns balances. Read them with the balances service for the
sub-account.orderbook::build_orderbook_datatakes the book's availability as a new
last argument.
Added
Order::reject_reasonandOrder::cancel_reasonon order reads and on the
orders of the private order stream's snapshots and units. A rejected order's
reject reason is formatted likeError::Api'scodefor the same refusal;
a canceled order's cancel reason is aCancelReasonproto name. Both are
Nonefor every other status, and a value this SDK does not know keeps its
number (UNKNOWN_ERROR_CODE(<n>),UNKNOWN(<n>)).OrderbookData::available: false while the book is being built or after it
was invalidated, when its levels are unknown rather than empty. It is the
server's value as sent, never inferred from the levels; a managed order book
subscription carries the value of its last snapshot. A server that predates
the field reports false.Trigger::version: 1 for the first state, higher for every later state
change. Keep the copy with the highest version.- Order error codes
ERROR_CODE_ATTACHED_LEGS_EXCEEDED,
ERROR_CODE_FEE_ASSET_INVALID,ERROR_CODE_FEE_CEILING_INVALID,
ERROR_CODE_UNSUPPORTED_FIELD_SET,ERROR_CODE_TRIGGER_FIRE_LIMIT_REACHED,
ERROR_CODE_CONDITION_FLAGS_INVALID,ERROR_CODE_CONDITION_PARAMETER_SET,
ERROR_CODE_TWAP_CAPACITY_REACHEDandERROR_CODE_CHILD_ORDER_INCONSISTENT
surface asError::Apicodes. Their outcome is known: they are not
retryable andmutation_outcome_unknown()is false.
v0.3.0
Package version: 0.3.0. Git tag: v0.3.0. Released 2026-10-31.
What a trading bot gains. Public trade, fill, ledger transfer and
trigger-event subscriptions now deliver every event; before, all but one
event of each batch was lost. SpotConfig and the catalog expose each pair's
order limits as typed values, including the new cap on one market order's
notional, so a bot can size orders before it sends them. A clock-skew
rejection from the API gateway is the retryable Error::TimestampSkew and no
longer ends a private order stream for good; other API-key rejections keep
their code. A duplicate client order ID names the order that already holds
it, replacement orders report the quantity they inherited, and slippage caps
and trigger inputs are checked before sending the way the API checks them.
This release works on devnet today, and on testnet after testnet's next
upgrade, which brings the new private order stream.
Breaking changes
- Batched subscriptions yield every event, and the single-event decoders
(market_trade_from_bytes,user_trade_from_bytes,
ledger_transfer_from_bytes,trigger_event_from_bytes) are replaced by
their..._batch_from_bytesversions, which return one result per event. spot_config_from_protoreturnsResult.- Connect
unimplementedand a bare HTTP 501 areError::NotImplemented
instead ofError::RouteNotFoundorError::Api. max_slippage_bpsis at most 9999 for a market order that sells, every
trailing stop andtriggers.modify.- The
marktrigger price source is rejected locally. - A buy trailing stop's
limit_pricemust be at least its
activation_price. - Public structs gain fields, so code that builds them with a struct literal
must set them.
Breaking
- Batched realtime publications deliver every event. Public trades,
user fills, ledger transfers and trigger events arrive as batches; before,
each batch was decoded as one event and the rest were lost. The
subscriptions now yield every event in order. The single-event decoders
market_trade_from_bytes,user_trade_from_bytes,
ledger_transfer_from_bytesandtrigger_event_from_bytesare replaced by
market_trade_batch_from_bytes,user_trade_batch_from_bytes,
ledger_transfer_batch_from_bytesandtrigger_event_batch_from_bytes,
which return one result per event. spot_config_from_protoreturnsResult: a malformed order limit is an
error instead of an untyped value.- Connect
unimplementedand a bare HTTP 501 areError::NotImplemented
instead ofError::RouteNotFoundorError::Api. A bare HTTP 404 is still
Error::RouteNotFound;Error::is_not_implemented()is true for both. - Slippage caps match the API. A market order that sells, every trailing
stop (standalone or attached, buy or sell) andtriggers.modifytake at
most 9999 bps; they accepted 10000, which the API rejects. A buy market
order, a buy stop-loss or take-profit market child and a TWAP slice still
take 10000. - The
marktrigger price source is rejected locally (standalone triggers
and attached legs): spot markets have no mark price. - A buy trailing stop's
limit_pricemust be at least its
activation_price. - Public structs gain fields (see Added), so code that builds them with a
struct literal must set them.
Fixed
- API-gateway rejections keep their code. The gateway rejects API-key
requests with a plain JSON body such as401 {"code":"TIMESTAMP_SKEW"}.
It was reported as a genericError::Authwith no code, so a clock-skew
rejection was not retryable and ended a private order stream for good. Now
TIMESTAMP_SKEWis the retryableError::TimestampSkew, and any other
code (SIGNATURE_INVALID,KEY_DISABLED,IP_NOT_ALLOWED, ...) is the
non-retryableError::ApiKeyRejectedwith its code and HTTP status. This
covers Connect calls and the realtime token requests. - A market overview subscription created with
symbolskeeps only those
markets in buffered and live updates, not only in its first snapshot.
Added
- Typed spot-config order limits:
SpotConfig.pair_order_limits
(PairOrderLimitswithmax_limit_qty_base,max_market_qty_base,
max_order_notional_quote,max_market_notional_quoteand
max_open_orders_per_pair) andSpotConfig.max_open_orders_total. The
decimal limits areNonewhen the pair has no maximum. The catalog
exposes the same values:catalogs.pair_order_limits_for_symbol(),
pair_order_limits_for_symbol_id()andmax_open_orders_total(). Order.inherited_cum_qty: the filled quantity a replacement inherited
from its predecessors.action_takenonBatchReplaceAdmissionItemandBatchReplaceStatusItem:
replaced, oramendedfor a cancel-only outcome with no successor.- A duplicate client order ID rejection names the order that already holds
the ID, when the server knows it:Error::existing_order_id()for single
creates andBatchCreateResultItem.existing_order_idfor batch creates. LedgerTransfer.transfer_id, shared by both legs of a transfer.triggers.modifyandtriggers.resume_with/resume_by_idno longer
need a symbol; without one they target the trigger's own market.TriggerTrailingDetails.trigger_price: a trailing stop's current
threshold.VIPStatus.settled_volume_qualityandaverage_aop_quality
(VIPMetricQuality:statusandincomplete_hours). When the volume's
status isprice_unavailable,settled_volume_30d_usdis a lower bound.realtime::Client::subscribe_proto_batchfor batched channels. An event
that fails to decode is reported through the subscription's error
callback, and the rest of its batch is still delivered.auth_codes::TIMESTAMP_SKEW;Error::auth_error_code()also returns the
gateway code ofError::TimestampSkewandError::ApiKeyRejected.
Internal
sdk-capabilities.jsonno longer carriespublicDescriptorSha256orgeneratedAt, so a proto publication that only changessrc/gen/andmanifest.jsonno longer makes it stale;manifest.jsonstays the single source of the descriptor hash.
v0.2.0
Package version: 0.2.0. Git tag: v0.2.0.
This release replaces 0.1.0-alpha.49 and covers every change since it.
From 0.2.0 on, the Go, Python and Rust SDKs share one version number and
are released together. Versions are plain SemVer (0.2.0, 0.2.1, ...) and
git tags are vX.Y.Z; the alpha pre-release suffixes (0.1.0-alpha.N, tag
v0.1.0aN) are retired. Upgrade from any 0.1.0-alpha.* release: those
releases use hosts that no longer exist and a price scale 1,000 times off
against the current API.
Breaking
- Trading prices now use the published fixed scale of 9 decimals: one
price tick is 0.000000001 quote units.PRICE_TICK_SCALEis9, so
Price::from_decimal_str,Price::as_decimal,Price::format, order,
trigger, trade, orderbook, market-overview and primary candle prices
encode and decode at 1e-9. Earlier releases used 1e-6 and are 1,000
times off against the current API. Code that buildsPrice::from_ticks
values by hand must multiply its old tick values by 1,000. OrdersService::subscribestreams account orders over the private
WebSocket (/v1/ws/private) and returns aPrivateOrdersSubscription
ofPrivateOrdersEvents (Connected,Snapshot,Unit,Ready,
Stale,Disconnected,Error) instead of aTypedSubscription<Order>. The
realtime order channels it used are retired and no longer issue
subscribe tokens. Snapshot and unit orders use the sameOrdermodel as
the order reads; units also carry removed order IDs and order events.
The call returns at once: the handshake result arrives asConnectedor
Error. The stream resumes from its last position after a gap or a
reconnect, and calls for the same account share one server subscription.
Readyarrives once per server subscription when the stream reaches the
account's read boundary; wait for it before relying on the stream. A
consumer that joins a ready stream gets it right after its catch-up
snapshot.Stalecarries anOrdersStalewithstale, the lowercase
reason(view_behind,order_unavailable, ...) andorder_ids: with
order_unavailableonly those orders are not current, the rest of the
view is and units keep arriving. A later report replaces the earlier one,
and a consumer that joins a stale stream gets the current report.- Removed
codecs::decode::order_from_bytes, the decoder for the retired
order channel's publications. ModifyTriggerParams.limit_priceis removed: a trigger's child limit
price is fixed at create, and the API rejects any modify that sets it.CancelAllOrdersResult,CancelAllAfterResult,GetOrderResult,
LifecycleFlowSummary,MarketTradesResult,GetTradesOptsand
Triggergain fields (below). These structs are not#[non_exhaustive],
so code that builds them with struct literals must add them.
Fixed
POLYESTER_TESTNET_ENVIRONMENTandenvironment_from_name("testnet")now
usehttps://api.testnet.polyester.comandwss://api.testnet.polyester.com.
Earlier versions pointed atapi-testnet.polyester.com, which does not
exist, so every testnet call failed with a DNS error. The devnet preset and
DEFAULT_API_URL/DEFAULT_WS_URLnow use the documented
api.devnet.polyester.comhost.- An order create, trigger create, order cancel or order modify that was sent
but not confirmed in time (ERROR_CODE_ORDER_CREATE_OUTCOME_UNKNOWN,
ERROR_CODE_TRIGGER_CREATE_OUTCOME_UNKNOWN,
ERROR_CODE_ORDER_CANCEL_OUTCOME_UNKNOWN,
ERROR_CODE_ORDER_MODIFY_OUTCOME_UNKNOWN) now reports
mutation_outcome_unknown()andis_retryable()true. It may still apply:
read the order or trigger back before retrying. Earlier versions reported
it as a definite failure.errors::order_codeslists these codes. AUTH_TEMPORARILY_UNAVAILABLEis now retryable: the account request
changed nothing, so send the same request again.- Stop-loss and take-profit triggers with a market child now send their
slippage cap.max_slippage_ticks/max_slippage_bpswere dropped on
create, so the child used the pair's default market slippage instead of
the requested cap. At most one of them is accepted, a sell child takes
fewer than 10000 bps, and a limit child rejects them. - Order reads no longer report an attached-risk leg whose state is
not_configured; the server sends that state for a leg the order does
not have. - An API error whose order, auth, withdraw or transfer code is newer than
this SDK version now reportscode = "UNKNOWN_ERROR_CODE(<n>)"instead
ofERROR_CODE_UNSPECIFIEDorAUTH_UNSPECIFIED, so the server's code is
never lost.
Added
- Index-price triggers and attached legs:
CreateTriggerParams.trigger_price_source
(last,indexormark, the labels trigger reads use) is sent for
stop-loss, take-profit and trailing-stop triggers, and
RiskLeg.trigger_price_source/TrailingStop.trigger_price_sourceare
sent on order create and modify.Nonewatches the last trade price.
Order reads now fill these leg fields, which are no longer deprecated, so
a read leg can be sent back unchanged. An unknown label is a validation
error, and TWAP and ladder triggers reject a price source. CancelAllOrdersResult.listing_status:included, or
not_retained_read_open_orderswhen a retry with the samerequest_id
returns the original counts with an emptycancelled_orders. An empty
retried list does not mean nothing was canceled.CancelAllAfterResult.effective_scope: the account, symbol and side the
armed switch cancels (DeadManSwitchScope);Nonewhen disabled.GetOrderResult.executions_complete: true when the order's trades across
every page add up to its filled quantity.LifecycleFlowSummary.is_delayed: an open flow that has made no progress
for well beyond its expected step time. Lifecycle reason
deposit_source_not_confirmed.- Trigger reads name the cancel reasons
account_repair,
pair_drain_trigger,pair_drain_twap,pair_drain_ladderand
pair_drain_attached_leg, and the failure reasons
index_price_unavailableandtrigger_would_trigger_immediately. Spot
config reports halted pairs asPAIR_STATUS_HALTED. - Standalone BUY trailing stops:
CreateTriggerParams.limit_priceis the
required maximum price of a BUY trailing stop (limit_price_ticks), and
must beNonefor a SELL one. Trigger reads show a BUY trailing stop
as an IOC limit child (order_typelimit,time_in_forceioc) with
the maximum price asTrigger.limit_price; the trailing details carry the
trough price. Trigger.max_slippage: the slippage cap of a stop-loss or take-profit
market child, or of a trailing stop.CancelAllOrdersResult.cancelled_orders(order ID and client order ID,
oldest first, at most 200),total_cancelledandtruncated.- Gap-free trade backfill:
GetTradesOpts.after_trade_id(not combinable
withstart,endorpage_token), and
MarketTradesResult.complete_through_trade_id,next_after_trade_idand
epoch_ends. Zero is a valid cursor and watermark. OrderMutationResult(order create),ModifyOrderResultand accepted
BatchCreateResultItems carrytake_profit_trigger_id,
stop_loss_trigger_idandtrailing_stop_trigger_id: the public ID of
each attached-risk leg's trigger, andNonefor a leg the order does not
have. These structs are not#[non_exhaustive], so code that builds them
with struct literals or destructures them exhaustively must add the new
fields.realtime::Client::subscribe_private_orders(account_id)and
proto::privatews(the private WebSocket contract).- Trigger events report
event_type = "activated"when a standalone
trailing trigger's activation condition is met and tracking begins.
trigger_event_type_from_label("activated")filters for them. - The generated
protoandconnectmodules now includecheckpoints::v1,
claims::v1,rewards::v1,swap::v1andswap::quickswap::v1. Their
code was already in the package but was not compiled into the crate.
These services have noClientwrappers: they need an interactive
session or a broker key, which this API-key SDK does not use.
Changed
MaxSlippage::Ticksand the trigger create/modifymax_slippage_ticks
are nowi64absolute price ticks, matching the 64-bit contract fields.- Candle and market-overview base volume now use the base asset
market_data_volume_scalefromget_spot_config. Primary candle prices
use the fixed price scale of 9. - Composite reference-candle OHLC uses the pair
reference_price_scale.
GetCandlesOpts.include_referencerequests that series.
MarketOverviewEntry.volume_24h_baseis the decoded decimal when the
catalog scale is known;volume_24h_base_scaledstays the integer. - The crate documentation link and the README links to the SDK capability
matrix and market order price protection point at the public docs on
polyester.com.
v0.1.0a49
Fixed
- Limit-order create now rejects
market_max_slippageinstead of dropping the supplied protection.
v0.1.0a48
Added
- Limit GTD orders:
CreateTimeInForce::Gtdplus requiredexpire_atencodeOrderIntent.limit_gtd(price, optionalpost_only, 1s–30d expiry) - Order reads expose
expire_atfor GTD and omit it otherwise
Changed
- Generated Connect/protobuf bindings now include
ClaimsService.GetDailyClaimStatusandClaimDailyReward. Those RPCs stay JWT/session-only and are not wrapped in this API-key SDK.