Developer

SpiritDAO: API Surface (Developer Documentation)

Audience: developers and integrators. This document maps the server-side API surface: how it authenticates, how it's rate-limited, and what the main route groups do.

Scope note: This is public-safe documentation. It describes the route surface and auth model conceptually. It omits exact authorization-gate logic, RLS policy details, and admin-only internals.


Shape of the API

The API is implemented as Next.js App Router route handlers under src/app/api/*. There are roughly 136 route files organized into about 36 groups (one folder per group). Each route.ts exports the HTTP verbs it supports (GET, POST, etc.).


Auth model

Most routes require a Supabase JWT Bearer token (issued at sign-in; see 01-identity-and-auth.md). The token carries a wallet_address claim, and that claim drives Row-Level Security on every Supabase query the route makes, so a route inherits per-wallet data scoping for free (see 05-data-model-and-rls.md).

A few routes are intentionally public (e.g. hat-registry lookup, the Sensemaker assistant) and a few are service-to-service (webhooks, cron).


Rate limiting

Sensitive routes are rate-limited via Upstash Redis (src/lib/ratelimit.ts), using sliding-window limiters with graceful fallback: if Redis is unavailable, the limiter fails open rather than blocking the app. Representative limits:

LimiterLimitWhy
sensemaker10 / minabuse protection on the public AI assistant
airdrop3 / hrprevents spam of gas-sponsored mints
notifications100 / hrcaps notification/push fan-out per sender
bountyCreate10 / hrcaps bounty creation per wallet

The canonical on-chain write pattern

Many routes that touch the chain follow the gasless write triad from 00-architecture-overview.md:

authorize (server verifies hat, returns calldata)
   → sendUserOperation (client smart wallet, gas sponsored by paymaster)
      → dbUpdate (server records result by txHash)

Routes named …/authorize, …/dbUpdate, or returning calldata are part of this pattern. The on-chain leg always runs on the caller's smart wallet, never an admin EOA.


Main route groups

GroupPurpose
/authWallet auth, JWT issuance, multi-device linking
/podsPod CRUD, review, permissions, role sync
/governanceProposals, vote recording, thresholds
/bountyCreate / bid / assign / work / dispute / treasury-distribute
/eventsEvent creation, calendar, check-in
/donationsStripe checkout → $SYSTEM minting flow
/webhooks/stripePayment settlement + downstream minting
/claimsBurn $SYSTEM to claim fiat
/self$SELF holdings, mint-batch processing
/admin/selfAdmin-side $SELF operations
/marketplaceListings, accessibility, search
/chat-messages, /chat-groupsGroup/DM chat messages and group management
/forumThreads, posts, categories, reactions
/giftsToken gifting: primarily $SYSTEM (see note below)
/notificationsIn-app notifications + /send web-push
/conferenceLiveKit tokens, room lifecycle, host-action
/hat-registryPublic hat-ID lookup (cached)
/inviteInvite-code validation
/onboardingMint Proof of Curiosity + Advocate credential
/community-agentPer-pod agent config, corpus, and subscribe (paid tier: 25 $SYSTEM/month, on-chain verified, pause/resume)
/sensemakerPublic Q&A assistant: chat, logging, health
/cronScheduled jobs

Note on /gifts

Gifting is primarily a $SYSTEM operation. Because $SELF is soulbound, it can only be earned or burned (never transferred), so it cannot be gifted wallet-to-wallet. Treat $SYSTEM as the giftable token; any $SELF "gifting" surface is constrained accordingly. See 03-tokens-and-treasury.md.


Where to go next