NEWMethodology v3.3 is open for public comment.Read the draft →
About Press Ratings Partners Compare Watchlist Advertise
Developers · API reference · v1

Onyx API documentation.

Read-only access to every public rating, case, and framework version. Base URL https://api.onyx.dev. JSON in, JSON out, signed on the way. For plans and fair-use rules, see API & data access.

Version v1 Methodology v3.2 Last breaking change none since 2025-11 OpenAPI spec openapi.json

#Introduction

The API serves exactly what the site shows — the public dataset, nothing privileged. There is no write API: scores are produced by the review desk and published; callers read. Responses are UTF-8 JSON. All timestamps are ISO-8601 UTC. All identifiers are stable slugs, never numeric IDs.

First request
curl https://api.onyx.dev/v1/projects?limit=3 \
  -H "Authorization: Bearer onyx_pk_····"
iFree-tier keys are issued instantly and require attribution ("Data: Onyx", linked). No wallet is needed to read data — consistent with the rest of the platform, keys gate volume, not content.

#Authentication

Pass your key in the Authorization header on every request. Keys are prefixed by tier: onyx_pk_ (free), onyx_pro_, onyx_ent_. Keys in query strings are rejected with 401 key_in_url — they end up in logs, and we'd rather fail loudly than leak quietly.

Header
Authorization: Bearer onyx_pro_4f8a····e21c
!Rotate keys from the account page. A revoked key returns 401 key_revoked within 60 seconds globally. Compromised-key reports: [email protected] — handled under the same disclosure policy as everything else.

#Pagination

List endpoints are cursor-paginated. Pass limit (max 100) and follow next_cursor until it is null. Cursors are stable across score updates — a paginating client never sees a project twice or misses one because ranks shifted mid-walk.

Response envelope
{
  "data": [  ],
  "next_cursor": "eyJyYW5rIjoyNH0",
  "total": 2418
}

#Rate limits

Limits are per key, per rolling 24 hours: 1,000 (Free), 100,000 (Pro), unmetered (Enterprise). Every response carries the remaining budget; exceeding it returns 429 with a Retry-After header. Limits gate volume only — no tier ever sees different data.

Headers
X-RateLimit-Limit: 100000
X-RateLimit-Remaining: 99871
X-RateLimit-Reset: 2026-07-12T00:00:00Z

#Errors

Errors are JSON with a stable machine code and a human sentence. The code is the contract; the message may improve without notice.

400 invalid_cursorThe cursor is malformed or from an old dataset generation. Restart the walk.
401 key_missing / key_revokedNo key, or a key that has been rotated or revoked.
403 plan_requiredThe endpoint exists but needs a higher tier — the response names it.
404 unknown_slugNo project by that slug. Removed projects still resolve — with their removal case attached.
410 project_removedOnly on history ranges after a removal date; the rating no longer exists past that point.
429 rate_limitedDaily budget exhausted. Honor Retry-After.

#Verifying signatures

Every response body is signed with the Onyx publishing key (Ed25519). The signature covers the raw body bytes plus the Date header — so a stored payload can prove, later, what we published and when. The public key is pinned at /disclosures and served from DNS.

Verify · Node
const ok = crypto.verify("ed25519", body,
  ONYX_PUBLIC_KEY, Buffer.from(res.headers["x-onyx-signature"], "base64"));
// ok === true → this is a real Onyx score
GET/v1/projectsFree

The ratings directory. Sorted by rank by default. Every filter the site's directory has is a query parameter here.

Query parameters
NameTypeDescription
categoryoptionalstringOne of the nine category slugs, e.g. dex, lending, gamefi.
tieroptionalstringcertified · verified · listed · provisional. Repeatable.
min_scoreoptionalinteger0–100. Combined with max_score for a range.
watchlistoptionalbooleantrue returns only projects with an open case.
limitoptionalinteger1–100, default 25.
cursoroptionalstringFrom the previous page's next_cursor.
GET/v1/projects/{slug}Free

The full rating object — everything on the project page. Fields a project chose not to provide are null, never omitted: absence is data here, and the shape is stable regardless.

