MadeOnSol Exports API
Bulk Parquet exports of every fully archived closed month (token_trades, rhc_trades, token_ohlc_1m, rhc_ohlc_1m) via presigned S3 links. BUSINESS+. 1 operation(s) of the keyed MadeOnSol API (Bearer msk_ key).
Bulk Parquet exports of every fully archived closed month (token_trades, rhc_trades, token_ohlc_1m, rhc_ohlc_1m) via presigned S3 links. BUSINESS+. 1 operation(s) of the keyed MadeOnSol API (Bearer msk_ key).
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/madeonsol:madeonsol-exports-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: MadeOnSol Exports API
version: 1.20.0
description: Real-time Solana & Robinhood Chain trading intelligence — KOL wallet trades, deployer reputation, token buyer-quality scoring, wallet tracking, and copy-trade signals across both chains (Robinhood Chain paths under `/rhc/*`).
contact:
name: MadeOnSol
url: https://madeonsol.com/contact
license:
name: Proprietary
url: https://madeonsol.com/terms
servers:
- url: https://madeonsol.com/api/v1
description: Production
security:
- BearerAuth: []
tags:
- name: Exports
description: Bulk Parquet exports of every fully archived closed month (token_trades, rhc_trades, token_ohlc_1m, rhc_ohlc_1m) via presigned S3 links. BUSINESS+.
paths:
/exports:
get:
tags:
- Exports
summary: Bulk Parquet exports of archived months (BUSINESS+)
description: 'BUSINESS+ (BASIC/PRO/ULTRA get 403 with an `upgrade` block; ENTERPRISE passes). Two modes on one route.
**Listing** (no params): every fully archived closed month per dataset — `token_trades`, `rhc_trades`, `token_ohlc_1m`, `rhc_ohlc_1m` — with row count, byte size and file count. A month appears only once both archive providers have verified it (the same ledger the nightly archive exporter writes), so the list is the set you can actually download.
**Download** (`dataset` + `month`): presigned S3 GET links for that month''s Parquet files (zstd-compressed, one or more files per month). Links are valid for about **1 hour** — fetch them when you are ready to download, not ahead of time; re-request to mint fresh ones. The ledger row count is returned so you can verify the files you pulled. Both params are required together.
The current (open) month is never listed — it is live in Postgres and served by the paginated endpoints (`/tokens/{mint}/trades`, `/rhc/trades`, `/tokens/{mint}/candles`). Files are identical to the immutable dual-provider archive described at https://madeonsol.com/data-integrity — ideal for backtests, model training and offline analytics without paging through the API.'
parameters:
- name: dataset
in: query
required: false
schema:
type: string
enum:
- token_trades
- rhc_trades
- token_ohlc_1m
- rhc_ohlc_1m
description: Dataset to download. Required together with `month`; omit both to list.
- name: month
in: query
required: false
schema:
type: string
pattern: ^\d{4}-\d{2}$
example: 2026-07
description: Closed month `YYYY-MM` (UTC). Required together with `dataset`.
responses:
'200':
description: Listing (no params) or one month's download links (dataset + month).
content:
application/json:
schema:
oneOf:
- type: object
title: ExportListing
required:
- datasets
properties:
datasets:
type: array
items:
type: object
required:
- dataset
- months
properties:
dataset:
type: string
enum:
- token_trades
- rhc_trades
- token_ohlc_1m
- rhc_ohlc_1m
months:
type: array
description: Fully archived closed months, newest first.
items:
type: object
required:
- month
- rows
- bytes
- files
properties:
month:
type: string
example: 2026-07
description: '`YYYY-MM`, UTC-derived closed month'
rows:
type: integer
description: Row count recorded in the archive ledger at export time
bytes:
type: integer
description: Total compressed Parquet bytes for the month
files:
type: integer
description: Number of Parquet files the month is split into
- type: object
title: ExportMonth
required:
- dataset
- month
- rows
- bytes
- files
- license_note
properties:
dataset:
type: string
enum:
- token_trades
- rhc_trades
- token_ohlc_1m
- rhc_ohlc_1m
month:
type: string
example: 2026-07
rows:
type: integer
bytes:
type: integer
files:
type: array
items:
type: object
required:
- name
- bytes
- url
- expires_at
properties:
name:
type: string
description: Object name, e.g. `token_trades/2026-07/part-0001.parquet`
bytes:
type: integer
url:
type: string
format: uri
description: Presigned S3 GET URL — no auth header needed, plain HTTP GET
expires_at:
type: string
format: date-time
description: When the presigned URL stops working (~1 h after issue)
license_note:
type: string
description: The terms the files are released under (BUSINESS embed license; redistribution is ENTERPRISE)
headers:
X-Request-Id:
$ref: '#/components/headers/XRequestId'
X-RateLimit-Limit:
$ref: '#/components/headers/XRateLimitLimit'
X-RateLimit-Remaining:
$ref: '#/components/headers/XRateLimitRemaining'
X-RateLimit-Used:
$ref: '#/components/headers/XRateLimitUsed'
X-RateLimit-Reset:
$ref: '#/components/headers/XRateLimitReset'
X-Data-Delay:
$ref: '#/components/headers/XDataDelay'
X-MadeOnSol-Quota-Warning:
$ref: '#/components/headers/XMadeOnSolQuotaWarning'
'400':
description: '`dataset` or `month` invalid, or only one of the two given.'
content:
application/json:
schema:
type: object
required:
- error
properties:
error:
type: string
enum:
- invalid_params
headers:
X-Request-Id:
$ref: '#/components/headers/XRequestId'
X-RateLimit-Limit:
$ref: '#/components/headers/XRateLimitLimit'
X-RateLimit-Remaining:
$ref: '#/components/headers/XRateLimitRemaining'
X-RateLimit-Used:
$ref: '#/components/headers/XRateLimitUsed'
X-RateLimit-Reset:
$ref: '#/components/headers/XRateLimitReset'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
description: Tier below BUSINESS. Standard tier-gate body with an `upgrade` block.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
headers:
X-Request-Id:
$ref: '#/components/headers/XRequestId'
X-RateLimit-Limit:
$ref: '#/components/headers/XRateLimitLimit'
X-RateLimit-Remaining:
$ref: '#/components/headers/XRateLimitRemaining'
X-RateLimit-Used:
$ref: '#/components/headers/XRateLimitUsed'
X-RateLimit-Reset:
$ref: '#/components/headers/XRateLimitReset'
'404':
description: That month is not (yet) fully archived for that dataset — it is either the open month or still being verified.
content:
application/json:
schema:
type: object
required:
- error
properties:
error:
type: string
enum:
- month_not_archived
headers:
X-Request-Id:
$ref: '#/components/headers/XRequestId'
X-RateLimit-Limit:
$ref: '#/components/headers/XRateLimitLimit'
X-RateLimit-Remaining:
$ref: '#/components/headers/XRateLimitRemaining'
X-RateLimit-Used:
$ref: '#/components/headers/XRateLimitUsed'
X-RateLimit-Reset:
$ref: '#/components/headers/XRateLimitReset'
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalError'
'502':
description: The archive store could not be reached to sign the links. Retry later; nothing was consumed from your quota.
content:
application/json:
schema:
type: object
required:
- error
properties:
error:
type: string
enum:
- archive_unavailable
headers:
X-Request-Id:
$ref: '#/components/headers/XRequestId'
X-RateLimit-Limit:
$ref: '#/components/headers/XRateLimitLimit'
X-RateLimit-Remaining:
$ref: '#/components/headers/XRateLimitRemaining'
X-RateLimit-Used:
$ref: '#/components/headers/XRateLimitUsed'
X-RateLimit-Reset:
$ref: '#/components/headers/XRateLimitReset'
'503':
$ref: '#/components/responses/AuthBackendUnavailable'
x-madeonsol-tier: BUSINESS
x-badges:
- name: BUSINESS
position: after
color: '#7c3aed'
operationId: getExports
x-operation-id-source: derived
components:
schemas:
ServiceUnavailableError:
type: object
description: '503: a temporary capacity or maintenance condition (e.g. a Postgres statement timeout during a partition move, or the API-key lookup itself being unavailable). Retry after `Retry-After` seconds.'
required:
- error
properties:
error:
type: string
code:
type: string
description: Machine-readable code where one exists, e.g. `auth_backend_unavailable`.
error_kind:
type: string
description: e.g. `statement_timeout`, `auth_backend`
retry_after_seconds:
type: number
retryable:
type: boolean
support:
type: string
_rid:
type: string
RateLimitError:
type: object
description: '429 when a quota is exhausted: the daily quota, the per-minute burst, or a free-tier network/key-rotation cap. `datasets` is added on `daily` only.'
required:
- error
- error_kind
- message
- tier
- limit
- resets_at
properties:
error:
type: string
enum:
- rate_limit_exceeded
error_kind:
type: string
enum:
- daily
- burst
- ip_cap
- ip_rotation
message:
type: string
tier:
type: string
enum:
- BASIC
- PRO
- ULTRA
- BUSINESS
- ENTERPRISE
limit:
type: integer
resets_at:
type: string
format: date-time
upgrade:
type: object
description: The plan that lifts this limit, with price and a checkout link.
properties:
tier:
type: string
enum:
- PRO
- ULTRA
- BUSINESS
- ENTERPRISE
price_eur_per_month:
type: number
price_usdc_per_month:
type: number
daily_limit:
type: integer
burst_limit:
type: integer
pitch:
type: string
url:
type: string
upgrade_url:
type: string
format: uri
reactivate:
type: boolean
description: Present (true) when the key's paid subscription has just lapsed and `tier` is the plan it held.
prior_tier:
type: string
enum:
- PRO
- ULTRA
- BUSINESS
datasets:
type: object
properties:
pitch:
type: string
url:
type: string
format: uri
ConcurrencyLimitError:
type: object
description: '429 from the heavy-query limiter: too many heavy requests in flight for this key (`concurrency`) or for the whole server (`capacity`). Clears as soon as in-flight requests finish.'
required:
- error
- error_kind
- retry_after_seconds
properties:
error:
type: string
error_kind:
type: string
enum:
- concurrency
- capacity
retry_after_seconds:
type: number
max_concurrent:
type: integer
support:
type: string
_rid:
type: string
Error:
type: object
description: Generic error envelope. `error` is always present (SDKs match on it). Errors returned after authentication also carry `_rid` and, on paid tiers, `support`; authentication-stage errors (missing/invalid key, origin) carry neither.
properties:
error:
type: string
description: Error message or machine code (e.g. `tier_required`, `rate_limit_exceeded`). Never changed once shipped.
message:
type: string
description: Human-readable explanation, when `error` is a machine code.
code:
type: string
description: Machine-readable sub-code on some errors (e.g. `invalid_query`, `invalid_wallet`, `origin_not_allowed`).
error_kind:
type: string
description: Machine-readable category on some errors (e.g. `statement_timeout`, `concurrency`, `daily`).
detail:
type: string
description: Extra human-readable context.
hint:
type: string
retry_after_seconds:
type: number
description: When present on a 429/503, the same value is sent as the `Retry-After` header.
signup_url:
type: string
format: uri
description: 'On the missing-key / bad-format 401: where to get a free key.'
docs_url:
type: string
format: uri
support:
type: string
description: 'Paid tiers, errors after authentication: priority support contact.'
_rid:
type: string
description: Request ID — include when reporting issues
required:
- error
headers:
XRateLimitReset:
description: When the window resets, as a Unix epoch in SECONDS (next 00:00 UTC for the daily quota; about 60 s ahead for a per-minute bucket).
schema:
type: integer
example: 1791158400
XRateLimitRemaining:
description: Calls left in that window. `0` on a quota 429.
schema:
type: integer
minimum: 0
example: 9412
XMadeOnSolQuotaWarning:
description: 'Free-tier only, past about 70 % of the daily quota: a human-readable usage line with an upgrade link.'
schema:
type: string
example: '150/200 used - upgrade for 50x higher limits: https://madeonsol.com/checkout?tier=PRO'
XRateLimitUsed:
description: Calls used in that window (`limit − remaining`).
schema:
type: integer
minimum: 0
example: 588
RetryAfter:
description: Seconds to wait before retrying (RFC 9110 delay-seconds, at least 1). Sent on every 429 (quota, concurrency, authentication-failure) and every 503; when the body carries `retry_after_seconds` it is the same value.
required: true
schema:
type: integer
minimum: 1
example: 10
XDataDelay:
description: 'Free-tier only: the feed in this body is delayed by this many seconds (same value as the body''s `delay_seconds`). Absent on real-time responses.'
schema:
type: integer
minimum: 1
example: 300
XRateLimitLimit:
description: 'Size of the rate-limit window this call was counted against: the daily quota for your tier on data endpoints, the per-minute bucket on `/stream/token` (10) and `/stream/sessions` (30), the hourly allowance for the public demo key. Sent once the key has been authenticated and rate-limited, so it is absent on authentication-stage errors.'
schema:
type: integer
minimum: 0
example: 10000
XRequestId:
description: Unique id of this response. On responses built after authentication it is also the `request_id` of the audit-log row for the call, so quote it in a support request. Present on every response of the keyed API.
required: true
schema:
type: string
format: uuid
example: 3f6c1d2e-8a4b-4f7e-9c21-5b0d7e6a9f13
responses:
AuthBackendUnavailable:
description: 'The API-key or subscription lookup could not be answered (authentication stage). Retryable and not your fault: it is never counted as a failed authentication. Honour `Retry-After`; no `X-RateLimit-*`, no `_rid`.'
headers:
X-Request-Id:
$ref: '#/components/headers/XRequestId'
Retry-After:
$ref: '#/components/headers/RetryAfter'
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceUnavailableError'
examples:
auth_backend:
summary: API-key lookup unavailable
value:
error: Authentication temporarily unavailable — please retry.
code: auth_backend_unavailable
error_kind: auth_backend
retryable: true
retry_after_seconds: 5
InternalError:
description: Unexpected server error from the route (`Internal server error`, with `_rid`). Safe to retry with backoff. A failed API-key lookup is a 503 `auth_backend_unavailable`, never a 500.
headers:
X-Request-Id:
$ref: '#/components/headers/XRequestId'
X-RateLimit-Limit:
$ref: '#/components/headers/XRateLimitLimit'
X-RateLimit-Remaining:
$ref: '#/components/headers/XRateLimitRemaining'
X-RateLimit-Used:
$ref: '#/components/headers/XRateLimitUsed'
X-RateLimit-Reset:
$ref: '#/components/headers/XRateLimitReset'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
route:
summary: Route error
value:
error: Internal server error
_rid: eyJ1IjoiZXhhbXBsZSIsInQiOjE3OTEwMDAwMDAwMDAsImgiOiIwMDAwMDAwMCJ9
Unauthorized:
description: 'Missing or invalid API key, or an expired free-tier key. Authentication-stage error: no `X-RateLimit-*` headers, no `_rid`.'
headers:
X-Request-Id:
$ref: '#/components/headers/XRequestId'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
missing_key:
summary: No Bearer key
value:
error: 'Missing authentication — use API key (Authorization: Bearer msk_...)'
hint: Get a free API key — 200 calls/day, no payment
signup_url: https://madeonsol.com/developer
docs_url: https://madeonsol.com/api-docs
bad_format:
summary: Malformed key
value:
error: Invalid API key format
hint: Get a free API key — 200 calls/day, no payment
signup_url: https://madeonsol.com/developer
docs_url: https://madeonsol.com/api-docs
RateLimited:
description: Too many requests. Every 429 carries `Retry-After`. A quota 429 (`rate_limit_exceeded`, with `X-RateLimit-*`), a heavy-query concurrency 429 (`error_kind` `concurrency`/`capacity`), or the per-IP authentication-failure block (30 failed auths/min; plain `error` + `retry_after_seconds`, no `X-RateLimit-*`).
headers:
X-Request-Id:
$ref: '#/components/headers/XRequestId'
X-RateLimit-Limit:
$ref: '#/components/headers/XRateLimitLimit'
X-RateLimit-Remaining:
$ref: '#/components/headers/XRateLimitRemaining'
X-RateLimit-Used:
$ref: '#/components/headers/XRateLimitUsed'
X-RateLimit-Reset:
$ref: '#/components/headers/XRateLimitReset'
Retry-After:
$ref: '#/components/headers/RetryAfter'
content:
application/json:
schema:
anyOf:
- $ref: '#/components/schemas/RateLimitError'
- $ref: '#/components/schemas/ConcurrencyLimitError'
- $ref: '#/components/schemas/Error'
examples:
daily:
summary: Daily quota exhausted
value:
error: rate_limit_exceeded
error_kind: daily
message: Daily rate limit exceeded — 200/day for BASIC tier. Resets at midnight UTC.
tier: BASIC
limit: 200
resets_at: '2026-10-05T00:00:00.000Z'
upgrade:
tier: PRO
price_eur_per_month: 43
price_usdc_per_month: 49
daily_limit: 10000
burst_limit: 300
pitch: …
url: https://madeonsol.com/pricing
upgrade_url: https://madeonsol.com/checkout?tier=PRO
datasets:
pitch: …
url: https://madeonsol.com/datasets
concurrency:
summary: Too many heavy queries in flight
value:
error: Too many concurrent heavy queries. Up to 8 of these endpoints may be in flight at once per key — retry in a moment, or lower your request concurrency.
error_kind: concurrency
retry_after_seconds: 2
max_concurrent: 8
_rid: eyJ1IjoiZXhhbXBsZSIsInQiOjE3OTEwMDAwMDAwMDAsImgiOiIwMDAwMDAwMCJ9
auth_failures:
summary: Per-IP authentication-failure block
value:
error: Too many authentication failures from this IP. Retry in 60s.
retry_after_seconds: 42
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: msk_...
description: Get a free API key at https://madeonsol.com/developer
x-madeonsol-tiers:
- tier: FREE
plan: BASIC
name: Free
price_eur_monthly: 0
price_eur_annual: 0
price_usd_monthly: 0
daily_limit: 200
burst_limit: 60
url: https://madeonsol.com/developer
- tier: PRO
plan: PRO
name: Pro
price_eur_monthly: 43
price_eur_annual: 430
price_usd_monthly: 49
daily_limit: 10000
burst_limit: 300
url: https://madeonsol.com/checkout?tier=PRO
- tier: ULTRA
plan: ULTRA
name: Ultra
price_eur_monthly: 131
price_eur_annual: 1310
price_usd_monthly: 149
daily_limit: 100000
burst_limit: 600
url: https://madeonsol.com/checkout?tier=ULTRA
- tier: BUSINESS
plan: BUSINESS
name: Business
price_eur_monthly: 400
price_eur_annual: 4000
price_usd_monthly: 456
daily_limit: 500000
burst_limit: 3000
url: https://madeonsol.com/checkout?tier=BUSINESS
- tier: ENTERPRISE
plan: ENTERPRISE
name: Enterprise
price_eur_monthly: null
price_eur_annual: null
price_usd_monthly: null
daily_limit: null
burst_limit: null
url: https://madeonsol.com/pricing#enterprise