api docs

Unfair Library API v1

This API is for app developers, researchers, and health builders who need structured supplement and intervention data they can trust. It helps you move from discovery to ranked evidence quickly with stable filtering, consistent pagination, and clear quota headers.

Base Path

/api/library/v1

Auth

Authorization: Bearer <token>

Response Type

application/json

Response Headers

  • x-library-version
  • x-contract-version
  • x-snapshot-id
  • x-rate-limit-remaining
  • x-rate-limit-reset

Intro

The Unfair Library API gives product teams, researchers, and developers structured access to supplement and intervention data backed by graded evidence.

Use it to power supplement detail pages, rank interventions by outcome, screen supplement safety, or build discovery experiences on top of the full intervention-outcome graph.

Start with the high-level routes when you are shipping product features quickly: product packs, ranked interventions, comparison endpoints, safety screening, bulk hydration, and release intelligence all reduce the amount of stitching logic you need to own.

Four core concepts drive everything in the API:

  • A supplement is an ingredient with dosing ranges, safety flags, and an evidence tier summary.
  • An intervention groups a treatment approach with its linked health outcomes and aggregate evidence score.
  • A health outcome is the specific measured result, a disease, biomarker, or behavior, you are trying to improve or track.
  • An evidence link is the raw edge between one intervention and one outcome, carrying grade, effect direction, and source metadata.

Most integrations follow the same path: browse or search supplements to target a health outcome, rank linked interventions by evidence quality, then drop to individual evidence links only when you need custom scoring logic or research tooling. When you already know the entities you want, use the bulk endpoints and include expansions to avoid N+1 fetches.

Quickstart

Start here if you want to confirm auth, test one endpoint, and then build a real workflow.

  1. Create or obtain an API token from your admin panel.
  2. Send it as a bearer token in the Authorization header.
  3. Use limit and offset for stable pagination.

Smoke Test

bash
curl -sS -H "Authorization: Bearer $UAF_TOKEN" "https://unfairapp.com/api/library/v1/meta"

Research Graph Smoke Test

bash
curl -sS -H "Authorization: Bearer $UAF_TOKEN" "https://unfairapp.com/api/library/v1/health-outcomes?category=disease&limit=3"

Versioning and Freshness

Every response includes x-library-version, x-contract-version, and x-snapshot-id. Treat them as separate signals: freshness, schema contract, and immutable snapshot identity.

  • Docs snapshot version: 2026-04-09T02:39:46.074Z.
  • Contract version: 1.0.0.
  • Snapshot id: snapshot.0e78bc69814bbd345e92.
  • Last supplement dataset update: 2026-04-08T23:20:44Z.
  • Last research dataset update: 2026-04-09T02:39:46.074Z.
  • If the version changes, invalidate cached lists and refetch.

Use /api/library/v1/snapshots and /api/library/v1/diffs when you need auditable changes between snapshots, and use /api/library/v1/releases plus /api/library/v1/changelog when you want a more decision-ready change feed.

Troubleshooting and Errors

Use this table when integrations fail. Each error includes cause, immediate fix, and whether automatic retry makes sense.

Error Payload

json
{
  "ok": false,
  "code": "capability_missing",
  "message": "API token is missing required capabilities",
  "details": {
    "requiredCapabilities": ["diffs.read"],
    "tokenCapabilities": ["library.read"]
  }
}

Structured failures include optional details. For example, capability_missing returns details.requiredCapabilities and details.tokenCapabilities. Query validation failures in strict mode return 400 invalid_query_param with details.fields describing each invalid parameter.

StatusCodeMeaningWhat to doRecoverability
401missing_tokenNo bearer token was providedSend Authorization with Bearer token and retry.Recoverable by client
401invalid_tokenToken hash does not match any active tokenRegenerate the token in admin and update your env.Recoverable after token update
403token_inactiveToken exists but has been revokedReach out through the contact page to re-enable access.Requires human action
403capability_missingToken is valid but missing required route capabilityUpdate token capabilities in admin for the premium contract routes.Requires token update
404not_foundRequested resource id or slug does not existCheck slug formatting and confirm id from list endpoints.Recoverable by request correction
429monthly_limit_exceededToken exhausted its monthly request quotaPause requests until reset time or request a higher quota. Honor the Retry-After header.Time based or support based recovery
400invalid_query_paramStrict mode rejected one or more query parametersFix fields listed in details.fields or remove strict=true during migration.Recoverable by request correction

