Asher Core

API Documentation

The AsherCore API is a plain HTTPS + JSON interface to our market-data platform and to Asher Wire, our news feed. Every endpoint is a GET, every response is JSON, and the base URL is https://ashercore.com. No SDK required.

Introduction

AsherCore serves normalized market data — OHLCV candles, live prices, funding rates, order books and a full instrument catalog — across crypto, equities and forex, all from our own store. Bundled with it on every plan is Asher Wire: a news feed where each story carries a machine-readable market signal. One key spans every asset class and the news about them.

# The canonical "hello world" — 3 hourly BTC candles
curl "https://ashercore.com/api/market/candles?coin=BTC&interval=1h&limit=3" \
  -H "Authorization: Bearer YOUR_ASHERCORE_KEY"

Authentication

Authenticate every request with your API key, available in your dashboard. Pass it either as a bearer token in the Authorization header (recommended) or as a key query parameter.

# Header (preferred)
-H "Authorization: Bearer core_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# …or query param
?key=core_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Keep your key server-side. Anyone with it can spend your quota. Rotate it anytime from the dashboard — the old key stops working immediately.

Rate limits & quotas

Each plan sets a monthly call quota and a per-second burst limit. Every response carries the limit headers, whether it succeeded or not:

HeaderMeaning
X-RateLimit-LimitYour monthly call allowance.
X-RateLimit-RemainingCalls left in the current month.
X-RateLimit-ResetSeconds until the monthly window rolls over.
X-RateLimit-PolicyBoth limits at once, e.g. 500000;w=month, 10;w=1.
X-RateLimit-Scopekey for an authenticated call, public-ip for a keyless one.
Retry-AfterSeconds to wait after a 429.

Exceeding either limit returns 429; an unrecognised key returns 401.

Calling without a key. The endpoints also answer keyless requests — that's what powers our own live Wire page and the free embeddable widgets on customers' sites. Keyless traffic is capped at 120 requests/minute per IP and gets no monthly allowance. It's there so a widget works out of the box, not to run an application on — use a key and you get your plan's limits.
On the per-second limit. Burst limiting is enforced per serving instance, so under heavy concurrency the effective ceiling can run slightly above the published figure. The monthly quota is the authoritative one — it's counted centrally and every call lands in it.
PlanMonthly callsRateHistory
Sandbox10,0001 / sec30 days
Starter500,00010 / secFull
Growth5,000,00050 / secFull
Scale25,000,000200 / secFull

Errors

AsherCore uses standard HTTP status codes. Error bodies carry an error string.

CodeMeaning
200OK.
400Bad request — e.g. an unsupported interval.
401Missing or invalid API key.
429Rate limit or monthly quota exceeded.
500Server error — retry with backoff.

Candles

GET/api/market/candles

OHLCV candles for any instrument, at the native base interval resampled to your requested timeframe.

ParamTypeDescription
coin requiredstringTicker, e.g. BTC, ETH, AAPL, EURUSD.
intervalstring1m · 5m · 15m · 1h · 4h · 1D · 1W. Default 1h.
limitintBars to return, 10–5000. Default 200.
beforeintUnix-seconds cursor for scroll-back — returns bars strictly older than this.
venuestringOptional venue override — one of /api/market/venues.
// Response
{
  "coin": "BTC",
  "interval": "1h",
  "exchange": "Binance",
  "source": "Binance Spot",
  "candles": [
    { "time": 1723420800, "open": 61240.1, "high": 61510.0,
      "low": 61180.4, "close": 61432.7, "volume": 812.44 }
  ]
}

Catalog

GET/api/market/catalog

The full instrument universe — every symbol we ingest, pre-tagged with venue and asset class. No parameters. Cached ~5 minutes.

{ "updated": 1723420800000, "count": 2506,
  "coins": [ { "symbol": "BTC", "venue": "binance", "class": "crypto" } ] }

Coins

GET/api/market/coins

The fast, cached snapshot of priced majors — last price and change for the top instruments. Ideal for a default watchlist view.

Quote

GET/api/market/quote

Latest quote for a single instrument.

ParamTypeDescription
coin requiredstringTicker, e.g. ETH.

Mids

GET/api/market/mids

Live mid prices — the low-latency map of ticker → price for building tickers and dashboards.

Funding