Response fields (abridged)
FieldTypeDescription
scoreinteger0–100, under the methodology version in methodology.
tierstringDerived from score plus tier minimums — not score alone.
criteriaobjectAll 14 sub-criteria with awarded points and category maximums.
watchlistobject · nullThe open case (action type, case ID, dates) or null.
auditsarrayFirm, date, scope, report link. Empty array if none published.
bug_bountyobject · nullnull when not provided — never lowers the score.
entityobjectLegal status: verified jurisdiction, pseudonymous, or unresolved.
GET/v1/projects/{slug}/historyPro

Score time series. Each point carries the methodology version it was scored under — framework changes re-label history, they never silently re-score it.

Response · point shape
{ "date": "2026-06-14", "score": 94, "tier": "certified",
  "methodology": "v3.2", "event": "scheduled_review" }
GET/v1/watchlistFree

All public cases, newest first. The case shape matches the public ledger: project, before/after score, action type, dated key facts, the project's response (or documented non-response), evidence links, reviewer of record, case ID.

Query parameters
NameTypeDescription
actionoptionalstringdowngrade · suspension · removal · reinstatement. Repeatable.
statusoptionalstringopen or resolved.
sinceoptionaldateCases opened on or after this date.
GET/v1/appsFree

The App Store directory — every reviewed-and-listed app. Detail at /v1/apps/{slug} returns the full listing: review record, permissions, on-chain usage (Onyx-indexed), version history, and wallet-verified review summary. Developer-supplied fields follow the platform rule — null when not provided, never omitted, never penalized.

Query parameters
NameTypeDescription
categoryoptionalstringApp category slug, e.g. wallet, dapp, analytics.
statusoptionalstringlisted (default) · delisted. Delisted apps stay queryable with their delisting reason attached.
chainoptionalstringFilter by supported chain. Repeatable.
rated_projectoptionalbooleantrue returns only apps whose developer has a rated project.
Detail response fields (abridged)
FieldTypeDescription
reviewobjectReview record — standard version, decision date, reviewer of record, automated-check results.
permissionsarrayRequested contract approvals and scopes, as verified at review.
usageobject · nullOnyx-indexed on-chain usage — active wallets, transactions. null for off-chain apps.
versionsarrayVersion history with re-review status per release.
sponsoredbooleantrue only while a paid placement is active — the flag mirrors the on-site label, so consumers can (and must) disclose it too.
GET/v1/providersFree

Marketplace providers — audit firms, security teams, legal counsel. Detail at /v1/providers/{slug} adds service lines with published pricing, the Onyx-measured response/delivery record, sample work, and client reviews. Pricing and team data are provider-supplied and therefore nullable.

Query parameters
NameTypeDescription
specializationoptionalstringe.g. smart-contract-audit, incident-response, legal. Repeatable.
min_engagementsoptionalintegerOnly providers with at least this many verified engagements.
publishes_pricingoptionalbooleantrue returns only providers with published pricing.
Detail response fields (abridged)
FieldTypeDescription
servicesarrayService lines; each with pricing (object · null when unpublished).
recordobjectOnyx-measured — median response time, on-time delivery rate, engagements verified. Measured by us, not self-reported.
reportsarrayPublished engagement reports with links; empty when none are public.
reviewsobject · nullWallet-verified client review summary — count, distribution.
teamarray · nullNamed team members and credentials, where the provider discloses them.
GET/v1/methodology/{version}Free

The framework as config: criteria, weights, tier thresholds and minimums, plus the diff against the prior version. latest resolves to the current version — v3.2 today.

GET/v1/exports/dailyPro

The entire public dataset as gzipped JSONL, regenerated daily at 00:30 UTC — and immediately after any correction. The manifest carries a signed checksum per file; verify before you ingest.

Manifest
{ "generated": "2026-07-11T00:30:04Z",
  "files": [ { "name": "projects.jsonl.gz", "sha256": "9f2c····", "rows": 2418 } ],
  "signature": "base64····" }
WS/v1/streamEnterprise

Websocket feed of publication events — score changes, new and resolved cases, tier moves, corrections — emitted at the moment they go public. The same events are available as signed webhooks. Nothing streams before it publishes: subscribers get speed, not foresight.

Event
{ "type": "score_change", "slug": "emberswap",
  "from": 71, "to": 42, "case": "ONX-2026-0114",
  "published": "2026-07-08T14:02:11Z" }