Developer API
Call Rigor from your code
Production-quality deliverables from a single API call. Rigor classifies your task, builds a methodology-driven plan, and executes each step — returning a structured deliverable with sources, quality score, and cost breakdown. Base URL: https://plith.ai
Authentication
All API requests require an API key sent via the x-api-key header. The Authorization header is not read — requests without x-api-key return 401 missing_api_key.
Keys are created at signup or via POST /api/keys. Your key identifies your organization — all workflows, billing, and data are scoped to it.
Anonymous mode (MCP only)
When connecting via MCP (Smithery, Claude Desktop, Cursor, etc.) without an API key, rigor_plan is available for evaluation against a demo org. Anonymous calls are rate-limited to 30 requests / minute and 500 requests / day per IP.
Quick start
1 · Get a key
curl -X POST https://plith.ai/api/keys \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "name": "My Org"}'
// Response — store api_key immediately, it cannot be retrieved again
{
"org_id": "a1b2c3d4-...",
"api_key": "plth_live_xxxxxxxxxxxx...",
"workspace_id": "ws_...",
"email_verified": false,
"credits": 2500,
"message": "Store this key securely — it will not be shown again. Verify your email to unlock 2,500 bonus credits."
}2 · Plan a workflow (free)
curl -X POST https://plith.ai/api/rigor/plan \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"task_description": "Design a caching layer for our API gateway"}'Returns a workflow_id and step sequence. No credits used.
3 · Execute
curl -X POST https://plith.ai/api/rigor/execute \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"workflow_id": "wr_2a4b6c8d...", "delivery": {"method": "polling"}}'4 · Get results
curl https://plith.ai/api/rigor/status/wr_2a4b6c8d... \ -H "x-api-key: YOUR_KEY"
Returns progress during execution and the full deliverable when complete.
Credits & billing
Plith is metered in credits at 1,000 credits per USD. New organizations receive 2,500 free credits immediately on signup. Verify your email to unlock 2,500 bonus credits (5,000 total). No monthly stipend — credits never expire.
Credit packs
| Amount | Credits |
|---|---|
| $10 | 10,000 |
| $25 | 25,000 |
| $100 | 100,000 |
| $250 | 250,000 |
| Custom ($5–$10,000) | 1,000 credits per dollar |
Purchase via POST /api/billing/checkout. Credits are deducted after each successful call; the amount deducted is reported as credits_used; your new balance as credits_remaining.
For Rigor workflows, credits accumulate server-side as steps execute. The pre-execution estimate appears in plan.cost; final usage is reported by GET /api/rigor/status as credits_used.
Rate limits
| Scope | Limit |
|---|---|
| Rigor endpoints (per org, sliding window) | 120 req / min |
/api/rigor/execute (per org, UTC day) | 1,000 req / day |
| Concurrent active workflows per org | Free: 1 · Pro: 3 · Team: 10 · Enterprise: unlimited |
/api/rigor/workflows/actions | 120 req / min |
| Anonymous MCP (per IP) | 30 req / min, 500 / day |
POST /api/keys (per IP) | 3 per 24 hours |
Active workflows (counting toward the concurrent limit): queued, executing, step_executing, resuming, quality_review, interactive_waiting, pending_approval, pending_human_review. When a rate limit is exceeded, the response includes retry_after (seconds) and a Retry-After HTTP header.
POST /api/rigor/plan
Classifies the task and builds a workflow plan without executing it. The plan is persisted so a subsequent /execute call can pass the workflow_id to skip re-classification.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
task_description | string (≥ 2 words) | Yes | What you want produced. Be specific. |
task_type | string | No | Hint to skip auto-classification. |
available_mcp_connections | object[] | No | Each: { id, label, server_url, capabilities } |
preferences | object | No | See preferences fields below. |
context | object | No | { additional_context: string } |
preferences fields
| Field | Type | Description |
|---|---|---|
rigor_level | "quick" | "standard" | "thorough" | Review depth. Default auto-detected. |
max_budget_usd | number | Budget ceiling; triggers budget_below_estimate warning. |
skip_frameworks | string[] | Framework display names to exclude. |
only_frameworks | string[] | Restrict to these frameworks (mutex with skip). |
add_frameworks | (string | obj)[] | Inject frameworks: { name, before_step } |
require_approval | boolean | Pause at pending_approval before the final step. |
approval_before_step | number[] | Zero-based step indices for approval gates. Out-of-range indices return 400 invalid_step_index. |
Response (200)
{
"ok": true,
"plan": {
"workflow_id": "wr_2a4b6c8d...",
"classification": { "task_type": "solution_design", "value_class": "operational" },
"sequence": [
{ "step": 1, "name": "Requirements Analysis", "estimated_credits": 80, "priority_class": "must" },
{ "step": 2, "name": "Solution Design", "estimated_credits": 240, "priority_class": "must" },
{ "step": 3, "name": "Assumption Verification","estimated_credits": 100, "priority_class": "should", "auto_added": true },
{ "step": 4, "name": "Review (Sonnet)", "estimated_credits": 120, "priority_class": "must" }
],
"cost": { "credits": 540, "usd": 0.54, "range": { "estimated_min": 400, "estimated_max": 680 } },
"rigor_level": "standard",
"warnings": [],
"info": ["Review: Haiku + Sonnet"]
}
}Review step names carry the model label: "Review (Haiku)", "Review (Sonnet)", "Review (Opus)".
Errors: 401 unauthorized · 400 invalid_body · 400 missing_field · 400 invalid_task_description · 400 vague_task_description · 429 rate_limit_exceeded · 504 plan_timeout · 500 plan_error
POST /api/rigor/execute
Executes a workflow end-to-end. Pass workflow_id to re-use a stored plan, or pass task_description to classify, plan, persist, and dispatch in a single call. Cost equals the plan's cost.credits. First Rigor workflow per org is free.
Delivery modes
| Mode | Set by | Returns |
|---|---|---|
| sse (default) | delivery.method: "sse" + Accept: text/event-stream | Event stream until completion or 290 s timeout |
| polling | delivery.method: "polling" | workflow_id + poll_url |
| webhook | delivery.method: "webhook" + HTTPS delivery.webhook_url | workflow_id + webhook_secret (32-byte hex HMAC) |
| interactive | mode: "interactive" | Returns interactive_waiting; driven step-by-step via /step |
SSE events
| Event | When |
|---|---|
workflow_started | Workflow metadata + steps preview |
step_started · step_completed · step_skipped | Per step |
quality_review | Score + summary after execution |
workflow_completed · workflow_pending_approval · workflow_error | Terminal events |
processing | Heartbeat every 15 s while waiting |
stream_timeout | Stream closes at 290 s; workflow continues — poll status |
Reconnect: each event carries an id: field of the form workflow_id:step_or_marker. To resume after a drop, resend the request with Last-Event-ID set to the last received id — missed events will be replayed.
GET /api/rigor/status/{workflow_id}
Returns workflow state and results. Only the owning organization can read a workflow.
Status values
pending · planned · queued · executing · step_executing · resuming · quality_review · interactive_waiting · pending_approval · pending_human_review · approved · completed · failed · cancelled · timed_out · blocked · halted
{
"ok": true,
"workflow": {
"workflow_id": "wr_2a4b6c8d...",
"status": "completed",
"task_type": "solution_design",
"current_step": 5,
"total_steps": 5,
"quality_score": 92,
"quality_review": {
"score": 92,
"summary": "Strong design with clear trade-offs.",
"path_to_100": ["Add p50/p95/p99 latency targets per cache tier."]
},
"deliverable": { "title": "...", "sections": [{ "heading": "...", "content": "..." }] },
"credits_used": 530,
"error": null
}
}POST /api/rigor/approve
{
"workflow_id": "wr_2a4b6c8d...",
"decision": "approved",
"notes": "OK to proceed",
"agent_id": "my-review-bot"
}Decision endpoint for workflows paused at pending_approval. On approval, the workflow automatically resumes. On rejection, the workflow is marked failed. Errors: 404 not_found · 409 invalid_status · 500 approve_failed
POST /api/rigor/resume
{
"workflow_id": "wr_2a4b6c8d...",
"revision_guidance": "Focus the rewrite on enterprise buyers; ignore SMB."
}Resumes a workflow from the last completed step. Permitted source statuses: executing, failed, approved, blocked, timed_out, pending_approval. Uses an optimistic lock — concurrent resume calls return resume_conflict.
POST /api/rigor/step
{
"workflow_id": "wr_2a4b6c8d...",
"action": "next",
"feedback": "Focus on security implications."
}Drives a workflow created with mode: "interactive". action accepts "next" | "skip" | "abort". Sessions expire after 30 minutes of inactivity. Errors: 409 invalid_status · 410 session_expired · 409 concurrent_step
GET /api/rigor/workflows
Lists workflows for the authenticated org with filtering and cursor-based pagination. Also returns a real-time concurrent-usage summary against your plan's concurrent workflow limit.
| Param | Type | Description |
|---|---|---|
status | string | Comma-separated (executing,queued). |
task_type | string | Filter by task type. |
created_after | ISO 8601 | After this time. |
created_before | ISO 8601 | Before this time. |
cursor | string | Opaque cursor from prior pagination.cursor. |
limit | integer | 1–100, default 20. |
POST /api/rigor/workflows/actions
{
"action": "cancel",
"workflow_ids": ["wr_aaa...", "wr_bbb..."],
"confirm": false,
"force": false
}Bulk workflow action endpoint. Currently supports action: "cancel". Two-phase: confirm: false (default) shows a preview, confirm: true executes. Max 20 workflow IDs per call.
GET /api/rigor/lineage/{workflowId}
Walks the prior_workflow_id chain backward and returns the full lineage, ordered oldest-first. Capped at 10 hops. Errors: 404 not_found · 422 chain_depth_exceeded
GET /api/rigor/templates
{
"templates": [{
"id": "uuid",
"task_type": "solution_design",
"template_name": "Solution Design",
"template_prompt": "...",
"placeholder_fields": ["system_name", "constraints"],
"description": "Architecture and design document for a technical system.",
"display_order": 1,
"version": 1,
"category": "Engineering"
}]
}Returns deliverable templates — 43 types across 8 categories. No auth required. Query: ?task_type= and/or ?category=.
POST /api/rigor/enhance
{ "task_description": "Design a caching layer", "tier": "llm" }Scores and optionally enhances a task description. tier: "deterministic" (default) is free, rule-based, no auth. tier: "llm" uses an LLM for richer suggestions — 270 credits, requires x-api-key. Response includes score (0–100), suggestions[], and (for llm tier) enhanced_prompt — a rewritten task. Errors: 400 input_too_long (10,000 char max) · 500 enhance_error
POST /api/rigor/connections
Registers a new MCP server connection. Server URL is validated for SSRF safety at registration time. Credentials are encrypted at rest immediately and never returned. Returns 201 with connection.status: "pending". Call /test to promote to active.
| Field | Type | Required | Description |
|---|---|---|---|
label | string | Yes | Human-readable name. |
server_url | string | Yes | HTTPS URL. |
auth_type | string | Yes | bearer_token | api_key | oauth | none |
transport | string | No | streamable-http (default) or sse |
auth_credential | object | Conditional | Required when auth_type is not none. |
GET /api/rigor/connections
Returns all connections registered for your organization. Credentials are never included. Status values: pending, active, error, revoked. capabilities is null until a connection test completes.
PATCH /api/rigor/connections/{id}
Updates a registered connection. All fields optional.
POST /api/rigor/connections/{id}/test
Tests connectivity. Performs DNS-level SSRF check. On success, status → active, last_tested_at recorded. On SSRF failure, status → error and the response is 400.
DELETE /api/rigor/connections/{id}
Soft delete. Record retained for audit, status set to revoked, credentials cleared. Revoked connections cannot be used in workflow execution.
Connection security
| Control | What it does |
|---|---|
| Credential encryption | AES-256-GCM at rest. Never returned in any response. |
| SSRF — registration | HTTPS only, no private IPs, no cloud metadata endpoints, no internal hostnames. |
| SSRF — test | DNS resolved at test time; all A/AAAA records checked against blocklist. |
| Read-only enforcement | Only resources/read and resources/list are executed. tools/call, prompts/*, sampling/*, all writes are blocked regardless of server capabilities. |
| Org isolation | Every request filtered by your org ID, derived from your API key. |
| Content sanitization | External MCP content wrapped in containment framing, scanned for prompt-injection patterns. |
Limits: max 10 connections per org · duplicate server_url rejected with 409 · HTTPS only.
MCP tools
Connect to Plith via MCP at https://plith.ai/api/mcp/rigor. Compatible with Claude Desktop, Cursor, Windsurf, Smithery, and any MCP-compatible client. Authenticate via the x-api-key header, or use anonymous mode (rate-limited: 30 req/min, 500 req/day per IP) for evaluation.
Discoverable tools
| Tool | Description |
|---|---|
rigor_plan | Plan a workflow without executing it (free). Available anonymously for evaluation. |
rigor_execute | Execute a planned or fresh workflow. |
rigor_status | Get workflow progress and results. |
Hidden tools
Callable but do not appear in tools/list:
| Tool | Description |
|---|---|
rigor_resume | Resume a stalled or failed workflow. |
rigor_approve | Approve or reject a workflow pending human review. |
rigor_step | Drive a single step of an interactive workflow. |
rigor_connections | Manage MCP connections. |
Plan-then-execute (recommended)
Plan first to see the step sequence and cost estimate. Execute only when satisfied.
# Step 1: Plan (free)
POST /api/rigor/plan
{ "task_description": "...", "preferences": { "rigor_level": "standard" } }
→ { plan: { workflow_id: "wr_...", sequence: [...], cost: { credits: 540 } } }
# Step 2: Execute with polling delivery
POST /api/rigor/execute
{ "workflow_id": "wr_...", "delivery": { "method": "polling" } }
→ { workflow_id: "wr_...", status: "queued", poll_url: "/api/rigor/status/wr_..." }
# Step 3: Poll until "completed"
GET /api/rigor/status/wr_...
→ { workflow: { status: "completed", deliverable: { ... } } }Webhook delivery
Receive results pushed to your endpoint instead of polling. Store webhook_secret and verify incoming payloads via HMAC-SHA256.
POST /api/rigor/execute
{
"workflow_id": "wr_...",
"delivery": {
"method": "webhook",
"webhook_url": "https://your-server.example.com/rigor-webhook"
}
}
→ { webhook_url: "...", webhook_status: "registered", webhook_secret: "..." }Approval gate
Request a human decision before final steps execute.
# Plan with approval gate
POST /api/rigor/plan
{ "task_description": "...", "preferences": { "require_approval": true } }
# Execute — workflow will pause at pending_approval
POST /api/rigor/execute
{ "workflow_id": "wr_...", "delivery": { "method": "polling" } }
# Poll until status === "pending_approval", then approve
POST /api/rigor/approve
{ "workflow_id": "wr_...", "decision": "approved", "notes": "Looks good" }
# workflow automatically resumes after approvalInteractive mode
Drive execution one step at a time. Sessions expire after 30 minutes of inactivity.
POST /api/rigor/execute
{ "task_description": "...", "mode": "interactive" }
→ { status: "interactive_waiting", sequence: [...] }
POST /api/rigor/step
{ "workflow_id": "wr_...", "action": "next" }
→ { status: "step_executing", poll_url: "..." }Workflow chaining
Inherit context from a completed workflow into a new one. Chain depth limit: 10 links.
POST /api/rigor/execute
{
"task_description": "Implement the solution from the prior design",
"prior_workflow_id": "wr_parent...",
"context_fields": ["deliverable", "quality_review"]
}Worked example
A complete plan → execute → poll cycle for a Solution Design.
curl -X POST https://plith.ai/api/rigor/plan \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"task_description": "Design a caching layer for our API"}'
# → plan.cost.credits = 560 · estimated cost shown before committing
curl -X POST https://plith.ai/api/rigor/execute \
-H "x-api-key: YOUR_KEY" \
-d '{"workflow_id": "wr_...", "delivery": {"method": "polling"}}'
# → status: queued · poll_url returned
curl https://plith.ai/api/rigor/status/wr_... \
-H "x-api-key: YOUR_KEY"
# → status: completed · quality_score: 92 · credits_used: 545Error reference
All endpoints return errors in this envelope:
{
"error": {
"code": "missing_field",
"message": "workflow_id is required.",
"request_id": "req_abc123def456...",
"fix": "POST /api/rigor/plan with your task_description",
"docs": "https://plith.ai/docs/errors#missing_field",
"details": { "field": "workflow_id" }
}
}fix, docs, and details are included only when available. request_id is always present.
Auth
| Code | HTTP | Summary |
|---|---|---|
missing_api_key | 401 | Provide x-api-key header. |
invalid_api_key | 401 | Key not found or revoked. |
forbidden | 403 | Resource belongs to a different org. |
Validation
| Code | HTTP | Summary |
|---|---|---|
invalid_body | 400 | Body must be valid JSON. |
missing_field | 400 | <field> required. |
invalid_task_description | 400 | Must contain at least 2 words. |
vague_task_description | 400 | Classifier confidence too low. |
input_too_long | 400 | Input exceeds maximum length. |
invalid_step_index | 400 | approval_before_step index out of range. |
Rate limiting
| Code | HTTP | Summary |
|---|---|---|
rate_limit_exceeded | 429 | Wait per Retry-After header. |
concurrent_limit_exceeded | 429 | Plan's concurrent workflow limit reached (Free: 1, Pro: 3, Team: 10). |
Workflow state
| Code | HTTP | Summary |
|---|---|---|
not_found | 404 | Workflow not found. |
no_plan | 400 | Workflow has no plan. |
insufficient_credits | 402 | Top up via /api/billing/checkout. |
workspace_budget_exceeded | 402 | Adjust budget or reduce plan. |
workflow_has_progress | 409 | Use /resume. |
invalid_status | 409 | Action not allowed in current state. |
duplicate_task | 409 | Identical task in last 5 min. |
already_complete | 409 | Nothing to resume. |
resume_conflict | 409 | Another resume in progress. |
pending_human_review | 409 | Use /approve. |
Chaining & connections
| Code | HTTP | Summary |
|---|---|---|
prior_not_found | 404 | Prior workflow not found. |
prior_not_terminal | 409 | Wait for prior to complete. |
chain_depth_exceeded | 422 | Max 10 hops. |
context_too_large | 422 | Use context_fields to restrict. |
feature_not_enabled | 501 | MCP gateway disabled. |
session_expired | 410 | 30-min TTL — use /resume. |
plan_timeout | 504 | Simplify or split the task. |
provider_exhausted | 503 | All providers failed — retry. |
internal_error | 500 | Retry; include request_id. |
Response conventions
Every successful response includes:
| Field | Type | Description |
|---|---|---|
request_id | string | Always req_ + 24 hex chars. Include when contacting support. |
credits_used | number | Credits deducted by this request. 0 for free endpoints. |
credits_remaining | number | Org balance after this request. |
fallback_behavior | string | What the system did when upstream was degraded — "none" when normal. |
Rigor workflow endpoints (/plan, /execute, /status, /approve, /resume, /step) use product-specific response shapes and do not include credits_used / credits_remaining at the top level. Credit usage for workflows is reported via the status endpoint as workflow.credits_used.