Create and Manage a Point Program

Use Merkl to index activity for your point program — you stay the source of truth for points

Merkl is an indexing layer for your point program — nothing more, nothing less.

Merkl tracks the onchain activity you specify and computes a time-weighted contribution per user, denominated in a mock token. You then read those numbers via the API and decide how many real points to credit to each address. Merkl never mints, holds, or distributes the points your users see.

This means:

  • You stay the source of truth. Your frontend and your database define the canonical points balance — Merkl only feeds you raw, comparable numbers.
  • You renormalize. Merkl outputs are denominated in mock-token units that are useful as a relative signal across users. To turn them into points, you apply your own multipliers, filters, and rules.
  • You stay in control. Exclude users, override allocations, blend results from multiple campaigns, change your multipliers retroactively — Merkl doesn't care, because Merkl never owned the points in the first place.

The rest of this page walks through the practical setup: deploying a mock token, configuring the indexing campaigns, fetching results, and renormalizing.

Step-by-step process

(Optional) 0. Deploy a point token with Merkl

Every Merkl campaign needs a token to "distribute" — that's how the system identifies what's being tracked. For a point program, this token is purely an accounting unit for indexing: an ERC20 (typically non-transferable, no monetary value) that lets Merkl emit per-user numbers you can read back.

We provide a template — PointToken.sol — and the Merkl team can deploy and mint one for you on the chain of your choice (typically a low-cost chain). You can configure the token's name, symbol, and logo.

The chain where the point token lives is independent of the chains where activity is tracked.

Once deployed and whitelisted, the point token effectively acts as your "API key" for spinning up tracking campaigns on Merkl.

1. Create indexing campaigns

Once you have a point token, you create Merkl campaigns that mirror the logic you want indexed (e.g. "1 point token per $1,000 deposited in this pool"). Campaigns can be created programmatically and support all of Merkl's standard customization options.

A few things to get right at this step:

Allocations. Each campaign needs a maximum allocation of point tokens. Don't pick an absurdly large number — extremely large allocations break Merkl's invariants. We recommend 3 billion points as a default cap: it's enough budget so the campaign won't run out early, and ensures every user holding more than $1 worth of activity earns something. Go higher only if you genuinely expect to distribute more than 3 billion points.

Duration. Campaign parameters are difficult to change once a campaign is live. Even if your program is meant to last 6 months, prefer shorter campaigns renewed periodically — it gives you flexibility to adjust rules without disruption.

Forwarders. Merkl's forwarder system automatically credits users whose positions sit behind intermediate contracts (e.g. wrappers, lending markets, gauges). One campaign on a stablecoin will typically cover holders across many downstream protocols without a separate setup.

Different multipliers per venue. If you want, say, x1 in-wallet and x5 in a specific lending market, two patterns work:

  • Forwarding enabled on the lending market — create an additional campaign for lenders with a x4 multiplier (the base x1 already comes from the main campaign).
  • Forwarding disabled on the lending market (blacklist the market address from the base campaign) — create the additional campaign with a x5 multiplier.

Fixed reward rate campaigns. Rates like "1 point per $1,000 deposited" require Merkl to be able to price the underlying assets. Confirm this by checking similar campaigns on the Merkl app, or ask the team if you're unsure.

Sanity-checking emission rates as a "virtual APR"

If each point were worth $1:

  • 1 point per $1 per day = 36,500% APR (100% / day × 365)
  • 1 point per $1,000 per day = 36.5% APR (0.1% / day × 365)

See the campaign configuration reference for the full mapping.

CLAMM campaigns. Concentrated-liquidity campaigns can't use fixed reward rates — distribution depends on token0/token1 and fees (v3) or liquidity contribution (v4), not dollar values. For these, use a variable rate with a generous budget and renormalize downstream based on the TVL during the period.

Once created, point campaigns appear in the Points section of the Merkl app.

The point tokens you "distribute" are non-transferable. Users cannot claim them through the Merkl UI — they exist purely as the accounting unit for indexing.

Numbers shown in the Merkl app are informational only. Leaderboards and totals displayed in the Merkl frontend are not the canonical source of points — your own UI and database are. Projects routinely adjust allocations before final airdrops based on their own rules.

