{"openapi":"3.1.0","info":{"title":"SignalPipe API","version":"3.7.1","description":"Public REST surface for the Mantidae scout backend. All endpoints require Bearer authentication with the operator key. Companion MCP server at api.signalpipe.io/mcp/sse exposes the same operations as 14 callable tools for AI agents.","contact":{"name":"SignalPipe","url":"https://signalpipe.io","email":"hello@signalpipe.io"},"license":{"name":"Proprietary","url":"https://signalpipe.io/terms"}},"servers":[{"url":"https://api.signalpipe.io","description":"Production"}],"components":{"securitySchemes":{"operatorKey":{"type":"http","scheme":"bearer","description":"Operator key — same value as OPERATOR_KEY in the backend env."}},"schemas":{"Mission":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["draft_needed","pending_approval","approved","sent","failed","rejected"]},"score":{"type":"integer","description":"Final signal_score (0–100, post-RL, post-floor)"},"outreach_channel":{"type":"string","enum":["twitter_reply","reddit_dm","manual"]},"draft_content":{"type":"string","nullable":true},"swarm_disagreement":{"type":"number","nullable":true},"leads":{"$ref":"#/components/schemas/Lead"},"products":{"type":"object","properties":{"name":{"type":"string"}}}}},"Lead":{"type":"object","properties":{"title":{"type":"string","nullable":true},"snippet":{"type":"string","nullable":true},"url":{"type":"string","nullable":true},"author_handle":{"type":"string","nullable":true},"source_platform":{"type":"string","enum":["rss","reddit","hn","twitter","youtube"]},"competitor_name":{"type":"string","nullable":true},"competitor_intent":{"type":"string","nullable":true},"signal_score":{"type":"integer","description":"Post-floor, post-RL final score"},"content_score":{"type":"integer","description":"Pre-floor truth signal — what the post actually says"},"strategy":{"type":"object","properties":{"role":{"type":"string","enum":["closer","advisor","educator"]},"tone":{"type":"string"}}}}}}},"security":[{"operatorKey":[]}],"paths":{"/health":{"get":{"summary":"Liveness probe","security":[],"responses":{"200":{"description":"Service is up","content":{"application/json":{"example":{"status":"ok","version":"3.7.1"}}}}}}},"/scout/launch_batch":{"post":{"summary":"Run a scout cycle across all active products","description":"Triggered by pg_cron every 2 hours. Can also be invoked manually for an on-demand cycle.","responses":{"200":{"description":"Batch dispatched","content":{"application/json":{"example":{"products_scanned":2,"leads_created":7,"missions_drafted":4}}}}}}},"/sync/missions":{"get":{"summary":"List pending missions","parameters":[{"name":"status","in":"query","schema":{"type":"string"},"description":"Filter by status (default: pending_approval)"},{"name":"include","in":"query","schema":{"type":"string"},"description":"Pass \"draft_context\" to include scoring breakdown"}],"responses":{"200":{"description":"List of missions","content":{"application/json":{"schema":{"type":"object","properties":{"missions":{"type":"array","items":{"$ref":"#/components/schemas/Mission"}}}}}}}}}},"/actions/upload_draft":{"post":{"summary":"Upload a draft for a mission","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mission_id","draft"],"properties":{"mission_id":{"type":"string","format":"uuid"},"draft":{"type":"string"},"reasoning":{"type":"string"}}}}}},"responses":{"200":{"description":"Draft accepted, mission moved to pending_approval"}}}},"/actions/approve":{"post":{"summary":"Approve a mission for outreach","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mission_id"],"properties":{"mission_id":{"type":"string","format":"uuid"},"edited_draft":{"type":"string"}}}}}},"responses":{"200":{"description":"Mission approved; queued for sidecar to send"}}}},"/actions/reject":{"post":{"summary":"Reject a mission","description":"Records a rejection and feeds the RL loop with a -0.02 weight nudge for the source feed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mission_id"],"properties":{"mission_id":{"type":"string","format":"uuid"},"rejection_reason":{"type":"string","enum":["not_real_intent","wrong_product","spam","competitor_seller","other","no_reason"]}}}}}},"responses":{"200":{"description":"Mission rejected"}}}},"/actions/ack":{"post":{"summary":"Acknowledge a sent mission","description":"Called by the sidecar after posting via tweepy / praw to update mission.status to \"sent\" or \"failed\".","responses":{"200":{"description":"Status updated"}}}},"/products/reload":{"post":{"summary":"Hot-reload the product / anchor cache","description":"Call after inserting or editing a row in the products table. No server restart needed.","responses":{"200":{"description":"Cache reloaded"}}}},"/stations/add":{"post":{"summary":"Add a new RSS station","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["product_id","name","rss_url"],"properties":{"product_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"platform":{"type":"string","default":"rss"},"rss_url":{"type":"string","format":"uri"},"keyword":{"type":"string"}}}}}},"responses":{"200":{"description":"Station added; will be picked up on the next scout cycle"}}}}}}