{"openapi":"3.1.0","info":{"title":"edwardtadros.com agent API","version":"1.1.0","description":"Public, rate-limited access to Edward Tadros's dossier and PROSPÆRO. Anonymous REST access requires no credentials; an optional OAuth bearer with dossier:ask raises the per-IP tier from 20 to 120 requests/minute and is required for the hosted MCP ask_prospaero tool. Ask routes omit Turnstile so software agents can use them; AI Gateway spend limits are the outer wall. Versioning: the URL path (/api/v1) is the stable surface and every response carries an API-Version header; retirements are announced at least 90 days ahead with Deprecation (RFC 9745) and Sunset (RFC 8594) headers and noted here. Nothing is deprecated. Limits are advertised in RateLimit-Policy and RateLimit-Limit; 429 responses carry Retry-After. Errors are JSON {error, message}.","contact":{"name":"Edward Tadros","email":"etadros@proticom.com","url":"https://edwardtadros.com/contact"},"termsOfService":"https://edwardtadros.com/privacy"},"externalDocs":{"description":"Human-readable API docs","url":"https://edwardtadros.com/docs"},"servers":[{"url":"https://edwardtadros.com/api/v1","description":"Stable versioned base URL"}],"x-api-version":"1","x-deprecation-policy":{"minimumNoticeDays":90,"headers":["Deprecation","Sunset"],"deprecated":[]},"x-rate-limit":{"anonymousRequestsPerMinute":20,"authenticatedRequestsPerMinute":120,"scope":"client IP","headers":["RateLimit-Policy","RateLimit-Limit","Retry-After"]},"paths":{"/search":{"get":{"operationId":"searchDossier","summary":"Search the public knowledge dossier","description":"Ranked excerpts from Edward Tadros's public dossier for a free-text query. Lexical ranking today, hybrid when vectors are published. Use before ask to find the relevant documents. Anonymous requests use the 20/minute tier; a valid dossier:ask bearer uses 120/minute.","security":[{},{"OAuth2":["dossier:ask"]}],"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1},"example":"Wikimedia pipeline"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":10,"default":5},"example":5}],"responses":{"200":{"description":"Ranked results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"},"example":{"query":"Wikimedia pipeline","mode":"lexical","results":[{"id":"gene-wikimedia-foundation","title":"Wikimedia Foundation — January 2019 to June 2026","score":0.93,"excerpt":"Edward designed and shipped an AI-augmented requirements and testing pipeline…","url":"/knowledge/gene-wikimedia-foundation.md"}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/ask":{"post":{"operationId":"askProspaero","summary":"Ask PROSPÆRO a question about Edward","description":"Synthesizes a concise, sourced answer (at most 120 words) about Edward Tadros from the dossier. If the model is unavailable the response still succeeds with live=false and the top dossier excerpt as the answer. GET /ask?q= is accepted as a convenience alias. Anonymous requests use the 20/minute tier; a valid dossier:ask bearer uses 120/minute.","security":[{},{"OAuth2":["dossier:ask"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["question"],"properties":{"question":{"type":"string","minLength":1,"maxLength":600}}},"example":{"question":"What has Edward delivered in regulated environments?"}}}},"responses":{"200":{"description":"A concise sourced answer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskResponse"},"example":{"question":"What has Edward delivered in regulated environments?","answer":"Edward has delivered in FDA, ISO, HIPAA-covered, and financial-services environments.","sources":[{"id":"gene-regulated-delivery","title":"Regulated delivery","url":"/knowledge/gene-regulated-delivery.md"}],"model":"anthropic/claude-sonnet-5","live":true,"latencyMs":320}}}},"400":{"$ref":"#/components/responses/BadRequest"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/prices":{"get":{"operationId":"listPrices","summary":"List configured model prices in USD","description":"Per-million-token input/output prices for the configured text models and per-image prices for image models, refreshed from OpenRouter with a static fallback.","responses":{"200":{"description":"Current OpenRouter prices or the static fallback","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricesResponse"},"example":{"updatedAt":"2026-08-28T05:43:27.055Z","source":"openrouter","models":{"anthropic/claude-sonnet-5":{"in":2,"out":10}},"images":{"xai/grok-imagine-image-2.0":{"perImage":0.04},"openai/gpt-image-2":{"perImage":null}}}}}},"405":{"$ref":"#/components/responses/MethodNotAllowed"}}}},"/health":{"get":{"operationId":"getHealth","summary":"Inspect public Worker health and configuration","description":"Liveness plus configuration: dossier document count, whether vectors and the AI Gateway are live, configured models.","responses":{"200":{"description":"Health summary","content":{"application/json":{"schema":{"type":"object","required":["ok","documents","models","defaultModel","gateway"],"properties":{"ok":{"type":"boolean"},"documents":{"type":"integer"},"vectors":{"type":"boolean"},"models":{"type":"array","items":{"type":"string"}},"defaultModel":{"type":"string"},"imageModel":{"type":"string"},"gateway":{"type":"boolean"}}},"example":{"ok":true,"documents":12,"vectors":false,"models":["anthropic/claude-sonnet-5"],"defaultModel":"anthropic/claude-sonnet-5","imageModel":"xai/grok-imagine-image-2.0","gateway":true}}}},"405":{"$ref":"#/components/responses/MethodNotAllowed"}}}},"/knowledge/index.json":{"servers":[{"url":"https://edwardtadros.com","description":"Unversioned site root"}],"get":{"operationId":"listKnowledgeDocuments","summary":"List public knowledge documents","description":"Manifest of every dossier document with id, title, category, tags, character count, and the URL of its markdown body (/knowledge/{id}.md).","responses":{"200":{"description":"Knowledge manifest","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeIndex"},"example":{"generated":"2026-08-28T05:43:27.055Z","documentCount":37,"documents":[{"id":"gene-accomplishments","title":"Accomplishments","category":"general","tags":["page"],"url":"/knowledge/gene-accomplishments.md","chars":3351}]}}}},"405":{"$ref":"#/components/responses/MethodNotAllowed"}}}}},"components":{"securitySchemes":{"OAuth2":{"type":"oauth2","description":"Optional for REST; required for the hosted MCP ask_prospaero tool. Registration: https://edwardtadros.com/auth.md","flows":{"authorizationCode":{"authorizationUrl":"https://edwardtadros.com/oauth/authorize","tokenUrl":"https://edwardtadros.com/oauth/token","scopes":{"dossier:ask":"Use the MCP ask tool and the 120/minute REST tier."}}}}},"responses":{"BadRequest":{"description":"Invalid or missing input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"bad_request","message":"The request was malformed or missing a required field."}}}},"MethodNotAllowed":{"description":"Wrong HTTP method; the Allow header lists accepted methods","headers":{"Allow":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"method_not_allowed","message":"This endpoint does not support that HTTP method."}}}},"RateLimited":{"description":"The selected anonymous or authenticated per-IP agent rate limit was reached","headers":{"Retry-After":{"description":"Seconds to wait","schema":{"type":"integer"}},"RateLimit-Policy":{"schema":{"type":"string"},"example":"20;w=60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"rate_limited","message":"Per-IP agent rate limit reached; retry after 60 seconds."}}}}},"schemas":{"Error":{"type":"object","description":"Every 4xx/5xx body. error is a stable machine-readable code; message is for humans.","required":["error","message"],"properties":{"error":{"type":"string","enum":["bad_request","not_found","method_not_allowed","rate_limited","turnstile"]},"message":{"type":"string"}}},"Source":{"type":"object","required":["id","title","url"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"url":{"type":"string"}}},"SearchResult":{"type":"object","required":["id","title","score","excerpt","url"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"score":{"type":"number"},"excerpt":{"type":"string","maxLength":300},"url":{"type":"string"}}},"SearchResponse":{"type":"object","required":["query","mode","results"],"properties":{"query":{"type":"string"},"mode":{"type":"string","enum":["hybrid","lexical"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/SearchResult"}}}},"AskResponse":{"type":"object","required":["question","answer","sources","model","live","latencyMs"],"properties":{"question":{"type":"string"},"answer":{"type":"string"},"sources":{"type":"array","items":{"$ref":"#/components/schemas/Source"}},"model":{"type":"string"},"live":{"type":"boolean"},"latencyMs":{"type":"integer","minimum":0}}},"ModelPrice":{"type":"object","required":["in","out"],"properties":{"in":{"type":"number","minimum":0},"out":{"type":"number","minimum":0}}},"PricesResponse":{"type":"object","required":["updatedAt","source","models","images"],"properties":{"updatedAt":{"type":"string","format":"date-time"},"source":{"type":"string","enum":["openrouter","static"]},"models":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ModelPrice"}},"images":{"type":"object","additionalProperties":{"type":"object","required":["perImage"],"properties":{"perImage":{"type":["number","null"]}}}}}},"KnowledgeDocument":{"type":"object","required":["id","title","category","tags","url","chars"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"category":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"url":{"type":"string"},"chars":{"type":"integer","minimum":0}}},"KnowledgeIndex":{"type":"object","required":["generated","documentCount","documents"],"properties":{"generated":{"type":"string","format":"date-time"},"documentCount":{"type":"integer"},"documents":{"type":"array","items":{"$ref":"#/components/schemas/KnowledgeDocument"}}}}}}}