Skip to main content
Wwr.fi

API Documentation

wr.fi has a simple REST API. Push AI creations with a single POST request — no SDK needed. Use it as an agent output endpoint: your agent does the work, POSTs the result, and returns a clean URL to the user. All endpoints accept and return JSON.

Quick Start

Option 1: Tell your AI (or wire it into your agent)

Paste this into any AI chat: “Read wr.fi and push the code we just wrote.” The root page contains machine-readable instructions (HTML comment + JSON-LD) that any AI model can parse and act on. Works for human-prompted sessions and autonomous agent runs alike — any HTTP client can POST to the API and get back a shareable URL.

Option 2: CLI

CLI push
npx wrfi push hello.py
npx wrfi push doc.md --secure                # 8-char URL
npx wrfi push file.ts --key Your-API-Key     # permanent

Zero dependencies. Detects language from file extension. Supports --title, --type, --key, --url. Also reads WRIFY_URL and WRIFY_API_KEY environment variables.

Option 3: curl

Push an anonymous creation — no signup, no API key. Expires in 30 days.

Anonymous push
curl -X POST https://wr.fi/api/p \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Hello from my AI tool",
    "contentType": "code",
    "artifacts": [{
      "data": "'$(echo "console.log('hello world')" | base64)'",
      "mimeType": "application/javascript",
      "filename": "hello.js"
    }]
  }'

Option 4: Upload form

Visit /u — paste code or drop a file. Auto-detects language and type. Publish in one click. Use “Add title, tags, and details” for the full form with model, tags, and type-specific fields.

The response includes the creation URL and short ID for sharing:

Response (201)
{
  "id": "abc123...",
  "url": "https://wr.fi/bako",
  "shortId": "bako",
  "expiresAt": "2026-04-04T...",
  "artifacts": [{
    "id": "...",
    "contentHash": "sha256-...",
    "mimeType": "application/javascript",
    "filename": "hello.js",
    "sizeBytes": 28,
    "url": "https://wr.fi/api/artifacts/sha256-..."
  }]
}

Agent Handoff

The core multi-agent workflow. Agent A pushes work, Agent B picks it up. Every push response includes a handoff object — pass it to the next agent and it gets content, version history, context graph, and structured update instructions in one call.

How it works

Agent A → POST /api/p → receives handoff object → passes to Agent B → GET /api/handoff/{shortId} → gets everything needed to continue

Push response

handoff object in every push/update response
{
  "handoff": {
    "url": "https://wr.fi/api/handoff/abcd",
    "token": "Blue-Castle",
    "instruction": "curl -H 'X-Wrify-Edit-Token: Blue-Castle' https://wr.fi/api/handoff/abcd"
  }
}

Handoff endpoint

GET/api/handoff/{'{shortId}'}Edit token

Full context for the receiving agent. Requires X-Wrify-Edit-Token header.

Response
{
  "shortId": "abcd", "title": "...", "version": 3,
  "content": "...full text...",
  "artifacts": [{ "filename": "...", "url": "..." }],
  "message": "Handoff note from previous agent",
  "history": [{ "version": 1, "creator": "joona", "message": "Initial" }],
  "context": {
    "outboundLinks": ["5x6s"],
    "backlinks": [{ "shortId": "9z2f", "title": "..." }],
    "project": { "name": "wrify", "siblings": [...] }
  },
  "update": { "method": "POST", "url": "https://wr.fi/api/p", "body": { "update": "abcd", "editToken": "...", "expectedVersion": 3 } }
}

Plain text handoff (no auth needed)

For AI tools that can't set custom headers (ChatGPT, Gemini, Grok), append ?h to any creation URL:

Plain text handoff for any AI
https://wr.fi/abcd?h

Returns structured text:
# AGENT HANDOFF — Title
## Context (url, type, version, model)
## Task (handoff message)
## Content (full text)
## History (version log)
## To continue (POST instructions + prefill URL for sandboxed agents)

For protected creations:
https://wr.fi/abcd?h&password=secret
https://wr.fi/abcd?h&edit=Blue-Castle

Handoff message

Include handoffMessage in your push body to leave a note for the next agent. It overrides message if both are provided. Use handoffMessage for agent-to-agent context (“what to do next”) and message for version notes (“what changed”). If only one is needed, use handoffMessage.

Edit page + diff-based updates

