> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rabbithole.gg/llms.txt
> Use this file to discover all available pages before exploring further.

# Bind a referee wallet to a referrer

> Accepts the referee's signed referral bind. A bind is global: it ties the referee wallet to one referrer across every campaign on every chain. A referral link carries either the referrer's wallet address (referrer) or their Rabbithole username (referrerUsername) — send exactly one. A username is resolved to that account's chosen payout wallet before anything else runs (404 REFERRER_NOT_FOUND when no account has claimed it; GET /v1/referrals/usernames/{username} performs the same resolution so a signer can obtain the address first). The server canonicalizes smart-wallet proxies (Polymarket/Forkast Safe) to their owner EOA before storing. The referee signs EIP-712 typed data: domain {name: 'Boost TBI Referrals', version: '1'} (no chainId — the bind is chain-independent), type ReferralBind {referrer: address, deadline: uint256}, where referrer is the (resolved) wallet address and deadline is unix seconds at most one hour ahead; deadline travels as a decimal string because it is signed as uint256. One referrer per referee wallet — the first accepted bind wins and repeat submissions of the same bind are idempotent (created: false). A bind only earns the referrer a share in campaigns the referee first accrues rewards in after binding (no retroactive attribution; applied per campaign when the distribution is built), so existing participation never blocks a bind. Referral links only work between Rabbithole-linked wallets: the referee (403 WALLET_NOT_LINKED) and the canonicalized referrer (409 REFERRER_NOT_LINKED) must each hold an active Rabbithole wallet link, and a referrer whose wallet has ever been linked to the same Rabbithole account as the referee is a self-referral (400 SELF_REFERRAL). Referral loops are rejected (409 CYCLIC_REFERRAL): a bind whose referrer is already referred by the referee, directly (A refers B, B refers A) or through a chain of binds (A refers B, B refers C, C refers A), is refused. Alternatively, Rabbithole sessions bind without the deadline/signature fields by sending a Clerk session token as an Authorization bearer; the server verifies the token and requires the referee's active wallet link to belong to that Clerk user (401 INVALID_SESSION / 403 WALLET_NOT_LINKED otherwise).



## OpenAPI

````yaml https://api-tbi.boost.xyz/v1/openapi.json post /v1/referrals/bind
openapi: 3.1.0
info:
  title: Boost Time-Based Incentives SDK API
  version: 1.0.0
  description: >-
    Public /v1 API surface for the Boost TBI SDK. Internal Rabbithole, admin,
    Polymarket, and widget routes are intentionally excluded.
servers:
  - url: https://api-tbi.boost.xyz
    description: Production
  - url: http://localhost:3000
    description: Local development
security: []
tags:
  - name: Campaigns
    description: Campaign discovery, detail, and stats endpoints.
  - name: Claims
    description: Claim proof and claim status endpoints.
  - name: Forwarder
    description: Boost Forwarder target discovery and direct deposit transaction builders.
  - name: Referrals
    description: >-
      Referral attribution: global referee → referrer binds, per-campaign
      referrer earnings, and claim proofs.
  - name: Users
    description: User rewards and balance endpoints.
paths:
  /v1/referrals/bind:
    post:
      tags:
        - Referrals
      summary: Bind a referee wallet to a referrer
      description: >-
        Accepts the referee's signed referral bind. A bind is global: it ties
        the referee wallet to one referrer across every campaign on every chain.
        A referral link carries either the referrer's wallet address (referrer)
        or their Rabbithole username (referrerUsername) — send exactly one. A
        username is resolved to that account's chosen payout wallet before
        anything else runs (404 REFERRER_NOT_FOUND when no account has claimed
        it; GET /v1/referrals/usernames/{username} performs the same resolution
        so a signer can obtain the address first). The server canonicalizes
        smart-wallet proxies (Polymarket/Forkast Safe) to their owner EOA before
        storing. The referee signs EIP-712 typed data: domain {name: 'Boost TBI
        Referrals', version: '1'} (no chainId — the bind is chain-independent),
        type ReferralBind {referrer: address, deadline: uint256}, where referrer
        is the (resolved) wallet address and deadline is unix seconds at most
        one hour ahead; deadline travels as a decimal string because it is
        signed as uint256. One referrer per referee wallet — the first accepted
        bind wins and repeat submissions of the same bind are idempotent
        (created: false). A bind only earns the referrer a share in campaigns
        the referee first accrues rewards in after binding (no retroactive
        attribution; applied per campaign when the distribution is built), so
        existing participation never blocks a bind. Referral links only work
        between Rabbithole-linked wallets: the referee (403 WALLET_NOT_LINKED)
        and the canonicalized referrer (409 REFERRER_NOT_LINKED) must each hold
        an active Rabbithole wallet link, and a referrer whose wallet has ever
        been linked to the same Rabbithole account as the referee is a
        self-referral (400 SELF_REFERRAL). Referral loops are rejected (409
        CYCLIC_REFERRAL): a bind whose referrer is already referred by the
        referee, directly (A refers B, B refers A) or through a chain of binds
        (A refers B, B refers C, C refers A), is refused. Alternatively,
        Rabbithole sessions bind without the deadline/signature fields by
        sending a Clerk session token as an Authorization bearer; the server
        verifies the token and requires the referee's active wallet link to
        belong to that Clerk user (401 INVALID_SESSION / 403 WALLET_NOT_LINKED
        otherwise).
      operationId: bindReferral
      parameters:
        - name: X-Boost-Ref-Id
          in: header
          required: false
          description: >-
            Optional partner attribution reference ID. Values are manually
            assigned by Boost and must be at most 128 characters.
          schema:
            type: string
            minLength: 1
            maxLength: 128
            pattern: ^[A-Za-z0-9][A-Za-z0-9._:-]*$
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReferralBindRequest'
      responses:
        '200':
          description: Stored referral bind
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReferralBind'
        '400':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/V1ErrorResponse'
        '401':
          description: Invalid or expired signature
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/V1ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/V1ErrorResponse'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/V1ErrorResponse'
        '409':
          description: Conflicting state
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/V1ErrorResponse'
        '429':
          description: Rate limited
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/V1ErrorResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/V1ErrorResponse'
components:
  schemas:
    ReferralBindRequest:
      type: object
      properties:
        referee:
          type: string
        referrer:
          type: string
        referrerUsername:
          type: string
          pattern: ^[a-z0-9_]{3,20}$
        deadline:
          type: string
          maxLength: 20
          pattern: ^(0|[1-9]\d*)$
        signature:
          type: string
          maxLength: 4096
          pattern: ^0x[0-9a-fA-F]+$
      required:
        - referee
      additionalProperties: false
      oneOf:
        - required:
            - referrer
        - required:
            - referrerUsername
    ReferralBind:
      type: object
      properties:
        referee: {}
        referrer: {}
        boundAt:
          type: string
          pattern: ^(0|[1-9]\d*)$
        created:
          type: boolean
      required:
        - referee
        - referrer
        - boundAt
        - created
      additionalProperties: false
    V1ErrorResponse:
      type: object
      properties:
        error:
          type: string
        code:
          type: string
          enum:
            - INVALID_PARAMS
            - NOT_FOUND
            - RATE_LIMITED
            - INTERNAL_ERROR
            - INVALID_SIGNATURE
            - SELF_REFERRAL
            - ALREADY_BOUND
            - INVALID_SESSION
            - WALLET_NOT_LINKED
            - REFERRER_NOT_LINKED
            - CYCLIC_REFERRAL
            - REFERRER_NOT_FOUND
        details:
          anyOf:
            - {}
            - type: 'null'
      required:
        - error
        - code
        - details
      additionalProperties: false

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.