GET/api/market/funding

Perpetual funding rates by instrument. Pair with /api/market/funding-radar for a ranked, cross-venue view of the richest funding.

Order book

GET/api/market/orderbook

Order-book depth snapshot for an instrument (bids/asks). Growth plan and above.

ParamTypeDescription
coin requiredstringTicker, e.g. BTC.

Screener

GET/api/market/screener

A ranked, filterable slice of the universe — perfect for discovery UIs and dynamic watchlists.

Venues

GET/api/market/venues

The venues we ingest and their coverage metadata — use the returned ids as the venue parameter on /api/market/candles.

Asher Wire

Asher Wire is our own newsroom feed, included on every AsherCore plan — no separate news subscription, no separate key, and it draws from the same monthly quota as the market-data endpoints.

The pipeline runs continuously: we ingest markets, economy, crypto and tech sources, write an original brief for each story in English and Spanish, and attach a structured market signal — a bias, the assets the story moves, and the reasoning behind it. That last part is why Wire sits inside a market-data API rather than beside one: the signal is machine-readable, so you can join it to the same symbol you pull candles for.

Content posture: Wire publishes an original brief plus attribution and a link to the source — never a republished article. Attribution fields (source, url) are on every record and must be preserved when you display a story.
# The whole product in one call — what's moving, and which way
curl "https://ashercore.com/api/wire/signals?limit=5" \
  -H "Authorization: Bearer YOUR_ASHERCORE_KEY"

Wire · Filters & streams

You should not have to take the firehose. Every filter below applies to the same normalized record, and both /api/wire/headlines and /api/wire/signals accept the full set — so a filtered feed and its signal board always agree.