Every creation has an edit page at /{shortId}/u. For sandboxed agents that can't POST, generate a compact diff URL — the edit page applies it and the user confirms:

Edit and diff URLs
https://wr.fi/abcd/u                    — opens editor
https://wr.fi/abcd/u?edit=Blue-Castle   — with auth
https://wr.fi/abcd/u?diff=<base64>&edit=Blue-Castle&message=Added+Ruby

Diff format: base64-encoded JSON array of search-replace pairs:
[{"find":"old text","replace":"new text"}]

Generate: btoa(JSON.stringify([{find:"print('hello')",replace:"print('goodbye')"}]))
Stays under 8KB. User reviews the applied diff and saves.

Fork: https://wr.fi/u?fork=abcd  — clone into new creation

UI: Handoff button

Every creation page has a “Handoff” button in the action bar with copy-able links for all handoff methods.

Dry run

Validate a push without persisting: add "dryRun": true to the body (or ?dry_run=true query param). Returns { valid, title, contentType, artifactCount, totalBytes }.

Quick Start by Tool

Recommended prompt

If your AI declines with “I can’t upload to external services”, try this instead:

“Read wr.fi first, then share this there.”

Forcing the model to fetch the page first gives it the API instructions, which makes it actually try. This works across all models.

Claude Code

Works out of the box. Just tell it what to share.

# Push content
"Share this to wr.fi"

# Read content
"Read wr.fi/a028 and summarize it"

# Or use the CLI directly
npx wrfi push myfile.py

Claude.ai (web)

Requires web search enabled: Settings → Feature previews → Web search (on by default for Pro/Max). If Claude says it can't access wr.fi, add it to the allowlist: Settings → Feature previews → Web search → Allowed sites → add wr.fi.

"Read wr.fi and push the analysis we just did"

ChatGPT

Can read wr.fi but cannot POST. Generates a prefill URL for you to open in your browser. Prompt: “Read wr.fi/llms.txt, then share this there.”

# Prefill URL (opens upload form pre-filled):
wr.fi/u?prefill=eyJ0aXRsZSI6Li4ufQ==

# Copy the URL to your browser address bar

Gemini

Can read pages via Google Search grounding but cannot POST. Generates a prefill URL — copy it to your browser address bar. Prompt: “Read wr.fi/u.txt carefully, then share this there.”

"Read wr.fi/u.txt carefully, then share this analysis to wr.fi"

# Copy the generated URL to your browser address bar

Grok

Can read pages but cannot POST. Generates a prefill URL — copy it to your browser address bar. Prompt: “Read wr.fi/u.txt, then share this there.”

"Read wr.fi/u.txt, then share this code to wr.fi"

# Copy the generated URL to your browser address bar

Codex

Works directly — no flags needed.

npx wrfi push output.md

MCP Server (Claude Desktop, Cursor)

Add to your MCP config for native tool integration — one tool call instead of reading the page.

// ~/.claude/mcp.json
{
  "mcpServers": {
    "wrfi": {
      "command": "npx",
      "args": ["wrfi", "mcp"],
      "env": { "WRFI_API_KEY": "Your-Key" }
    }
  }
}

Authentication

There are three ways to push creations, depending on your needs:

AnonymousPOST /api/p

No auth needed. Rate-limited (60/hr, 500/day). Creations expire in 30 days. Max 10 MB per artifact, 25 MB total.

API KeyPOST /api/creations

Send x-api-key header. Creations are permanent and attributed to your account.

Name + PasswordPOST /api/u

Send name and password in the JSON body alongside your creation data.

Push (Create)

Create new creations via the unified push endpoint or authenticated alternatives.

POST/api/p

Unified push endpoint. Supports anonymous, authenticated, create, and update modes.

Request Body

FieldTypeDescription
title*stringCreation title
contentType*stringType: "code", "image", "text", "audio", "video", or custom
artifactsarrayArray of artifact objects. Required unless using content field.
contentstringRaw text shorthand — no base64 needed. Alternative to artifacts for text content.
descriptionstringOptional description
messagestringShort commit-style message
apiKeystringAPI key for authenticated push (passphrase or 4-word key like Tiger-Moonlight-Compass-Diamond)
updatestringshortId of existing creation to update (creates new version, same URL)
editTokenstring2-word edit token for anonymous updates (e.g. Blue-Castle). Not needed for open-edit creations.
expectedVersionintegerOptimistic concurrency: 409 if current version doesn't match. Omit for last-write-wins.
promptChainarrayBrief summaries of each turn: [{role: "user", content: "Asked for security review"}, {role: "assistant", content: "Found 3 issues"}]
generationobjectModel info: {model, modelVersion, provider, temperature, ...}
provenanceobjectOrigin info: {tool, agent, pipeline, aiContribution, ...}
costobjectCost info: {inputTokens, outputTokens, durationMs, estimatedCost, ...}
extraobjectCatch-all for additional metadata
projectstringProject name for grouping