Need help with credentials or quota updates? Reach out through our contact page.

Endpoints

Use this section as a map. Each endpoint description explains what it does and what to do with the result.

List endpoints support two validation modes. Default mode is lenient and may return warnings[] when parameters are invalid or clamped. Add strict=true to fail fast with 400 invalid_query_param.

GET/api/library/v1/supplements

Returns a list of supplements. Filters apply before sorting, so results are ranked by evidence tier strength and then alphabetically.

q

Example: q=creatine. Use this to narrow results by keyword.

category

Example: category=amino-acid. Use this to scope to one category.

tier

Example: tier=B. Use this to keep only stronger evidence bands.

cohort

Example: cohort=adults-18-39. Filter by cohort suitability profile.

region

Example: region=us. Filter by regional regulatory profile.

limit

Example: limit=25. Use this to control payload size per page.

offset

Example: offset=50. Use this to page forward through results.

Tip: If you apply a tier filter, the ranking still uses the same sort rule inside that tier.

GET/api/library/v1/supplements/{slug}

Returns one supplement by slug. Unknown slugs return a 404. Double-check spelling because supplement slugs are lowercase and hyphenated.

include

Example: include=content,coverage,identifiers. Expands the base supplement with article markdown, premium contract metadata, or linked studies in one call.

GET/api/library/v1/supplements/{slug}/content

Returns the full article markdown for a supplement. Use this when you need the content separately from the structured data.

GET/api/library/v1/supplements/{slug}/product-pack

Product-ready supplement bundle. Returns a curated response for product pages with summary, dose, safety, evidence highlights, supporting traces, and related entities.

include

Example: include=content,studies. Pulls extra content into the pack without separate detail requests.

POST/api/library/v1/supplements/bulk

Bulk hydration endpoint family. Send a non-empty ids array plus optional lookupBy and include values to resolve many entities in one request and avoid N+1 fetch patterns.

The same request shape is also available at /api/library/v1/health-outcomes/bulk, /api/library/v1/interventions/bulk, and /api/library/v1/studies/bulk.

Use lookupBy=slug for supplement slugs and use include to expand coverage, identifiers, studies, or content when those routes support it.

GET/api/library/v1/meta

Returns library metadata and filter facets (categories and tiers), plus research graph metadata/facets for health outcomes and interventions.

Tip: Call this endpoint once during app start to prefill filters and cache metadata.

Includes contracts.validation so clients can render machine-readable query parameter rules and strict-mode support per route.

GET/api/library/v1/health-outcomes

Returns paginated health outcomes with category/source filters and intervention linkage counts.

q

Example: q=sleep. Use this to find matching outcomes quickly.

category

Example: category=disease. Use this to constrain outcome class.

sourceType

Example: sourceType=healthOutcomeFile. Use this to target curated outcomes only.

hasInterventions

Example: hasInterventions=true. Use this to return actionable outcomes.

limit / offset

Example: limit=20&offset=0. Use this for stable pagination windows.

Gotcha: sourceType=interventionDerived means the outcome was inferred from intervention mappings, while healthOutcomeFile comes from curated outcome records.

GET/api/library/v1/health-outcomes/{id}

Returns one health outcome by id. Missing ids return 404 with code: not_found.

include

Example: include=coverage,identifiers. Expands the base outcome with premium contract metadata in one response.

GET/api/library/v1/health-outcomes/{id}/brief

Decision-ready outcome brief. Returns a compact summary, top interventions, and evidence distributions for the outcome so you can render “what helps this?” without custom aggregation.

GET/api/library/v1/health-outcomes/{id}/ranked-interventions

Ranked intervention shortlist with transparent score breakdowns, explanations, top evidence, and coverage confidence. Use this when your product needs a shortlist, not raw graph traversal.

minGrade

Example: minGrade=B. Drop weaker evidence grades from the shortlist.

sort

Example: sort=coverage_first. Reorder by default score, grade strength, evidence volume, or coverage confidence.

GET/api/library/v1/health-outcomes/{id}/interventions

