Skip to main content
This guide wires referrals into your product: capture the code from a link, bind the referee before their first deposit, show referrers what they have earned, and let them claim. The rules behind each step (global binds, the pool cap, the claim window) are in How Referrals Work.
Referrals need SDK 0.3.0 or later. Both the referee and the referrer must have wallets linked to a Rabbithole account; binds between unlinked wallets are rejected.

The Flow

  1. Capture the referral code from the link: a wallet address or a Rabbithole username.
  2. Bind the referee with a signed message, before they sign their first deposit.
  3. Show the referrer their per-campaign earnings.
  4. Claim each payout once its campaign has finalized, before the claim window closes.

Capture the Code

A referral link carries the referrer’s address or their Rabbithole username. Neither is a secret, and there is nothing to register. Read it however your routing works, and keep it until the user deposits:
The SDK’s bind takes an address, because the referee signs over the address. When the link carries a username, resolve it to the account’s payout wallet with the transport escape hatch first:
Usernames are 3 to 20 lowercase letters, digits, or underscores, and never change. The payout wallet behind a username can be re-pointed, though, so resolve at bind time rather than caching the address.

Bind Before the Deposit

The referee’s wallet signs an EIP-712 message and the SDK submits it. The wallet can be on any network: the message has no chainId, because a bind applies to every campaign on every chain.
Where to call it. Put the bind in your deposit flow, right before the user signs the deposit transaction. A bind made after the referee has entered a campaign is stored, but earns the referrer nothing in that campaign. The server allows five minutes of grace for a deposit that lands just before its bind, and no more.
Binding is one extra signature, and it is free: no gas, no transaction. If you only want to ask once, skip the prompt for wallets you have already bound. A repeat bind to the same referrer is harmless and returns created: false.

Handle Rejections

Rejections are TbiApiErrors with a machine-readable code. None of them should block the deposit itself; the user can still deposit, they just will not be attributed.
Two failures happen in the SDK before the wallet is asked to sign: a walletClient with no account, and a deadline that is already past or more than an hour away. The default deadline is ten minutes from now, so you only hit the second one if you pass your own.
Only EOA signatures are accepted. A smart-contract wallet that signs through EIP-1271 cannot bind today, so check for that case before you prompt for a signature you know will be rejected.

Signing Outside viem

Build the exact payload with referralBindTypedData, sign it with the referee’s EOA through your own stack, and submit the signed fields with submitBind:
The domain is { name: "Boost TBI Referrals", version: "1" } with no chainId, and the message type is ReferralBind { address referrer; uint256 deadline }. Sign referrer exactly as you submit it. Over raw REST, deadline travels as a decimal string.

Show Earnings

referrals.stats returns one entry per campaign where the referrer has counted referees:
Pass { chainId } as the second argument to limit the list to one reward chain. How to present the two states:
  • "estimated": the campaign is live. Label the number as an estimate. It moves with your referees’ earnings and with every other referrer’s, because all of them share one pool.
  • "final": the payout is settled. Once claimWindowEnd is set, the payout is claimable until then. Show the deadline next to the button.
claimTxHash and claimedAt mark a payout as claimed, but they trail the chain by the indexer’s confirmation delay. Use them for history, not to gate the button.

Claim the Payout

Referral payouts have their own claim flow. tbi.claim and tbi.claimAll do not apply.

Fetch the Proof

What comes back:

Gate, Simulate, Submit

The SDK throws TbiClaimError before submitting when the wallet is on the wrong chain, the proof does not match the campaign or referrer, the root is not published yet, or the payout is zero. simulate reports those last two as willSucceed: false instead of throwing. Claiming is permissionless: any wallet can submit, and the tokens always go to the referrer in the proof. That makes relayer-sponsored claims work out of the box.

Non-viem Stacks

to is the TBI Manager, not the distributor. The distributor only accepts calls from the Manager.

After the Claim

As with reward claims, do not re-read the API to decide whether the claim went through. Mark the payout claimed once you have a receipt, or read claimed(referrer) on proof.distributorAddress for the authoritative answer. See Referral Claims.

Keep Exploring

How Referrals Work

Binding rules, the pool cap, and the claim window.

Errors

Every bind rejection code and what it means.

Contracts

claimReferral and the distributor’s revert selectors.