API Documentation

Everything an agent or a human needs to send traces and read verdicts. Search below, or jump to a section. Machine-readable spec at /openapi.json; agent guide at /llms.txt.

AuthenticationWhat’s a Snapback?EndpointsSubmit a traceOpenTelemetry (OTLP)Get the verdictPre-flight (before you run)MCP (for AI agents)Connect the skillCoverage — 46 familiesSelf-healing & gate contractDelivery channelsErrorsVerifying webhook signatures

Authentication

#auth

Every request carries your source's ingest token as a Bearer header. Create a source on the Connect tab to get one.

header
Authorization: Bearer vdk_YOUR_TOKEN

What's a Snapback?

#snapbacks

A Snapback is the verdict you get back for a failed agent run. Each Snapback contains: the failure_class (the diagnosed failure mode, drawn from a continuously-growing taxonomy), the failed_at_step and failure_agent (exactly where and who broke), the root_cause (why), a fix_suggestion (what to do), a confidence score, and cost forensics (what the run cost in tokens).

You send a trace, you get a Snapback. Many are answered instantly from the shared pattern library with no LLM call (source: "library"); the rest are diagnosed live and fold back into the library. So "a Snapback" is your billing unit too — one completed diagnosis.

Endpoints

#endpoints
POST
/v1/traces

Submit a failure trace. Returns a trace_id; poll the verdict endpoint.

POST
/v1/traces/otlp

Send OpenTelemetry (OTLP/JSON) traces. Already emitting OTel via Langfuse/MLflow/etc.? Point your exporter here — no re-instrumentation.

GET
/v1/verdicts/{trace_id}

Fetch the verdict once produced (202 while processing).

GET
/v1/preflight

Ask what commonly fails for ?agent_stack=&tags=. Free. Self-correct before you run.

POST
/v1/preflight/feedback

Tell us a preflight card helped or was noise: {pattern_id, useful:true|false}. Sharpens what preflight surfaces.

POST
/v1/feedback

Rate a verdict: {verdict_id, correct:true|false}. Your correction sharpens the shared library.

Full machine-readable spec: OpenAPI 3.1 at /openapi.json, and an LLM roadmap at /llms.txt. Imports into MuleSoft, Kong, Apigee, Postman, and Apidog.

Submit a trace

#submit-trace

Send a failed run. Only failures are diagnosed. PII is scrubbed by default.

curl
curl -X POST "https://ingest.snapback.sh/v1/traces" \
  -H "Authorization: Bearer vdk_YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "outcome": "failure",
    "steps": [
      {"i": 1, "agent": "planner", "text": "plan the task"},
      {"i": 2, "agent": "executor", "text": "retry retry stuck in a loop"}
    ]
  }'
python
import requests

r = requests.post(
    "https://ingest.snapback.sh/v1/traces",
    headers={"Authorization": "Bearer vdk_YOUR_TOKEN"},
    json={"outcome": "failure", "steps": [
        {"i": 1, "agent": "planner", "text": "plan the task"},
        {"i": 2, "agent": "executor", "text": "retry retry stuck in a loop"},
    ]},
)
trace_id = r.json()["trace_id"]

Get the verdict

#get-verdict

Poll until the verdict is ready. source: "library" means a known pattern matched instantly — no LLM call.

curl
curl "https://ingest.snapback.sh/v1/verdicts/TRACE_ID" \
  -H "Authorization: Bearer vdk_YOUR_TOKEN"
json
{
  "failure_class": "loop",
  "root_cause": "The agent repeated the same action without a termination condition...",
  "fix_suggestion": "Add a max-iterations cap and a no-progress break condition.",
  "confidence": 0.9,
  "source": "library"
}

Pre-flight (before you run)

#preflight

Ask what commonly fails for your setup and self-correct in advance. Free.

curl
curl "https://ingest.snapback.sh/v1/preflight?agent_stack=openclaw&tags=tool_calling" \
  -H "Authorization: Bearer vdk_YOUR_TOKEN"

OpenTelemetry (OTLP)

#otel

Already emitting OpenTelemetry traces (via Langfuse, MLflow, OpenLLMetry, AgentOps, and similar)? Point your existing OTLP/JSON exporter at Snapback — no re-instrumentation. We read the OTel GenAI and OpenInference conventions and diagnose with the same engine.