Returns interventions associated with a health outcome, ordered by combined evidence strength.

condition

Example: condition=Insomnia. Use this to target one condition context.

minGrade

Example: minGrade=B. Use this to exclude weaker evidence grades.

effect

Example: effect=decrease. Use this to align direction with your goal.

limit / offset

Example: limit=50&offset=0. Use this to paginate ranked interventions.

Tip: Use minGrade to narrow the response to better supported interventions.

GET/api/library/v1/interventions

Returns paginated interventions with condition and linked-outcome category filters.

q

Example: q=theanine. Use this to find interventions by name or context.

condition

Example: condition=Anxiety. Use this to focus on one target condition.

outcomeCategory

Example: outcomeCategory=behavior-and-context. Use this to narrow outcome type.

noStudyDatabase

Example: noStudyDatabase=false. Use this to keep evidence-backed entries.

limit / offset

Example: limit=20&offset=20. Use this for paginated browsing.

Tip: Use condition first, then add outcomeCategory for tighter targeting.

GET/api/library/v1/interventions/{id}

Returns one intervention by id. Missing ids return 404 with code: not_found.

include

Example: include=coverage,identifiers. Expands the base intervention with premium contract metadata.

GET/api/library/v1/interventions/{id}/brief

Decision-ready intervention brief. Returns the strongest linked outcomes, related conditions, and evidence distributions for a single intervention.

GET/api/library/v1/interventions/ranked

Global ranked intervention listing with filterable condition, outcome category, and minimum grade. Use this when you want a shortlist before choosing exact outcomes to compare.

condition

Example: condition=Insomnia. Scope ranking to one condition context.

outcomeCategory

Example: outcomeCategory=Feel. Constrain the ranking to one outcome class.

sort

Example: sort=evidence_volume. Reorder by score, grade, evidence volume, or coverage confidence.

GET/api/library/v1/interventions/{id}/health-outcomes

Returns health outcomes associated with an intervention, ordered by combined evidence strength.

category

Example: category=disease. Use this to focus linked outcomes by category.

condition

Example: condition=Insomnia. Use this to keep one condition thread.

minGrade

Example: minGrade=B. Use this to remove lower confidence links.

effect

Example: effect=increase. Use this for directional outcome analysis.

limit / offset

Example: limit=50&offset=0. Use this to page linked outcome sets.

Tip: Start with minGrade=B if you want a high confidence subset.

POST/api/library/v1/compare/interventions

Pairwise comparison endpoints. Send left, right, and optional compareOn values to get shared outcomes, advantages, safety deltas, and a winner summary without writing your own comparison logic.

The same request shape is also available at /api/library/v1/compare/supplements.

GET/api/library/v1/evidence-links

Returns individual evidence links between interventions and outcomes. Most integrations do not need this endpoint unless you are building custom ranking or graph logic.

q

Example: q=magnesium. Use this to locate relevant evidence links quickly.

outcomeID / interventionID

Example: interventionID=l-theanine. Use this for one-node graph slices.

condition / category

Example: condition=Insomnia. Use this to refine graph context.

grade / effect

Example: grade=B&effect=decrease. Use this for custom ranking inputs.

limit / offset

Example: limit=100&offset=0. Use this to stream large edge sets safely.

GET/api/library/v1/studies

Returns paginated studies with search, PubMed ID lookup, and effect estimate filtering. Each study includes structured metadata: design details (blinding, randomization, duration), population (sample size, age range, sex), publication info (journal, year, authors), conclusions, adverse events, and funding sources.

q

Example: q=creatine cognition. Full-text search across study titles and abstracts.

pmid

Example: pmid=12345678. Lookup by PubMed ID directly.

doi

Example: doi=10.1234/example. Lookup by DOI.

hasEffectEstimates

Example: hasEffectEstimates=true. Only return studies with quantitative effect data.

limit / offset

Example: limit=100&offset=0. Paginate through the study catalog.

GET/api/library/v1/studies/{studyID}

Returns one study by id with full metadata and linked supplement associations. The response includes structured design, population, intervention, and publication objects along with author details, conclusions, adverse events, and funding.

design

type, blinding, control, durationDays, randomized

population

description, sampleSize, ageRange, sex

interventions

description, dose

publication

journal, year

authors