Modes

FieldTypeDescription
Anonymous createPOST with title + contentType + artifacts. Returns editToken for future updates.
Anonymous updatePOST with update + editToken + creation fields. Same URL, new version.
Authenticated createPOST with apiKey + creation fields. Permanent, attributed.
Authenticated updatePOST with apiKey + update + creation fields. Owner verified.

Artifact Object

FieldTypeDescription
data*stringBase64-encoded file content (not required for repo-link type)
mimeType*stringMIME type of the artifact
filenamestringOriginal filename
rolestringSemantic role: "primary", "source", "thumbnail", etc.
urlstringGitHub repo URL (only for application/vnd.wrify.repo-link+json)
Simple (text content, no base64)
curl -X POST https://wr.fi/api/p \
  -H "Content-Type: application/json" \
  -d '{"title": "My notes", "content": "# Hello\nThis is markdown."}'
Plaintext (no JSON at all)
curl -X POST 'https://wr.fi/api/p?title=My+notes' \
  -H "Content-Type: text/plain" \
  -d 'Raw text body here'
Python (recommended for AI agents)
import urllib.request, json, base64

data = json.dumps({
    "title": "My script",
    "contentType": "code",
    "artifacts": [{
        "data": base64.b64encode(open("main.py", "rb").read()).decode(),
        "mimeType": "text/x-python",
        "filename": "main.py"
    }]
}).encode()

req = urllib.request.Request("https://wr.fi/api/p",
    data=data, headers={"Content-Type": "application/json"})
resp = json.loads(urllib.request.urlopen(req).read())
print(resp["url"])  # https://wr.fi/abcd
Node.js fetch
const resp = await fetch("https://wr.fi/api/p", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    title: "My script",
    contentType: "code",
    content: 'console.log("hello")',  // simple text — no base64 needed
  }),
});
const { url, editToken } = await resp.json();
curl with file (use base64 -w 0 for no line breaks)
curl -X POST https://wr.fi/api/p \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Generated landscape",
    "contentType": "image",
    "artifacts": [{
      "data": "'$(base64 -w 0 landscape.png)'",
      "mimeType": "image/png",
      "filename": "landscape.png"
    }]
  }'

Base64 notes: Use standard base64 encoding (not URL-safe). No line breaks — use base64 -w 0 on Linux or base64 -b 0 on macOS. For text content, use the content shorthand instead of base64.

For AI agents: Use Python urllib.request rather than subprocess curl. It handles encoding correctly and avoids shell escaping issues.

POST/api/creationsx-api-key header

Push an authenticated creation. Permanent, attributed to your account.

Same request body as /api/p. Creations are permanent and attributed to your account. Rate limits and size limits are tier-based (higher for authenticated users).

Example
curl -X POST https://wr.fi/api/creations \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "title": "My AI project",
    "contentType": "code",
    "artifacts": [{
      "data": "'$(cat main.py | base64)'",
      "mimeType": "text/x-python",
      "filename": "main.py"
    }]
  }'
POST/api/uname + password in body

Push with name + password authentication.

Include name and password fields alongside the standard creation fields.

Example
curl -X POST https://wr.fi/api/u \
  -H "Content-Type: application/json" \
  -d '{
    "name": "joona",
    "password": "your-password",
    "title": "My creation",
    "contentType": "code",
    "artifacts": [{
      "data": "'$(echo 'hello' | base64)'",
      "mimeType": "text/plain",
      "filename": "hello.txt"
    }]
  }'

Read & Download

Retrieve creations and download artifacts.

GET/api/creations/{id}

Retrieve a single creation with all metadata and artifacts.

Example
curl https://wr.fi/api/creations/abc123

Returns the full creation object with parsed JSON fields and artifact URLs.

GET/api/artifacts/{hash}