curl
curl -X POST "https://ingest.snapback.sh/v1/traces/otlp" \
  -H "Authorization: Bearer vdk_YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "resourceSpans": [{"scopeSpans": [{"spans": [
      {"spanId":"s1","name":"execute_tool web_search","startTimeUnixNano":"1000",
       "attributes":[{"key":"gen_ai.tool.name","value":{"stringValue":"web_search"}}]},
      {"spanId":"s2","name":"chat gpt-4o","startTimeUnixNano":"2000",
       "attributes":[
         {"key":"gen_ai.request.model","value":{"stringValue":"gpt-4o"}},
         {"key":"gen_ai.usage.input_tokens","value":{"intValue":"800"}},
         {"key":"gen_ai.usage.cost","value":{"doubleValue":0.05}}]}
    ]}]}]
  }'

Returns 202 with trace_id, verdict_id, and spans_ingested. Poll the verdict endpoint as usual.

MCP (for AI agents)

#mcp

Two ways to hand this to an agent: point it at snapback.sh/llms.txt and let it work out the rest — or point an MCP client at https://api.snapback.sh/mcp and it gets the same catalogue as callable tools. Discovery, docs (search_docs), and mid-run loop checks (detect_loop) are free and need no token.

Production path (recommended): pay-per-call via x402. POST your trace to https://api.snapback.sh/mcp/x402 with no account — you get an HTTP 402 with the price (~$0.0032 USDC), pay from your agent wallet, and get the verdict. No signup, no monthly limits. This is the path built for autonomous agents at scale.

