Documentation
ProceedGate is a reusable pre-call guard for expensive or sensitive AI workflow tool calls. Add one POST /v1/check before OpenAI, Replicate, SerpAPI, Firecrawl, Apify, SAP, CRM, or internal HTTP steps to detect repeated tasks, budget pressure, and runaway loops before the next paid request runs. Scraping and retry-storm workloads are supported as a secondary pattern — see Scraping.
Where to place ProceedGate
Insert the guard immediately before the tool call that spends money or touches sensitive data — not after the vendor responds.
// Illustrative flow (any orchestrator) Webhook / trigger → ProceedGate /v1/check // agent_id + task_hash → IF allowed → SerpAPI / Firecrawl / OpenAI / CRM → IF blocked → alert + stop (no vendor call) // n8n: HTTP Request → IF on allowed / zone → expensive nodes
See Using ProceedGate with n8n and Runaway workflow simulator (client-side demo).
Quickstart
Get a free API key at proceedgate.dev/pay.html — 5,000 checks/month, no credit card.
1. Make your first check
curl -X POST https://governor.proceedgate.dev/v1/check \ -H "Authorization: Bearer $PG_KEY" \ -H "Content-Type: application/json" \ -d '{ "agent_id": "my-agent", "task_hash": "sha256-of-current-task", "action": "tool_call" }'
2. Handle the response
// ✅ Allowed (HTTP 200) { "allowed": true, "zone": "safe", "iteration_count": 3, "proceed_token": "eyJ...", "credits_remaining": 1997 } // 🚫 Loop detected (HTTP 429) { "allowed": false, "zone": "storm", "iteration_count": 11, "error": "loop_detected", "reason": "11 identical requests in 60s" }
3. Drop it into your agent loop
// Node.js async function pgCheck(agentId, taskHash) { const res = await fetch('https://governor.proceedgate.dev/v1/check', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.PG_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ agent_id: agentId, task_hash: taskHash, action: 'tool_call' }), }); if (res.status === 429) throw new Error('loop_detected'); if (!res.ok) throw new Error('check_failed'); return res.json(); } // In your agent loop: for (const url of urls) { await pgCheck('scraper', sha256(url)); // throws on block const data = await fetch(url); }
Authentication
All requests require a Bearer token in the Authorization header:
Authorization: Bearer pg_ws_<your-key>
pg_ws_. Get yours at proceedgate.dev/pay.html — free, no card needed.Base URL
All endpoints are served over HTTPS. The API is hosted on Cloudflare Workers (global edge, <50ms p99).
POST/v1/check
The primary endpoint. Runs loop detection + credit check and returns a signed proceed_token. Auto-derives your workspace from the API key — no extra config needed.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
agent_id | string | ✓ | Identifier for the agent making the call (e.g. "scraper-prod-1") |
task_hash | string | ✓ | SHA-256 (or any hash) of the current task/input. Identical hashes trigger loop detection. |
action | enum | tool_call · model_call · retry · override · plan_execute. Default: tool_call | |
step_hash | string | Optional sub-step hash for finer loop granularity. | |
session_id | string | Optional session ID for cumulative budget tracking. When set, spend is tracked against the session budget and response includes X-Proceedgate-Session-Spent / X-Proceedgate-Session-Remaining headers. |
Response (200 — allowed)
| Field | Type | Description |
|---|---|---|
allowed | boolean | Always true on 200 |
zone | "safe" | "gray" | Loop detection zone. gray means AI reviewed and approved. |
iteration_count | number | Times this exact pattern was seen in the last 60 seconds. |
proceed_token | string | Signed ES256 JWT — proof this check passed. Expires in 45s. |
credits_remaining | number | Credits left in your workspace after this call. |
Response (429 — blocked)
| Field | Type | Description |
|---|---|---|
allowed | boolean | Always false |
zone | "storm" | "gray" | Why it was blocked |
iteration_count | number | How many identical requests triggered the block |
error | string | loop_detected |
reason | string | Human-readable explanation |
hint | string | How to fix (vary task_hash, wait 60s) |
POST/v1/governor/check
Full governance check with AI reasoning, loop detection, and policy evaluation. Returns detailed reasoning chain and confidence scores.
Request body
| Field | Type | Description |
|---|---|---|
policy_id | string | retry_friction_v1 or low_confidence_loop_v1 |
action | string | Action type: tool_call, model_call, retry |
actor.id | string | Agent identifier |
actor.project | string | Workspace ID |
context.attempt_in_window | number | Attempt count in current window |
context.window_seconds | number | Window duration |
context.tool | string | Tool name |
context.confidence | number | Optional: confidence score (0-1) |
context.session_id | string | Optional: session ID for cumulative budget tracking |
Response (200 allowed)
{
"allowed": true,
"decision_id": "dec_01KMT...",
"proceed_token": "eyJhbG...",
"expires_in_seconds": 45,
"reason_code": "none",
"confidence": 0.98,
"ai_reasoning": "All governance checks passed...",
"reasoning_chain": [
{ "step": "pattern_check", "conclusion": "Request is within safe limits" },
{ "step": "budget_check", "conclusion": "Cost budget allows operation" },
{ "step": "governance_decision", "conclusion": "ALLOW" }
]
}
Response (402 friction required)
Returned when your workspace is out of checks (credits). Top up packs are available at /topup.html.
x402-price: 0.004 USDC x402-recipient: 0x607Fc9D41858Aa... x402-chain: BSC
POST/v1/governor/redeem
Resolve friction by providing a payment transaction hash. Returns a proceed_token upon successful verification.
Request
Header: x402-tx-hash: 0x...
{
"decision_id": "dec_01KMT..."
}
Response (200)
{
"ok": true,
"decision_id": "dec_01KMT...",
"proceed_token": "eyJhbG...",
"expires_in_seconds": 45,
"receipt": {
"tx_hash": "0x...",
"paid_price": "0.004 USDC",
"paid_chain": "bsc"
}
}
POST/v1/check/batch
Check multiple agent tasks in a single HTTP call. Useful when orchestrating many parallel agents. Returns an array of results in the same order as the input.
Request body
{
"checks": [
{ "agent_id": "researcher", "task_hash": "abc123", "action": "model_call" },
{ "agent_id": "scraper", "task_hash": "def456", "action": "tool_call" }
]
}
Maximum 50 checks per batch. Each check follows the same schema as /v1/check.
Response (200)
{
"ok": true,
"results": [
{ "allowed": true, "zone": "safe", "iteration_count": 1, "proceed_token": "eyJ..." },
{ "allowed": false, "zone": "storm", "iteration_count": 12, "error": "loop_detected" }
],
"credits_remaining": 1990
}
GET/v1/me
Returns workspace info for the authenticated API key — plan, credits, features.
curl https://governor.proceedgate.dev/v1/me \
-H "Authorization: Bearer $PG_KEY"
{
"ok": true,
"workspace_id": "free-abc123",
"plan": { "id": "free", "name": "Free" },
"credits": { "remaining": 1997, "included": 2000 }
}
GET/v1/me/stats
Returns real-time governance stats for your workspace: decisions, storms blocked, cost saved, and a 60-minute storm chart.
{
"ok": true,
"workspace_id": "free-abc123",
"total_decisions": 42,
"storms_blocked": 3,
"cost_saved_usd": 0.15,
"decisions": [ /* last 50 */ ],
"storm_chart": [ /* 60 per-minute buckets */ ]
}
GET/v1/billing/balance
Returns current credit balance and usage.
curl "https://governor.proceedgate.dev/v1/billing/balance?workspace_id=free-abc123" \
-H "Authorization: Bearer $PG_KEY"
PUT/v1/billing/budget
Set daily, weekly, or monthly spend caps. When the cap is hit, /v1/check returns 402 and optionally fires a webhook.
curl -X PUT https://governor.proceedgate.dev/v1/billing/budget \ -H "Authorization: Bearer $PG_KEY" \ -H "Content-Type: application/json" \ -d '{ "workspace_id": "free-abc123", "daily": 100, "weekly": 500 }'
GET/v1/billing/usage
Returns detailed usage breakdown for your workspace: credits used by action type, tool, and daily totals.
curl "https://governor.proceedgate.dev/v1/billing/usage?workspace_id=free-abc123&period=week" \
-H "Authorization: Bearer $PG_KEY"
Response (200)
{
"workspace_id": "free-abc123",
"period": "week",
"total_credits_used": 142,
"total_cost_usd": 0.00142,
"breakdown": {
"by_action": { "tool_call": 100, "model_call": 42 },
"by_tool": { "web_scrape": 80, "search_api": 62 },
"by_day": [
{ "date": "2026-03-28", "credits": 45 }
]
}
}
PUT/v1/billing/:workspaceId/webhook
Configure a webhook endpoint for real-time governance alerts. Webhooks are HMAC-SHA256 signed — verify the X-ProceedGate-Signature header to ensure authenticity.
curl -X PUT https://governor.proceedgate.dev/v1/billing/YOUR_WORKSPACE_ID/webhook \ -H "Authorization: Bearer $PG_KEY" \ -H "Content-Type: application/json" \ -d '{ "webhook_url": "https://your-server.com/webhook", "webhook_secret": "whsec_...", "events": ["storm.detected", "credits.low"] }'
Supported events
| Event | When fired |
|---|---|
storm.detected | Loop enters storm zone (>10 identical requests/min). Includes block_count, estimated_cost_saved_usd, and behavioral fingerprint. |
credits.low | Credits fall below threshold |
subscription.created | New subscription activated |
subscription.renewed | Subscription extended |
subscription.expiring | 7 days before expiration |
budget.exceeded | Daily/weekly/monthly budget limit hit |
storm.detected payload
{
"event": "storm.detected",
"timestamp": "2026-05-01T12:34:56.000Z",
"data": {
"workspace_id": "w1",
"request_hash": "sha256:abc123...",
"block_count": 47,
"total_blocked_ms": 5230,
"estimated_cost_saved_usd": 2.35,
"alert_severity": "high",
"fingerprint": { "burst_index": 0.87, "entropy": 0.341, "fanout_ratio": 2.1 }
}
}
Signature verification (Node.js)
// Verify incoming webhook from ProceedGate import { createHmac, timingSafeEqual } from 'node:crypto'; function verifyWebhook(rawBody, signatureHeader, secret) { const expected = createHmac('sha256', secret).update(rawBody).digest('hex'); const a = Buffer.from('sha256=' + expected); const b = Buffer.from(signatureHeader); return a.length === b.length && timingSafeEqual(a, b); } // Usage: verifyWebhook(rawBody, req.headers['x-proceedgate-signature'], SECRET)
See examples/storm-webhook-slack.mjs for a complete Slack integration with deduplication and severity-based routing.
POST/v1/governor/session
Open a budget session. Sessions track cumulative spend across multiple /v1/check calls — like an escrow with a hard cap. Inspired by the MPP voucher accumulation pattern.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
agent_id | string | ✓ | Agent that owns this session |
budget_usd | string | ✓ | Maximum USD spend for this session (e.g. "50.00") |
duration_hours | number | Session lifetime in hours. Default: 24 |
Response (201)
{
"ok": true,
"session_id": "ses_m1abc_x7k3f2",
"budget_usd": "50.00",
"expires_at": "2026-03-29T14:30:00.000Z"
}
Example: full session flow
# 1. Open session with $50 budget curl -X POST https://governor.proceedgate.dev/v1/governor/session \ -H "Authorization: Bearer $PG_KEY" \ -H "Content-Type: application/json" \ -d '{ "agent_id": "scraper-1", "budget_usd": "50.00", "duration_hours": 8 }' # 2. Run checks with session_id — spend is tracked cumulatively curl -X POST https://governor.proceedgate.dev/v1/governor/check \ -H "Authorization: Bearer $PG_KEY" \ -H "Content-Type: application/json" \ -d '{ "agent_id": "scraper-1", "task_hash": "abc123", "session_id": "ses_m1abc_x7k3f2" }' # Response headers include: # X-Proceedgate-Session-Spent: 0.010000 # X-Proceedgate-Session-Remaining: 49.990000 # 3. Close session when done (settle) curl -X DELETE https://governor.proceedgate.dev/v1/governor/session/ses_m1abc_x7k3f2 \ -H "Authorization: Bearer $PG_KEY"
GET/v1/governor/session/:id
Get the current status of a session — cumulative spend, remaining budget, and request count.
Response (200)
| Field | Type | Description |
|---|---|---|
session_id | string | Session identifier |
agent_id | string | Agent that owns the session |
status | enum | open · closed · exceeded |
budget_usd | string | Original budget cap |
total_spent_usd | string | Cumulative spend so far |
remaining_usd | string | Budget remaining |
request_count | number | Total checks made in this session |
expires_at | ISO 8601 | Session expiry time |
created_at | ISO 8601 | Session creation time |
DELETE/v1/governor/session/:id
Close a session and finalize the cumulative spend. Like an MPP settlement — no more checks can be made against this session after closing.
Response (200)
{
"ok": true,
"session_id": "ses_m1abc_x7k3f2",
"final_spent_usd": "12.350000",
"request_count": 247,
"status": "closed"
}
GET/.well-known/jwks.json
Public key discovery for verifying proceed_token JWTs. Standard JWKS format. Use this to verify governance tokens downstream without calling the governor.
curl https://governor.proceedgate.dev/.well-known/jwks.json
Usage with jose (Node.js)
import * as jose from 'jose'; const JWKS = jose.createRemoteJWKSet( new URL('https://governor.proceedgate.dev/.well-known/jwks.json') ); const { payload } = await jose.jwtVerify(proceedToken, JWKS, { issuer: 'https://governor.proceedgate.dev', audience: 'agent-cost-governor', }); // payload.sub = agent_id, payload.jti = decision_id
GET/health
Returns 200 OK with API status and latency. Use for uptime monitoring.
curl https://governor.proceedgate.dev/health
Node.js Integration
Set PG_KEY in your environment, then call pgCheck() before each agent action.
// pgCheck.js const PG_KEY = process.env.PG_KEY; const PG_URL = 'https://governor.proceedgate.dev/v1/governor/check'; export async function pgCheck(agentId, taskHash, action = 'tool_call') { const res = await fetch(PG_URL, { method: 'POST', headers: { 'Authorization': `Bearer ${PG_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ agent_id: agentId, task_hash: taskHash, action }), }); const data = await res.json(); if (res.status === 429) throw new Error(`loop_detected: ${data.reason}`); if (res.status === 402) throw new Error('insufficient_credits'); if (!res.ok) throw new Error(`pg_error: ${data.error}`); return data; // { allowed, zone, proceed_token, credits_remaining } } // Usage in Apify actor: import { createHash } from 'crypto'; const sha256 = s => createHash('sha256').update(s).digest('hex'); for (const url of urlQueue) { await pgCheck('apify-actor', sha256(url)); const html = await fetch(url).then(r => r.text()); await processPage(html); }
Python Integration
# pg_check.py import os, hashlib, httpx PG_KEY = os.environ["PG_KEY"] PG_URL = "https://governor.proceedgate.dev/v1/governor/check" def pg_check(agent_id: str, task_hash: str, action: str = "tool_call"): res = httpx.post( PG_URL, headers={"Authorization": f"Bearer {PG_KEY}", "Content-Type": "application/json"}, json={"agent_id": agent_id, "task_hash": task_hash, "action": action}, timeout=10, ) data = res.json() if res.status_code == 429: raise RuntimeError(f"loop_detected: {data.get('reason')}") if res.status_code == 402: raise RuntimeError("insufficient_credits") res.raise_for_status() return data # Usage: def sha256(s): return hashlib.sha256(s.encode()).hexdigest() for url in urls: pg_check("scraper", sha256(url)) html = httpx.get(url).text
@proceedgate/node
Framework-agnostic Node.js / TypeScript SDK. Detects retry storms, enforces budgets, returns signed tokens. Works with any agent framework.
npm i @proceedgate/node
gateStep — non-throwing check
import { createProceedGateClient, gateStep } from '@proceedgate/node';
const client = createProceedGateClient({
baseUrl: 'https://governor.proceedgate.dev',
actor: { id: 'my-agent', project: 'my-workspace-id' },
apiKey: process.env.PG_KEY,
});
const result = await gateStep(client, {
policyId: 'retry_friction_v1',
action: 'tool_call',
context: { attempt_in_window: 3, window_seconds: 60, tool: 'web_scrape' },
});
if (result.kind === 'ok') {
// Allowed — proceed_token in result.proceedToken
} else {
console.log('Blocked:', result.friction?.price); // e.g. "0.004 USDC"
}
requireGateStepOk — throws on friction
import { requireGateStepOk, ProceedGateFrictionError } from '@proceedgate/node';
try {
await requireGateStepOk(client, {
policyId: 'retry_friction_v1',
action: 'retry',
context: { attempt_in_window: 7, window_seconds: 60 },
});
// Allowed — run action
} catch (e) {
if (e instanceof ProceedGateFrictionError) {
console.log('Blocked:', e.decisionId, e.friction);
}
}
@proceedgate/langchain
LangChain integration with three components: callback handler, tool wrapper, and agent executor. Works with @langchain/core ≥0.2.
npm i @proceedgate/langchain
Callback handler (intercepts all LLM + tool calls)
import { ProceedGateCallbackHandler } from '@proceedgate/langchain';
import { ChatOpenAI } from '@langchain/openai';
const handler = new ProceedGateCallbackHandler({
apiKey: process.env.PG_KEY,
workspaceId: 'my-workspace',
onFriction: 'block',
});
const model = new ChatOpenAI({ callbacks: [handler] });
Tool wrapper
import { wrapToolWithGate } from '@proceedgate/langchain';
const gatedSearch = wrapToolWithGate(searchTool, {
apiKey: process.env.PG_KEY,
workspaceId: 'my-workspace',
});
@proceedgate/vercel-ai
Vercel AI SDK integration. Wraps language models and tools with ProceedGate governance via the middleware API. Compatible with ai ≥3.0.
npm i @proceedgate/vercel-ai
Middleware (gates every LLM call)
import { generateText, wrapLanguageModel } from 'ai';
import { openai } from '@ai-sdk/openai';
import { proceedGateMiddleware } from '@proceedgate/vercel-ai';
const model = wrapLanguageModel({
model: openai('gpt-4o'),
middleware: proceedGateMiddleware({
apiKey: process.env.PG_KEY,
workspaceId: 'my-workspace',
onFriction: 'block',
maxBudget: 5.00, // $5 hard cap
}),
});
const result = await generateText({ model, prompt: 'Analyze...' });
Tool gating
import { tool } from 'ai';
import { z } from 'zod';
import { gatedTool } from '@proceedgate/vercel-ai';
const gate = gatedTool({ apiKey: process.env.PG_KEY, workspaceId: 'ws' });
const searchTool = gate(
tool({
description: 'Search the web',
parameters: z.object({ query: z.string() }),
execute: async ({ query }) => doSearch(query),
}),
{ costEstimate: 0.01 }
);
proceedgate-crewai (Python)
CrewAI integration for Python agents. Three components: callback handler, tool decorator, and budget-aware crew wrapper.
pip install proceedgate-crewai
Tool decorator
from proceedgate_crewai import gated_tool @gated_tool(api_key="pg_ws_...", workspace_id="my-ws") def search_web(query: str) -> str: return external_search_api(query)
Budget-aware crew
from crewai import Crew, Agent, Task from proceedgate_crewai import BudgetAwareCrew crew = Crew(agents=[...], tasks=[...]) gated = BudgetAwareCrew( crew=crew, api_key="pg_ws_...", workspace_id="my-ws", max_budget=2.50, # $2.50 hard stop ) result = gated.kickoff(inputs={"topic": "lead enrichment workflow"}) print(f"Spent: ${gated.total_cost:.4f}")
@proceedgate/mcp-server
Model Context Protocol server for AI coding tools (Claude Code, Cursor, etc.). Exposes 5 tools for governance, balance, and usage reporting.
npm i -g @proceedgate/mcp-server
Claude Desktop / Claude Code setup
// claude_desktop_config.json { "mcpServers": { "proceedgate": { "command": "proceedgate-mcp", "args": ["--api-key", "pg_ws_...", "--workspace-id", "my-ws"] } } }
Available MCP tools:
| Tool | Description |
|---|---|
gate_check | Check if an action is allowed under current policy |
gate_redeem | Resolve friction and get proceed token after payment |
get_balance | Current credit balance and budget status |
set_budget | Set daily/weekly/monthly spending limits |
get_usage_report | Cost breakdown by action type and tool |
Error Codes
| HTTP | error | Meaning | Fix |
|---|---|---|---|
| 400 | invalid_request | Missing or invalid body field | Check agent_id and task_hash are present |
| 401 | missing_authorization | No Bearer token in header | Add Authorization: Bearer pg_ws_... |
| 401 | invalid_api_key_format | Key doesn't start with pg_ws_ | Use the key from your dashboard |
| 402 | insufficient_credits | Workspace out of credits | Top up at proceedgate.dev/pay.html |
| 404 | workspace_not_found | API key not linked to a workspace | Re-generate your key from the dashboard |
| 402 | session_budget_exceeded | Session budget cap reached | Close session and open a new one with a higher budget |
| 404 | session_not_found | Session ID doesn't exist | Check the session_id or create a new session |
| 410 | session_expired | Session past its duration_hours | Open a new session |
| 429 | loop_detected | Retry storm detected | Vary task_hash between tasks; wait 60s to reset |
| 500 | internal_error | Server error | Retry with exponential backoff; check status page |
task_hash for genuinely new work, or wait 60 seconds for the window to reset.
GET/openapi.json
Returns the full OpenAPI 3.1 specification for the ProceedGate API. AI agents can use this endpoint to auto-discover capabilities, pricing, and payment requirements before making requests.
curl https://governor.proceedgate.dev/openapi.json
The spec includes two custom extensions designed for machine-to-machine discovery:
x-cost-info Extension
Each endpoint in the OpenAPI spec includes an x-cost-info object that tells agents what a request will cost before they make it. This follows the same discovery pattern as MPP's x-payment-info.
Example (on /v1/check)
{
"x-cost-info": {
"creditCost": 1,
"creditPriceMicroUsdc": 10,
"loopDetection": {
"enabled": true,
"maxIdenticalRequests": 10,
"windowSeconds": 60,
"zones": ["safe", "gray", "storm"]
},
"budgetLimits": ["daily", "weekly", "monthly"],
"sessionSupport": true
}
}
| Field | Type | Description |
|---|---|---|
creditCost | number | Credits consumed per request (0 for free endpoints) |
creditPriceMicroUsdc | number | Price per credit in microUSDC (10 = $0.00001) |
loopDetection | object | Loop detection config: max requests, window, zone names |
budgetLimits | string[] | Supported budget cap granularities |
sessionSupport | boolean | Whether cumulative session tracking is available |
/v1/billing/balance have "creditCost": 0 so agents know they can call them without spending credits.x-service-info Extension
The top-level info object includes x-service-info — a machine-readable summary of what ProceedGate does and which protocols it supports. This helps AI agents decide whether this API is relevant to their task.
{
"x-service-info": {
"realm": "cost-governance",
"categories": ["ai-agents", "cost-control", "loop-detection", "budget-management"],
"supportedIntents": ["check", "budget", "session"],
"documentation": "https://proceedgate.dev",
"protocols": ["x402", "mpp"]
}
}
| Field | Type | Description |
|---|---|---|
realm | string | Service domain — "cost-governance" |
categories | string[] | Tags for agent discovery / search |
supportedIntents | string[] | What actions the API supports |
protocols | string[] | Payment protocols supported (x402, MPP) |