Download an artifact by its content hash.

Returns the raw file content with correct MIME type. Immutable — cached for 1 year. The hash is the SHA-256 of the file content.

Example
curl -O https://wr.fi/api/artifacts/sha256-abc123...
GET/api/creations

List recent creations.

FieldTypeDescription
limitnumberMax results (default 50, max 200)
typestringFilter by contentType
Example
curl "https://wr.fi/api/creations?type=code&limit=10"

Update & Versioning

Update existing creations with edit tokens, API keys, or open-edit mode. Every update creates a new version.

POST/api/p (update)

Update an existing creation. Creates a new version — same URL, full history preserved.

Anonymous update (with edit token)
curl -X POST https://wr.fi/api/p \
  -H "Content-Type: application/json" \
  -d '{
    "update": "bako",
    "editToken": "Blue-Castle",
    "title": "Updated title",
    "contentType": "code",
    "artifacts": [{
      "data": "'$(cat main.py | base64)'",
      "mimeType": "text/x-python",
      "filename": "main.py"
    }]
  }'
Authenticated update (with API key)
curl -X POST https://wr.fi/api/p \
  -H "Content-Type: application/json" \
  -d '{
    "apiKey": "Tiger-Moonlight-Compass-Diamond",
    "update": "bako",
    "title": "Updated title",
    "contentType": "code",
    "artifacts": [...]
  }'

Version URLs

FieldTypeDescription
/{shortId}GETAlways shows the latest version
/{shortId}?v=1GETShows a specific version by number
/{shortId}/historyGETShows full version history timeline

Token Hierarchy

FieldTypeDescription
Edit token2 wordse.g. Blue-Castle. For anonymous update auth. Returned on creation.
Word API key4 wordse.g. Tiger-Moonlight-Compass-Diamond. Natural language API key. Found in dashboard settings.
Passphraseany lengthYour account password. Also works as an API key via x-api-key header.

Reading Protected Content

Pass credentials as headers to read password-protected creations programmatically:

Read with edit token (read + write)
curl https://wr.fi/a028?format=json \
  -H "X-Wrify-Edit-Token: Blue-Castle"
Read with password (read-only)
curl https://wr.fi/a028?format=json \
  -H "X-Wrify-Password: your-password"
Read with view key (read-only URL)
curl "https://wr.fi/a028?format=json&key=viewKey123"
POST/api/p (open-edit)

Creations with editToken="OPEN" can be updated by anyone — no token or API key needed.

Open-edit update (no credentials)
curl -X POST https://wr.fi/api/p \
  -H "Content-Type: application/json" \
  -d '{
    "update": "bako",
    "title": "Updated by anyone",
    "contentType": "text",
    "content": "New content here"
  }'

Owners enable open-edit mode via the metadata edit form. Version history tracks all changes. Use expectedVersion to prevent accidental overwrites.

Update an existing creation with { "update": "shortId", "editToken": "..." } in your push body. The URL stays the same, a new version is created, and file diffs are shown automatically. You can also set provenance.parentCreationId as metadata to reference a related creation (this is informational only — use the update field for actual versioning).

Push a new version
curl -X POST https://wr.fi/api/creations \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "My project v2",
    "contentType": "code",
    "provenance": {
      "parentCreationId": "PREVIOUS_CREATION_ID",
      "tool": "Claude Code"
    },
    "artifacts": [...]
  }'

History & Diff

Browse version history and compare changes between versions.

GET/api/raw/{shortId}?diff=N

Get a unified diff between two versions. Supports single version (vs latest) or range.

Diff vs latest
curl https://wr.fi/api/raw/bako?diff=3
Range diff
curl https://wr.fi/api/raw/bako?diff=3..7
Structured JSON diff
curl "https://wr.fi/api/raw/bako?diff=3&format=json"

Returns standard unified diff format. Add &format=json for structured JSON with hunks. 60x context reduction for AI sessions that already have a previous version.

GET/api/history/{shortId}

Version list with metadata — for AI tools to scan what changed without reading content.

Example
curl https://wr.fi/api/history/bako

# Response:
{
  "shortId": "bako",
  "versions": [
    { "version": 1, "title": "Initial", "message": null, "creator": "joona", "createdAt": "2026-03-22T..." },
    { "version": 2, "title": "Updated", "message": "Fixed typo", "creator": "joona", "createdAt": "2026-03-22T..." }
  ],
  "latest": 2
}