Array of name, affiliation, email

conclusions / adverseEvents / funding

Free-text fields extracted from the source paper.

GET/api/library/v1/studies/{studyID}/content

Returns the paper content markdown for a study. Use this for full-text rendering in research tools.

GET/api/library/v1/evidence

Returns structured evidence statements linking supplements to outcomes with predicate, population, and source metadata.

supplementID

Example: supplementID=creatine. Filter statements to one supplement.

predicateID

Example: predicateID=improves. Filter by relationship type.

objectID

Example: objectID=cognitive-performance. Filter by target outcome.

population

Example: population=elderly. Scope to a specific population context.

limit / offset

Example: limit=100&offset=0. Paginate evidence statements.

GET/api/library/v1/evidence/reverse

Reverse evidence query: given an outcome, find which supplements have evidence for it. Returns grouped statements with supplement IDs.

objectID

Example: objectID=cognitive-performance. The outcome to reverse-lookup.

predicateID

Example: predicateID=improves. Filter by relationship direction.

population

Example: population=athletes. Narrow to a population group.

Tip: Use this to power “what helps with X?” discovery experiences.

GET/api/library/v1/interactions

Returns supplement-drug and supplement-supplement interactions with target typing and external code references.

q

Example: q=warfarin. Search interactions by name or target.

targetType

Example: targetType=drug. Filter by interaction target category.

system / code

Example: system=rxnorm&code=11289. Lookup by external coding system.

limit / offset

Example: limit=100&offset=0. Paginate interaction results.

GET/api/library/v1/lookup

Cross-reference lookup. Maps external identifiers (PubChem, UNII, RxNorm) to Unfair entity IDs and back. Use this to bridge your existing data with the Unfair graph.

system

Example: system=pubchem. The external identifier system.

code

Example: code=586. The external code to resolve.

source / externalID

Example: source=unii&externalID=MU72812GK0. Alternative crosswalk lookup.

GET/api/library/v1/assertions

Canonical assertion ledger endpoint. Query claims, interactions, contraindications, regulatory facts, and intervention-outcome edges from one schema.

kind

Example: kind=claim. Filters assertion domain.

subjectType / subjectID

Example: subjectType=supplement&subjectID=creatine.

studyID

Example: studyID=pmid-12345678. Keeps only assertions linked to one study.

coverage

Example: coverage=text_only. Filters by machine-readable status.

Requires capability assertions.read.

GET/api/library/v1/assertions/{id}

Returns one assertion by deterministic id for audit trails and deep links.

Requires capability assertions.read.

GET/api/library/v1/interaction-facts

Structured interaction facts view over the assertion ledger with supplement, target typing, severity, and coverage fields.

supplementID

Example: supplementID=st-johns-wort. Filter to one supplement.

severity

Example: severity=major. Filter by interaction severity level.

targetType

Example: targetType=drug. Filter by what the supplement interacts with.

coding

Example: coding=complete. Filter by machine-readable coding status.

limit / offset

Example: limit=100&offset=0. Paginate interaction facts.

Requires capability interaction-facts.read.

GET/api/library/v1/identifiers

Identifier graph and crosswalk lookup across supplements, studies, outcomes, and interventions.

entityType

Example: entityType=supplement. Scope to one entity kind.

entityID

Example: entityID=creatine. Get all identifiers for a specific entity.

system / code

Example: system=pubchem&code=586. Find entities by external identifier.

limit / offset

Example: limit=100&offset=0. Paginate identifier records.

Requires capability identifiers.read.

GET/api/library/v1/coverage

Per-entity coverage transparency for evidence linkage, coding completeness, and unresolved gaps.

entityType

Example: entityType=supplement. Scope coverage to one entity kind.

entityID

Example: entityID=ashwagandha. Check coverage for one entity.

gap

Example: gap=missing_evidence. Filter to entities with a specific gap type.

limit / offset

Example: limit=100&offset=0. Paginate coverage records.

Requires capability coverage.read.

POST/api/library/v1/safety/screen

Productized safety screen. Submit candidate supplements plus medication, condition, stack, and profile context to receive a machine-readable clear, warn, block, or insufficient_coverage decision with blockers, warnings, and trace IDs.

Requires capabilities interaction-facts.read, assertions.read, and coverage.read.

