Appearance
Frontend Integration Guide
The single onboarding entry point for frontend developers new to this project. For backend operations see backend/RUNBOOK.md; for module internals see backend/README.md.
Relative links are resolved against the doc/ directory.
1. The whole picture in one page
Pump Party is a game where users create clones (AI trader personas), validate them through a 6-hour audition, and later enter them into races. The v1 backend has the paid audition path and prop-account runtime mostly in place; race operations are the main missing product vertical.
User (wallet → backend)
│ SIWE login → JWT issued
▼
[Clone Service] ── clone identity, strategy graph, entitlement
│
│ pay audition fee (SignedVault on MegaETH)
▼
[Economy] ── deposit confirmation/sync → entitlement grant
│
│ start the audition
▼
[Lifecycle] ── 6h audition window → evaluator (pass / fail)
▼
[Prop Trading] ── synthetic account ($100k fake USDC), positions,
safety gates, paper fills
▲
│ AI trader proposes actions → safety gates reject policy violations →
│ surviving actions are filled at the latest Hyperliquid mid price,
│ updating the synthetic account's cash + positions
│
[AI Trading] ── model calls, prompt v1, artifact storage
│
[Public Profile] ── publishes immediately on submit. Anyone can report;
admins triage reports and can retire profiles.Each module is its own directory inside the backend (backend/src/modules/{user,clone,ai-trading,prop-trading,economy,lifecycle,data-ingestion}/) and modules talk to each other only through service interfaces. From a frontend perspective it's all one HTTP API.
2. Quickstart
For the current local app commands, frontend env, optional workers, and VitePress docs server, start with Development Quick Start.
bash
# Backend setup is in backend/RUNBOOK.md
curl http://127.0.0.1:8787/api/v1/assets # 401 expected (auth required)Smoke the documented frontend flow against a running local backend:
bash
cd backend
npm run api
# in another terminal
npm run test:smoke:frontend-flowThe smoke runner uses real SIWE auth, then walks through clone creation, strategy draft/publish, audition-fee quote, public profile, reporting, and audition submission. If local SignedVault env or a real deposit nonce is unavailable, it seeds the audition entitlement through local service auth so the lifecycle route can still be exercised. Set PUMP_PARTY_SMOKE_DEPOSIT_NONCE=<nonce> to test the real /economy/audition-fee/submit step. If the local API has PUMP_PARTY_BACKEND_SERVICE_TOKEN configured, expose the same value to the smoke runner or set PUMP_PARTY_SMOKE_SERVICE_TOKEN.
Get a JWT (or use the dev shortcut from §5):
bash
# 1) ask for a challenge
curl -X POST http://127.0.0.1:8787/api/v1/auth/siwe/challenge \
-H 'content-type: application/json' \
-d '{"address":"0x...","chainId":4326,"domain":"localhost:3000","uri":"http://localhost:3000"}'
# 2) wallet signs the returned `message`
curl -X POST http://127.0.0.1:8787/api/v1/auth/siwe/verify \
-H 'content-type: application/json' \
-d '{"message":"...","signature":"0x..."}'
# response: { accessToken, refreshToken, user, ... }Every subsequent call:
Authorization: Bearer <accessToken>3. Domain glossary
The full vocabulary lives at domain-language. The terms you'll see in conversation:
| Term | One-line definition |
|---|---|
| Clone | A user-created AI trader persona. Operational identity (owner, model, strategy) and public identity (display name / bio) are split. |
| Strategy graph / draft | The data-block graph that defines the clone's behaviour. |
| Entitlement | The model strength + concurrent asset count a clone is allowed to use. Granted by paying an audition_fee. |
| Audition | A 6-hour qualifying round the clone must clear (return target + drawdown cap). If it fails, the user pays again and retries. |
| Voided audition | A round the admin invalidates because of infrastructure failure / data outage / post-hoc moderation strike. Refunds are out of scope for v1. |
| Prop account | The synthetic (fake) trading account lifecycle creates. Starts with fake $100,000 USDC. No real assets. Every fill / position lives inside this account; nothing reaches a real exchange. |
| Position | A long/short the synthetic account is holding. Mark-to-market keeps unrealized PnL fresh. |
| Safety gates | Eleven deterministic checks that drop AI actions violating policy (allowedSymbols, maxLeverage, available balance, position caps, etc.). Surviving actions go to the filler. |
| Paper fill | The simulator does not place real exchange orders. It assumes the action filled at the latest mid price and updates the synthetic account's cash + positions. Pretend money, pretend fills. |
| Decision run / action | One AI trader cycle. If a proposed action survives the safety gates a paper fill follows. |
| SignedVault | The MegaETH ETH escrow contract. Deposits are verified on-chain; withdrawals are authorised via EIP-712 signatures. |
| Mark-to-market | Reprices every open position from the latest mid. Auto-liquidates if drawdown breaches 50%. |
4. Authentication (SIWE on MegaETH)
Supported chains: mainnet 4326, testnet 6343 (controlled by AUTH_ALLOWED_CHAIN_IDS). Both EOA wallets and Porto Relay smart wallets are supported.
The frontend may obtain the signer from an injected wallet, WalletConnect/Reown, Porto, or a Privy embedded wallet. In all cases, Pump Party auth is the SIWE message/signature verified by the backend. Do not use Privy JWTs or privy-token as Pump Party app auth.
Flow
[frontend] [backend]
│ │
│ 1) POST /auth/siwe/challenge │
│ { address, chainId, domain, uri } │
│ ─────────────────────────────────────────────► │
│ │
│ { nonce, message, expiresAt, ... } │
│ ◄───────────────────────────────────────────── │
│ │
│ 2) wallet signs `message` │
│ injected / WalletConnect / Porto / Privy │
│ │
│ 3) POST /auth/siwe/verify │
│ { message, signature } │
│ ─────────────────────────────────────────────► │
│ │
│ { accessToken, refreshToken, accessExpiresAt, │
│ refreshExpiresAt, user, isNewUser } │
│ ◄───────────────────────────────────────────── │message already contains the nonce/domain/chainId; just feed the signed result straight into verify.
After verify, use the returned Pump Party accessToken as the bearer token for product APIs. Store and rotate only the Pump Party refreshToken; Privy user ids and tokens are not canonical user identity.
Token lifetimes
- Access JWT: 24 hours by default (
AUTH_ACCESS_TTL_SECONDS). - Refresh token: 14 days by default (
AUTH_REFRESH_TTL_SECONDS). - Refresh tokens rotate: using the same refresh token twice triggers reuse-detection and revokes the whole session. Always store only the most recently issued refresh token.
Auth endpoints
POST /api/v1/auth/siwe/challenge → { message, nonce, ... }
POST /api/v1/auth/siwe/verify → { accessToken, refreshToken, user, ... }
POST /api/v1/auth/session/refresh { refreshToken } → fresh token pair
DELETE /api/v1/auth/session (Bearer) revoke session (logout)
GET /api/v1/me (Bearer) current user + primary walletFull spec: User Service Auth.
5. Dev-mode shortcut (development only)
Set AUTH_DEV_FALLBACK=true in .env and you can authenticate with a single header instead of going through SIWE:
x-user-id: dev-user-1Production ignores this regardless of value. It exists so styling / layout work doesn't get blocked on signing flows.
6. API surface catalogue
Grouped by who is allowed to call. Bearer = SIWE-logged-in users. Service token (x-service-token) = backend-to-backend calls and admin tooling.
6.1 User-facing (Bearer)
| Method | Path | Purpose |
|---|---|---|
GET | /api/v1/me | Current user + primary wallet |
GET | /api/v1/clone/clones | List clones owned by the authenticated user |
GET | /api/v1/clone/clones/:cloneId | Clone metadata |
PATCH | /api/v1/clone/clones/:cloneId | Update clone name / model / etc. |
POST | /api/v1/clone/clones/:cloneId/public-profile | Owner submit/edit public profile (name, username, description, square image URL) |
GET | /api/v1/clone/clones/:cloneId/public-profile | Owner-facing public profile read |
GET | /api/v1/clone/public-profiles | List public profiles owned by the authenticated user |
GET | /api/v1/clone/clones/:cloneId/entitlement | Current entitlement |
GET/PUT | /api/v1/clone/clones/:cloneId/strategy/draft | Work-in-progress strategy graph |
POST | /api/v1/clone/clones/:cloneId/decision-backtest | Start an async backtest |
GET | /api/v1/clone/clones/:cloneId/decision-backtest/jobs/:jobId | Poll a backtest |
POST | /api/v1/clone/clones/:cloneId/strategy/publish | Publish a new strategy version |
GET | /api/v1/clone/clones/:cloneId/strategy/versions | List strategy versions |
GET | /api/v1/clone/clones/:cloneId/strategy/versions/:strategyVersionId | One version |
POST | /api/v1/economy/audition-fee/quote | Pricing quote ({ tier, assetCapacity, modelStrength }) |
POST | /api/v1/economy/audition-fee/submit | Confirm/sync the authenticated wallet's deposit, optionally create a paid clone, and return the entitlement |
GET | /api/v1/assets | Tradeable assets |
GET | /api/v1/polymarket/markets/search?... | Polymarket search |
GET | /api/v1/defillama/subjects/search?... | DefiLlama search |
GET | /api/v1/ingestion/health | Data ingestion health |
GET | /api/v1/ingestion/dashboard | User-facing ingestion dashboard data |
6.2 Public read (no auth)
| Method | Path | Purpose |
|---|---|---|
GET | /api/v1/public/clones/:cloneId/profile | Publicly visible clone profile. Returns 404 if the profile has been retired. |
6.3 User reports (Bearer)
| Method | Path | Purpose |
|---|---|---|
POST | /api/v1/public/clones/:cloneId/report | Any user reports a public clone ({ category, detail? }). Self-reports are refused. |
6.4 Backend / admin (Service token)
These are called by ops tooling or by other backend services. The frontend does not call these directly. If the frontend needs an admin UI, route it through a BFF.
Prop trading:
POST /api/v1/prop/accounts # create
GET /api/v1/prop/accounts/:propAccountId
GET /api/v1/prop/clones/:cloneId/accounts
POST /api/v1/prop/accounts/:propAccountId/{start,complete,liquidate}
GET /api/v1/prop/accounts/:propAccountId/{ledger,snapshot,orders,fills,positions}
GET /api/v1/prop/accounts/:propAccountId/decision-context
POST /api/v1/prop/accounts/:propAccountId/decision-actions
GET /api/v1/prop/decision-actions/:propActionId
POST /api/v1/prop/accounts/:propAccountId/mark-to-market
POST /api/v1/prop/mark-to-market-allAudition lifecycle:
POST /api/v1/lifecycle/auditions # submit an audition
GET /api/v1/lifecycle/auditions/:auditionRunId
GET /api/v1/lifecycle/clones/:cloneId/auditions
POST /api/v1/lifecycle/auditions/:auditionRunId/evaluate { force? }
POST /api/v1/lifecycle/auditions/evaluate-due # cadence hook
POST /api/v1/lifecycle/auditions/:auditionRunId/void # admin: void a round ({ adminUserId, reason })Public profile + admin moderation (report-based):
GET /api/v1/admin/moderation/reports?status=open|resolved|dismissed
GET /api/v1/admin/moderation/clones/:cloneId/reports
POST /api/v1/admin/moderation/reports/:reportId/resolve # { resolutionAction: retired|dismissed|no_action, ... }
POST /api/v1/admin/moderation/clones/:cloneId/retire # direct retire ({ adminUserId, reason })
POST /api/v1/admin/moderation/clones/:cloneId/reinstate
GET /api/v1/admin/moderation/clones/:cloneId/historyProp admin (incident response):
POST /api/v1/admin/prop/accounts/:propAccountId/{pause,resume,lock,liquidate,recompute}
POST /api/v1/admin/prop/accounts/:propAccountId/{void-order,void-fill}
GET /api/v1/admin/prop/accounts/:propAccountId/audit-logInternal monitoring:
GET /api/v1/internal/health/workers # worker heartbeat summary7. End-to-end scenarios
7.1 First-time signup
1. Connect wallet → wagmi/viem
2. POST /auth/siwe/challenge → message
3. Wallet signs the message
4. POST /auth/siwe/verify → accessToken, refreshToken
5. Persist tokens in localStorage / secure storage
6. GET /me → user.id, primaryWallet
7. GET /clone/clones → load existing clones
8. POST /economy/audition-fee/quote → quote paid clone creation
9. Wallet deposits ETH to SignedVault
10. POST /economy/audition-fee/submit { createClone, depositNonce, ... }
# v1 confirmation key; future intent flow can hide the nonceRefresh both tokens just before the access token expires (e.g. 60s before) by calling POST /auth/session/refresh. Replace the stored pair with the new one.
7.2 Build a clone and run an audition
1. POST /economy/audition-fee/quote # pricing
2. Wallet deposits ETH to SignedVault (on-chain step)
3. POST /economy/audition-fee/submit { createClone, depositNonce, ... }
# confirm deposit, create clone, return entitlement
4. PUT /clone/clones/:cloneId/strategy/draft # write the graph
5. POST /clone/clones/:cloneId/decision-backtest # run a sampled AI backtest
6. POST /lifecycle/auditions { cloneId, allowedSymbols, ... }
7. (wait 6 hours — the worker auto-evaluates)
8. GET /lifecycle/auditions/:id # read the resultAudition failed (evaluator below target):
11. The user fixes the strategy and submits a new audition fee.
POST /economy/audition-fee/submit + POST /lifecycle/auditions { previousAuditionRunId }Operationally voided round:
11. POST /lifecycle/auditions/:id/void { adminUserId, reason }Public profile — instant publish, report-based moderation:
11. POST /clone/clones/:cloneId/public-profile # auto-approved → live at /public/...
12. (another user reports it) POST /public/clones/:cloneId/report
13. (admin reviews queue) GET /admin/moderation/reports?status=open
14. (admin decides) POST /admin/moderation/reports/:id/resolve
{ resolutionAction: 'retired' | 'dismissed' | 'no_action', ... }Lifecycle owner routes are now frontend-safe backend user-auth routes. Evaluator and void routes remain internal service-token routes and should not be called directly from user UI.
7.3 Live clone status
To monitor an in-flight clone:
GET /api/v1/prop/accounts/:propAccountId/snapshot → equity, drawdown, returnPct
GET /api/v1/prop/accounts/:propAccountId/positions → open positions
GET /api/v1/prop/accounts/:propAccountId/fills → recent fills
GET /api/v1/prop/accounts/:propAccountId/ledger → every event (decision/fill/mark/...)Suggested polling intervals:
- snapshot: 5–10s
- ledger: 30s+ if you only need new-action notifications
(There is no WebSocket / SSE in v1. Build polling or wrap a server-side SSE adapter if needed.)
7.4 E2E smoke test coverage
npm run test:smoke:frontend-flow is the local API smoke test for the frontend-critical route contract. It should run against an already-running backend and answer one question: can a new wallet complete the main backend flow the frontend depends on?
Covered path:
| Step | Routes | Assertion |
|---|---|---|
| Auth gate | GET /api/v1/assets without auth | Protected route returns 401 unauthorized. |
| Wallet login | POST /auth/siwe/challenge, POST /auth/siwe/verify, GET /me | Real SIWE signature returns Pump Party tokens and a primary wallet. |
| Clone setup | GET /clone/clones, POST /economy/audition-fee/submit { createClone, depositNonce, ... }, GET /clone/clones/:cloneId | A new user starts with no clones; Economy creates the clone only after the authenticated wallet deposit is confirmed. |
| Strategy loop | GET/PUT /strategy/draft, POST /decision-backtest, POST /strategy/publish | Default graph can be edited, backtested with the standard 100k USDC account, and published. |
| Payment gate | POST /economy/audition-fee/quote | Quote succeeds when SignedVault env is configured, or returns the expected local economy_unavailable error. |
| Entitlement bridge | POST /economy/audition-fee/submit | With PUMP_PARTY_SMOKE_DEPOSIT_NONCE, the real deposit confirmation path creates the clone and returns entitlement. There is no direct entitlement-write HTTP fallback. |
| Public identity | POST/GET /clone/clones/:cloneId/public-profile, GET /public/clones/:cloneId/profile | Owner publishes a profile and public read returns it. |
| Reporting | POST /public/clones/:cloneId/report | A second SIWE user can report the public clone. |
| Audition start | POST /lifecycle/auditions, GET /lifecycle/auditions/:id, GET /lifecycle/clones/:cloneId/auditions | Owner starts an audition, receives a running prop account, and can read/list the run. |
Deliberately not covered:
- Real on-chain deposit submission unless
PUMP_PARTY_SMOKE_DEPOSIT_NONCEis supplied for a deposit that matches the local SignedVault config. Without that nonce, paid clone creation is skipped instead of using a direct clone or entitlement write route. - 6-hour audition evaluation, Arena Entry promotion, and race settlement. Those are worker/service-token flows, not frontend-critical first-run routes.
- Live model-provider behavior. The smoke test is expected to work with the default noop provider so local runs are deterministic.
8. Response and error conventions
Success
Most endpoints return 200 OK with a single JSON object. Routes that create return 201 Created; idempotent re-submits return 200 and set a flag like alreadyExisted: true.
Errors
json
{
"error": {
"code": "invalid_transition",
"message": "Audition aud_xxx is in terminal status passed; cannot void"
}
}| Status | Meaning |
|---|---|
400 | Bad input (invalid_*) |
401 | Auth missing / expired / invalid |
402 | Payment required (no_audition_entitlement) |
403 | Authenticated but not authorised (forbidden) |
404 | Resource not found |
405 | Method not allowed |
409 | State conflict (already_*, concurrent_*, invalid_transition) |
422 | Business-rule violation |
503 | A dependency is not configured |
code is the stable identifier. The frontend maps codes to user-facing copy; the backend message is for operators (English, terse).
Codes worth knowing:
concurrent_submit/concurrent_create— two identical requests raced. Retry shortly.idempotency_key_*_mismatch— same idempotency key was used with a different cloneId/owner. Use a fresh key.
9. Environments
| Environment | API base | Chain | Vault |
|---|---|---|---|
| local dev | http://127.0.0.1:8787 | testnet 6343 | (after env setup) |
| staging | (deploy URL) | testnet 6343 | testnet vault |
| production | (deploy URL) | mainnet 4326 | mainnet vault |
The SIWE domain field must match the wallet-facing host exactly (localhost:3000, pumpparty.fun, etc.).
10. Reference docs
| Topic | Link |
|---|---|
| Domain vocabulary | domain-language |
| Clash of Clones product spec | clash-of-clones-product-spec |
| Backend module layout | backend/README.md |
| Backend operations (how to run it) | backend/RUNBOOK.md |
| Prop trading module contract | Prop Trading Module |
| Clone Service details | Clone Service |
| Entitlements behavior | Clone Service Module and Capacity And Model Tiers |
| All backend data contracts | backend-contract |
| Implementation roadmap / silo progress | implementation-roadmap |
11. What v1 deliberately does not include
- Race / tickets / settlement UI — held until race operations begin. Arena Entry now has backend read/sync/admin routes, but normal users still do not manage Arena slots directly.
- Personal wallet (user-level asset management) — 0%, decided alongside race.
- WebSocket / SSE — polling only.
- A user-facing clone-creation endpoint — handled by an admin / internal tool today; if a self-service flow is needed it requires backend work.
- Payment methods beyond ETH — no ERC20 / stablecoin support yet.