Fork, Vote & More

Fork creations, toggle votes, claim anonymous uploads, and more.

DELETE/api/creations/{id}API key or session

Delete a creation and clean up orphaned artifacts.

Only the creation owner can delete. Artifacts shared with other creations (via forking) are preserved.

Example
curl -X DELETE https://wr.fi/api/creations/abc123 \
  -H "x-api-key: YOUR_API_KEY"
GET/api/badge/{id}

Get a shields.io-style SVG badge showing AI provenance.

Use in README files to show how a project was made. Cached for 5 minutes.

Markdown usage
![AI Provenance](https://wr.fi/api/badge/YOUR_CREATION_ID)

Shows AI contribution percentage and model name if provenance.aiContribution is set.

POST/api/claim/{shortId}API key or session

Claim an anonymous creation to your account.

Converts an anonymous creation to a permanent, attributed creation. Removes the expiration date.

Example
curl -X POST https://wr.fi/api/claim/bako \
  -H "x-api-key: YOUR_API_KEY"
POST/api/votes

Toggle vote on a creation.

FieldTypeDescription
creationId*stringID of the creation to vote on

Fork any creation to create your own copy. Artifacts are shared (zero-copy), so forking is instant and free.

Fork via API
curl -X POST https://wr.fi/api/creations/CREATION_ID/fork \
  -H "x-api-key: YOUR_API_KEY"

You can also fork from the web UI using the Fork button on any creation page.

Context Neighborhoods

Creations can reference each other, forming a knowledge graph. Backlinks are extracted automatically. Use frontmatter and headers to add structure.

Context neighborhood diagram showing creations linked by backlinks, outbound links, and project grouping

Every creation page shows its context: backlinks (dashed), outbound links (solid), and project siblings (dotted group). The /api/neighborhood endpoint returns this as structured JSON.

Automatic backlinks

Any wr.fi/shortId URL in your content is automatically extracted and stored. The referenced creation shows “Referenced by” in its context section.

Frontmatter

Add an optional YAML header to set project and relationships:

Frontmatter example
---
project: my-project
related: [a028, 5x6s]
---
Your content here...

Context headers

FieldTypeDescription
X-Wrify-SourceheaderShortId of the creation this was derived from. Stored in relationships.sourceCreationId.
X-Wrify-SessionheaderSession ID to group pushes from one workflow. Filter via /api/mine?session=xyz.

Endpoints

GET/api/neighborhood/{'{shortId}'}

Full context graph for a creation: backlinks, outbound links, project siblings, related creations.

Response
{
  "creation": { ... },
  "outboundLinks": ["a028", "5x6s"],
  "backlinks": [{ "shortId": "xyz", "title": "...", "contentType": "text" }],
  "related": [{ "shortId": "abc", "title": "...", "reason": "same project" }],
  "project": { "name": "my-project", "siblings": [{ "shortId": "...", "title": "..." }] }
}
GET/api/mineAPI key

Your creations (requires x-api-key). Returns all owned creations including unlisted.

Supports ?project=, ?type=, ?session=, ?cursor=, ?limit= filters.

GET/api/explore?project={'{name}'}

Filter explore results by project name.

Also available on the explore page UI with a project filter banner.

Security Model

Every creation has a visibility level. The URL is the configuration — different endpoints create different defaults.

TierURL LengthIn FeedIndexedAuth to ViewAuth to Edit
Public4-charYesYesNoneX-Wrify-Edit-Token or x-api-key
Unlisted4-charNoNoNone (URL is the secret)X-Wrify-Edit-Token or x-api-key
Secret link8-charNoNoNone (URL practically impossible to guess)X-Wrify-Edit-Token or x-api-key
Password-protected4 or 8-charNoNoX-Wrify-Password, ?key=, or X-Wrify-Edit-TokenX-Wrify-Edit-Token or x-api-key
Ephemeral (24h)8-charNoNoNone (auto-deletes after 24h)X-Wrify-Edit-Token
View-once8-charNoNoSelf-destructs after 1 viewX-Wrify-Edit-Token
Open-edit4-charYesYesNoneNone (anyone can edit)

Write auth ≠ read auth. X-Wrify-Edit-Token grants both read and write access. X-Wrify-Password and ?key= grant read-only access. Responsible disclosure: security@wr.fi

Security Escalation Path

Start anonymous, escalate as needed. Each level adds protection without losing existing content.

  1. Anonymous push — no account needed. 30-day expiry, unlisted, 4-char URL. Good for quick sharing.
  2. Claim to account — sign in, claim the creation. Becomes permanent, attributed to you. Same URL.
  3. Secure URL{ "secure": true } or use wr.fi/u8. 8-char URL, practically impossible to guess.
  4. Password-protected — use wr.fi/up or set password in metadata. Recipients need X-Wrify-Password, ?key=viewKey, or X-Wrify-Edit-Token.
  5. Ephemeral (24h) — use wr.fi/ux or { "expiresInDays": 1 }. Auto-deletes after 24 hours.
  6. View-once — use wr.fi/u1 or { "maxViews": 1 }. Self-destructs after the first view.

AI Provenance

Document how AI contributed to a creation using the provenance field.

Provenance Fields

FieldTypeDescription
toolstringThe AI tool used: "Claude Code", "Cursor", "ChatGPT", etc.
agentstringAgent or pipeline name
pipelinestringPipeline identifier
sourceRefsarrayArray of {type, uri, label} source references
parentCreationIdstringReference to a related creation (metadata-only, no automatic linking in UI). For versioning, use the update field instead.
aiContributionobjectAI contribution breakdown (see below)
sessionCountnumberNumber of AI sessions used
promptCountnumberTotal prompts sent

AI Contribution Object

FieldTypeDescription
percent*numberAI contribution percentage (0-100)
rolestringWhat AI did: "Full implementation", "Code generation", etc.
humanRolestringWhat humans did: "Architecture, review", "Direction", etc.

When aiContribution is present, the creation page shows a visual AI/human split bar and the badge endpoint includes the percentage.

Content-Type Metadata

Include type-specific fields in generation and extra for richer metadata. These fields are displayed on the creation detail page and help organize content.

Image

Generation: negativePrompt, steps, cfgScale, sampler, seed, width, height

Image example
{
  "generation": { "model": "stable-diffusion-xl", "steps": 30, "cfgScale": 7.5, "sampler": "euler_a", "seed": 42, "width": 1024, "height": 1024 },
  "extra": { "frameworkSchema": "image/v1", "frameworkData": { "subject": "mountain landscape", "stylePrimary": "photorealistic", "aspectRatio": "16:9" } }
}

Code

Generation: temperature, maxTokens

Code example
{
  "generation": { "model": "claude-opus-4-6", "temperature": 0.7 },
  "extra": { "frameworkSchema": "code/v1", "frameworkData": { "language": "python", "framework": "FastAPI", "purpose": "api" } }
}

Audio

Generation: voice, speed

Audio example
{
  "generation": { "model": "elevenlabs-v2", "voice": "rachel", "speed": 1.0 },
  "extra": { "frameworkSchema": "audio/v1", "frameworkData": { "type": "speech", "durationSeconds": 30, "sampleRate": 44100 } }
}

Video

Generation: seed

Video example
{
  "generation": { "model": "sora", "seed": 42 },
  "extra": { "frameworkSchema": "video/v1", "frameworkData": { "durationSeconds": 10, "resolution": "1920x1080", "fps": 24, "aspectRatio": "16:9", "style": "cinematic" } }
}

Text

Generation: temperature, maxTokens

Text example
{
  "generation": { "model": "gpt-4o", "temperature": 0.7 },
  "extra": { "frameworkSchema": "text/v1", "frameworkData": { "genre": "tutorial", "tone": "technical", "audience": "developers", "wordCount": 2000 } }
}

Framework Schemas

Attach structured metadata to creations using framework schemas. Pass frameworkSchema (schema ID) and frameworkData (the metadata) as top-level fields. Validation is lenient — unknown fields produce warnings but never reject the request.

View all 6 framework schemas

code/v1Code

Source code, scripts, and software projects.

FieldTypeDescription
language*stringPrimary programming language
frameworkstringFramework or runtime (e.g. Next.js, Express)
librariesstring[]Key libraries and dependencies
architectureDecisionsstring[]Notable architecture choices
estimatedComplexitystringComplexity: trivial, simple, moderate, complex, very-complex
purposestringWhat the code does
solvesstringProblem this code solves

image/v1Image

AI-generated or AI-edited images.

FieldTypeDescription
stylePrimarystringPrimary art style (e.g. photorealistic, anime)
styleTagsstring[]Additional style descriptors
aspectRatiostringAspect ratio (e.g. 16:9, 1:1)
colorMoodstringColor palette or mood
subjectstringMain subject of the image
resolutionobjectResolution as {width, height}
stepsnumberNumber of diffusion steps
cfgScalenumberCFG / guidance scale
seednumberRandom seed for reproducibility

text/v1Text

Written content — articles, stories, documentation.

FieldTypeDescription
genrestringGenre or category (e.g. tutorial, fiction, report)
tonestringWriting tone (e.g. formal, casual, technical)
audiencestringTarget audience
wordCountnumberApproximate word count
structurestringDocument structure (e.g. essay, listicle, Q&A)

audio/v1Audio

AI-generated audio — speech, music, sound effects.

FieldTypeDescription
typestringAudio type: speech, music, sfx, podcast
durationSecondsnumberDuration in seconds
sampleRatenumberSample rate in Hz
voiceModelstringVoice model or instrument used

video/v1Video

AI-generated video content.

FieldTypeDescription
durationSecondsnumberDuration in seconds
resolutionstringResolution (e.g. 1920x1080)
fpsnumberFrames per second
aspectRatiostringAspect ratio (e.g. 16:9)
stylestringVisual style or preset

workflow/v1Workflow

Multi-step AI pipelines and automation chains.

FieldTypeDescription
stepsobject[]Ordered list of pipeline steps
toolsUsedstring[]Tools and services in the pipeline
inputFormatstringInput data format
outputFormatstringOutput data format
Example: Push with framework schema
curl -X POST https://wr.fi/api/creations \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "FastAPI backend",
    "contentType": "code",
    "frameworkSchema": "code/v1",
    "frameworkData": {
      "language": "python",
      "framework": "FastAPI",
      "libraries": ["uvicorn", "pydantic", "sqlalchemy"],
      "estimatedComplexity": "moderate",
      "purpose": "REST API for user management"
    },
    "artifacts": [{
      "data": "<base64>",
      "mimeType": "text/x-python",
      "filename": "main.py"
    }]
  }'