GET/api/library/v1/snapshots

Snapshot manifests with contract version, artifact digests, and immutable snapshot identifiers.

limit / offset

Example: limit=20&offset=0. Paginate through snapshot history.

Requires capability snapshots.read.

Supports conditional requests with If-None-Match. Successful cache validation returns 304 with an ETag header.

GET/api/library/v1/releases

Change-intelligence feeds built on top of snapshots and diffs. Use /releases for classified release summaries and /changelog for a more human-readable stream of the latest impactful changes.

The companion feed is /api/library/v1/changelog.

Requires capabilities snapshots.read and diffs.read.

GET/api/library/v1/diffs

Classified diff feed. Compare two snapshots to see added, modified, and removed entities plus impact type, severity, and recommended downstream action.

fromSnapshotID

Example: fromSnapshotID=snap-2026-02. Preferred baseline snapshot to diff from.

sinceSnapshotID

Example: sinceSnapshotID=snap-2026-02. Alias for fromSnapshotID for migration compatibility.

toSnapshotID

Example: toSnapshotID=snap-2026-03. Optional, defaults to current snapshot.

entityType

Example: entityType=supplement. Scope the diff to one entity kind.

limit / offset

Example: limit=100&offset=0. Paginate diff entries.

Requires capability diffs.read.

Supports conditional requests with If-None-Match. If neither fromSnapshotID nor sinceSnapshotID is provided, the API returns 400 missing_from_snapshot.

Workflow Examples

These are job based examples you can copy and adapt.

1. Get a ranked intervention shortlist for an outcome

Outcome Ranking Workflow

bash
# 1) Find sleep-related outcomes
curl -sS -H "Authorization: Bearer $UAF_TOKEN" \
  "https://unfairapp.com/api/library/v1/health-outcomes?q=sleep&limit=1"

# 2) Ask for a ranked shortlist instead of stitching edges yourself
curl -sS -H "Authorization: Bearer $UAF_TOKEN" \
  "https://unfairapp.com/api/library/v1/health-outcomes/OUTCOME_ID/ranked-interventions?minGrade=B&limit=10"

# 3) Pull a brief for the top candidate you want to explain
curl -sS -H "Authorization: Bearer $UAF_TOKEN" \
  "https://unfairapp.com/api/library/v1/interventions/INTERVENTION_ID/brief?minGrade=B&limit=5"

Expected Output Shape

json
{
  "outcomeID": "sleep-latency",
  "topCandidate": "l-theanine",
  "topScore": 84,
  "why": [
    "strongest linked grade is B",
    "6 linked studies across 600 participants"
  ]
}

2. Build a supplement product page fast

Use the product pack when your UI needs a curated bundle, then use bulk hydration for adjacent cards or comparison rails.

Supplement Product Pack Workflow

bash
# 1) Fetch a product-ready supplement pack
curl -sS -H "Authorization: Bearer $UAF_TOKEN" \
  "https://unfairapp.com/api/library/v1/supplements/alpha-gpc/product-pack?include=content,studies"

# 2) Bulk hydrate adjacent cards without N+1 detail requests
curl -sS -X POST -H "Authorization: Bearer $UAF_TOKEN" \
  -H "Content-Type: application/json" \
  "https://unfairapp.com/api/library/v1/supplements/bulk" \
  -d '{"ids":["alpha-gpc","citicoline"],"lookupBy":"slug","include":["coverage","identifiers"]}'

# 3) Render dose, safety, evidence highlights, and related entities from one response

Expected Output Shape

json
{
  "productPack": {
    "slug": "alpha-gpc",
    "coverageStatus": "complete",
    "topOutcome": "focus"
  },
  "bulkFound": 2,
  "acceptedIncludes": ["coverage", "identifiers"]
}

3. Compare ranked intervention candidates

Use ranked listings to narrow the field, then use the comparison endpoints to explain tradeoffs without writing scoring or overlap logic yourself.

Comparison Workflow

bash
# 1) Rank interventions for a condition
curl -sS -H "Authorization: Bearer $UAF_TOKEN" \
  "https://unfairapp.com/api/library/v1/interventions/ranked?condition=Insomnia&minGrade=B&limit=5"

