Clear ExchangeDocs Live demo

Rate card schema

A rate card is a publisher's price list: per-retrieval prices for each usage tier, the default licence terms, and optional price rules. It is a standalone, versioned JSON document. Validation lives in src/ratecard/schema.ts; pricing in src/ratecard/pricing.ts (a pure function).

The rate card is deliberately separate from the entitlement (which carries the resolved terms that were sold and references the card only by rate_card_ref) and from telemetry (which references it as terms_ref).

Example

data/rate-cards/harbour-ledger.json:

{
  "schema": "clear-exchange.rate-card",
  "schema_version": "1.2",
  "rate_card_id": "rc_harbour_ledger_std",
  "version": 3,
  "publisher_id": "pub_harbour_ledger",
  "currency": "USD",
  "effective_from": "2026-01-01T00:00:00Z",
  "effective_until": null,
  "default_terms": {
    "citation_required": true,
    "attribution": "The Harbour Ledger",
    "max_snippet_chars": 320,
    "retention_seconds": 86400,
    "ai_training": "prohibited",
    "commercial_use": true,
    "share_alike": false,
    "caching_allowed": true,
    "reuse_across_end_users": false
  },
  "tiers": [
    { "usage": "grounding_only", "price_micros": 4000 },
    { "usage": "display_snippet", "price_micros": 8000 },
    { "usage": "full_text", "price_micros": 20000, "terms": { "retention_seconds": 3600 } }
  ],
  "rules": [
    { "id": "markets-premium", "match": { "sections": ["markets"] }, "multiplier_bps": 15000 },
    { "id": "archive-discount", "match": { "min_age_days": 365 }, "multiplier_bps": 5000 }
  ]
}

Fields

FieldTypeRequiredMeaning
schemastringyesAlways "clear-exchange.rate-card".
schema_versionstringyes"MAJOR.MINOR". This exchange reads any 1.x.
rate_card_idstringyesStable id of the card.
versioninteger ≥ 1yesMonotonic revision. Offers and entitlements pin to rate_card_id@vN (rate_card_ref).
publisher_idstringyesMust match the publisher of the source that uses the card.
currencystringyesISO 4217 code. All prices on the card are in micros of it.
effective_fromdate-timeyesThe card prices nothing before this.
effective_untildate-time or nullnoThe card prices nothing from this moment.
default_termsobjectyesLicence terms for every tier unless a tier overrides them. See Terms.
tiersarrayyesAt least one; at most one per usage tier. Each is { usage, price_micros, terms?, extensions? }. price_micros is a non-negative integer. terms overrides fields of default_terms for that tier.
rulesarraynoOrdered price rules. See Rules.
extensionsobjectnoNamespaced extra data, for example "com.clear-exchange" or "com.example". Allowed at the top level, per tier and per terms object.

Usage tiers are grounding_only, display_snippet and full_text, narrowest first; each includes the rights of the narrower ones (see API conventions).

Terms

FieldTypeRequiredMeaning
citation_requiredbooleanyesThe agent must cite the source when it uses the content in an answer.
retention_secondsinteger ≥ 0yesHow long the agent may retain or cache the content. Retrieval returns licence.retain_until.
ai_trainingstringyes"prohibited", or "per_content_licence" for openly licensed content, where the open licence governs.
attributionstringnoAttribution text to show with citations.
max_snippet_charsintegernoMost characters that may be displayed under display_snippet.
content_licenceobjectsince 1.1; required when ai_training is "per_content_licence"{ id, name, url, share_alike, attribution_to? }. id uses SPDX where one exists, for example CC-BY-SA-4.0.
commercial_usebooleansince 1.2; noThe buyer may use the content commercially. Default true, unless content_licence is non-commercial (NC).
share_alikebooleansince 1.2; noAdaptations must be shared under the same licence. Default: content_licence.share_alike, else false. Cannot be false when the open licence is share-alike.
caching_allowedbooleansince 1.2; noThe buyer may cache the content for retention_seconds. Default true when retention_seconds > 0; cannot be true when it is 0.
reuse_across_end_usersbooleansince 1.2; noOne retrieval may serve more than one of the buyer's end users within the caching window. Default true for openly licensed content, otherwise false.

From these the exchange derives the key licence terms on every offer and entitlement, with a one-line plain-English summary. See Licence terms for the fields, the defaults and how buyers filter on them. A tier's terms can override any of the flags for that tier.

Rules

Rules adjust a tier's price by content attributes. For each tier, every matching rule is applied in order:

  1. fixed_price_micros (a map of tier to price) replaces the current price for the listed tiers;
  2. then multiplier_bps multiplies the current price (10000 = 1×, 15000 = 1.5×), rounding half up in integer micros.

match fields, all of which must hold (an empty match matches everything):

FieldMatches when
sectionsThe item's section is in the list.
tagsThe item has at least one of the tags.
content_idsThe item's content_id is in the list.
max_age_daysThe item was published at most this many days ago.
min_age_daysThe item was published at least this many days ago.

Age rules never match an item without published_at. The ids of the rules applied appear in the offer's licence.applied_rules.

Worked example with the card above: a markets article published two years ago, display_snippet: 8000 × 1.5 = 12000, then × 0.5 = 6000 micros (USD 0.006) publisher price, and applied_rules: ["markets-premium", "archive-discount"].

How an offer is priced

For a requested tier, the exchange:

  1. ignores the card if it is not in effect now;
  2. considers every tier at least as broad as the one requested, prices each with the rules, and quotes the cheapest (on a tie, the broader tier). So an agent asking for display_snippet can be sold full_text if that is cheaper; the offer's licence.usage says what is sold;
  3. treats the card as a ceiling: a source may offer an item below the card price for a tier (price_breakdown.discounted: true), never above it. An offer above the card is priced at the card and counted in stats.offers_above_card;
  4. adds the clearing fee on top: fee = floor(publisher price × CLEARING_FEE_BPS / 10000) (default 1000 bps, 10%, a placeholder), so rounding never favours the exchange. The agent's max_price applies to the all-in price.

Offers whose card currency differs from the query's are excluded (stats.currency_mismatch); there is no conversion.

Compatibility rules

  • Readers accept any 1.x document and ignore unknown fields. A new major version is a breaking change and is rejected at load.
  • Put publisher- or marketplace-specific data in extensions under your own namespace, not in new top-level fields.
  • Version 1.1 added content_licence and ai_training: "per_content_licence".
  • Version 1.2 added the optional licence flags commercial_use, share_alike, caching_allowed and reuse_across_end_users. A 1.0 or 1.1 card still loads; the flags take their defaults. Every shipped card is 1.2 and states each flag. Cards whose effective terms changed when the flags were set explicitly (Cobble & Byte, Quaymark Reference, Stackhollow Guides, Emberline Preprints) moved to a new version.

Where rate cards come from

  • Seeded catalogue publishers: data/rate-cards/*.json, referenced from data/catalogue/publishers.json.
  • http-offer publishers: the rate_card field of the source entry, a path or an inline object (see Adding a source).
  • Other adapters supply a card on each candidate (SupplyCandidate.rate_card).

Cards are validated at startup; an invalid card stops the server before it listens. There is no API to upload or change a rate card yet (see Roadmap). Operators can read the current cards at GET /v1/admin/rate-cards.

Demo cards

Cards whose extensions["com.clear-exchange"] carries demo_pricing: true (Wikimedia) or demo_publisher: true (the fictional mock publishers) are demo listings. The Wikimedia prices are for the exchange's retrieval, entitlement and telemetry service; the Wikimedia Foundation and contributors are not parties to them and receive nothing. See Live sources.