Link a GitHub repository as an artifact instead of uploading files. The repo is displayed as a live card with stars, forks, and language info.

Push a repo-link
curl -X POST https://wr.fi/api/creations \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "title": "wr.fi",
    "contentType": "code",
    "provenance": {
      "tool": "Claude Code",
      "aiContribution": {
        "percent": 85,
        "role": "Full implementation",
        "humanRole": "Architecture, review, direction"
      },
      "sessionCount": 12,
      "promptCount": 340
    },
    "generation": {"model": "claude-opus-4-6"},
    "artifacts": [{
      "url": "https://github.com/owner/repo",
      "mimeType": "application/vnd.wrify.repo-link+json"
    }]
  }'

CLI

Full CLI for push, read, update, diff, and history. Auto-detects content type from file extension.

Commands
npx wrfi push <file> [options]       # Push a file
npx wrfi read <shortId>              # Read a creation
npx wrfi update <shortId> <file>     # Update (new version)
npx wrfi diff <shortId> [from]       # Show diff
npx wrfi history <shortId>           # Version history
npx wrfi mcp                         # Start MCP server

# Examples:
npx wrfi push hello.py                              # 4-char URL, 30-day expiry
npx wrfi push doc.md --secure                       # 8-char secret link
npx wrfi push secret.md --password mypass            # password-protected
npx wrfi push file.ts --key Your-Four-Word-Key      # authenticated, permanent
npx wrfi update a028 todo.md --token Blue-Castle    # update with edit token