# 2) Compare the top two candidates on the same outcome
curl -sS -X POST -H "Authorization: Bearer $UAF_TOKEN" \
  -H "Content-Type: application/json" \
  "https://unfairapp.com/api/library/v1/compare/interventions" \
  -d '{"left":"magnesium","right":"l-theanine","compareOn":["sleep-latency"]}'

# 3) Use the winner, shared outcomes, and score summary in your chooser UI

Expected Output Shape

json
{
  "rankedCount": 5,
  "comparisonWinner": "l-theanine",
  "sharedOutcomes": ["sleep-quality", "sleep-latency"],
  "reason": "L-theanine has stronger aggregate linked evidence"
}

4. Safety check before recommending a supplement

Use the safety screen endpoint when you need a machine-readable decision for a real user context instead of manually stitching interaction, assertion, and coverage calls together.

Use strictness=high_safety when you want coverage gaps to surface as insufficient_coverage instead of silently defaulting to a weaker answer.

Safety Check Workflow

bash
curl -sS -X POST -H "Authorization: Bearer $UAF_TOKEN" \
  -H "Content-Type: application/json" \
  "https://unfairapp.com/api/library/v1/safety/screen" \
  -d '{
    "candidates": [{"supplementID": "st-johns-wort"}],
    "medications": [{"label": "sertraline"}],
    "conditions": [{"label": "pregnancy"}],
    "profile": {"strictness": "high_safety"}
  }'

Expected Output Shape

json
{
  "overallDecision": "block",
  "results": [
    {
      "supplementID": "st-johns-wort",
      "decision": "block",
      "confidence": "medium",
      "blockers": [
        {
          "type": "interaction",
          "severity": "major",
          "reason": "serotonergic interaction risk",
          "target": { "id": "sertraline", "label": "Sertraline" },
          "sources": ["assertion.interaction.st-johns-wort.5fbb50ba372ebafc"]
        }
      ],
      "warnings": [],
      "coverage": {
        "status": "has_gaps",
        "gaps": ["Interaction target is free text and not yet mapped to external codes"]
      },
      "trace": {
        "assertionIDs": [
          "assertion.interaction.st-johns-wort.5fbb50ba372ebafc",
          "assertion.contraindication.st-johns-wort.6c9eb735d4aa0db4"
        ],
        "interactionFactIDs": [
          "assertion.interaction.st-johns-wort.5fbb50ba372ebafc"
        ],
        "coverageEntityID": "st-johns-wort"
      }
    }
  ]
}

5. Audit trail across data updates

Use releases and changelog for the fast answer, then fall back to raw diffs when you need exact entity-level action.

Audit Trail Workflow

bash
# 1) See the most recent classified releases
curl -sS -H "Authorization: Bearer $UAF_TOKEN" \
  "https://unfairapp.com/api/library/v1/releases?limit=5"

# 2) Pull the human-readable changelog feed
curl -sS -H "Authorization: Bearer $UAF_TOKEN" \
  "https://unfairapp.com/api/library/v1/changelog?limit=10"

# 3) Fetch exact diff rows when you need entity-level action
curl -sS -H "Authorization: Bearer $UAF_TOKEN" \
  "https://unfairapp.com/api/library/v1/diffs?fromSnapshotID=snap-2026-02&toSnapshotID=snap-2026-03&entityType=supplement"

Expected Output Shape

json
{
  "releaseSummary": "2 safety-impacting changes detected",
  "changelogKind": "safety",
  "recommendedAction": "review_safety_screening",
  "entityType": "supplement"
}

6. Cross-reference external identifiers

Use identifiers and lookup to map between Unfair entity IDs and external systems like PubChem, UNII, or RxNorm.

Cross-Reference Workflow

bash
# 1) Find all external identifiers for a supplement
curl -sS -H "Authorization: Bearer $UAF_TOKEN" \
  "https://unfairapp.com/api/library/v1/identifiers?entityType=supplement&entityID=creatine"

# 2) Reverse lookup: find the Unfair entity from an external code
curl -sS -H "Authorization: Bearer $UAF_TOKEN" \
  "https://unfairapp.com/api/library/v1/lookup?system=pubchem&code=586"

Expected Output Shape

