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.

Need more checks? Top up packs ($5 / $10 / $15) add checks to your workspace in one transaction.

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>
API keys start with pg_ws_. Get yours at proceedgate.dev/pay.html — free, no card needed.

Base URL

https://governor.proceedgate.dev

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

FieldTypeRequiredDescription
agent_idstringIdentifier for the agent making the call (e.g. "scraper-prod-1")
task_hashstringSHA-256 (or any hash) of the current task/input. Identical hashes trigger loop detection.
actionenumtool_call · model_call · retry · override · plan_execute. Default: tool_call
step_hashstringOptional sub-step hash for finer loop granularity.
session_idstringOptional 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)

FieldTypeDescription
allowedbooleanAlways true on 200
zone"safe" | "gray"Loop detection zone. gray means AI reviewed and approved.
iteration_countnumberTimes this exact pattern was seen in the last 60 seconds.
proceed_tokenstringSigned ES256 JWT — proof this check passed. Expires in 45s.
credits_remainingnumberCredits left in your workspace after this call.

Response (429 — blocked)

FieldTypeDescription
allowedbooleanAlways false
zone"storm" | "gray"Why it was blocked
iteration_countnumberHow many identical requests triggered the block
errorstringloop_detected
reasonstringHuman-readable explanation
hintstringHow 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

FieldTypeDescription
policy_idstringretry_friction_v1 or low_confidence_loop_v1
actionstringAction type: tool_call, model_call, retry
actor.idstringAgent identifier
actor.projectstringWorkspace ID
context.attempt_in_windownumberAttempt count in current window
context.window_secondsnumberWindow duration
context.toolstringTool name
context.confidencenumberOptional: confidence score (0-1)
context.session_idstringOptional: 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

EventWhen fired
storm.detectedLoop enters storm zone (>10 identical requests/min). Includes block_count, estimated_cost_saved_usd, and behavioral fingerprint.
credits.lowCredits fall below threshold
subscription.createdNew subscription activated
subscription.renewedSubscription extended
subscription.expiring7 days before expiration
budget.exceededDaily/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.

Sessions are optional. If you just want per-workspace budget limits, use PUT /v1/billing/budget instead. Sessions are useful when you need per-agent, per-task budget caps with a defined time window.

Request body

FieldTypeRequiredDescription
agent_idstringAgent that owns this session
budget_usdstringMaximum USD spend for this session (e.g. "50.00")
duration_hoursnumberSession 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.

GET /v1/governor/session/ses_m1abc_x7k3f2

Response (200)

FieldTypeDescription
session_idstringSession identifier
agent_idstringAgent that owns the session
statusenumopen · closed · exceeded
budget_usdstringOriginal budget cap
total_spent_usdstringCumulative spend so far
remaining_usdstringBudget remaining
request_countnumberTotal checks made in this session
expires_atISO 8601Session expiry time
created_atISO 8601Session 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:

ToolDescription
gate_checkCheck if an action is allowed under current policy
gate_redeemResolve friction and get proceed token after payment
get_balanceCurrent credit balance and budget status
set_budgetSet daily/weekly/monthly spending limits
get_usage_reportCost breakdown by action type and tool

Error Codes

HTTPerrorMeaningFix
400invalid_requestMissing or invalid body fieldCheck agent_id and task_hash are present
401missing_authorizationNo Bearer token in headerAdd Authorization: Bearer pg_ws_...
401invalid_api_key_formatKey doesn't start with pg_ws_Use the key from your dashboard
402insufficient_creditsWorkspace out of creditsTop up at proceedgate.dev/pay.html
404workspace_not_foundAPI key not linked to a workspaceRe-generate your key from the dashboard
402session_budget_exceededSession budget cap reachedClose session and open a new one with a higher budget
404session_not_foundSession ID doesn't existCheck the session_id or create a new session
410session_expiredSession past its duration_hoursOpen a new session
429loop_detectedRetry storm detectedVary task_hash between tasks; wait 60s to reset
500internal_errorServer errorRetry with exponential backoff; check status page
On 429, do not retry immediately — that will just extend the block. Use a different 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
  }
}
FieldTypeDescription
creditCostnumberCredits consumed per request (0 for free endpoints)
creditPriceMicroUsdcnumberPrice per credit in microUSDC (10 = $0.00001)
loopDetectionobjectLoop detection config: max requests, window, zone names
budgetLimitsstring[]Supported budget cap granularities
sessionSupportbooleanWhether cumulative session tracking is available
Free endpoints like /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"]
  }
}
FieldTypeDescription
realmstringService domain — "cost-governance"
categoriesstring[]Tags for agent discovery / search
supportedIntentsstring[]What actions the API supports
protocolsstring[]Payment protocols supported (x402, MPP)