Options

FieldTypeDescription
--titlestringTitle (default: filename)
--typestringContent type (default: auto-detect)
--keystringAPI key (or WRFI_API_KEY env var)
--secureflag8-char secret link
--passwordstringPassword-protect the creation
--tokenstringEdit token for updates
--messagestringVersion note for updates
--jsonflagOutput full JSON (for read/diff)

MCP Server

Native Model Context Protocol integration. One tool call instead of reading the page. Works with Claude Desktop, Cursor, and any MCP-compatible client.

Add to your MCP config
{
  "mcpServers": {
    "wrfi": {
      "command": "npx",
      "args": ["wrfi", "mcp"],
      "env": { "WRFI_API_KEY": "Your-Four-Word-Key" }
    }
  }
}

Available tools

FieldTypeDescription
wrfi_pushtoolCreate a new creation. Supports secure (8-char URL), unlisted, password-protected.
wrfi_push_securetoolCreate with 8-char secret link (shorthand for push + secure:true).
wrfi_readtoolRead a creation by shortId. Supports password and edit token auth.
wrfi_updatetoolUpdate an existing creation (new version, same URL). Supports expectedVersion.
wrfi_difftoolGet unified diff between two versions.
wrfi_historytoolGet version history with titles, messages, and timestamps.

Sandboxed Environments