json
{
  "entityID": "creatine",
  "identifiers": [
    { "system": "pubchem", "code": "586" },
    { "system": "unii", "code": "MU72812GK0" }
  ]
}

7. Deep evidence drill-down with studies

Use studies, evidence, and evidence/reverse to build research tools that trace claims back to primary sources.

Deep Evidence Workflow

bash
# 1) Search studies with effect estimates for a supplement
curl -sS -H "Authorization: Bearer $UAF_TOKEN" \
  "https://unfairapp.com/api/library/v1/studies?q=creatine&hasEffectEstimates=true&limit=5"

# 2) Get structured evidence statements
curl -sS -H "Authorization: Bearer $UAF_TOKEN" \
  "https://unfairapp.com/api/library/v1/evidence?supplementID=creatine&limit=10"

# 3) Reverse query: which supplements have evidence for an outcome?
curl -sS -H "Authorization: Bearer $UAF_TOKEN" \
  "https://unfairapp.com/api/library/v1/evidence/reverse?objectID=cognitive-performance"

Expected Output Shape

json
{
  "studyCount": 5,
  "evidenceStatements": 10,
  "reverseHits": ["creatine", "omega-3", "caffeine"],
  "topStudyType": "Systematic review",
  "exampleStudy": {
    "sampleSize": 281,
    "blinding": "double-blind",
    "randomized": true,
    "journal": "Journal of the ISSN",
    "publicationYear": 2017
  }
}

Language Examples

curl

Request

bash
curl -i -sS \
  -H "Authorization: Bearer $UAF_TOKEN" \
  "https://unfairapp.com/api/library/v1/supplements?limit=2&offset=0"

Response

http
HTTP/2 200
x-library-version: 2026-04-09T02:39:46.074Z
x-contract-version: 1.0.0
x-snapshot-id: snapshot.0e78bc69814bbd345e92
x-rate-limit-remaining: 497
x-rate-limit-reset: 2026-03-01T00:00:00.000Z

{
  "ok": true,
  "total": 384,
  "limit": 2,
  "offset": 0,
  "filters": {
    "q": null,
    "category": null,
    "categoryLabel": null,
    "tier": null
  },
  "data": [
    {
      "slug": "5-htp",
      "displayName": "5-HTP",
      "categoryID": "amino-acid"
    },
    {
      "slug": "7-keto-dhea",
      "displayName": "7-Keto DHEA",
      "categoryID": "hormone"
    }
  ]
}

Field Glossary

These fields are domain-specific and are easiest to use when you know what they represent.

  • tier is the normalized evidence strength bucket. Higher quality evidence sorts first.
  • endpointRelevance scores how directly a study endpoint supports the claim.
  • biasRisk estimates methodological risk of bias for that evidence entry.

Evidence Definitions

Evidence Tier

Evidence tier is a normalized confidence label used for sorting and filtering. Higher tiers represent stronger supporting evidence and are surfaced first in ranked responses.

Use tiers to control strictness in your product. For example, start with minGrade=B in decision-focused views, then allow lower tiers in exploration views.

Evidence Quality Metadata

Evidence quality metadata helps explain why an item was ranked a certain way. Fields like endpointRelevance and biasRisk describe how directly a study supports a claim and how likely the result is to be biased.

Use these fields for transparency in your UI. Show users when a recommendation is backed by stronger endpoint alignment and lower bias risk, and flag weaker entries as lower confidence.

For deeper definitions, see the Evidence Tier and Evidence Quality Metadata glossary entries.

Rate Limit Strategy

Build clients that respect quotas by reading response headers on every request.

  • Use x-rate-limit-remaining to decide when to throttle prefetching.
  • Use x-rate-limit-reset to schedule retries after quota resets.
  • Use x-library-version as a cache key so clients can skip unnecessary refetches.
  • Monthly quota is configured per token, so limits vary by plan.
  • At zero remaining requests, API calls fail with 429 monthly_limit_exceeded until reset.
  • For 429, use Retry-After to choose the next attempt window.
  • Conditional requests are available on /meta, /snapshots, and /diffs using ETag and If-None-Match. Current behavior still applies quota checks before a possible 304.
  • In production, back off immediately at low remaining values and alert your team before zero is reached.
  • If traffic grows, request a higher limit through the contact page before launch windows.

Documentation Checklist

