Earn Products
A rate is only half the story. The earn products endpoints expose the canonical graph of what is actually on offer: each product is one provider × asset × category, and each of its variants carries the terms — lockup, tier, minimum deposit, payout cadence, withdrawal notice, TVL, promo status — along with how we collected each field, how confident we are, and where the product can be used. Use it to answer "what are the real terms behind this rate?"
This is an Earn Intelligence endpoint. It requires an API key on a Pro or Enterprise plan. Anonymous, Free, Starter, and Growth requests receive 403 PLAN_UPGRADE_REQUIRED (see Errors). Compare plans at pro.bitcompare.net/pricing or issue a key from your dashboard. Agents get the same data through the list_earn_products MCP tool.
Access and plan gating
Authenticate with your key as a Bearer token (see Authentication). Unlike the rate-change feed, there is no history window here — the graph is a current-state read — so the only plan question is whether the endpoint answers.
| Plan | Endpoint access |
|---|---|
| Anonymous (no key) | 403 PLAN_UPGRADE_REQUIRED |
| Free | 403 PLAN_UPGRADE_REQUIRED |
| Starter | 403 PLAN_UPGRADE_REQUIRED |
| Growth | 403 PLAN_UPGRADE_REQUIRED |
| Pro | Full |
| Enterprise | Full |
The product model
A product is the stable identity a rate hangs off. It survives provider delistings: a delisted product keeps its id and its history, it just moves to status: "delisted".
Properties
- Name
id- Type
- integer
- Description
Stable numeric identifier. Use it with
/earn/products/:id.
- Name
provider- Type
- string
- Description
Provider slug, e.g.
"nexo","aave-v3".
- Name
symbol- Type
- string
- Description
Asset symbol, upper-case.
- Name
category- Type
- string
- Description
lending,borrowing, orstaking.
- Name
coinId- Type
- string | null
- Description
Canonical coin identifier, when the symbol resolved.
- Name
platformType- Type
- string | null
- Description
cefi,defi, orhybrid, from the provider registry.
- Name
status- Type
- string
- Description
active,inactive, ordelisted.
- Name
firstObservedAt- Type
- string
- Description
ISO 8601 instant the product was first seen.
- Name
lastObservedAt- Type
- string
- Description
ISO 8601 instant the product was last seen in a provider's offer set.
- Name
variants- Type
- array
- Description
The product's variants (below). Present unless
includeVariants=false. On the list endpoint onlyactivevariants are returned; the single-product endpoint returns variants of every status.
The variant model
A variant is one concrete offer of a product: the "flexible" tier and the "90-day locked" tier of the same asset are two variants. Any term we could not verify is null — we never guess.
Properties
- Name
id- Type
- integer
- Description
Variant identifier.
- Name
variantKey- Type
- string
- Description
Stable key within the product, e.g.
"flexible","locked-90d","tier-platinum".
- Name
name- Type
- string | null
- Description
Provider's display name for the offer.
- Name
termType- Type
- string | null
- Description
flexible,fixed, etc.
- Name
termDays- Type
- integer | null
- Description
Lockup length in days for fixed terms.
- Name
tierName- Type
- string | null
- Description
Loyalty or balance tier the offer applies to.
- Name
minDeposit- Type
- number | null
- Description
Minimum deposit, in
minDepositCurrency.
- Name
minDepositCurrency- Type
- string | null
- Description
Currency of
minDeposit.
- Name
maxEligibleBalance- Type
- number | null
- Description
Balance above which the rate stops applying.
- Name
requiredToken- Type
- string | null
- Description
Token that must be held to qualify (e.g. a platform token).
- Name
requiredTokenAmount- Type
- number | null
- Description
Quantity of
requiredTokenneeded.
- Name
rewardAsset- Type
- string | null
- Description
Asset the yield is paid in, when it differs from the deposited asset.
- Name
compounding- Type
- string | null
- Description
Compounding cadence, e.g.
daily,none.
- Name
payoutFrequency- Type
- string | null
- Description
How often rewards are paid, e.g.
daily,weekly,at_maturity.
- Name
withdrawalNoticeDays- Type
- integer | null
- Description
Notice period before funds can be withdrawn.
- Name
kycRequired- Type
- boolean | null
- Description
Whether identity verification is required.
- Name
promotional- Type
- boolean
- Description
truewhen the offer is a time-limited promotion.
- Name
promotionExpiresAt- Type
- string | null
- Description
ISO 8601 expiry of the promotion, when known.
- Name
tvlUsd- Type
- number | null
- Description
On-chain TVL in USD for DeFi variants.
- Name
riskLevel- Type
- string | null
- Description
Provider- or reviewer-assigned risk label.
- Name
collectionMethod- Type
- string
- Description
Baseline collection method for the variant:
pull_api,push,onchain,websocket,multi_source,manual,provider_confirmed,backfill, orunknown.
- Name
confidence- Type
- integer | null
- Description
0–100 variant-level confidence score.
- Name
confidenceBand- Type
- string
- Description
Derived from
confidence:high(≥ 80),medium(50–79),low(< 50), orunknownwhen no score.
- Name
lastVerifiedAt- Type
- string | null
- Description
ISO 8601 instant a human or provider last verified the terms.
- Name
verifiedBy- Type
- string | null
- Description
Who verified: a reviewer handle or the provider.
- Name
fieldProvenance- Type
- object | null
- Description
Per-field overrides of the baseline provenance — see Confidence and provenance. Served verbatim.
- Name
effectiveGeo- Type
- object
- Description
Resolved geographic eligibility — see Geo resolution.
- Name
metadata- Type
- object | null
- Description
Provider-specific extras, served verbatim.
- Name
lastObservedAt- Type
- string
- Description
ISO 8601 instant the variant was last seen.
Geo resolution
Each variant carries an effectiveGeo object so you never have to merge provider-level and offer-level restrictions yourself. Resolution is: if the variant declares its own allow or block list, use that (source: "variant"); otherwise fall back to the provider's country lists (source: "provider"); if neither exists, both lists are null and source is "none".
effectiveGeo
{
"allowed": null,
"blocked": ["US", "GB", "CA"],
"source": "provider"
}
allowed and blocked are arrays of ISO 3166-1 alpha-2 codes or null. An allowed list means only those countries; a blocked list means everywhere except those countries. source: "none" means we have no eligibility data, not that the offer is available everywhere.
Confidence and provenance
Every variant has a baseline collectionMethod and confidence. When individual fields were captured differently — the lockup was provider-attested but the fee schedule was parsed from a web page, say — fieldProvenance records the override per field. The object is keyed by variant field name and served exactly as stored:
fieldProvenance
{
"termDays": {
"source": "provider_portal",
"method": "provider_confirmed",
"verified_at": "2026-09-02T09:14:00Z",
"confidence": 100
},
"minDeposit": {
"source": "https://example-provider.com/earn/terms",
"method": "manual",
"verified_at": "2026-08-28T16:40:00Z",
"confidence": 80
}
}
A method of provider_confirmed means the provider attested to the value through Bitcompare's attestation programme, which is activating now; the Coverage endpoint reports how many providers and variants are attested at any time.
List products
Paginated list of products with their active variants, ordered by provider, symbol, category.
Optional attributes
- Name
provider- Type
- string
- Description
Restrict to one provider slug.
- Name
symbol- Type
- string
- Description
Restrict to one asset symbol.
- Name
category- Type
- string
- Description
lending,borrowing, orstaking.
- Name
status- Type
- string
- Description
active(default),inactive, ordelisted.
- Name
minConfidence- Type
- integer
- Description
0–100. Only return products with at least one active variant at or above this confidence.
- Name
includeVariants- Type
- string
- Description
true(default) orfalse. Omit thevariantsarray for a lighter response.
- Name
limit- Type
- integer
- Description
Page size, 1–200. Defaults to 50.
- Name
offset- Type
- integer
- Description
Zero-based offset for paging. Defaults to 0.
Response
{ data: { products, pagination } }. pagination carries total, limit, offset, and hasMore. Responses are Cache-Control: private, max-age=60.
Request
# BITCOMPARE_API_KEY is your ck_live_… key from https://pro.bitcompare.net/dashboard/keys
curl -G https://api.bitcompare.net/api/v1/earn/products \
-H "Authorization: Bearer $BITCOMPARE_API_KEY" \
-d provider=nexo \
-d symbol=BTC \
-d category=lending
Response
{
"data": {
"products": [
{
"id": 4182,
"provider": "nexo",
"symbol": "BTC",
"category": "lending",
"coinId": "bitcoin",
"platformType": "cefi",
"status": "active",
"firstObservedAt": "2026-07-21T00:57:15.412Z",
"lastObservedAt": "2026-09-16T02:30:04.118Z",
"variants": [
{
"id": 9931,
"variantKey": "flexible",
"name": "Flexible",
"termType": "flexible",
"termDays": null,
"tierName": null,
"minDeposit": null,
"minDepositCurrency": null,
"maxEligibleBalance": null,
"requiredToken": null,
"requiredTokenAmount": null,
"rewardAsset": "BTC",
"compounding": "daily",
"payoutFrequency": "daily",
"withdrawalNoticeDays": 0,
"kycRequired": true,
"promotional": false,
"promotionExpiresAt": null,
"tvlUsd": null,
"riskLevel": null,
"collectionMethod": "pull_api",
"confidence": 85,
"confidenceBand": "high",
"lastVerifiedAt": null,
"verifiedBy": null,
"fieldProvenance": null,
"effectiveGeo": {
"allowed": null,
"blocked": ["US"],
"source": "provider"
},
"metadata": {},
"lastObservedAt": "2026-09-16T02:30:04.118Z"
},
{
"id": 9932,
"variantKey": "locked-90d-platinum",
"name": "Fixed 90 days — Platinum",
"termType": "fixed",
"termDays": 90,
"tierName": "Platinum",
"minDeposit": null,
"minDepositCurrency": null,
"maxEligibleBalance": null,
"requiredToken": "NEXO",
"requiredTokenAmount": null,
"rewardAsset": "NEXO",
"compounding": "none",
"payoutFrequency": "at_maturity",
"withdrawalNoticeDays": null,
"kycRequired": true,
"promotional": false,
"promotionExpiresAt": null,
"tvlUsd": null,
"riskLevel": null,
"collectionMethod": "manual",
"confidence": 80,
"confidenceBand": "high",
"lastVerifiedAt": "2026-08-28T16:40:00.000Z",
"verifiedBy": "reviewer:bitcompare-ops",
"fieldProvenance": {
"termDays": {
"source": "https://nexo.com/earn-crypto",
"method": "manual",
"verified_at": "2026-08-28T16:40:00Z",
"confidence": 80
}
},
"effectiveGeo": {
"allowed": null,
"blocked": ["US"],
"source": "provider"
},
"metadata": {},
"lastObservedAt": "2026-09-16T02:30:04.118Z"
}
]
}
],
"pagination": {
"total": 1,
"limit": 50,
"offset": 0,
"hasMore": false
}
}
}
Get a product
One product by id, with variants of every status (a delisted product's history is still data). Works for inactive and delisted products that the list endpoint's default status=active filter would hide.
Path parameters
- Name
id- Type
- integer
- Description
The product's
idfrom the list endpoint.
Response
{ data: { product } } with the same product shape as the list endpoint. Responses are Cache-Control: private, max-age=60.
Request
# BITCOMPARE_API_KEY is your ck_live_… key from https://pro.bitcompare.net/dashboard/keys
curl https://api.bitcompare.net/api/v1/earn/products/4182 \
-H "Authorization: Bearer $BITCOMPARE_API_KEY"
Response
{
"data": {
"product": {
"id": 4182,
"provider": "nexo",
"symbol": "BTC",
"category": "lending",
"coinId": "bitcoin",
"platformType": "cefi",
"status": "active",
"firstObservedAt": "2026-07-21T00:57:15.412Z",
"lastObservedAt": "2026-09-16T02:30:04.118Z",
"variants": [ "…same variant shape as the list endpoint…" ]
}
}
}
Errors
- Name
403 PLAN_UPGRADE_REQUIRED- Description
No key, or a key on a plan without Earn Intelligence (Free, Starter, Growth). The body carries
feature: "intelligence"and an absoluteupgradeUrl.
- Name
404 NOT_FOUND- Description
No product with that
id.
- Name
422 VALIDATION_ERROR- Description
idnot a positive integer,limitoutside 1–200,minConfidenceoutside 0–100, or an unknowncategory/status.
- Name
429 RATE_LIMIT_EXCEEDED- Description
Plan per-minute budget exhausted. See Rate Limiting.
The full error envelope is described on the Errors page.
403 PLAN_UPGRADE_REQUIRED
{
"error": {
"message": "Earn Intelligence endpoints require a Pro or Enterprise plan.",
"code": "PLAN_UPGRADE_REQUIRED",
"feature": "intelligence",
"upgradeUrl": "https://pro.bitcompare.net/pricing"
}
}
See also
- Rate Changes — the observation log those rates come from
- Stablecoin Earn Benchmark — the BEI-Stable index
- Coverage — product, variant, and attestation counts from the live database
- Rates — the current-rate endpoints
- MCP Tool Catalog —
list_earn_productsfor agents