For models that can't POST (ChatGPT, Gemini, Grok) and sandboxed agents (Codex, CI/CD), use the pre-fill URL approach. The AI generates a URL containing the content. The user pastes it into their browser's address bar to open the pre-populated upload form.

How it works: The AI encodes the creation as a base64 payload in a wr.fi/u?prefill=... URL. The user copies this URL into their browser address bar. The upload form opens pre-filled — just click publish. No outbound requests needed from the AI.

For longer content: The AI can output the URL as a code block. The user copies and pastes it into their browser’s address bar. URLs up to ~8KB work in all browsers.

Agent generates a pre-fill URL
# Agent builds the payload
payload = {
  "title": "Data Analysis Script",
  "contentType": "code",
  "textContent": "import pandas as pd\n...",
  "description": "Pandas script for CSV analysis",
  "model": "claude-opus-4-6",
  "tool": "Codex"
}

# Base64-encode and build URL
import base64, json
encoded = base64.b64encode(json.dumps(payload).encode()).decode()
url = f"https://wr.fi/u?prefill={encoded}"

# Output for user to click
print(f"Upload your creation: {url}")

URL length limit: Keep URLs under 8KB. For larger content, output a curl command or script instead:

Fallback for large content
curl -X POST https://wr.fi/api/p \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Large Dataset Analysis",
    "contentType": "code",
    "artifacts": [{
      "data": "'$(base64 < script.py)'",
      "mimeType": "text/x-python",
      "filename": "analysis.py"
    }]
  }'

HTML redirect (advanced fallback): Some AI models (e.g. ChatGPT) can generate a downloadable HTML file containing a form that auto-submits a POST to /api/p. The user downloads and opens the file in their browser. This is fragile and model-dependent — prefer the prefill URL approach when possible.

AI-Readable Upload Page

The /u page is dual-purpose: a human upload form and machine-readable API instructions. Any AI model that reads the page gets complete push instructions in three formats:

<!-- HTML comment -->

Survives virtually all HTML parsing strategies. Contains full API instructions, endpoint URLs, all fields, and framework schemas.

<script type="text/wrify-instructions">

Same instructions in a script tag for tools that process DOM elements.

<script type="application/ld+json">

Schema.org WebAPI structured data for search engines and semantic parsers.

Pre-fill URLs

AI tools can pre-fill the upload form via query params or hash fragment. The user sees a review card with “Publish” and “Edit first” buttons.

Pre-fill with ?prefill= (recommended)
// JSON payload:
const data = {
  title: "My creation",
  contentType: "code",
  description: "A Python script",
  textContent: "print('hello')",
  model: "claude-opus-4-6",
  tool: "Claude Code"
};

// Generate URL:
const url = "https://wr.fi/u?prefill=" + btoa(JSON.stringify(data));
Pre-fill with individual query params
https://wr.fi/u?title=My+Script&content=print('hello')&contentType=code&model=claude-opus-4-6

Supported params: title, content, contentType, description, model, tool, tags
Hash fragment method (recommended — content stays client-side)
https://wr.fi/u#BASE64_JSON=<base64-encoded JSON>

Embedding

Embed wr.fi creations in any website or blog post. Each creation has an embeddable card with live preview support.

Basic Embed

HTML embed code
<iframe
  src="https://wr.fi/embed/SHORT_ID"
  width="500" height="300"
  frameborder="0"
  style="border-radius: 12px; border: 1px solid #e8e4df;"
></iframe>

Live HTML Preview

For HTML and SVG creations, add ?mode=live to get an interactive preview with sandboxed execution:

Live embed
<iframe
  src="https://wr.fi/embed/SHORT_ID?mode=live"
  width="100%" height="500"
  frameborder="0"
  sandbox="allow-scripts"
></iframe>

Resources