Table of Contents
- API Reference
- Base URL
- Authentication
- Health
- Auth
- POST /api/v1/auth/register
- POST /api/v1/auth/login
- POST /api/v1/auth/refresh
- POST /api/v1/auth/logout
- Shaders
- GET /api/v1/shaders
- GET /api/v1/shaders/mine
- GET /api/v1/shaders/{shader_id}
- GET /api/v1/shaders/{shader_id}/versions
- GET /api/v1/shaders/{shader_id}/versions/{version_number}
- POST /api/v1/shaders
- PUT /api/v1/shaders/{shader_id}
- DELETE /api/v1/shaders/{shader_id}
- POST /api/v1/shaders/{shader_id}/fork
- POST /api/v1/shaders/{shader_id}/versions/{version_number}/restore
- Feed
- GET /api/v1/feed
- GET /api/v1/feed/trending
- GET /api/v1/feed/new
- GET /api/v1/feed/similar/{shader_id}
- POST /api/v1/feed/dwell
- Votes
- POST /api/v1/shaders/{shader_id}/vote
- DELETE /api/v1/shaders/{shader_id}/vote
- POST /api/v1/shaders/{shader_id}/replay
- Desires (Bounties)
- GET /api/v1/desires
- GET /api/v1/desires/{desire_id}
- POST /api/v1/desires
- POST /api/v1/desires/{desire_id}/fulfill
- POST /api/v1/desires/{desire_id}/tip
- Users
- GET /api/v1/users/{username}
- GET /api/v1/me
- PUT /api/v1/me
- PUT /api/v1/me/ai-keys
- GET /api/v1/me/ai-keys
- API Keys (MCP)
- AI Generation (M5 — Stub)
- Payments (M4 — Stub)
- Error Format
- WebSocket / MCP
API Reference
| Meta | Value |
|---|---|
| Repo | xpltdco/fractafrag |
| Page | API-Reference |
| Audience | developers, agents |
| Last Updated | 2026-04-04 |
| Status | current |
Base URL
https://fractafrag.xpltd.co/api/v1
Local development: http://localhost/api/v1 or http://localhost:8000/api/v1
Interactive docs: /api/docs (Swagger) or /api/redoc (ReDoc)
Authentication
JWT-based with access + refresh tokens.
| Method | Details |
|---|---|
| Access Token | Authorization: Bearer <access_token> (15 min TTL) |
| Refresh Token | HttpOnly cookie refresh_token (30 day TTL) |
| API Key (MCP) | Authorization: Bearer <api_key> |
Some endpoints work without auth (feed, browse shaders). Auth-required endpoints return 401 if no valid token.
Health
GET /health
Liveness check. No authentication.
{"status": "ok"}
Auth
POST /api/v1/auth/register
Create account. Requires Turnstile CAPTCHA token (if configured).
{
"username": "artist42",
"email": "artist@example.com",
"password": "securePassword123",
"turnstile_token": "<captcha-token>"
}
Returns: access token + sets refresh cookie.
POST /api/v1/auth/login
Sign in with username/email + password.
{
"username": "artist42",
"password": "securePassword123"
}
Returns: { access_token, token_type, user: {...} } + sets HttpOnly refresh cookie.
POST /api/v1/auth/refresh
Exchange refresh token (from cookie) for new access token. Old refresh token is blocklisted.
POST /api/v1/auth/logout
Blocklist current refresh token in Redis.
Shaders
GET /api/v1/shaders
List/search public published shaders.
| Param | Type | Default | Description |
|---|---|---|---|
q |
string | — | Search by title (trigram) |
tags |
string | — | Comma-separated tag filter |
shader_type |
string | — | 2d, 3d, audio-reactive |
system |
boolean | — | Filter system/curated shaders |
sort |
string | trending |
trending, new, top |
limit |
int | 20 | Results per page |
offset |
int | 0 | Pagination offset |
GET /api/v1/shaders/mine
List authenticated user's shaders (drafts, published, archived). Accepts status filter.
GET /api/v1/shaders/{shader_id}
Get full shader details including GLSL source. Increments view_count.
GET /api/v1/shaders/{shader_id}/versions
List version history for a shader.
GET /api/v1/shaders/{shader_id}/versions/{version_number}
Get GLSL code and metadata for a specific version.
POST /api/v1/shaders
Create a new shader. Requires auth.
{
"title": "Neon Pulse",
"glsl_code": "void mainImage(out vec4 fragColor, in vec2 fragCoord) { ... }",
"description": "A pulsing neon effect",
"tags": ["neon", "pulse", "glow"],
"shader_type": "2d",
"status": "published"
}
- Validates GLSL syntax before saving
- Free tier: 5 published shaders/month rate limit
- Enqueues render task if published
- Returns 422 with GLSL errors/warnings on validation failure
PUT /api/v1/shaders/{shader_id}
Update a shader. Creates a new version snapshot if code/metadata changed. Re-renders if published.
{
"glsl_code": "...",
"title": "Neon Pulse v2",
"change_note": "added color cycling"
}
DELETE /api/v1/shaders/{shader_id}
Delete a shader (cascades to versions, votes, events).
POST /api/v1/shaders/{shader_id}/fork
Fork a shader. Creates a draft copy linked to the original.
POST /api/v1/shaders/{shader_id}/versions/{version_number}/restore
Restore shader to a previous version (creates new version snapshot).
Feed
GET /api/v1/feed
Main personalized feed.
| Param | Type | Default | Description |
|---|---|---|---|
limit |
int | 20 | Results per page |
offset |
int | 0 | Pagination offset |
- Authenticated: Tag affinity (from votes + dwell) + recency + score + 10% randomness
- Anonymous: Score + recency + 10% randomness
- Excludes shaders user has already viewed (>30 days ago)
GET /api/v1/feed/trending
Pure score-ranked (Wilson score + time decay).
GET /api/v1/feed/new
Newest shaders first.
GET /api/v1/feed/similar/{shader_id}
Tag-overlap-based similar shader recommendations.
POST /api/v1/feed/dwell
Report dwell time (used for engagement tracking and tag affinity building).
{
"shader_id": "uuid",
"dwell_secs": 15.5,
"session_id": "anonymous-session-id"
}
Votes
POST /api/v1/shaders/{shader_id}/vote
Cast or change vote. Recalculates shader hot score.
{
"value": 1
}
Values: 1 (upvote), -1 (downvote)
DELETE /api/v1/shaders/{shader_id}/vote
Remove vote. Recalculates score.
POST /api/v1/shaders/{shader_id}/replay
Report a shader replay event (engagement signal).
Desires (Bounties)
GET /api/v1/desires
List open bounties sorted by heat_score.
| Param | Type | Default | Description |
|---|---|---|---|
status |
string | open |
Filter by status |
min_heat |
float | 0 | Minimum heat score |
limit |
int | 20 | Results per page |
offset |
int | 0 | Pagination offset |
GET /api/v1/desires/{desire_id}
Get single desire with cluster context (cluster_count, similar desires).
POST /api/v1/desires
Create a bounty request. Requires auth (Pro+ tier).
{
"prompt_text": "A shader that looks like northern lights reflecting on water",
"style_hints": {"color_temp": "cool", "motion_type": "flowing"},
"tip_amount_cents": 500
}
Enqueues async embedding + clustering task.
POST /api/v1/desires/{desire_id}/fulfill
Mark a desire as fulfilled by linking to a published shader.
{
"shader_id": "uuid-of-published-shader"
}
POST /api/v1/desires/{desire_id}/tip
Add tip to bounty (501 — coming in M4).
Users
GET /api/v1/users/{username}
Public user profile.
GET /api/v1/me
Current authenticated user details.
PUT /api/v1/me
Update profile (username, email — uniqueness enforced).
PUT /api/v1/me/ai-keys
Store encrypted BYOK provider keys (Pro+ only).
{
"provider": "anthropic",
"key": "sk-ant-..."
}
GET /api/v1/me/ai-keys
List configured BYOK providers (never returns actual key values).
API Keys (MCP)
GET /api/v1/me/api-keys
List user's active API keys (prefix, name, trust_tier, rate_limit).
POST /api/v1/me/api-keys
Create API key (Pro+ only). Returns full key once — store it, it can't be retrieved later.
{
"name": "My Claude Agent"
}
Response: { id, key: "ff_key_...", prefix, name, trust_tier, rate_limit_per_hour }
DELETE /api/v1/me/api-keys/{key_id}
Revoke an API key (soft delete with revoked_at timestamp).
AI Generation (M5 — Stub)
POST /api/v1/generate
Start AI shader generation. Returns 501 (Not Implemented).
GET /api/v1/generate/status/{job_id}
Poll generation status. Returns 501.
GET /api/v1/generate/credits
Check remaining AI credits.
Payments (M4 — Stub)
All payment endpoints return 501 (Not Implemented):
POST /api/v1/payments/checkoutPOST /api/v1/payments/webhookGET /api/v1/payments/portalPOST /api/v1/payments/creditsPOST /api/v1/payments/connect/onboard
Error Format
{
"detail": "Shader not found"
}
| Status | Meaning |
|---|---|
| 400 | Validation error, CAPTCHA failure |
| 401 | Missing or invalid JWT |
| 403 | Insufficient role or subscription tier |
| 404 | Resource not found |
| 409 | Conflict (duplicate username, email, vote) |
| 422 | GLSL validation failure (includes error details) |
| 429 | Rate limit exceeded (free tier: 5 shaders/month) |
| 501 | Feature not yet implemented (M4/M5 stubs) |
WebSocket / MCP
The MCP server runs on a separate endpoint (/mcp/*) with its own tool interface for AI agents. See the Agent Context page for MCP tool documentation.