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
volumefield of a candle (GET /v1/candles, andvin 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 (itstime), isother_feed_untilfor 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
429with the codeTOO_MANY_ATTEMPTSfromPOST /v1/tokens,GET /v1/candlesorPOST /v1/ws-ticketnow carries aRetry-Afterheader: the seconds left in the window that refused the call. Waiting that long is enough; before, a client could only guess. /v1/openapi.jsonnames its base URL,https://api.adona-robot.com, inservers(it said/, which a client generated from a downloaded copy could not resolve), and its contact and terms of service ininfo.
Two corrections to the reference: how to open the stream, and what a refusal looks like.
Corrected in the reference
/v1/openapi.jsonand thePOST /v1/ws-ticketresponse said to pass the ticket in the query string of/v1/stream. The API has never read it there: offer two subprotocols,adona.data.v1andticket.<ticket>, as innew 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 a422adds a colon and the reason. Reading the part before the first colon works for both.
The reference is public.
Added
/v1/openapi.jsonand/v1/docsare public: the shape of every response, and every refusal code of every route with what to do about it (retry, wait forRetry-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/tokensdeclares 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-ticketandPOST /v1/tokensanswer403 CUSTOMER_TRIAL_EXPIRED, and/v1/streamcloses with1008 CUSTOMER_TRIAL_EXPIRED, at connect and on a stream already open. It is notCUSTOMER_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 fromPOST /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, not429: 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 aRetry-Afterheader carrying the wait, when the plan's per-minute allowance is spent; the stream answers it as an error frame. It clears by waiting, unlikeCUSTOMER_DAILY_CAP, which does not.limitonGET /v1/candlesaccepts up to 5000 bars, up from 500.INVALID_LIMITmoves with it.- A
subscribethat is refused is rolled back, and the stream sendssubscribedagain 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
422with a coded string,{"detail": "CODE: reason"}, instead of a list of objects. Branch on the code. TIMEFRAME_UNSUPPORTEDis a422, not a400. No request could produce the400, so no client can have relied on it.END_USER_ID_REQUIREDis gone. A blank or overlongend_user_idonPOST /v1/tokensanswersINVALID_END_USER_ID.- A missing parameter answers
INVALID_REQUEST, notTIMEFRAME_UNSUPPORTED. - A body that is not valid UTF-8 answers
422 INVALID_REQUESTinstead of an uncoded400.
Corrected in the reference
/v1/openapi.jsonno longer advertisesHTTPValidationError, a shape/v1does not send.TIMEFRAME_UNSUPPORTEDis never a close code. A bad step oncandle.watchanswers acandle.watch.rejectedframe and the stream stays open.
Added
- One code per field:
INVALID_END_USER_IDonPOST /v1/tokens;INVALID_SYMBOL,INVALID_LIMITandINVALID_BEFOREonGET /v1/candles. A request wrong in two ways at once answersINVALID_REQUEST.
Two routes are callable from a browser.
Added
GET /v1/candlesandPOST /v1/ws-ticketanswer 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./v1answers carryVary: Origin, andRetry-AfterandX-Adona-Hintare exposed to the page.POST /v1/tokensrefuses a browser preflight, on purpose: it takes your API key, which belongs on your server.api.adona-robot.comcaps request bodies at 16 KB.
The API has its own hostname.
Added
https://api.adona-robot.comserves/v1.
First version of /v1.
Added
POST /v1/tokensexchanges an API key, sent asAuthorization: Bearer, for a twelve-hour token per end user (end_user_id).GET /v1/candlesreads candle history with a cursor;POST /v1/ws-ticketissues a single-use ticket valid 30 seconds;/v1/streamis the live stream, on the subprotocoladona.data.v1.- API keys carry their prefix,
adk_live_oradk_test_, and the prefix is part of the key. A key sent where a token belongs answersEXPECTED_ACCESS_TOKEN, a token sent toPOST /v1/tokensanswersEXPECTED_API_KEY, and a trader token answersEXPECTED_DATA_TOKEN.