{"openapi":"3.1.0","info":{"title":"ANB Data Consultancy — Preflight APIs","version":"0.2.0","summary":"Checklist preflight tools for AI-built apps (anb-data-consultancy).","description":"Agent-callable HTTP APIs from ANB Data Consultancy: secrets, authz, webhooks, OpenAPI lint, deps (OSV), and supply-chain smell.\n\n**Not a penetration test or security certification.**\n\n**Pricing (year-1):** free, experimental, no SLA, no API key.\n**Pricing (planned):** Stripe machine payments if demand is proven.\n\n**Legal:** Terms `/terms` · Privacy `/privacy`.","termsOfService":"/terms","contact":{"name":"ANB Data Consultancy","email":"services@andrenbrown.com","url":"https://www.andrenbrown.com/contact"},"license":{"name":"UNLICENSED"}},"servers":[{"url":"http://127.0.0.1:8787","description":"Local spike"}],"tags":[{"name":"discovery","description":"How agents find tools and contracts"},{"name":"preflight","description":"Checklist analysis endpoints"}],"paths":{"/":{"get":{"operationId":"getLanding","tags":["discovery"],"summary":"Human landing page (HTML) or JSON service index","description":"Browsers receive HTML with curl examples and JSON-LD. Clients that send `Accept: application/json` (without `text/html`) receive a JSON discovery index.","responses":{"200":{"description":"Landing HTML or JSON index","content":{"text/html":{"schema":{"type":"string"}},"application/json":{"schema":{"type":"object","properties":{"service":{"type":"string"},"message":{"type":"string"},"discovery":{"type":"object"}}}}}}}}},"/robots.txt":{"get":{"operationId":"getRobotsTxt","tags":["discovery"],"summary":"robots.txt with absolute Sitemap URL","responses":{"200":{"description":"robots.txt","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/sitemap.xml":{"get":{"operationId":"getSitemap","tags":["discovery"],"summary":"XML sitemap for the landing and discovery URLs","responses":{"200":{"description":"sitemap.xml","content":{"application/xml":{"schema":{"type":"string"}}}}}}},"/health":{"get":{"operationId":"getHealth","tags":["discovery"],"summary":"Liveness and rule-pack metadata","responses":{"200":{"description":"Service is up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/.well-known/agent.json":{"get":{"operationId":"getAgentCard","tags":["discovery"],"summary":"Agent discovery card (tools, OpenAPI, pricing posture)","responses":{"200":{"description":"Agent card","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentCard"}}}}}}},"/openapi.json":{"get":{"operationId":"getOpenApi","tags":["discovery"],"summary":"OpenAPI 3.1 document for this service","responses":{"200":{"description":"OpenAPI document","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/llms.txt":{"get":{"operationId":"getLlmsTxt","tags":["discovery"],"summary":"Plain-text guide for LLM/agent clients","responses":{"200":{"description":"llms.txt","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/v1/preflight/secrets":{"post":{"operationId":"preflightSecrets","tags":["preflight"],"summary":"Scan config blobs for leaked-secret patterns","description":"Send one or more text blobs (e.g. .env, CI YAML, config snippets). Returns risk_band, flags with hints, and summary_for_agent.\n\nWhen to call: before commit/PR/deploy when an agent wrote or edited env/CI/config files.\n\nMax total UTF-8 bytes across all blob contents: 65536.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretsPreflightRequest"},"examples":{"leakyEnv":{"summary":"Suspicious .env","value":{"app_name":"demo-app","blobs":[{"name":".env","content":"STRIPE_SECRET_KEY=sk_live_51ABCDEFGHIJKLMNOPQRSTUVWXYZdemokey99\n"}]}},"cleanExample":{"summary":"Clean placeholders","value":{"app_name":"demo-app","blobs":[{"name":".env.example","content":"STRIPE_SECRET_KEY=\nNEXT_PUBLIC_APP_URL=http://localhost:3000\n"}]}}}}}},"responses":{"200":{"description":"Checklist result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretsPreflightResponse"}}}},"400":{"description":"Invalid JSON or body shape","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment required (planned — not enforced in spike)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Payload exceeds size limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/preflight/authz":{"post":{"operationId":"preflightAuthz","tags":["preflight"],"summary":"Checklist authz review of API routes","description":"Max 25 routes, 64KB. OWASP-aligned checklist heuristics.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["routes"],"properties":{"app_name":{"type":"string"},"ownership_model":{"type":"string"},"routes":{"type":"array","items":{"type":"object","required":["method","path"],"properties":{"method":{"type":"string"},"path":{"type":"string"},"auth":{"type":"string"},"notes":{"type":"string"},"ownership_check":{"oneOf":[{"type":"boolean"},{"type":"string","enum":["unknown"]}]}}}}}}}}},"responses":{"200":{"description":"Checklist result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretsPreflightResponse"}}}},"400":{"description":"Bad request"},"413":{"description":"Payload too large"},"429":{"description":"Rate limited"}}}},"/v1/preflight/webhooks":{"post":{"operationId":"preflightWebhooks","tags":["preflight"],"summary":"Webhook/callback trust checklist","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["callbacks"],"properties":{"app_name":{"type":"string"},"callbacks":{"type":"array","items":{"type":"object","required":["path","verification"],"properties":{"path":{"type":"string"},"method":{"type":"string"},"verification":{"type":"string","enum":["signature","shared_secret","none","unknown"]},"provider":{"type":"string"},"notes":{"type":"string"},"raw_body":{"type":"boolean"},"idempotency":{"oneOf":[{"type":"boolean"},{"type":"string","enum":["unknown"]}]},"secret_url_only":{"type":"boolean"}}}}}}}}},"responses":{"200":{"description":"Checklist result"},"400":{"description":"Bad request"},"413":{"description":"Payload too large"},"429":{"description":"Rate limited"}}}},"/v1/preflight/openapi":{"post":{"operationId":"preflightOpenapi","tags":["preflight"],"summary":"OWASP-aligned OpenAPI lint (curated subset)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["document"],"properties":{"app_name":{"type":"string"},"document":{"description":"OpenAPI 3.x as JSON object or JSON string (64KB)","oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"responses":{"200":{"description":"Lint result"},"400":{"description":"Bad request"},"413":{"description":"Payload too large"},"429":{"description":"Rate limited"}}}},"/v1/preflight/deps":{"post":{"operationId":"preflightDeps","tags":["preflight"],"summary":"OSV dependency preflight (capped package list)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"app_name":{"type":"string"},"ecosystem":{"type":"string","enum":["npm"]},"lockfile_excerpt":{"type":"string"},"packages":{"type":"array","items":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"version":{"type":"string"}}}}}}}}},"responses":{"200":{"description":"OSV-oriented result"},"400":{"description":"Bad request"},"413":{"description":"Payload too large"},"429":{"description":"Rate limited"}}}},"/v1/preflight/supplychain":{"post":{"operationId":"preflightSupplychain","tags":["preflight"],"summary":"npm supply-chain smell heuristics","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["packages"],"properties":{"app_name":{"type":"string"},"packages":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Heuristic result"},"400":{"description":"Bad request"},"413":{"description":"Payload too large"},"429":{"description":"Rate limited"}}}},"/v1/receipts/{receipt_id}":{"get":{"operationId":"getServiceReceipt","tags":["preflight"],"summary":"Fetch proof-of-provision receipt (payer only — planned)","description":"Not implemented in the free spike.\n\n**Security:** Receipts exist only for paid calls. This endpoint MUST authenticate the payer (API key / payment proof / magic link bound to the Stripe customer). Unguessable `receipt_id` alone is insufficient — return 401 if unauthenticated, 403 if authenticated but not the payer, 404 if unknown. Free-tier calls never mint receipts.","security":[{"PayerApiKey":[]},{"PaymentProof":[]}],"parameters":[{"name":"receipt_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Receipt (payer only)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceReceipt"}}}},"401":{"description":"Authentication required"},"403":{"description":"Authenticated but not the payer for this receipt"},"404":{"description":"Unknown receipt"},"501":{"description":"Not implemented in spike"}}}}},"components":{"securitySchemes":{"PayerApiKey":{"type":"apiKey","in":"header","name":"X-Api-Key","description":"API key belonging to the account that paid for the call that minted the receipt"},"PaymentProof":{"type":"apiKey","in":"header","name":"X-Payment-Proof","description":"Machine-payment / SPT proof bound to payment_id on the receipt (planned)"}},"schemas":{"RiskBand":{"type":"string","enum":["low","medium","high","critical"]},"SecretBlob":{"type":"object","required":["content"],"properties":{"name":{"type":"string","description":"Optional label (e.g. .env, deploy.yml)","examples":[".env.local"]},"content":{"type":"string","description":"Raw text to scan"}}},"SecretsPreflightRequest":{"type":"object","required":["blobs"],"properties":{"app_name":{"type":"string","description":"Optional app identifier for logs"},"blobs":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/SecretBlob"}}}},"SecretFlag":{"type":"object","required":["code","severity","confidence","evidence","hint"],"properties":{"code":{"type":"string","description":"Rule id (Gitleaks-mapped or custom)"},"severity":{"$ref":"#/components/schemas/RiskBand"},"confidence":{"type":"number","minimum":0,"maximum":1},"evidence":{"type":"string","description":"Redacted location/snippet"},"hint":{"type":"string","description":"Agent-actionable remediation guidance"}}},"SecretsPreflightResponse":{"type":"object","required":["request_id","product","risk_score","risk_band","flags","summary_for_agent","disclaimer"],"properties":{"request_id":{"type":"string"},"product":{"type":"string","const":"secrets"},"risk_score":{"type":"number"},"risk_band":{"$ref":"#/components/schemas/RiskBand"},"flags":{"type":"array","items":{"$ref":"#/components/schemas/SecretFlag"}},"summary_for_agent":{"type":"string","description":"One-paragraph next action for the calling agent"},"disclaimer":{"type":"string"},"receipt":{"$ref":"#/components/schemas/ServiceReceipt","description":"Present only when this call was paid. Omitted on free tier. Payer-only."}}},"ServiceReceipt":{"type":"object","description":"Payer-only proof that a paid preflight result was provided. Never issued for free calls. Exposes payment_ref (opaque), not raw Stripe payment_id.","required":["receipt_id","request_id","tool","provided_at","payment_ref","risk_band","request_body_sha256","disclaimer"],"properties":{"receipt_id":{"type":"string","description":"Unguessable receipt id (payer-only retrieval)"},"request_id":{"type":"string"},"tool":{"type":"string","examples":["preflight_secrets"]},"provided_at":{"type":"string","format":"date-time"},"payment_ref":{"type":"string","description":"Opaque payer-facing payment reference (e.g. payref_…). Maps server-side to Stripe payment_id. Do not put raw pi_… here.","examples":["payref_…"]},"risk_band":{"$ref":"#/components/schemas/RiskBand"},"flag_codes":{"type":"array","items":{"type":"string"}},"request_body_sha256":{"type":"string","description":"SHA-256 of canonical request body; raw secrets not stored"},"rules_pin_ref":{"type":"string","examples":["gitleaks@v8.28.0"]},"disclaimer":{"type":"string"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}},"HealthResponse":{"type":"object","properties":{"ok":{"type":"boolean"},"product_spike":{"type":"string"},"max_body_bytes":{"type":"integer"},"discovery":{"type":"object","additionalProperties":{"type":"string"}},"pricing":{"type":"object","additionalProperties":true},"rules":{"type":"object","additionalProperties":true}}},"AgentCard":{"type":"object","description":"Lightweight discovery document for agents","additionalProperties":true}}}}