Historical price and catalog data for 1,864 assets — crypto, stablecoins, US stocks/ETFs, commodities, and 27 international stock markets — served as a REST/JSON API. Built in Rust, deployed on Vercel's official Rust runtime.
This repository is the public engineering reference for the API: its real source (architecture, routing, auth, database access), MIT-licensed. It does not contain the database schema, the data-ingestion pipeline, or any proprietary data — every example below is a real, live response, but this repo itself ships no data. For live usage, current docs, and to request an API key, see www.cryptoally.dev.
curl -H "x-api-key: YOUR_KEY" \
"https://www.cryptoally.dev/api/prices?market=crypto&symbol=bitcoin&from=2024-01-01&to=2024-01-03"[
{
"date": "2024-01-01",
"open": "42280.23437500",
"high": "44175.43750000",
"low": "42214.97656250",
"close": "44167.33203125",
"volume": 18426978443
},
{
"date": "2024-01-02",
"open": "44187.14062500",
"high": "45899.70703125",
"low": "44176.94921875",
"close": "44957.96875000",
"volume": 39335274536
}
]Prices are always in the asset's native currency (see its currency field from
/api/assets) — there's no server-computed USD field; converting to USD or any other
currency is a client concern.
Don't have a key yet? See Usage & access.
Every endpoint except /api/health requires an x-api-key header. A missing or
invalid key gets a 401 before any database query runs:
curl "https://www.cryptoally.dev/api/assets"{ "error": "missing or invalid API key (x-api-key header)" }HTTP/2 401
Keys are opaque, random tokens; only their SHA-256 hash is ever stored server-side — the plaintext is shown once, at issuance, and never persisted. See Usage & access to request one.
All responses are JSON. Standard status codes throughout: 200 success, 400
malformed request, 401 missing/invalid key, 404 no such asset/entry, 500/503
server- or database-side failure.
Liveness + database connectivity check. The only public endpoint — no API key required.
curl "https://www.cryptoally.dev/api/health"{ "status": "ok", "database": "ok" }Screener-style asset list — filter, search, paginate, and localize the market name.
| Param | Type | Description |
|---|---|---|
type |
string | crypto | stablecoin | stock | etf | index | commodity |
market |
string | A market slug, e.g. japan, crypto, us |
search |
string | Matches against symbol or name |
limit |
int | Default 50, max 500 |
offset |
int | Default 0 |
lang |
string | en (default) | es | pt | ja | zh — localizes market_name |
curl -H "x-api-key: YOUR_KEY" \
"https://www.cryptoally.dev/api/assets?market=crypto&search=bitcoin"[
{
"id": 21,
"symbol": "BCH",
"name": "Bitcoin Cash",
"asset_type": "crypto",
"currency": "USD",
"market": "crypto",
"market_name": "Crypto",
"index_name": null
},
{
"id": 22,
"symbol": "BTC",
"name": "Bitcoin",
"asset_type": "crypto",
"currency": "USD",
"market": "crypto",
"market_name": "Crypto",
"index_name": null
}
]Daily OHLCV history for one asset, in its native currency (see the asset's currency
field from /api/assets) — there's no server-computed USD field, since for USD-native
assets that'd just duplicate close, and for the ~1,600 non-USD assets it'd be a
redundant FX-converted copy of every row with no server-side reader. Converting to USD
or any other currency is left to the client. Resolve the asset either with asset_id
directly, or with both market and symbol — a ticker alone isn't unique across
markets (the same symbol can exist on more than one exchange).
| Param | Type | Description |
|---|---|---|
asset_id |
int | Direct asset id (or use market + symbol) |
market |
string | A market slug — required if using symbol |
symbol |
string | A ticker (AAPL) or crypto id (bitcoin) — required if using market |
from / to |
date | YYYY-MM-DD, default full history |
limit |
int | Default 2000, max 10000 |
curl -H "x-api-key: YOUR_KEY" \
"https://www.cryptoally.dev/api/prices?market=crypto&symbol=bitcoin&from=2024-01-01&to=2024-01-03"[
{
"date": "2024-01-01",
"open": "42280.23437500",
"high": "44175.43750000",
"low": "42214.97656250",
"close": "44167.33203125",
"volume": 18426978443
},
{
"date": "2024-01-02",
"open": "44187.14062500",
"high": "45899.70703125",
"low": "44176.94921875",
"close": "44957.96875000",
"volume": 39335274536
},
{
"date": "2024-01-03",
"open": "44961.60156250",
"high": "45503.24218750",
"low": "40813.53515625",
"close": "42848.17578125",
"volume": 46342323118
}
]A well-formed request for an asset that doesn't exist returns 404, not an empty
200 — that distinction is enforced at the resolver, not left to callers to infer
from an empty array.
Founders, founding date, a short history, and official links for one asset. Same
asset-resolution rule as /api/prices (asset_id, or market + symbol).
| Param | Type | Description |
|---|---|---|
asset_id |
int | Direct asset id (or use market + symbol) |
market / symbol |
string | Same pairing rule as /api/prices |
lang |
string | en (default) | es | pt | ja | zh |
curl -H "x-api-key: YOUR_KEY" \
"https://www.cryptoally.dev/api/catalog?market=crypto&symbol=bitcoin"{
"asset_id": 22,
"founders": ["Satoshi Nakamoto (pseudonymous, identity never confirmed)"],
"founded": "2009-01-03 (genesis block)",
"history": "The first decentralized cryptocurrency. Introduced in an October 2008 whitepaper as a peer-to-peer electronic cash system; the network launched with the genesis block on 2009-01-03. Uses proof-of-work mining and a fixed 21 million coin supply cap.",
"official_website": "https://bitcoin.org",
"logo_url": "https://coin-images.coingecko.com/coins/images/1/large/bitcoin.png",
"info_url": "https://www.coingecko.com/en/coins/bitcoin",
"issuer": null,
"index_provider": null,
"inception_date": null
}founded/history are resolved server-side to a single string in the requested
?lang=, falling back to English for any asset not yet translated into that language
— translation coverage fills in incrementally, so this is never a 404, only a
graceful fallback.
Daily historical value of one currency against the US dollar — a dedicated dataset
(fx_rates), not part of assets/daily_prices, since exchange rates aren't
tradeable assets with a market/exchange. Currently covers BRL, CNY, JPY, EUR,
KRW.
| Param | Type | Description |
|---|---|---|
currency |
string | Required. One of BRL, CNY, JPY, EUR, KRW — anything else is a 400 |
from / to |
date | YYYY-MM-DD, default full history |
limit |
int | Default 2000, max 10000 |
curl -H "x-api-key: YOUR_KEY" \
"https://www.cryptoally.dev/api/fx?currency=BRL&from=2024-01-01&to=2024-01-03"[
{
"date": "2024-01-01",
"open": "0.2061643084",
"high": "0.2061090744",
"low": "0.2060793422",
"close": "0.2061643084"
},
{
"date": "2024-01-02",
"open": "0.2060835949",
"high": "0.2062066556",
"low": "0.2038694475",
"close": "0.2060835949"
},
{
"date": "2024-01-03",
"open": "0.2031488010",
"high": "0.2041210781",
"low": "0.2027205112",
"close": "0.2031488010"
}
]Every value is USD per 1 unit of currency (e.g. a close of 0.2061643084 for BRL
means 1 BRL was worth about $0.206 USD that day) — normalized to this direction
server-side regardless of which way the underlying source quotes it, so every
currency's data means the same thing.
1,864 assets across 36 markets — 27 international stock exchanges, US equities/ETFs, crypto, and commodities:
| Market | Assets |
|---|---|
| Japan | 225 |
| South Korea | 200 |
| Australia | 196 |
| United States | 182 |
| United Kingdom | 100 |
| Brazil | 90 |
| Crypto | 62 |
| United Arab Emirates | 61 |
| Saudi Arabia | 60 |
| Canada | 60 |
| India | 50 |
| Taiwan | 50 |
| Colombia | 50 |
| China | 50 |
| New Zealand | 48 |
| Peru | 43 |
| South Africa | 33 |
| Mexico | 32 |
| Chile | 31 |
| Singapore | 30 |
| Egypt | 27 |
| Poland | 20 |
| Austria | 20 |
| Switzerland | 20 |
| Hungary | 20 |
| Argentina | 19 |
| Germany | 17 |
| Portugal | 17 |
| France | 15 |
| Czech Republic | 14 |
| Netherlands | 6 |
| Italy | 5 |
| Commodities | 4 |
| Spain | 4 |
| Belgium | 2 |
| Finland | 1 |
| Total | 1,864 |
Query any of these via /api/assets?market=<slug> — slugs are lowercase, e.g. japan,
south_korea, uae, crypto.
- Clean architecture, dependency-inversion layers:
domain/— entities, newtypes (AssetId,MarketSlug,Lang,ApiKeyHash, …), and repository traits ("ports"). Nosqlx, noaxum— this layer knows nothing about HTTP or Postgres.application/— thin services orchestrating the ports.infrastructure/— the real Postgres-backed repository implementations.http/— the axumRouter, handlers, auth middleware, error mapping.
- One axum
Router, one Vercel function. Every route is matched for real inside axum (not per-file bins) — this is what makes auth a single middlewareLayerinstead of copy-pasted per handler, and what makes the endpoints properly testable. - SQL injection is structurally ruled out, not just avoided. Every query goes
through
sqlxwith parameterized, compile-time-checked binds — no query is ever built by string interpolation. - Newtype pattern.
AssetId(i64),MarketSlug(String),ApiKeyPlaintextvs.ApiKeyHash— wrapping primitives so the type system, not convention, prevents mixing up e.g. a plaintext key and a stored hash. - Least-privilege database access. The API's runtime credential is read-only and distinct from any credential used by data ingestion, which runs entirely out-of-band from this API. There is no write endpoint, authenticated or otherwise.
- API-key auth, SHA-256 hash lookup against a hashed-credential store — never plaintext at rest, never a JWT (no signed/stateless token here — a request is checked against the database on every call, which is what makes a key instantly revocable).
- Tested against fakes, not a live database.
domain::portstraits mean the HTTP layer — routing, auth, status codes, JSON shape — is exercised end-to-end in tests through in-memory fake repositories, with zero database dependency in the test process.
This API and the data it serves are open for CryptoAlly users, with attribution.
An API key is required for every endpoint except /api/health, and keys are
currently issued on request rather than self-service.
If you display, publish, or build on data from this API, please credit Artificialss:
Data provided by Artificialss (https://artificialss.ai)
Prefer a badge? Use this markdown:
[](https://artificialss.ai)
To request a key, visit cryptoally.app. Full, current usage terms live at www.cryptoally.dev/#usage — that page is the source of truth, not this repository.
This repo does not include: database schema or migrations, the data-ingestion pipeline, any raw or processed dataset, deployment credentials/environment configuration, or the API's homepage/UI. Those live in a separate, private repository.
The source code in this repository is released under the MIT License. This covers the code only — it does not grant any rights to the CryptoAlly data or API service itself; see Usage & access above for those terms.
CryptoAlly is built by Artificialss. This repository is the public engineering reference for the API; the product itself — screeners, charts, and the rest of the CryptoAlly experience — lives at cryptoally.app, with the live API and its full docs at www.cryptoally.dev.
Under the hood: a Postgres database (hosted on Neon, Vercel's
Marketplace-native serverless Postgres) holds every asset, market, and daily price
point, reachable only through this Rust API — no client, browser, or mobile app ever
connects to the database directly. The API itself runs on Vercel's official Rust
runtime, built around the clean-architecture layers documented above (domain /
application / infrastructure / http), with role-scoped database credentials
(api_readonly for every live request, a separate seed_writer for the offline
ingestion job) so the request path that serves you has no write access to the data at
all.
Questions, feedback, or an API key request? Reach out via artificialss.ai.
Built by Artificialss