Create API-Reference wiki page for fractafrag

xpltd_admin 2026-04-03 22:51:34 -06:00
parent 1c4977a166
commit c640f13e15

383
API-Reference.-.md Normal file

@ -0,0 +1,383 @@
# 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.
```json
{"status": "ok"}
```
---
## Auth
### `POST /api/v1/auth/register`
Create account. Requires Turnstile CAPTCHA token (if configured).
```json
{
"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.
```json
{
"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.
```json
{
"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.
```json
{
"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).
```json
{
"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.
```json
{
"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).
```json
{
"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.
```json
{
"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).
```json
{
"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.
```json
{
"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/checkout`
- `POST /api/v1/payments/webhook`
- `GET /api/v1/payments/portal`
- `POST /api/v1/payments/credits`
- `POST /api/v1/payments/connect/onboard`
---
## Error Format
```json
{
"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](Agent-Context) page for MCP tool documentation.