Filter creator addresses. For fixed-reward-rate campaigns, any unallocated points at the end of the campaign are credited to the creator address. Always exclude creator addresses from your leaderboards when consuming API data.

2. Pull the indexing results from the API

Once campaigns are running, you pull two things from the Merkl API:

  • The list of addresses that earned point tokens.
  • Each address's amount, in point-token units (a relative measure of their contribution).

That's the raw input for your point system — nothing more.

Update cadence. API values refresh roughly every 2 hours under normal conditions, in line with Merkl's reward computation cycle. If a campaign hits a delay or invariant issue, values pause until the next successful computation. Status: Merkl status page.

Total per user. For each address, sum the amount and pending fields:

totalPoints (in point-token units) = amount + pending

The distinction between amount and pending matters for real reward distribution but is irrelevant for indexing — both are computed values you can use immediately.

The Merkl API integration page covers all the relevant routes. The most useful for point programs:

  • All your campaignsGET /v4/campaigns?creatorAddress=<YOUR_ADDRESS> (example)
  • Per-campaign breakdownGET /v4/rewards?chainId=<chain>&campaignId=<id> (example)
  • Aggregate by point tokenGET /v4/rewards/token/?chainId=<chain>&address=<point_token> returns every address ever rewarded with that token across all your campaigns (example). Note: cancelled campaigns also appear here, so filter or renormalize accordingly.

chainId refers to the point token's chain, not the activity chain.

If your point token is deployed on Gnosis (chainId: 100), use chainId=100 in API calls — even when your campaigns are tracking activity on other chains. Merkl groups rewards by the reward token's deployment chain.

3. Renormalize into points

This is the step where Merkl numbers become your points.

The API gives you point-token units. To turn them into the points your users see, you apply whatever logic your program needs — typically:

  • Per-campaign multipliers — e.g. campaign A at x1, campaign B at x5.
  • Per-user adjustments — exclude addresses, cap individuals, boost specific cohorts.
  • Cross-campaign aggregation — sum across campaigns, weight differently per asset, blend with offchain data.
  • Cleanups — drop cancelled campaigns, filter creator addresses, handle outliers.

Worked example: campaign A and campaign B each emit 1 point token per $1,000 deposited, but you want B's protocol to count 5× more. If address 0xabc earned 2 point tokens from B, you credit them 2 × 5 = 10 points from B (plus whatever they earned from A at x1).

If renormalization later feels redundant for a given campaign, you can bake the multiplier into the campaign's reward rate up front — but most teams find it easier to keep all campaigns at a flat rate and apply multipliers in the consumption layer, where they're easy to change.

Cancelled campaigns. Their numbers still appear in some API routes. Either filter them out at consumption time, or renormalize their contributions explicitly.

4. Display points in your own UI

Your frontend renders points from your own database, populated from the renormalized Merkl data. A leaderboard, a dashboard, an account page — whatever fits your program. The Merkl app's points section is purely informational and should not be presented to your users as the canonical view.

5. Run your airdrop

When you're ready to convert points into real rewards, export the renormalized list and use it as input for an airdrop campaign on Merkl.

Pricing

Indexing campaigns are priced per point source (the specific pool, market, vault, or contract being tracked).

Standard campaigns

  • $30 per week per point source configurable via the Merkl UI
  • + $0.015 per recipient if a campaign has more than 500 recipients

Advanced campaigns

  • $300 one-time setup fee for campaigns requiring custom development (e.g. net-lending on Aave)
  • $30 per week ongoing, same as standard

What counts as a point source? A specific opportunity Merkl is monitoring — e.g. one Uniswap pool, one Morpho market, one staking contract.

Cost optimization

  • Longer durations beat short renewals — the per-recipient fee applies once per campaign, so fewer, longer campaigns are cheaper.
  • Lean on forwarders — one campaign on a token can cover users across multiple downstream protocols, instead of one campaign per protocol.
  • Free TGE distribution — if you use Merkl post-TGE to incentivize the same token, your TGE airdrop is included.

Invoicing

Billing cycle. Invoiced retroactively at month end for every campaign run during the month. Campaigns cancelled shortly after creation are usually waived as a goodwill gesture; close-to-a-full-week ones are billed.

Payment terms. 7 days. Late payment pauses ongoing campaigns and temporarily blocks new ones until resolved.