spb/cancerindex
Public
TypeScript 97.2%
SQL 1.5%
CSS 0.6%
JavaScript 0.5%
1import type { Metadata } from 'next';2import Link from 'next/link';3import { PageHeader, Section, Note } from '@/components/ui/section';4import { SITE_URL } from '@/lib/site';56export const metadata: Metadata = { title: 'Developers', description: 'CancerIndex public API: envelope, rate limits, examples and OpenAPI docs.' };78export default function DevelopersPage() {9 return (10 <div className="ci-prose max-w-3xl">11 <PageHeader kicker="Developers" title="Public API" lede="Everything on the site is available as JSON under /api/v1, served by the CancerIndex API service and proxied through this host. Identifiers are stable; every response names its sources." />12 <Section id="docs" kicker="Reference" title="OpenAPI documentation">13 <p>14 Interactive documentation is served by the API at{' '}15 <a className="ci-link" href="/api/v1/docs">16 /api/v1/docs17 </a>18 . Base URL: <code>{SITE_URL}/api/v1</code>.19 </p>20 </Section>21 <Section id="envelope" kicker="Format" title="Response envelope">22 <p>Every successful response wraps its payload with the sources that contributed and the data release, so attribution travels with the data:</p>23 <pre className="ci-code">{`{24 "data": { ... } | [ ... ],25 "sources": [ { "slug": "oncotree", "name": "OncoTree", "license": "CC BY 4.0", "retrievedAt": "2026-09-08T09:07:07Z" } ],26 "dataRelease": "2026-09-08",27 "meta": { "page": 1, "pageSize": 50, "total": 865 } // on paginated endpoints28}`}</pre>29 <p>Errors return <code>{`{ "error": { "code": "not_found", "message": "…" } }`}</code> with the matching HTTP status.</p>30 </Section>31 <Section id="limits" kicker="Fair use" title="Rate limits">32 <ul>33 <li>Anonymous: 60 requests per minute per IP.</li>34 <li>35 With an API key (<code>Authorization: Bearer …</code>): per-key limit according to tier (free 60/min, research and institutional tiers on request).36 </li>37 <li>38 Responses include <code>X-RateLimit-Limit</code>, <code>X-RateLimit-Remaining</code> and <code>Retry-After</code> on 429.39 </li>40 </ul>41 </Section>42 <Section id="examples" kicker="Examples" title="curl">43 <pre className="ci-code">{`# One cancer entity with codes, aliases and counters44curl -s ${SITE_URL}/api/v1/cancers/diffuse-glioma | jq .4546# Search across entities47curl -s "${SITE_URL}/api/v1/search?q=glioma" | jq '.data[] | {type, title}'4849# Current ranking snapshot for a metric and scope50curl -s "${SITE_URL}/api/v1/rankings/active_trials?scope=geo=WORLD|sex=all|age=all|year=latest|level=top" | jq .5152# Same ranking as CSV with attribution rows (served by the web app)53curl -sL "${SITE_URL}/api/export/rankings.csv?metric=active_trials" -o active_trials.csv`}</pre>54 </Section>55 <Section id="identifiers" kicker="Identifiers" title="Stable identifiers">56 <p>57 Public IDs look like <code>CI-CAN-00000123</code> (cancer), <code>CI-GENE-…</code>, <code>CI-VAR-…</code>, <code>CI-DRUG-…</code>, <code>CI-TRIAL-…</code>, <code>CI-PUB-…</code>, <code>CI-SOURCE-…</code>. They are minted once and never reused; merged entities redirect to the surviving record. Upstream identifiers (NCIt, OncoTree, ICD-10, DOID, HGNC, NCT, PMID) are returned alongside with their match type.58 </p>59 </Section>60 <Note>61 Terms: attribution required (see <Link className="ci-link" href="/data">Data</Link>); no medical advice; respect the upstream licenses listed on each <Link className="ci-link" href="/sources">source</Link>.62 </Note>63 </div>64 );65}66