API Docs
Full reference for the CryHub REST and WebSocket APIs — auth, schemas, and copy-paste samples in cURL, Node.js, Python, and Go.
CryHub API Reference
Real-time crypto market data — unified REST and WebSocket access with multi-currency pricing, order books, klines, trades, and top movers.
/llms.txt. Point your agent at that URL instead of scraping this page.Authentication
Every request requires a 32-character access token (letters + digits).
REST — Authorization header
curl https://api.cryhub.io/rest/v1/market/ticker?source=s1"e=usdt&symbols=btc \
-H "Authorization: Bearer YOUR_32_CHAR_TOKEN"WebSocket — token query param
const ws = new WebSocket('wss://api.cryhub.io/ws?token=YOUR_32_CHAR_TOKEN');Sources & symbols
Every REST call and WebSocket channel is scoped to a source. Each source publishes its own set of quote currencies.
| source | Coverage | REST quotes | WebSocket quotes |
|---|---|---|---|
s1 | Spot feed — crypto | usdt · tmn · aed · eur | usdt · tmn |
s2 | Perp feed — crypto, equities, commodities, indices, FX | usdc · tmn | usdc · tmn |
s1.btcaed.ticker subscribe successfully but never emit a frame. Use REST for those quotes. s2 does not support AED or EUR anywhere.Fiat quotes (TMN, AED, EUR) are converted server-side with rates refreshed every 4 seconds. Every price in every response is already in the requested quote — no client-side conversion needed.
Symbol format
REST symbols/symbol take base assets only; a WebSocket {pair} is base + quote.
REST symbols=btc,eth,xrp → symbol: "btcusdt", "ethusdt", …
WebSocket s1.btcusdt.ticker → pair: base + quote (btcusdt, btctmn, …)
# Builder-DEX markets (s2 only) use a <dex>-<coin> prefix
REST symbols=xyz-tsla,cash-meta → symbol: "xyz-tslausdc", "cash-metausdc"
WebSocket s2.xyz-tslausdc.ticker → pair: <dex>-<coin><quote>On s2, eight builder-deployed perp DEXes extend the main perp universe: xyz · flx · vntl · hyna · km · abcd · cash · para. The same coin name can exist on several DEXes, so DEX markets are always addressed with the prefix. Mixed lists (main perp + DEX) are allowed in one request, and every endpoint and channel works identically for both. A hyphen in symbol is the reliable way to tell them apart client-side.
symbol not found (REST) or invalid symbol (WebSocket subscribe). The listing refreshes hourly; global top_mover channels are exempt from the check.REST response shape
All REST responses share a common envelope:
{
"data": /* main payload — array or object */,
"next_cursor": 1711612800000, // kline + trade only, when data is non-empty
"message": "ok", // always present; error text on failure
"success": true, // present on success only
"ts": 1711612800000 // server time, Unix ms
}On error the response returns HTTP 4xx/5xx and omits "success" — use the HTTP status as the primary error signal; "message" contains the human-readable reason.
Pagination
The kline and trade endpoints return next_cursor for cursor-based pagination — pass it as end_time on the next request to fetch the older page.
next_cursor is the oldest item timestamp in the current page, and is absent when data is empty. /market/detail never returns it — treat that endpoint as a snapshot.
Omitted zero values
{ symbol, ts, open, high, low, close } with no vol, amount or count. Always treat a missing numeric field as 0.GET /market/ticker
/rest/v1/market/ticker24-hour ticker for one or more symbols. Includes open / high / low / close, volume, and best bid/ask.
Parameters
| Param | Required | Values | Notes |
|---|---|---|---|
source | required | s1 · s2 | Spot feed (s1) or perp feed (s2) |
quote | required | s1: usdt · tmn · aed · eur s2: usdc · tmn | Quote currency |
symbols | required | e.g. btc,eth,xrp | Comma-separated base symbols (lowercase) |
Example request
curl "https://api.cryhub.io/rest/v1/market/ticker?source=s1"e=usdt&symbols=btc,eth,xrp" \
-H "Authorization: Bearer YOUR_TOKEN"Example response
{
"data": [
{
"symbol": "btcusdt",
"open": 65000.0,
"high": 67000.0,
"low": 64500.0,
"close": 66500.0,
"last_price": 66500.0,
"bid": 66490.0,
"bid_size": 0.5,
"ask": 66510.0,
"ask_size": 0.3,
"last_size": 0.1,
"vol": 1234.56,
"amount": 85432000.0,
"count": 142300
}
],
"message": "ok",
"success": true,
"ts": 1711612800000
}symbol = base + quote. With quote=tmn and symbols=btc the symbol is btctmn.
GET /market/detail
/rest/v1/market/detail24-hour market detail — price, change, volume, and percent change derived from kline history.
Parameters
| Param | Required | Values | Default |
|---|---|---|---|
source | required | s1 · s2 | — |
quote | required | s1: usdt · tmn · aed · eur s2: usdc · tmn | — |
symbols | required | btc,eth | — |
slice | required | Kline period — see reference | — |
size | optional | 1–2000 | 500 |
start_time | optional | Unix ms | — |
end_time | optional | Unix ms | — |
One detail entry is produced per kline candle per symbol, so this endpoint takes the same parameters and the same four query modes as /market/kline. It adds the derived change and change_percent fields.
next_cursor — treat it as a snapshot. The most common call is size=1 with slice=1day, which gives the current price and 24-hour stats for each symbol in one request.Example
# Latest 30 daily candles for BTC and ETH in TMN
curl "https://api.cryhub.io/rest/v1/market/detail?source=s1"e=tmn&symbols=btc,eth&slice=1day&size=30" \
-H "Authorization: Bearer YOUR_TOKEN"
# Specific time range
curl "https://api.cryhub.io/rest/v1/market/detail?source=s1"e=usdt&symbols=btc&slice=1hour&start_time=1711526400000&end_time=1711612800000" \
-H "Authorization: Bearer YOUR_TOKEN"Response
{
"data": [
{
"symbol": "btctmn",
"price": 4056500000.0,
"change": 91500000.0,
"high": 4087000000.0,
"low": 3935500000.0,
"volume_quote": 5185000000000.0,
"change_percent": 2.31,
"volume": 1234.56,
"count": 142300
}
],
"message": "ok", "success": true, "ts": 1711612800000
}GET /market/kline
/rest/v1/market/klineCandlestick (OHLCV) data for one or more symbols. Supports four query modes and cursor pagination.
Parameters
| Param | Required | Values | Default |
|---|---|---|---|
source | required | s1 · s2 | — |
quote | required | s1: usdt · tmn · aed · eur s2: usdc · tmn | — |
symbols | required | btc,eth | — |
slice | required | 1min · 5min · 15min · 30min · 60min · 4hour · 1day · 1week · 1mon | — |
size | optional | 1–2000 | 500 |
start_time | optional | Unix ms, inclusive | — |
end_time | optional | Unix ms, exclusive | — |
slice=1year is not supported by any REST provider and returns HTTP 400. For yearly candles use the WebSocket channel s1.{pair}.kline.1y — s2 has no yearly interval at all.Query modes
| Mode | Parameters | Order | Use case |
|---|---|---|---|
| A | size | newest-first | Initial chart load |
| B | size + end_time | oldest-first | Scroll left / backward pagination |
| C | size + start_time | oldest-first | Jump to a date, forward window |
| D | start_time + end_time | oldest-first | Fixed range, server cap 2000 |
size with both start_time and end_time is rejected.Example
# 60 1-minute BTC/TMN candles
curl "https://api.cryhub.io/rest/v1/market/kline?source=s1"e=tmn&symbols=btc&slice=1min&size=60" \
-H "Authorization: Bearer YOUR_TOKEN"
# Older page via cursor (backward pagination)
curl "https://api.cryhub.io/rest/v1/market/kline?source=s1"e=usdt&symbols=btc&slice=1day&size=100&end_time=1711526400000" \
-H "Authorization: Bearer YOUR_TOKEN"
# Exact time window
curl "https://api.cryhub.io/rest/v1/market/kline?source=s1"e=usdt&symbols=btc&slice=1hour&start_time=1711526400000&end_time=1711612800000" \
-H "Authorization: Bearer YOUR_TOKEN"Response
{
"data": [
{
"symbol": "btcusdt",
"slice": "1day",
"ts": 1711526400000, // candle timestamp, Unix ms — see note below
"open": 65000.0,
"high": 67000.0,
"low": 64500.0,
"close": 66500.0,
"vol": 1234.56, // quote volume (converted to the quote param)
"amount": 85432000.0, // base volume (coin units, not converted)
"count": 142300
}
],
"next_cursor": 1711526400000,
"message": "ok", "success": true, "ts": 1711612800000
}s1, ts is the candle open time and is period-aligned. On s2 it is the candle close boundary minus 1 ms. Pagination and bar-matching work the same either way — just use ts consistently as the bar key, and never assume ts % interval === 0 on s2.With several symbols, all candles arrive in one flat data array — group by symbol before rendering. next_cursor is the global minimum ts across all of them, so reuse the same end_time for every symbol to keep pages aligned. Stop paginating when data.length < size.
GET /market/depth
/rest/v1/market/depthOrder book snapshot for one symbol. Six aggregation levels supported.
Parameters
| Param | Required | Values | Default |
|---|---|---|---|
source | required | s1 · s2 | — |
quote | required | s1: usdt · tmn · aed · eur s2: usdc · tmn | — |
symbol | required | btc | — |
step | optional | step0–step5 | step0 |
Aggregation levels
| step (REST) | agg (WebSocket) | Notes |
|---|---|---|
| step0 | agg0 | Raw order book — no aggregation |
| step1 | agg1 | Prices rounded to 1 decimal place |
| step2 | agg2 | Prices rounded to 2 decimal places |
| step3 | agg3 | Prices rounded to the nearest integer |
| step4 | agg4 | Prices rounded to the nearest 10 |
| step5 | agg5 | Prices rounded to the nearest 100 — most aggregated |
Example
curl "https://api.cryhub.io/rest/v1/market/depth?source=s1"e=usdt&symbol=btc&step=step0" \
-H "Authorization: Bearer YOUR_TOKEN"Response
{
"data": {
"symbol": "btcusdt",
"ts": 1711612800000,
"version": 123456789,
"bids": [
{ "price": 66490.0, "qty": 0.5 },
{ "price": 66480.0, "qty": 1.2 }
],
"asks": [
{ "price": 66510.0, "qty": 0.3 },
{ "price": 66520.0, "qty": 0.9 }
]
},
"message": "ok", "success": true, "ts": 1711612800000
}bids are price-descending; asks are price-ascending. version is an exchange sequence number — use it to detect a stale snapshot.
{ price, qty } objects; the WebSocket depth channel returns [price, qty] arrays. Map accordingly when you seed a book from REST and then keep it live over the socket.GET /market/trade
/rest/v1/market/tradeRecent trades for a symbol. For real-time data use the WebSocket trade channel.
Parameters
| Param | Required | Values | Default |
|---|---|---|---|
source | required | s1 · s2 | — |
quote | required | s1: usdt · tmn · aed · eur s2: usdc · tmn | — |
symbol | required | eth | Single base symbol — one per request |
size | optional | 1–2000 | 500 |
start_time | optional | Unix ms, inclusive | — |
end_time | optional | Unix ms, exclusive | — |
trade channel instead.Example
curl "https://api.cryhub.io/rest/v1/market/trade?source=s1"e=aed&symbol=eth&size=50" \
-H "Authorization: Bearer YOUR_TOKEN"Response
{
"data": [
{
"symbol": "ethaed",
"id": 987654321,
"ts": 1711612800000,
"data": [
{
"price": 12300.0,
"amount": 0.5,
"direction": "buy",
"ts": 1711612800000
}
]
}
],
"next_cursor": 1711612800000,
"message": "ok", "success": true, "ts": 1711612800000
}Each batch carries one or more executions in its own data array. direction is "buy" when the taker bought and "sell" when the taker sold. next_cursor is the ts of the oldest batch in the page.
GET /market/top-mover
/rest/v1/market/top-moverCurrent top gainers, losers, or highest-volume symbols. Recomputed every ~3 seconds and returned pre-sorted, up to 25 symbols per request.
Parameters
| Param | Required | Values | Notes |
|---|---|---|---|
source | required | s1 · s2 | Spot feed (s1) or perp feed (s2) |
currency | required | s1: usdt · tmn s2: usdc · tmn | Not named “quote” on this endpoint |
type | required | gainer · loser · volume | — |
currency rather than quote.| type | Sort order |
|---|---|
| gainer | Descending by change_percent |
| loser | Ascending by change_percent |
| volume | Descending by quote_volume |
Example
curl "https://api.cryhub.io/rest/v1/market/top-mover?source=s1¤cy=usdt&type=gainer" \
-H "Authorization: Bearer YOUR_TOKEN"Response
{
"data": [
{
"symbol": "btcusdt",
"price": 79124.07,
"change": 1580.25,
"quote_volume": 240482890.81,
"change_percent": 2.04,
"volume": 2974.03
}
],
"message": "ok", "success": true, "ts": 1711612800000
}On s2 the ranking pools main-perp coins and builder-DEX coins together. Filter client-side on a hyphen in symbol if you need one or the other.
GET /health
/healthLiveness probe at the domain root — note it is not under /rest/v1, where it would 404. Returns HTTP 200 with the plain-text body ok and no JSON envelope.
curl -i https://api.cryhub.io/health
# HTTP/1.1 200 OK
# okWebSocket — connect
Right after connecting, the server sends a welcome message:
{ "msg": "Connected to Cryhub Stream", "ts": 1711612800000 }Full connection example
const ws = new WebSocket('wss://api.cryhub.io/ws?token=YOUR_TOKEN');
ws.onopen = () => {
ws.send(JSON.stringify({
action: 'sub',
channels: [
's1.btcusdt.ticker',
's1.btcusdt.kline.1m',
's1.btcusdt.depth.agg0',
's1.usdt.global.top_mover.gainer'
]
}));
};
ws.onmessage = ({ data }) => {
const msg = JSON.parse(data);
// Reply to server ping
if (msg.ping) {
ws.send(JSON.stringify({ action: 'pong', data: { pong: String(msg.ping) } }));
return;
}
// Market data
if (msg.ch) {
console.log(`[${msg.ch}]`, msg.tick, msg.ts);
}
};
ws.onerror = (e) => console.error('WS error', e);
ws.onclose = (e) => console.log('WS closed', e.code);WebSocket — protocol
Client → Server
| action | Description |
|---|---|
| sub | Subscribe to one or more channels |
| unsub | Unsubscribe |
| pong | Reply to server ping — timestamp must be sent as a string |
{
"action": "sub",
"channels": [
"s1.btcusdt.ticker",
"s1.btctmn.ticker",
"s1.btcusdt.kline.1m",
"s1.btcusdt.depth.agg0",
"s1.usdt.global.top_mover.gainer"
]
}Server → Client
| Field | Description |
|---|---|
| ch | Channel name — on data and sub-ack messages |
| tick | Market data — shape varies by channel type |
| ping | Non-zero on heartbeat — must reply with pong |
| msg | System text, sub ack, or error message |
| ts | Server time, Unix ms |
Heartbeat — Ping/Pong
The server sends a ping every 30 seconds. After 3 unanswered pings the connection is closed.
{ "ping": 1711612830000, "ts": 1711612830000 }Subscription ack
{ "ch": "s1.btcusdt.ticker,s1.btctmn.ticker", "msg": "sub", "ts": 1711612800000 }WebSocket — channels
{source}.{pair}.{stream}[.{arg}] — per-pair streams
{source}.{currency}.global.top_mover.{type} — global top movers| Channel | Delivery | Description |
|---|---|---|
s1.{pair}.ticker | always-on | 24-hour rolling ticker |
s2.{pair}.ticker | always-on | 24-hour rolling ticker — 0.01% price-delta gate |
s1.{pair}.detail | always-on | 24-hour market detail snapshot |
s2.{pair}.detail | always-on | 24-hour market detail snapshot |
s1.{pair}.bbo | always-on | Best bid/offer |
s2.{pair}.bbo | Lazy | Best bid/offer — shares its upstream feed with depth |
s1.{pair}.trade | always-on | Executed trade batches |
s2.{pair}.trade | Lazy | Executed trade batches |
s1.{pair}.kline.{tf} | Lazy | tf: 1m · 5m · 15m · 30m · 60m · 4h · 1d · 1w · 1mo · 1y |
s2.{pair}.kline.{tf} | Lazy | tf: 1m · 5m · 15m · 30m · 60m · 4h · 1d · 1w · 1mo |
s1.{pair}.depth.{agg} | Lazy | agg: agg0–agg5 |
s2.{pair}.depth.{agg} | Lazy | agg: agg0–agg5 — all levels share one upstream feed |
s1.{currency}.global.top_mover.{type} | always-on | currency: usdt · tmn — type: gainer · loser · volume |
s2.{currency}.global.top_mover.{type} | always-on | currency: usdc · tmn — type: gainer · loser · volume |
pair = base + quote: btcusdt · btctmn (s1) · btcusdc · xyz-tslausdc · cash-metausdc (s2)
usdt and tmn are published over WebSocket on s1, and only usdc and tmn on s2. AED and EUR pairs — including top_mover — accept a subscription and then stay silent forever. Fetch those over REST.WebSocket Ticker
Channels: s1.{pair}.ticker · s2.{pair}.ticker
{
"ch": "s1.btcusdt.ticker",
"tick": {
"symbol": "btcusdt",
"open": 65000.0,
"high": 67000.0,
"low": 64500.0,
"close": 66500.0,
"last_price": 66500.0,
"bid": 66490.0,
"bid_size": 0.5,
"ask": 66510.0,
"ask_size": 0.3,
"last_size": 0.1,
"vol": 1234.56,
"amount": 85432000.0,
"count": 142300
},
"ts": 1711612800000
}s2: OHLC comes from the last candle snapshot and can lag the live mid-price slightly; bid, ask and last_priceare mid-price derived; volume and size fields are omitted when zero; and frames only publish once the price moves 0.01% (roughly a 1–3 second cadence).WebSocket Market Detail
Channels: s1.{pair}.detail · s2.{pair}.detail. Field names are identical to REST /market/detail, and high, low, volume_quote and volume are 24-hour values.
{
"ch": "s1.btcusdt.detail",
"tick": {
"symbol": "btcusdt",
"price": 66500.0,
"change": 1500.0,
"high": 67000.0,
"low": 64500.0,
"volume_quote": 85000000.0,
"change_percent": 2.31,
"volume": 1234.56
},
"ts": 1711612800000
}WebSocket BBO
Channels: s1.{pair}.bbo · s2.{pair}.bbo — a lightweight spread indicator that updates whenever the top of the book changes. Use it instead of ticker when the spread is all you need.
{
"ch": "s1.btcusdt.bbo",
"tick": {
"symbol": "btcusdt",
"bid": 66490.0,
"ask": 66510.0,
"bid_size": 0.5,
"ask_size": 0.3
},
"ts": 1711612800000
}WebSocket Kline
Channels: s1.{pair}.kline.{tf} · s2.{pair}.kline.{tf}. Every frame is the current in-progress candle, updated on each trade — use REST /market/kline for closed and historical candles. Lazy channel.
1m · 5m · 15m · 30m · 60m · 4h · 1d · 1w · 1mo · 1y — 1y is WebSocket-only and s1-only; s2.*.kline.1y is rejected at subscribe.{
"ch": "s1.btcusdt.kline.1m",
"tick": {
"symbol": "btcusdt",
"ts": 1711612800000,
"open": 66000.0,
"high": 66800.0,
"low": 65900.0,
"close": 66500.0,
"vol": 12.34,
"amount": 815481.0,
"count": 320
},
"ts": 1711612800000
}Bar update logic
if (tick.ts === currentBar.ts) {
// same candle — update close/high/low/vol/amount/count in place
updateBar(tick);
} else if (tick.ts > currentBar.ts) {
// a new candle opened — append it
appendBar(tick);
}
// tick.ts is in MILLISECONDS. Chart libraries that expect seconds
// (e.g. Lightweight Charts) need tick.ts / 1000.
// vol / amount / count are omitted when zero — default them.ts matches the REST candle ts for the same source, so it identifies which bar to update — but remember the convention differs: s1 sends the candle open time, s2the close boundary minus 1 ms.WebSocket Depth
Channels: s1.{pair}.depth.{agg} · s2.{pair}.depth.{agg}, where agg0–agg5 map 1:1 to the REST step0–step5 levels. Lazy channel.
{
"ch": "s1.btcusdt.depth.agg0",
"tick": {
"symbol": "btcusdt",
"bids": [[66490.0, 0.5], [66480.0, 1.2]],
"asks": [[66510.0, 0.3], [66520.0, 0.9]]
},
"ts": 1711612800000
}Each entry is a 2-element array: [price, quantity]
WebSocket Trade
Channels: s1.{pair}.trade · s2.{pair}.trade — executed trades in real time. Prepend incoming trades to the top of your list and trim it to a maximum length to avoid unbounded memory growth.
{
"ch": "s1.btcusdt.trade",
"tick": {
"trades": [
{
"symbol": "btcusdt",
"price": 66500.0,
"amount": 0.15,
"direction": "buy",
"ts": 1711612800000
}
]
},
"ts": 1711612800000
}WebSocket Top Mover
Channel format: {source}.{currency}.global.top_mover.{type}
| Source | Currencies | Notes |
|---|---|---|
s1 | usdt · tmn | aed/eur channels exist but never emit |
s2 | usdc · tmn | Pools main-perp and builder-DEX symbols into one ranking; minimum $10,000 daily volume |
| type | Description |
|---|---|
| gainer | Top 25 by 24h % gain |
| loser | Top 25 by 24h % loss |
| volume | Top 25 by 24h volume |
tick is an array and the only one that uses short field names. Every other channel sends long-form keys — do not add short-key fallbacks elsewhere. Lists are recomputed every ~3 seconds.{
"ch": "s1.usdt.global.top_mover.gainer",
"tick": [
{
"sym": "shibusdt",
"p": 0.00002845, // price
"c": 0.00000412, // 24h change
"qv": 985400000.0, // 24h quote volume
"prt": 16.93, // 24h percent change
"v": 34600000000.0 // 24h base volume
}
],
"ts": 1711612800000
}Kline periods
| REST (slice) | WebSocket (timeframe) | Description |
|---|---|---|
| 1min | 1m | 1 minute |
| 5min | 5m | 5 minutes |
| 15min | 15m | 15 minutes |
| 30min | 30m | 30 minutes |
| 60min | 60m | 1 hour |
| 4hour | 4h | 4 hours |
| 1day | 1d | Daily |
| 1week | 1w | Weekly |
| 1mon | 1mo | Monthly |
| — | 1y | Yearly — WebSocket only, and s1 only |
1y: slice=1year returns HTTP 400 on both sources, and s2.*.kline.1y is rejected at subscribe time.Supported currencies
| Code | Name | Sources | Availability |
|---|---|---|---|
| usdt | Tether | s1 | REST + WebSocket — native, no conversion |
| usdc | USD Coin | s2 | REST + WebSocket — native, no conversion |
| tmn | Iranian Toman | s1 · s2 | REST + WebSocket — converted server-side |
| aed | UAE Dirham | s1 | REST only — never published over WebSocket |
| eur | Euro | s1 | REST only — never published over WebSocket |
Errors
| HTTP | message | Cause |
|---|---|---|
| 400 | source X is not supported | Invalid source — use s1 or s2 |
| 400 | symbols is required | Missing symbols param |
| 400 | quote is required | Missing quote param |
| 400 | quote not supported for this source | e.g. aed on s2 |
| 400 | invalid slice for this provider: "1year" | Slice not available on this source |
| 400 | invalid size: N, accepted range 1 to 2000 | size out of range |
| 400 | cannot combine size with both start_time and end_time | Invalid param combination |
| 400 | start_time must be earlier than end_time | Bad time window |
| 400 | invalid step "X", accepted: step0..step5 | Invalid step |
| 400 | type "X" is not supported; valid values: gainer, loser, volume | Invalid top-mover type |
| 401 | unauthorized(invalid token) | Invalid or malformed token |
| 401 | unauthorized(token required) | Token missing |
| 500 | symbol not found: xyz | Unknown or delisted symbol |
| 500 | failed to fetch market data | Upstream or server error |
Error response example
Error responses return HTTP 4xx/5xx and omit "success". Use the HTTP status code as the primary signal.
{
"message": "start_time must be earlier than end_time",
"ts": 1711612800000
}WebSocket error messages
Socket errors arrive as a plain msg frame with no ch.
{ "msg": "invalid action: foo", "ts": 1711612800000 }
{ "msg": "channels are empty", "ts": 1711612800000 }
{ "msg": "invalid source: s9", "ts": 1711612800000 }
{ "msg": "invalid symbol: foousdt", "ts": 1711612800000 }
{ "msg": "failed to sub: ...", "ts": 1711612800000 }
{ "msg": "ping timeout. connection closed.", "ts": 1711612800000 }