Use this checklist when adding or updating endpoints so docs stay consistent.

  • Confirm the endpoint fits the mental model section.
  • Add at least one workflow that uses the endpoint.
  • Document each parameter with an example and why it matters.
  • Describe failure modes and recovery steps.
  • Document quota behavior and retry strategy.

Sample JSON Responses

GET /supplements

json
{
  "ok": true,
  "total": 384,
  "limit": 50,
  "offset": 0,
  "filters": {
    "q": null,
    "category": null,
    "categoryLabel": null,
    "tier": null
  },
  "data": [
    {
      "slug": "5-htp",
      "displayName": "5-HTP",
      "scientificName": "5-Hydroxy-L-tryptophan",
      "categoryID": "amino-acid",
      "summary": "5-HTP is a serotonin precursor...",
      "dose": {
        "typical": "100-300 mg/day"
      },
      "evidence": {
        "tier": "C",
        "effectWindow": "2-4 weeks"
      }
    }
  ]
}

GET /supplements/{slug}

json
{
  "ok": true,
  "data": {
    "slug": "5-htp",
    "displayName": "5-HTP",
    "mechanismSummary": "Precursor to serotonin...",
    "dose": {
      "min": "Not established",
      "typical": "100-300 mg/day",
      "maxCaution": "Low-risk cautious titration"
    },
    "safety": {
      "contraindications": ["pregnancy", "lactation"],
      "interactions": ["SSRI", "SNRI", "MAOI"]
    },
    "evidence": {
      "tier": "C",
      "effectWindow": "2-4 weeks",
      "table": [
        {
          "sourceID": "SRC-001",
          "studyType": "Systematic review",
          "studyURL": "https://pubmed.ncbi.nlm.nih.gov/12345678/",
          "endpointRelevance": 4,
          "biasRisk": 4,
          "blinding": "double-blind",
          "sampleSize": 120,
          "durationDays": 56,
          "randomized": true,
          "conclusions": "Significant improvement in...",
          "adverseEvents": "Well tolerated, mild GI...",
          "dose": "300 mg/day",
          "journal": "Nutrients",
          "publicationYear": 2020
        }
      ]
    }
  }
}

GET /meta

json
{
  "ok": true,
  "data": {
    "metadata": {
      "generatedAt": "2026-04-08T23:20:44Z",
      "sourceManifestGeneratedAt": "2026-03-14T11:01:19Z",
      "sourceSupplementCount": 384,
      "importedSupplementCount": 384,
      "exportedSupplementCount": 384,
      "byCategory": {
        "chemical-compound": 16,
        "amino-acid": 31
      }
    },
    "facets": {
      "categories": ["chemical-compound", "amino-acid"],
      "tiers": ["A", "B", "C", "D"]
    },
    "research": {
      "metadata": {
        "generatedAt": "2026-04-09T02:39:46.074Z",
        "counts": {
          "healthOutcomeCount": 781,
          "interventionCount": 182,
          "edgeCount": 3919
        },
        "quality": {
          "level": "High"
        }
      },
      "facets": {
        "healthOutcomeCategories": ["Behavior and Context", "Biology"],
        "interventionConditions": ["Acute Respiratory Infection", "Aerobic Exercise Performance"]
      }
    },
    "contracts": {
      "contractVersion": "1.0.0",
      "snapshotID": "snapshot.0e78bc69814bbd345e92",
      "supportedAssertionKinds": [
        "claim",
        "interaction",
        "contraindication",
        "avoid_if",
        "regulatory",
        "intervention_outcome"
      ],
      "artifactDigests": {
        "assertions": "sha256:...",
        "coverage": "sha256:..."
      },
      "validation": {
        "strictModeQueryParam": "strict",
        "routes": [
          {
            "path": "/api/library/v1/supplements",
            "requiredCapabilities": ["library.read"],
            "strictMode": {
              "supported": true,
              "queryParam": "strict",
              "enabledValue": "true",
              "defaultValue": false
            },
            "params": [
              { "name": "q", "type": "string" },
              { "name": "tier", "type": "grade", "enumValues": ["A", "B", "C", "D", "F"] },
              { "name": "limit", "type": "integer", "min": 0, "max": 200 }
            ]
          }
        ]
      }
    }
  }
}