adona-robot — données de marché à la capacité

API changelog

Changes to the /v1 contract only: routes, fields, refusal codes and stream frames. Newest first. A breaking change says what your code must do.

Last change: · API reference · openapi.json

The reference says what volume counts.

Added

  • The volume field of a candle (GET /v1/candles, and v in the stream's candle frames) is a tick volume: the number of price updates received in the bar. It is not a traded volume. Some bars of the history come from another price feed and carry its tick volume, not counted the same way: on every timeframe, the last day holding one, by the bar's open time in UTC (its time), is other_feed_until for each symbol in /symbols.json, 2026-06-05 at the latest. The value itself did not change.

A rate-limit refusal says how long to wait.

Added

  • A 429 with the code TOO_MANY_ATTEMPTS from POST /v1/tokens, GET /v1/candles or POST /v1/ws-ticket now carries a Retry-After header: the seconds left in the window that refused the call. Waiting that long is enough; before, a client could only guess.
  • /v1/openapi.json names its base URL, https://api.adona-robot.com, in servers (it said /, which a client generated from a downloaded copy could not resolve), and its contact and terms of service in info.

Two corrections to the reference: how to open the stream, and what a refusal looks like.

Corrected in the reference

  • /v1/openapi.json and the POST /v1/ws-ticket response said to pass the ticket in the query string of /v1/stream. The API has never read it there: offer two subprotocols, adona.data.v1 and ticket.<ticket>, as in new WebSocket(url, ["adona.data.v1", "ticket." + ticket]). A ticket sent only in the URL is refused with an HTTP 403.
  • The reference said every refusal is {"detail": "CODE: text"}. The routes in the reference answer the bare code, {"detail": "CODE"}, and only a 422 adds a colon and the reason. Reading the part before the first colon works for both.

The reference is public.

Added

  • /v1/openapi.json and /v1/docs are public: the shape of every response, and every refusal code of every route with what to do about it (retry, wait for Retry-After, or stop).
  • The live stream is described there too: the ticket, the subprotocol, the five frames, the channels, and every close code with whether to reconnect.
  • Refusal and close codes that predate this changelog without an entry of their own are listed there, as of this date.
  • POST /v1/tokens declares its authentication: the API key goes as a Bearer token, so a client generated from the document sends it.

A trial ends, and reads only its own window of history.

Added

  • When a free trial ends, GET /v1/candles, POST /v1/ws-ticket and POST /v1/tokens answer 403 CUSTOMER_TRIAL_EXPIRED, and /v1/stream closes with 1008 CUSTOMER_TRIAL_EXPIRED, at connect and on a stream already open. It is not CUSTOMER_ACCESS_REVOKED: the same key works again on a paid plan. An account that is also revoked is answered as revoked.
  • A trial reads history back to the start of its window only. The bar containing that limit is served whole, the cursor stops there, and a page entirely before it comes back empty and is not billed.

The trial has a connection limit.

Added

  • On the trial, a stream opened past the plan's simultaneous connections is closed with 1008 CUSTOMER_CONNECTION_LIMIT, and the close reason carries only that code. The ticket is spent by then, so a retry needs a new one from POST /v1/ws-ticket.

Pacing per plan, and pages of up to 5000 bars.

Breaking

  • A request both revoked and over its daily budget answers 401 CUSTOMER_ACCESS_REVOKED, not 429: the answer that names what you can act on. A refused request is no longer counted against the daily budget, nor billed.

Added

  • 429 CUSTOMER_MINUTE_CEILING, with a Retry-After header carrying the wait, when the plan's per-minute allowance is spent; the stream answers it as an error frame. It clears by waiting, unlike CUSTOMER_DAILY_CAP, which does not.
  • limit on GET /v1/candles accepts up to 5000 bars, up from 500. INVALID_LIMIT moves with it.
  • A subscribe that is refused is rolled back, and the stream sends subscribed again with the channels the connection actually holds.

Every refusal on /v1 is a coded string, including a validation failure.

Breaking

  • A request that fails validation answers 422 with a coded string, {"detail": "CODE: reason"}, instead of a list of objects. Branch on the code.
  • TIMEFRAME_UNSUPPORTED is a 422, not a 400. No request could produce the 400, so no client can have relied on it.
  • END_USER_ID_REQUIRED is gone. A blank or overlong end_user_id on POST /v1/tokens answers INVALID_END_USER_ID.
  • A missing parameter answers INVALID_REQUEST, not TIMEFRAME_UNSUPPORTED.
  • A body that is not valid UTF-8 answers 422 INVALID_REQUEST instead of an uncoded 400.

Corrected in the reference

  • /v1/openapi.json no longer advertises HTTPValidationError, a shape /v1 does not send.
  • TIMEFRAME_UNSUPPORTED is never a close code. A bad step on candle.watch answers a candle.watch.rejected frame and the stream stays open.

Added

  • One code per field: INVALID_END_USER_ID on POST /v1/tokens; INVALID_SYMBOL, INVALID_LIMIT and INVALID_BEFORE on GET /v1/candles. A request wrong in two ways at once answers INVALID_REQUEST.

Two routes are callable from a browser.

Added

  • GET /v1/candles and POST /v1/ws-ticket answer cross-origin requests, without credentials, once your page's origin is declared on your account. The bearer token is the access control, not the origin. /v1 answers carry Vary: Origin, and Retry-After and X-Adona-Hint are exposed to the page.
  • POST /v1/tokens refuses a browser preflight, on purpose: it takes your API key, which belongs on your server.
  • api.adona-robot.com caps request bodies at 16 KB.

The API has its own hostname.

Added

  • https://api.adona-robot.com serves /v1.

First version of /v1.

Added

  • POST /v1/tokens exchanges an API key, sent as Authorization: Bearer, for a twelve-hour token per end user (end_user_id).
  • GET /v1/candles reads candle history with a cursor; POST /v1/ws-ticket issues a single-use ticket valid 30 seconds; /v1/stream is the live stream, on the subprotocol adona.data.v1.
  • API keys carry their prefix, adk_live_ or adk_test_, and the prefix is part of the key. A key sent where a token belongs answers EXPECTED_ACCESS_TOKEN, a token sent to POST /v1/tokens answers EXPECTED_API_KEY, and a trader token answers EXPECTED_DATA_TOKEN.