GODLE API reference
The GODLE API gives you programmatic access to 185 expert roles and 1,741 prompt templates, plus a stateful execution engine that handles LLM calls, eval-driven retries, sessions, streaming, and multi-step workflow orchestration.
The API has two layers with different base URLs:
Both layers are live. Layer 1 is open and requires no API key. Layer 2 requires a Bearer token — see the authentication section.
Quick start
Fetch a role and run it against any LLM in under two minutes.
No auth required. Layer 1 is open and CDN-cached.
curl https://godle.app/api/v3/roles/copywriter.json
You get the role's systemPrompt, all its templates with pre-written prompts, eval rubrics, and nextSteps for chaining to other roles.
Not sure which role to use? Match a natural-language intent against all 1,741 capabilities (requires Layer 2).
curl -X POST https://orchestration.godle.app/api/v3/capabilities/match \
-H "Authorization: Bearer sk-godle-your-key" \
-H "Content-Type: application/json" \
-d '{"intent": "write a compelling product launch email"}'
Layer 2 calls the LLM, runs eval checks, and retries automatically. You get a live SSE stream.
// Submit a task const { id: taskId } = await fetch('https://orchestration.godle.app/api/v3/tasks', { method: 'POST', headers: { 'Authorization': 'Bearer sk-godle-your-key', 'Content-Type': 'application/json' }, body: JSON.stringify({ roleId: 'copywriter', templateKey: 'product-launch-email', input: 'Product: TaskFlow. Audience: remote teams.', autoApprove: true }) }).then(r => r.json()); // Stream output via SSE const res = await fetch(`https://orchestration.godle.app/api/v3/tasks/${taskId}/stream`, { headers: { 'Authorization': 'Bearer sk-godle-your-key' } }); // ... handle ReadableStream (see Streaming section)
Prefer a no-setup path? Load the SDK from CDN and call GODLE.run('copywriter', 'your prompt') — it handles the fetch, eval, and output in one call. See the SDK reference.
Architecture
The API has two layers that work together. You can use Layer 1 alone, or combine both.
| Layer 1 | Layer 2 | |
|---|---|---|
| Host | Vercel CDN | Cloudflare Workers |
| Auth | None required | Bearer API key |
| State | Stateless JSON | Durable Objects (12h TTL) |
| Deploy | Live — Vercel CDN | Live — orchestration.godle.app |
| Use for | Roles, templates, capability index | Task execution, sessions, streaming |
Authentication
All Layer 2 endpoints require a Bearer token in the Authorization header:
Authorization: Bearer sk-godle-your-key-here
For MCP endpoints, the key can alternatively be passed as params._apiKey inside the JSON-RPC body. The MCP and A2A endpoints also function in an unauthenticated mode (no rate limiting applied).
Layer 1 endpoints (CDN static files) require no authentication.
Provisioning API keys
API keys are stored as a Cloudflare Worker secret. Set them before deploying:
# Comma-separated list of valid keys wrangler secret put GODLE_API_KEYS # When prompted, enter: sk-godle-key1,sk-godle-key2
Every response from Layer 2 includes an X-Request-Id header (req_xxxxxxxx) for distributed tracing.
Rate limits
Layer 2 enforces a sliding-window limit of 60 requests per minute per API key, backed by Cloudflare KV.
The limit is configurable via the RATE_LIMIT_RPM environment variable in wrangler.toml.
Rate-limited requests return HTTP 429:
{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Limit: 60/min"
}
}
Layer 1 (CDN) has no rate limits. Requests are served directly from the Vercel edge cache with a Cache-Control: public, max-age=3600, s-maxage=86400 header.
Error format
All Layer 2 errors use a consistent JSON envelope:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable description"
}
}
| HTTP | Code | When |
|---|---|---|
| 400 | BAD_REQUEST | Malformed JSON or missing required field |
| 401 | UNAUTHORIZED | Missing or invalid API key |
| 402 | BUDGET_EXHAUSTED | Session token budget exceeded |
| 404 | NOT_FOUND | Resource does not exist |
| 405 | METHOD_NOT_ALLOWED | Wrong HTTP method for this path |
| 409 | CONFLICT | Resource already exists or invalid state transition |
| 410 | GONE | Session has expired (12h TTL) |
| 413 | PAYLOAD_TOO_LARGE | Request body exceeds 100 KB |
| 429 | RATE_LIMITED | Exceeded 60 requests/minute |
| 500 | INTERNAL_ERROR | Unexpected worker error |
| 502 | LAYER1_UNAVAILABLE | Worker failed to fetch from CDN |
Layer 1 — static endpoints
All Layer 1 endpoints are served from https://godle.app/api/v3. No authentication. Responses are CDN-cached for up to 24 hours at the edge (s-maxage=86400) and 1 hour in browsers (max-age=3600).
Roles
Returns all 185 expert roles — slugs, names, categories, descriptions, system prompts, templates, and nextSteps for multi-role chains.
{
"version": "3.0.0",
"generatedAt": "2026-02-25T00:00:00Z",
"totalRoles": 185,
"roles": [
{
"slug": "copywriter",
"name": "Copywriter",
"category": "content",
"description": "Expert at persuasive, brand-aligned copy",
"systemPrompt": "You are an expert copywriter...",
"templates": [
{
"key": "product-launch-email",
"label": "Product Launch Email",
"prompt": "Write a product launch email for..."
}
],
"nextSteps": ["designer", "strategist"]
}
]
}
Returns a single role by slug with full template list and eval rubric data. The slug is the role's slug field (e.g., copywriter, software-engineer).
Returns only the template array for a role. Useful for lighter payloads when you already have the role metadata.
Returns all 24 role categories with labels and slugs. Use this to build category filters or navigation.
Returns all workflow definitions including DAG step configs, input mappings, and handoff schemas. Use these as templates for POST /api/v3/tasks/compose.
Capability index
Returns the full capability index: 1,741 entries, each representing one role + template pair. Each entry includes intent phrases, tags, domains, expected output sections, and token estimates. This is the data source used by POST /capabilities/match on Layer 2.
{
"id": "copywriter--product-launch-email",
"roleId": "copywriter",
"templateKey": "product-launch-email",
"templateLabel": "Product Launch Email",
"intent": ["write launch email", "announce product"],
"tags": ["email", "marketing", "launch"],
"domains": ["saas", "ecommerce", "startup"],
"outputSections": ["subject", "preview", "body", "cta"],
"constraints": { "estimatedOutputTokens": 800 }
}
Eval rubrics
Returns the LLM-as-judge eval rubric for a specific role + template pair. The task executor fetches this automatically when evalRetry: true is set on a task. The rubric defines scoring criteria and pass/fail thresholds.
curl https://godle.app/api/v3/evals/copywriter--product-launch-email.json
SDK bundle and protocol manifests
The UMD SDK bundle. Load in a <script> tag to get window.GODLE with all 7 modules. See the SDK reference for the full API surface.
MCP tool manifest. Register this URL with any MCP host to expose GODLE's 4 tools (godle/list_roles, godle/match_capability, godle/execute_task, godle/compose_workflow).
A2A Agent Card. Register this URL with an A2A orchestrator to make GODLE available as an agent. The card describes supported skills and input/output schemas.
Layer 2 — Capabilities
These endpoints run on https://orchestration.godle.app and require a valid API key.
Find the best role + template for a natural-language intent. Scores all 1,741 capabilities by keyword overlap across intent[], tags[], domains[], and the capability ID. Returns ranked matches.
{ "intent": "write a compelling product launch email" }
{
"intent": "write a compelling product launch email",
"totalCandidates": 1741,
"matches": [
{
"capabilityId": "copywriter--product-launch-email",
"roleId": "copywriter",
"templateKey": "product-launch-email",
"score": 4,
"outputSections": ["subject", "preview", "body", "cta"],
"constraints": { "estimatedOutputTokens": 800 }
}
]
}
Negotiate model hint, token budget, and estimated cost/latency for a capability before running it. Useful for cost-gating or latency-sensitive UIs.
{
"capabilityId": "copywriter--product-launch-email",
"budget": 0.10,
"latencyMs": 4000,
"qualityLevel": "high"
}
| Field | Type | Required | Description |
|---|---|---|---|
capabilityId | string | Required | Capability ID from /match or capabilities.json |
budget | number | Optional | Max cost in USD |
latencyMs | number | Optional | Max acceptable latency |
qualityLevel | string | Optional | "fast" | "balanced" (default) | "high" |
Sessions
Sessions are server-side stateful contexts stored in Cloudflare Durable Objects. They persist for 12 hours by default and can hold memory, token budgets, and task references across multiple calls.
Create a new session. Returns HTTP 201 on success.
{
"config": {
"defaultTone": "balanced",
"maxConcurrentTasks": 5,
"costBudgetTokens": 100000
},
"callerAgent": { "name": "my-agent", "version": "1.0" }
}
{
"id": "ses_abc12345",
"version": "3.0.0",
"keyId": "key_abc12345",
"createdAt": "2026-02-25T10:00:00Z",
"expiresAt": "2026-02-25T22:00:00Z",
"status": "active",
"config": {
"defaultTone": "balanced",
"costBudgetTokens": 100000,
"costConsumedTokens": 0
},
"tasks": []
}
Retrieve current session state including token consumption and task list. Returns 410 GONE if the session has expired, 404 NOT_FOUND if it was explicitly deleted.
Terminate a session immediately. All associated memory is deleted. Tasks that were attached to this session are not cancelled — they continue running but can no longer debit the session's token budget.
{ "id": "ses_abc12345", "status": "ended" }
Sessions expire automatically after 12 hours. If your app is long-running, create a fresh session before the old one expires and pass the new sessionId on subsequent tasks.
Tasks
Tasks are the core execution unit. Each task runs inside a Cloudflare Durable Object, supporting streaming, human-in-the-loop approval gates, and eval-driven automatic retries.
Task lifecycle
Submit a task for execution. Returns HTTP 202 immediately. Execution starts within ~50 ms via a Durable Object alarm. Poll GET /tasks/{id} or connect to the SSE stream to receive the result.
| Field | Type | Default | Description | |
|---|---|---|---|---|
roleId | string | — | Godle role slug (e.g., copywriter) | |
templateKey | string | — | Template within the role | |
input | string | "" | Task description or user prompt | |
sessionId | string | — | Attach to a session for memory and token budget | |
tone | string | "balanced" | "fast" | "balanced" | "detailed" | |
evalRetry | boolean | true | Automatically retry if eval fails (up to 3×) | |
autoApprove | boolean | false | Skip human approval gates |
{
"id": "task_xyz98765",
"status": "submitted",
"roleId": "copywriter",
"templateKey": "product-launch-email",
"createdAt": "2026-02-25T10:00:00Z"
}
Get the current task state. When status is "completed", the response includes the artifacts array with the generated content, eval result, and provenance metadata.
{
"id": "task_xyz98765",
"status": "completed",
"completedAt": "2026-02-25T10:00:42Z",
"artifacts": [
{
"id": "art_abc12345",
"type": "text",
"mimeType": "text/plain",
"content": "Subject: Something big is coming...",
"evalResult": { "passed": true, "score": 92, "checks": [] },
"provenance": {
"modelUsed": "claude-sonnet-4-6",
"generatedAt": "2026-02-25T10:00:42Z",
"attempt": 1
}
}
],
"runLog": {
"totalAttempts": 1,
"model": "claude-sonnet-4-6",
"usage": { "input_tokens": 512, "output_tokens": 280, "total_tokens": 792 },
"evalScore": 92,
"evalPassed": true
}
}
Cancel a task in any non-terminal state. Returns 409 CONFLICT if the task has already completed, failed, or been cancelled.
Approve or reject a task that is in awaiting_approval state. When approved: false, the task transitions to failed.
{ "approved": true, "reason": "Looks good, proceed" }
Streaming (SSE)
Connect to a Server-Sent Events stream for a running task. The stream closes automatically when the task reaches a terminal state (completed, failed, or cancelled).
The browser EventSource API does not support custom headers. Use fetch() with a ReadableStream reader to pass the Authorization header.
| Event type | Data shape | Description |
|---|---|---|
heartbeat | {} | Sent on connect to confirm the stream is live |
status | { taskId, status } | Emitted on every state transition |
progress | { taskId, attempt, message } | Progress notes per execution attempt |
partial_artifact | { taskId, attempt, preview } | First 500 chars of the output, streamed early |
eval_result | { taskId, attempt, eval } | Score and pass/fail after each eval check |
complete | Full task object | Final state — stream closes after this event |
error | { taskId, error } | Task failed — stream closes after this event |
cancelled | Full task object | Task was cancelled — stream closes |
const res = await fetch(`/api/v3/tasks/${taskId}/stream`, { headers: { 'Authorization': 'Bearer sk-godle-your-key' } }); const reader = res.body.getReader(); const decoder = new TextDecoder(); let buf = ''; let currentEvent = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buf += decoder.decode(value, { stream: true }); const lines = buf.split('\n'); buf = lines.pop(); // keep the incomplete trailing line for (const line of lines) { if (line.startsWith('event: ')) { currentEvent = line.slice(7).trim(); continue; } if (!line.startsWith('data: ')) continue; const data = JSON.parse(line.slice(6)); if (currentEvent === 'partial_artifact') { renderPreview(data.preview); // stream preview to UI } if (currentEvent === 'complete') { console.log(data.artifacts[0].content); reader.cancel(); } if (currentEvent === 'error') { console.error(data.error); reader.cancel(); } } }
Workflow compose
Submit a multi-step workflow as a directed acyclic graph (DAG). Steps with no dependsOn run in parallel. Steps with dependsOn wait for their predecessors and can reference prior outputs via interpolation.
Output interpolation
| Expression | Resolves to |
|---|---|
{{steps.{stepId}.output}} | Text output of a completed step |
{{steps.{stepId}.artifact.content}} | Artifact content of a completed step |
{{workflow.inputs.{key}}} | Top-level input value from the inputs field |
{
"workflow": {
"id": "launch-campaign",
"steps": [
{
"id": "research",
"roleId": "researcher",
"input": "Top SaaS growth strategies 2025"
},
{
"id": "copy",
"roleId": "copywriter",
"prompt": "Write a launch email using these insights: {{steps.research.output}}",
"dependsOn": ["research"],
"modelHint": "balanced"
}
]
},
"inputs": { "audience": "remote teams" },
"autoApprove": true
}
MCP — Model Context Protocol
GODLE implements the Model Context Protocol (MCP) as a JSON-RPC 2.0 endpoint. Register GODLE with any MCP host and your AI agent can discover and invoke any of GODLE's 4 tools automatically.
Auth is via Authorization: Bearer header or params._apiKey in the request body. Unauthenticated requests are accepted but not rate-limited by key.
Supported methods
| Method | Description |
|---|---|
initialize | MCP handshake — returns protocol version, server capabilities, and tool list |
tools/list | List all 4 available GODLE tools |
tools/call | Invoke a tool by name with arguments |
resources/list | List available MCP resources |
resources/read | Read godle://capabilities as JSON |
Available tools
| Tool name | Required params | Description |
|---|---|---|
godle/list_roles | — | List roles (optional: category, limit) |
godle/match_capability | intent | Find the best role + template for an intent string |
godle/execute_task | roleId, input | Execute a task synchronously, wait for result (max 50 s) |
godle/compose_workflow | workflow | Execute a multi-step workflow and wait for all results |
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "godle/execute_task",
"arguments": {
"roleId": "copywriter",
"input": "Write a tagline for a coffee brand"
}
}
}
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [{ "type": "text", "text": "Wake up, world." }],
"taskId": "task_xyz",
"evalResult": { "passed": true, "score": 95 }
}
}
A2A — Agent-to-Agent Protocol
GODLE implements the Google Agent-to-Agent Protocol, allowing any A2A orchestrator to discover and delegate tasks to GODLE as an agent. Authentication is optional but recommended for rate-limiting by key.
Supported methods
| Method | Description |
|---|---|
tasks/send | Submit a task and poll until completion (synchronous) |
tasks/get | Get task status by ID |
tasks/cancel | Cancel a running task |
tasks/sendSubscribe | Submit a task and receive a live SSE stream |
State mapping
| GODLE state | A2A state |
|---|---|
submitted | submitted |
running / streaming | working |
awaiting_approval | input-required |
completed | completed |
failed | failed |
cancelled | canceled |
{
"method": "tasks/send",
"id": "my-task-123",
"message": {
"role": "user",
"parts": [{ "type": "text", "text": "Write a product tagline for a coffee brand" }]
},
"skill": { "roleId": "copywriter" }
}
{
"id": "my-task-123",
"status": { "state": "completed" },
"artifacts": [{
"index": 0,
"name": "output",
"parts": [{ "text": "Wake up, world." }]
}],
"metadata": { "godleTaskId": "task_xyz98765" }
}
SDK reference
The GODLE SDK is a UMD bundle exposing 7 modules under window.GODLE. Load it from the CDN — no build step, no npm package.
<script src="https://godle.app/api/v3/godle-sdk.js"></script>
.step(), set dependsOn, then .build() and GODLE.run().onProgress and onComplete.listRoles, matchCapability, executeTask.send(), get(), cancel() methods. Pair with GODLE.a2a.makeMessage() and toA2ATask().Core — GODLE.run()
const result = await GODLE.run('copywriter', 'Write a tagline for a coffee brand', { tone: 'friendly', model: 'claude-sonnet-4-6' }); console.log(result.output); // "Wake up, world." console.log(result.evalResult.score); // 0–100
Intent router — GODLE.suggest()
const suggestions = await GODLE.suggest('I need a compelling product launch email'); // Returns ranked role + template matches
Workflow builder — GODLE.buildWorkflow()
const wf = GODLE.buildWorkflow('launch-campaign') .step('research', 'researcher', 'Top SaaS strategies 2025') .step('copy', 'copywriter', '{{steps.research.output}}', { dependsOn: ['research'] }) .build(); const result = await GODLE.run(wf);
Sessions — GODLE.createSession()
const session = await GODLE.createSession({
baseUrl: 'https://orchestration.godle.app',
apiKey: 'sk-godle-your-key',
config: { costBudgetTokens: 50000 }
});
// session.id is a server-side ID, e.g. "ses_abc12345"
const result = await GODLE.run('copywriter', 'Write a tagline', { session });
Streaming — GODLE.connectStream()
const stream = await GODLE.connectStream(taskId, {
baseUrl: 'https://orchestration.godle.app',
apiKey: 'sk-godle-your-key',
onProgress: msg => console.log('progress:', msg),
onComplete: task => console.log(task.artifacts[0].content)
});
MCP client — GODLE.mcp.client()
const mcp = GODLE.mcp.client({ baseUrl: 'https://orchestration.godle.app', apiKey: 'sk-godle-...' });
const roles = await mcp.listRoles({ limit: 10 });
const result = await mcp.executeTask({ roleId: 'copywriter', input: 'Write a tagline' });
A2A client — GODLE.a2a.client()
const a2a = GODLE.a2a.client({ baseUrl: 'https://orchestration.godle.app' });
const task = await a2a.send({
message: GODLE.a2a.makeMessage('Write a product tagline for a coffee brand'),
skill: { roleId: 'copywriter' }
});
const a2aTask = GODLE.a2a.toA2ATask(task);
console.log(a2aTask.artifacts[0].parts[0].text);
Provider adapters
Use GODLE.adapters to integrate with Anthropic or OpenAI directly (Layer 1 pattern — you bring your own API key).
const adapter = GODLE.adapters.anthropic({ apiKey: 'sk-ant-...' });
// or
const adapter = GODLE.adapters.openai({ apiKey: 'sk-...' });
const result = await GODLE.run('copywriter', 'Write a tagline', { adapter });
Playground
The interactive API playground lets you test every endpoint live — including Layer 1 fetches, task submission, streaming, MCP calls, and workflow composition. It auto-generates curl commands and saves your configuration in localStorage.
Try the API interactively
Set your worker URL and API key once. Then test any endpoint and see the raw request, response, and auto-generated curl command side by side.
Keyboard shortcut: Cmd+Enter (macOS) or Ctrl+Enter (Windows/Linux) sends a request in the playground.
v2 → v3 migration
The v3 API is a superset of v2. All Layer 1 static endpoints and SDK methods remain backward-compatible. Layer 2 is live at orchestration.godle.app and purely additive — use it alongside v2 without any breaking changes.
What you need to change
| If you use | Change required |
|---|---|
| Static role/template JSON | Update /api/v2/ → /api/v3/ in fetch URLs |
| SDK bundle | Update the <script src> path from /v2/ to /v3/ |
GODLE.run() / GODLE.suggest() | No change — API surface is identical |
| Layer 2 features (tasks, sessions) | Deploy the Cloudflare Worker — then opt in per request |
v1 and v2 URLs remain live and will not be removed without a deprecation period of at least 90 days with advance notice.
Deploying Layer 2 for the first time
# 1. Create the KV namespace for rate limiting wrangler kv:namespace create RATE_LIMITS # → copy the returned id into wrangler.toml # 2. Set secrets wrangler secret put GODLE_API_KEYS # sk-godle-key1,sk-godle-key2 wrangler secret put ANTHROPIC_API_KEY # sk-ant-... wrangler secret put OPENAI_API_KEY # sk-... (optional) # 3. Deploy wrangler deploy
For the full step-by-step deploy runbook including staging environment setup and CI/CD configuration, see the DEPLOY.md in the repository.