FilterExampleDescription
qq=fed ratesFree text across headline and summary.
category / not_categorycategory=crypto,techComma-separated. markets · economy · crypto · tech.
sources / not_sourcesnot_sources=NDTVPublisher substring match, so reuters catches "Reuters Business".
assets (alias tickers)assets=BTC,oilStories whose signal names these assets — matches the label or the mapped ticker.
biasbias=bullish,mixedOnly these biases. On /signals it filters the rolled-up row instead.
has_signalhas_signal=trueOnly stories that carry a signal (or only those that don't).
lead_onlylead_only=trueLead stories only.
since / untilsince=12hISO 8601, or relative shorthand: 30m, 12h, 7d, 2w.
exclude_duplicatesexclude_duplicates=1Collapses the same story filed by several outlets.
sortsort=relevancedate (default) or relevance against q.
langlang=esen (default) or es.

Filtered responses report scanned and matched alongside count, so you can always see how much of the wire your filter actually kept.

Streams — configure once, call one URL

A stream is a saved filter set encoded into a token. Mint one from /api/wire/stream (GET with filters, or POST a JSON body), then pass ?stream= to any Wire endpoint instead of re-sending a dozen params. Explicit params still win, so you can reuse a stream and tweak one knob.

GET/api/wire/stream
# 1. configure
curl "https://ashercore.com/api/wire/stream?category=crypto&assets=BTC,ETH&bias=bullish&exclude_duplicates=1"

# → { "stream": "st_eyJjYXRlZ29yeSI6…",
#     "describes": "Wire stories: crypto; mentioning BTC, ETH; bullish only.",
#     "urls": { "headlines": "…", "signals": "…" } }

# 2. use it — forever
curl "https://ashercore.com/api/wire/headlines?stream=st_eyJjYXRlZ29yeSI6…" \
  -H "Authorization: Bearer YOUR_ASHERCORE_KEY"

# 3. inspect one you were handed
curl "https://ashercore.com/api/wire/stream?stream=st_eyJjYXRlZ29yeSI6…"
Stream tokens are stateless and self-describing — they decode straight back to the filters they hold, never expire, and are safe to share or commit. They are not credentials and grant nothing: your API key still governs access and quota. Build one visually on the live Wire page under “⚙ Configure stream”.

Wire · Live push (SSE)

GET/api/wire/live

Polling is the wrong shape for news — you either hammer the endpoint or you're late. /api/wire/live is the same wire, pushed, over Server-Sent Events. It takes the identical filter surface, ?stream= included, so a configured stream can be consumed live without re-stating a single filter.

EventWhenPayload
readyOnce, on connectResolved filters, poll interval, and the id you resumed from.
storyPer matching articleThe same article shape as /api/wire/headlines. Backfill items are flagged replay: true.
pingKeepaliveFeed timestamp and how many stories currently match.
byeBefore the connection is cutReconnect. EventSource does this for you.
ParamTypeDescription
backfillintMatching stories to replay on connect, 0–50. Default 10.
intervalintSeconds between checks of our store, 5–120. Default 20.
Last-Event-IDheaderResume after this story id — no duplicates on reconnect. Every story carries its id in the SSE id: field.
# watch it in a terminal
curl -N "https://ashercore.com/api/wire/live?category=crypto&bias=bullish&backfill=5" \
  -H "Authorization: Bearer YOUR_ASHERCORE_KEY"
// browser — reconnection and resume are handled for you
const es = new EventSource("https://ashercore.com/api/wire/live?stream=st_…");
es.addEventListener("story", (e) => {
  const a = JSON.parse(e.data);
  console.log(a.headline, a.signal?.bias, a.signal?.assets);
});
# python
import httpx, json
with httpx.stream("GET", "https://ashercore.com/api/wire/live?assets=BTC",
                  headers={"Authorization": "Bearer YOUR_ASHERCORE_KEY"}, timeout=None) as r:
    for line in r.iter_lines():
        if line.startswith("data: "):
            print(json.loads(line[6:]).get("headline"))
A connection is closed after roughly five minutes and you'll get a bye first — that's the platform's function ceiling, not an error. Reconnect with Last-Event-ID and you resume exactly where you stopped. SSE rather than a WebSocket on purpose: it's plain HTTP, so there's no upgrade path to punch through a corporate proxy and no socket server for you to babysit.

Wire · Headlines

GET/api/wire/headlines

The live wire, newest first. Passing q or page switches the query to the rolling archive instead of the current feed.

ParamTypeDescription
limitint1–100. Default 20.
categorystringmarkets · economy · crypto · tech.
langstringen (default) or es. Sets headline, summary and rationale language.
qstringFree-text search across the archive.
pageintArchive page, 24 per page. Response carries hasMore.
# Response
{
  "source": "wire", "updated": "2026-08-17T02:01:48.763Z", "count": 20,
  "articles": [{
    "id": "1sn2dq9",
    "headline": "Oil Flat Amid Stalled Iran Talks, Hormuz Shipping Strain",
    "summary": "…", "category": "markets", "source": "NDTV Profit",
    "url": "https://…", "image": "", "published": "…", "lead": true, "lang": "en",
    "signal": { "bias": "neutral", "assets": ["Oil", "Brent Crude"], "rationale": "…" }
  }]
}

Wire · Signals

GET/api/wire/signals

Per-asset rollup of the wire's signals. Each row is an asset with a net score from −1 (uniformly bearish coverage) to +1 (uniformly bullish), the breakdown of story biases behind it, and the stories themselves.

ParamTypeDescription
assetstringCase-insensitive substring match on the asset label, e.g. BTC.
biasstringbullish · bearish · neutral.
langstringen (default) or es.
limitint1–200. Default 50.
{
  "updated": "…", "articles": 20, "signalled": 17, "count": 5,
  "assets": [{
    "asset": "Oil", "mentions": 4, "score": -0.25, "bias": "bearish",
    "breakdown": { "bullish": 1, "bearish": 2, "neutral": 1, "mixed": 0 },
    "articles": [{ "id": "…", "headline": "…", "bias": "bearish", "rationale": "…" }]
  }]
}
signalled vs articles is the honest denominator: not every story carries a signal, and we tell you how many did rather than padding the board.

Wire · Article

GET/api/wire/article

Fetch a story by id — one, or up to 25 comma-separated. Returns article (the first match) and articles (all matches). Responds 404 when nothing matches.

ParamTypeDescription
id requiredstringArticle id, or comma-separated ids (max 25).
langstringen (default) or es.

Wire · Calendar

GET/api/wire/calendar

The economic calendar — upcoming and just-released events with impact rating and forecast / previous / actual, so you can line a print up against the candle that reacted to it.

ParamTypeDescription
impactstringhigh · medium · low.
limitint1–500. Default 200.
Ready to build? Grab a free key and make your first call in under a minute. Questions? hello@ashercore.com.