HTTP API reference
The Fastify API listens on port 4000 by default. In production the Next.js application proxies /api/v1/* to the private API service. JSON is used for request and response bodies.
Conventions
- Validation failures return
400with anerrorcode; some endpoints include Zoddetails. - Unconfigured or unavailable identity dependencies return
503. - Identity endpoints use the
raidz_sessioncookie. If a valid session does not exist, the API creates a user/profile/session and sends an HttpOnly, SameSite=Lax cookie, Secure in production, with a 30-day maximum age. - Challenge IDs are UUIDs and expire after five minutes.
- Current CORS configuration does not grant cross-origin browser access.
Health
GET /health
Liveness only. Does not check PostgreSQL.
{ "status": "ok" }
GET /ready
Runs dependency checks, currently PostgreSQL by default. Returns 200 {"status":"ready"} or 503 {"status":"not_ready"}. Both health endpoints set Cache-Control: no-store.
Score
POST /v1/score/preview
Calculates Raidz Score V0 without persistence. Supply eleven numeric signals, completedCampaigns, and evidence for every component.
{
"accountMaturity": 80,
"audienceQuality": 75,
"realReach": 70,
"contentQuality": 85,
"topicRelevance": 90,
"socialScale": 60,
"campaignPerformance": 0,
"conversionPerformance": 0,
"reliability": 0,
"marketplaceRatings": 0,
"verificationSignals": 0,
"completedCampaigns": 0,
"evidence": {
"accountMaturity": { "sourceTimestamp": "2026-09-03T00:00:00.000Z", "confidence": 0.9, "explanationReason": "Account age and continuity" },
"audienceQuality": { "sourceTimestamp": "2026-09-03T00:00:00.000Z", "confidence": 0.7, "explanationReason": "Sampled audience quality" },
"realReach": { "sourceTimestamp": "2026-09-03T00:00:00.000Z", "confidence": 0.7, "explanationReason": "Recent median reach" },
"contentQuality": { "sourceTimestamp": "2026-09-03T00:00:00.000Z", "confidence": 0.7, "explanationReason": "Original content review" },
"topicRelevance": { "sourceTimestamp": "2026-09-03T00:00:00.000Z", "confidence": 0.8, "explanationReason": "Web3 topic fit" },
"socialScale": { "sourceTimestamp": "2026-09-03T00:00:00.000Z", "confidence": 0.9, "explanationReason": "Normalized scale" },
"campaignPerformance": { "sourceTimestamp": "2026-09-03T00:00:00.000Z", "confidence": 0, "explanationReason": "No completed Raidz campaign" },
"conversionPerformance": { "sourceTimestamp": "2026-09-03T00:00:00.000Z", "confidence": 0, "explanationReason": "No consented outcome history" },
"reliability": { "sourceTimestamp": "2026-09-03T00:00:00.000Z", "confidence": 0, "explanationReason": "No platform history" },
"marketplaceRatings": { "sourceTimestamp": "2026-09-03T00:00:00.000Z", "confidence": 0, "explanationReason": "No platform ratings" },
"verificationSignals": { "sourceTimestamp": "2026-09-03T00:00:00.000Z", "confidence": 0, "explanationReason": "No additional verification" }
}
}
The response contains score, tier, performanceShare, all normalized components plus evidence, and version. Numeric signals are clamped to 0–100; evidence confidence is validated within 0–1.
Campaign policy
POST /v1/campaigns/preflight
{
"channel": "x",
"jurisdiction": "US",
"category": "web3 product",
"text": "Publish one original, clearly disclosed product review.",
"compensated": true
}
Channels are x, telegram, web, onchain, or event. The response is ELIGIBLE or BLOCKED, a unique list of reason codes, and the policy version.
Missions
GET /v1/missions
Currently returns an empty live dataset:
{
"data": [],
"source": "database",
"live": false,
"notice": "No funded campaigns are represented by fixtures."
}
Profile and providers
GET /v1/profile
Returns the current profile and provider availability. x and telegram are true only when their necessary runtime configuration exists; wallet linking is available. Telegram bot ID and username may be returned as public configuration.
PATCH /v1/profile
All fields are optional: displayName, bio, locale, jurisdiction, languages, regions, narratives, availability, and profileVisibility. Collection sizes and string lengths are bounded by the route schema.
Wallet ownership
POST /v1/auth/wallet/challenge
{ "address": "0x1111111111111111111111111111111111111111", "chainId": 4663 }
Returns challengeId, the exact message to sign, expiry, and chain ID. Any other chain returns WRONG_CHAIN.
POST /v1/auth/wallet/verify
{
"challengeId": "00000000-0000-4000-8000-000000000000",
"address": "0x1111111111111111111111111111111111111111",
"signature": "0x..."
}
The server checks the address against the challenge, verifies the EVM personal-message signature, atomically consumes the challenge, and links the checksummed address. Errors distinguish invalid input, expired/used challenge, wrong wallet, invalid signature, and replay.
X OAuth
GET /v1/auth/x/start
Creates a PKCE challenge and returns { "url": "https://x.com/i/oauth2/authorize?..." }. The browser must navigate to the returned URL.
GET /v1/auth/x/callback
X redirects here with code and compound state. The API validates session/state/PKCE, exchanges the code, reads the current profile, consumes the challenge, encrypts the token response, and redirects to the profile view with a success or error query.
Telegram Login
POST /v1/auth/telegram/verify
Accepts the Telegram Login payload fields id, auth_date, hash, and optional name, username, and photo URL. The signature and five-minute age are verified before the subject is pseudonymized and linked.
Disconnect
DELETE /v1/auth/:provider
provider is x, telegram, or wallet. Social links are deleted; active wallet links are marked revoked. Returns the updated profile.
Not yet exposed
There are no public endpoints yet for persistent campaign CRUD, claims, deliverables, verifier decisions, settlement, service bookings, reviews, analytics intake, Pons state, or admin operations.

ATTENTION, WITH PROOF.