Skip to main content
This page covers the domain model behind the API types, enough to read any response correctly before you write a line of integration code. For the reward math itself, see Reward Calculation.

Campaign Identity

A campaign is identified by a compound key, not a single scalar ID:
In URL paths and query strings the key serializes to "chainId:campaignIndex", so { chainId: 8453, campaignIndex: 56 } becomes "8453:56". The SDK does that conversion for you; every method takes the object form.
There is no string overload. Passing "8453:56" to an SDK method will not typecheck. Always pass { chainId, campaignIndex }.
Each campaign also exposes configHash, the keccak256 commitment of its configuration that was submitted on-chain. If you want to verify a campaign’s parameters independently, recompute the hash and compare.

Event Chain Versus Reward Chain

Two chains matter for every campaign, and confusing them is the most common integration bug. They are the same for most campaigns. They differ for cross-chain campaigns, such as positions tracked on Polygon with rewards claimed on Worldchain. The operating rule:
  • Filtering campaigns by vault or pool address? Use the event chain.
  • Connecting a wallet to claim? Use the reward chain.

Lifecycle and Claimability

Claimability is governed by published merkle roots, not by status. Rewards become claimable when a root covering them is published on the reward chain, which happens periodically while a campaign runs, not only at the end. Never gate a claim button on status === "active": ended campaigns stay claimable, and finalized means everything earned is claimable. Gate on claimable > 0n and let the amount decide.
For the business-facing view of these phases (what a creator can change in each, and when budget becomes recoverable), see Campaign Lifecycle.

Reading Accrual From the API

Rewards are computed off-chain by Boost’s indexers from on-chain events. You never reproduce the math; you read a field. Two properties of the accrual engine matter when you build a UI:
  • Earnings are continuous and already exact. accumulatedRewards reflects every second up to the latest on-chain event or price checkpoint. There is no per-second feed to poll.
  • There is no retroactive credit. Time a user was not holding is time they did not accumulate, which is why, at equal size, an earlier holder out-earns a later one.
For priced targets such as prediction-market shares or LP positions, balance is the position’s value, not its raw token count, and it drifts with price checkpoints even when the user does not trade. Plain ERC-20 targets count raw token units.

Modes as Data

campaign.modes is a keyed object. A key is present only when that mode is enabled, and {} means a plain pro-rata campaign. Modes compose, so a campaign can carry several at once. Units. *Bps fields are basis points (1250 = 12.5%). *Usd fields are USD with 6 decimals. Bare balance fields are raw target-token units. earningCap.maxRewards is the exception: it caps rewards, so it is denominated in reward-token units. For what each mode is for (the campaign-design view rather than the data view), see Campaign Modes.

Targets

campaign.target describes the position being tracked. Its shape varies by tokenStandard, and fields that do not apply to a standard are omitted entirely rather than set to null: Match on target.address for ERC-20 style targets and on target.poolId for Uniswap v4 pools. shareModel on a v4 target says how an LP’s slice is computed. Treat it as an open string rather than a closed set:
The SDK type currently narrows shareModel to "weighted" | "tvl", but the API returns "fees" on live v4 campaigns. Do not write an exhaustive switch over it; fall through on values you do not recognise.

What Discovery Returns

campaigns.list and campaigns.active exclude campaigns that require a Forwarder deposit unless you pass includeForwarderRequired: true. That keeps integrations from surfacing campaigns their users cannot earn from. campaigns.get returns any campaign regardless of the flag.
Discovery also omits some internal Boost-operated campaigns from browse results.
This is a visibility convention for partner discovery, not an authorization boundary. If you already have a campaign ID, campaigns.get and campaigns.stats still work, and rewards.forUser and claims.get still return that user’s financial data.

Keep Exploring

How Claiming Works

Merkle roots, cumulative amounts, and the three reward numbers.

Data Conventions

Wire formats, bigint amounts, and pagination.

Forwarder Deposits

Routing deposits for campaigns that require them.