What we accept & how it settles. x402 pays in USDC on multiple chains — Solana and the EVM chains Base, Arbitrum, Polygon, Avalanche. The 402 response returns an accepts array (one entry per chain, each with network, payTo, asset (the USDC contract/mint) and, on EVM, the EIP-712 domain) plus a facilitator URL (https://facilitator.payai.network). To pay: sign the payment for a chosen chain (EVM → EIP-3009 transferWithAuthorization; Solana → x402 SVM scheme, facilitator co-signs as fee payer so only USDC is needed — build the partial tx with extra.feePayer), base64 it, and retry the same POST with it in the PAYMENT-SIGNATURE header — you get 200 + the verdict + a receipt ({paid, tx, network}). Your wallet pays on whichever chain it holds USDC. Always read the live 402's accepts + facilitator at request time — it's the source of truth for what's currently enabled.

Just validating the integration? An agent can self-register for a starter allowance: POST https://api.snapback.sh/v1/agents/register with {"name":"my-agent","framework":"openclaw","accepted_terms":true} returns a token it uses as Authorization: Bearer <token> (accepted_terms required — agrees to the terms). For persistent or team access, create a full account.

Snapback speaks the Model Context Protocol, so an agent can diagnose its own failures as a native tool call — no bespoke HTTP glue. The MCP server exposes these tools:

TOOL
diagnose_trace

Submit a trace and get a verdict (same pipeline as POST /v1/traces).

TOOL
diagnose_infra_error

Instant verified fix for a cryptic infrastructure error across 46 families — payments (x402, eip3009, cctp, Stripe/procurement), banking (ACH/NACHA/Plaid), on-chain (Solana, token2022, EVM/Phantom wallets), protocol (MCP, mcp-tools, RPC, Airnode, gRPC), infra (database, container-OOM, cloud-teardown, filesystem, concurrency, DNS/TLS/certs), messaging (Kafka/SQS), data (type-encoding, vector-db, webhook-drift), enterprise (CRM-sync, API-integration, Shopify/Amazon, calendar-ETag), travel (Amadeus/Sabre GDS), auth (OAuth, JWT/AWS-SigV4, vendor/LLM-API quirks, LLM-output truncation). Free, no token, no LLM.

TOOL
budget_guard

Mid-run guards: context %, token/cost burn, step budget, and off-task drift. Free, no LLM. Pass format:'summary_only' for a one-line answer.

TOOL
get_verdict

Fetch a verdict by trace_id.

TOOL
preflight

Ask what commonly fails for a given agent_stack/tags before running.

TOOL
submit_feedback

Tell Snapback whether a verdict was correct — sharpens the shared library.

Point your MCP client at the Snapback MCP endpoint with your ingest token. The agent then self-diagnoses in-loop: run, catch a failure, call diagnose_trace, apply the fix_suggestion, and continue.

Chat agents (Telegram / Slack / Discord): pass format:"summary_only" to diagnose_infra_error, diagnose_trace, or budget_guard to get back ONE relayable line (plus a short headline) instead of a large JSON object — relay it straight to the user. Prefer the instant, free tools (diagnose_infra_error / detect_loop) in a chat turn, treat diagnose_trace as async (a novel diagnosis can take ~25s), and don't open a live session over chat — sessions are in-process and idle out between slow chat turns. Full recipe: Using Snapback from a chat agent.

Connect the skill (any MCP agent)

#connect

Snapback is a standard MCP server, so any MCP-capable agent connects and calls its tools — OpenClaw, GitHub Copilot, Hermes (Ollama/vLLM), Claude & Claude Code, Cursor, OpenAI Agents, or a custom client. Register it once against the endpoint:

shell
openclaw mcp add snapback --transport streamable-http \
  --url https://api.snapback.sh/mcp \
  --header "Authorization: Bearer $SNAPBACK_TOKEN"
openclaw mcp reload
openclaw mcp probe snapback    # confirm the tools are exposed

Other frameworks use their own MCP-add command with the same URL: https://api.snapback.sh/mcp. The token is optional — discovery, search_docs, detect_loop, budget_guard, diagnose_infra_error and live sessions all work with no token. Call every tool via tools/call (not as a top-level method, which returns -32601); the result is in result.content[0].text as a JSON string.

New here? The step-by-step connect guide walks the whole flow, and /llms.txt is the machine-readable version for agents.

Coverage — 46 infrastructure families

#coverage

Beyond behavioural failures (loops, wrong-tool, hallucinated schemas), Snapback diagnoses cryptic infrastructure errors across 46 families — each a cluster of real, documented error signatures with a verified fix, sourced from official docs and specs. Call diagnose_infra_error({error}) (free, no token, no LLM) to map any cryptic error to its family and fix. By domain:

Payments
x402, EIP-3009, CCTP, Stripe / procurement (declines, Radar blocks)
Banking
ACH / NACHA return codes, Plaid item states
On-chain
Solana, Token-2022, EVM & Phantom wallets
Protocol
MCP, mcp-tools, RPC, AirnodeHub, gRPC
Infrastructure
database, container-OOM, cloud-teardown, filesystem, concurrency, DNS / TLS / certs
Messaging
Kafka & SQS queues (visibility & rebalance), Twilio A2P 10DLC SMS (30007 filtered / 30034 unregistered)
Data
type-encoding, vector-db consistency, webhook drift, Snowflake / Databricks (Delta ConcurrentAppendException, warehouse-suspended)
Enterprise
CRM-sync, API-integration, Shopify / Amazon + GitHub GraphQL cost-throttling (200-is-a-lie), calendar ETags
Travel
Amadeus / Sabre GDS — segment-sell races, price-before-book, throttles, session expiry
Orchestration
Kubernetes — ImagePullBackOff, admission-webhook denials, FailedScheduling, Evicted (read the Pod event, not the status)
Service mesh
Istio / Envoy — 503 response flags (UF / UO / NR), gRPC UNAVAILABLE / DEADLINE_EXCEEDED (the flag is the diagnosis)
Serverless
AWS Lambda — TooManyRequestsException / Rate-Exceeded (rate vs concurrency throttle), silent async-throttle to DLQ
Infra-as-code
Terraform / OpenTofu — state-lock (don't blind force-unlock, read Who/Created), state drift
Identity / KYC
Persona / Alloy / Socure — REVIEW is a routing decision not a retry; re-submitting a REJECT risks blacklisting
CI / CD
GitHub Actions — 403 Resource not accessible (GITHUB_TOKEN read-only; add a least-privilege permissions block), runner labels
Payments (deep)
Stripe SCA / 3DS authentication_required (do 3DS, don't retry off-session), webhook signature verification
Healthcare
X12 EDI 837 / 835 / 277CA — a clean 999 + rejected 277CA = valid file, failed payer edits; CARC CO vs PR
Cache
Redis — OOM maxmemory (noeviction rejects writes, not a container OOMKill), cluster MOVED / ASK (use a cluster-aware client)
Search
Elasticsearch — circuit_breaking_exception ('Data too large', a memory guard as HTTP 429, not rate-limiting), all-shards-failed
Microsoft
Graph / Entra — 429 honors Retry-After; 403 Authorization_RequestDenied is a consent problem, not throttling
Ad-tech
OpenRTB — a 204 is the normal no-bid (not an error); nbr / AUCTION_LOSS explain win-rate; nurl / burl for win/billing
Auth
OAuth, JWT / AWS-SigV4, vendor / LLM-API quirks, LLM-output truncation

Each family encodes the fix the base model usually gets wrong — a calendar 410 that means "re-sync" not "re-auth," a Kafka CommitFailedException that means "don't retry the commit." Full per-class detail lives in the failure encyclopedia; the machine-readable family list is in /llms.txt.

Self-healing & the gate contract

#self-heal

Don't want to remember to call Snapback? Make it automatic. Every diagnose_infra_error response carries a machine-readable gate contract so an agent can decide, without a human, whether it's safe to auto-apply the fix:

json
{ "matched": true, "family": "dns-tls", "fix": "...", "confidence": 1.0,
  "source": "library", "action_class": "config", "auto_safe": true,
  "gate": { "auto_apply_ok": true, "contract": "auto-apply only when
    confidence>=0.85 AND source=='library' AND auto_safe==true;
    never auto-apply mutate/destructive" } }

Auto-apply a fix ONLY when confidence >= 0.85 AND source == "library" AND auto_safe == true (action_class is retry / refetch / config = reversible). NEVER auto-apply a mutate or destructive fix (creates/changes state, money, auth) — escalate those. gate.auto_apply_ok is the ready-made verdict. Framework plugins wrap this automatically: the OpenClaw self-heal interceptor and a Hermes plugin (hooks post_tool_call / api_request_error) — both pip install snapback-selfheal. Any other MCP client (Copilot, Cursor, Claude Code, Windsurf) calls the tools directly.

Newer agent-ops tools (all free, no token, no LLM):

what_others_did
The crowd: anonymized, aggregated across all agents — what did OTHERS do about this failure and did it work? The network effect.
recommend_failover
retry-same / switch-provider / fall-back-chain / stop, with the reason — so a flaky RPC isn't retried 5x.
cascade_root
given N errors, finds the TRUE root (the one that cascaded), not the final symptom.
suggest_budget_recovery
ranks the least-disruptive recovery: truncate context / cheaper model / batch steps.

Delivery channels

#delivery

Verdicts can be pushed to you the moment they're produced. Set these up on the Delivery tab.

Slack
  1. Slack API → Create New App → From scratch. Name it Snapback, pick your workspace.
  2. Open Incoming Webhooks, turn it On, then Add New Webhook to Workspace.
  3. Choose the channel and Allow. Copy the hooks.slack.com/services/… URL.
  4. Paste it into the Slack card on the Delivery tab.
Webhook
  1. Stand up an endpoint that accepts a POST with a JSON body.
  2. Paste its URL into the Webhook card. We POST each verdict as JSON.
  3. Set a signing secret to verify the X-Snapback-Signature header.
Telegram
  1. Message @BotFather, send /newbot, and copy the bot token it gives you.
  2. Open a chat with your new bot and send it any message (this unlocks it to message you).
  3. Message @userinfobot to get your numeric chat ID.
  4. Paste the bot token and chat ID into the Telegram card on the Delivery tab. Done.

Errors

#errors

Errors return a stable machine code so agents can retry or self-heal.

json
{ "detail": "monthly cap reached", "code": "cap_reached_soft_stop" }
  • 401 — missing or unrecognized ingest token.
  • 413 — payload too large: the trace exceeds the max spans or max bytes. Split it or trim the trace.
  • 429 — too many failed auth attempts from your IP. Back off and honor the Retry-After header; a successful auth clears it.

Verifying webhook signatures

#webhook-signing

When a delivery channel has a signing secret, each outbound webhook carries two headers so you can verify it's really from Snapback and hasn't been tampered with:

  • X-Snapback-Timestamp — unix seconds when the request was signed.
  • X-Snapback-Signaturesha256=<hmac_sha256(secret, "<timestamp>.<raw body>")>
python
import hmac, hashlib, time

def verify(secret, headers, raw_body, max_age_s=300):
    ts  = headers.get("X-Snapback-Timestamp", "")
    sig = headers.get("X-Snapback-Signature", "")
    if not ts or not sig.startswith("sha256="):
        return False
    if abs(time.time() - int(ts)) > max_age_s:   # reject replays
        return False
    expect = "sha256=" + hmac.new(
        secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(sig, expect)

Verify against the raw request body (before any JSON re-serialization), and reject stale timestamps to prevent replay.