Surface Map
Access Rules
- A wallet with Mainnet access never needs a code. Access is lasting: once a wallet has redeemed a code it keeps signing in without one, and only deactivating the wallet blocks it. A wallet that signed in while invite mode was off also has access.
- A wallet without access needs a code, existing accounts included. An account that never received access is refused like a new wallet.
- A code is only redeemed when it is needed. For a wallet that already has access, a code passed to sign-in is neither checked nor redeemed. For a wallet without access while invite mode is off, the code is not redeemed (the sign-in grants access on its own), but it still goes through the invite-attempt checks: it can be refused with
429while this wallet or client address is in its cooldown, or503when codes cannot be validated right now. - A code redeems once. It is a bearer secret: whoever signs in with it first gets access, and it is then spent.
Sign-In With a Code
Sign in without a code first. If the wallet has no access, the sign-in is refused with403 and the stable code INVITE_CODE_REQUIRED, read from APIError.serverCode. Show a code-entry step and sign in again with the code.
login call creates a new challenge and asks the wallet to sign it again, so a code retry is a second wallet prompt. If the user arrived with a code (for example from a ?invite= link your app defines), you can pass it on the first sign-in to save that prompt; a wallet that already has access skips the code entirely. A wallet without access sends the code through the invite-attempt checks even while invite mode is off, so on a 429 or 503 from that first attempt, retry without the code before showing the refusal.
Refusals to Handle
Codes are exactly 10 case-sensitive letters or digits. Check the format before submitting, and never change the case of what the user typed: a malformed code is refused as
INVITE_CODE_INVALID and counts toward the cooldown like a wrong one.
React
useAuth().login takes the same inviteCode option, reading clientId from the provider. The refusal is the same APIError:
Share Invite Codes
A signed-in wallet with Mainnet access has an allowance of codes: one initial code, plus one more per 250,000 USDC of Mainnet volume. Two signed calls back an “invite friends” panel:listInviteCodes()reads the allowance and the codes the wallet minted, newest first. It never mints a code or uses a slot, so call it on page load and poll it to show progress toward the next code. It also recovers a code whose mint response was lost.requestInviteCodes()mints one code and uses up a slot. Call it only when the user asks for a new code, never on page load. When the allowance is used up it returns nocode.
useAuth() returns the same listInviteCodes and requestInviteCodes.
- An entry’s
statusisissued,redeemedorrevoked. Only anissuedentry carries itscode; a redeemed or revoked one shows itsmilestoneand dates only. milestone0is the initial code; milestone N is the Nth 250,000 USDC of volume.- A revoked code never refunds its slot.
mainnetVolumeUsdis a decimal string. Format it for display; do not parse it as a float for comparisons.
403: they act for the owner wallet only. requestInviteCodes also needs the wallet to have active Mainnet access. Both return 503 when invite codes are temporarily unavailable; retry. See Mainnet Invite Codes for the full response shapes and error list.
Handling Codes Safely
- A code is a bearer secret until it is redeemed. Never log it, send it to analytics, or include it in error reports, and do not store the codes from
listInviteCodesbeyond the session: read them again when you need them. - Do not put a code in a URL your app sends to third parties (referrer headers, link previews). If you support invite links, read the code from the link on arrival and drop it from the address bar.

