{"openapi":"3.0.3","info":{"title":"DoubleOh API","version":"0.1.0","description":"Your agents learn from every fix. When an agent gets stuck, one of your own people fixes it once in a live browser; the fix compiles into a skill your whole fleet reuses. SDKs: `pip install doubleoh`, `npm i @doubleoh/sdk`, MCP server `doubleoh-mcp`."},"servers":[{"url":"https://api.doubleoh.ai"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"x-api-key","description":"Your key. Starts with oo_live_."}},"schemas":{"Skill":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"instructions":{"type":"string","description":"The steps, as prose. Put this in your agent's context."},"timesWorked":{"type":"integer","description":"Raw counts, not a rate: 5 for 5 is worth following, 1 for 1 is a guess that worked once."},"timesFailed":{"type":"integer"}}},"InterventionStatus":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"task":{"type":"string"},"status":{"type":"string","enum":["open","resolved","abandoned","expired"]},"skillName":{"type":"string","nullable":true,"description":"The skill this fix produced, once it has."},"blockedRuns":{"type":"integer","description":"How many runs hit this wall while it was open. Triage by it: biggest first."},"createdAt":{"type":"string","format":"date-time"}}},"Error":{"type":"object","properties":{"error":{"type":"string"}}}}},"paths":{"/v1/interventions":{"post":{"summary":"Ask a human to fix what your agent could not","description":"Opens an intervention and returns a fix link for a human to drive the stuck page. Three shapes come back: a fresh fix link (201); a deflection (200, `deflected: true`) when a learned skill already answers this wall — nobody is paged, retry with the skill, and a second ask reaches a human; or a duplicate (200, `duplicateOf`) when this exact wall is already waiting — `blockedRuns` says how many runs are stuck on it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","task"],"properties":{"url":{"type":"string","description":"The public http(s) page the agent is stuck on. Private and loopback addresses are refused."},"task":{"type":"string","maxLength":500,"description":"One sentence. Phrase it the same way each time — it is part of the skill's identity."}}}}}},"responses":{"200":{"description":"Deflected (skill answers instead, nobody paged) or duplicate (already waiting).","content":{"application/json":{"schema":{"type":"object","properties":{"intervention":{"type":"object","properties":{"id":{"type":"string","nullable":true},"fixUrl":{"type":"string","nullable":true},"prepared":{"type":"boolean"},"deflected":{"type":"boolean"},"skill":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"instructions":{"type":"string","description":"The steps, as prose. Put this in your agent's context."},"timesWorked":{"type":"integer","description":"Raw counts, not a rate: 5 for 5 is worth following, 1 for 1 is a guess that worked once."},"timesFailed":{"type":"integer"}},"nullable":true},"duplicateOf":{"type":"string"},"waitingSince":{"type":"string","format":"date-time"},"blockedRuns":{"type":"integer"}}}}}}}},"201":{"description":"A human has been asked; `fixUrl` is the link to send your team.","content":{"application/json":{"schema":{"type":"object","properties":{"intervention":{"type":"object","properties":{"id":{"type":"string"},"fixUrl":{"type":"string"},"prepared":{"type":"boolean","description":"Whether the stuck page was pre-opened for the fixer."}}}}}}}},"400":{"description":"Bad input, or a refused target URL.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"402":{"description":"Free plan cap reached. Learned skills keep working.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Hourly rate limit. `retry-after` header says when.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"get":{"summary":"Recent fixes across your fleet, newest first","responses":{"200":{"description":"Up to 50 interventions.","content":{"application/json":{"schema":{"type":"object","properties":{"interventions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"task":{"type":"string"},"status":{"type":"string","enum":["open","resolved","abandoned","expired"]},"skillName":{"type":"string","nullable":true,"description":"The skill this fix produced, once it has."},"blockedRuns":{"type":"integer","description":"How many runs hit this wall while it was open. Triage by it: biggest first."},"createdAt":{"type":"string","format":"date-time"}}}}}}}}}}}},"/v1/interventions/{id}":{"get":{"summary":"How one fix is going","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The intervention, with `skillName` once a skill was compiled.","content":{"application/json":{"schema":{"type":"object","properties":{"intervention":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"task":{"type":"string"},"status":{"type":"string","enum":["open","resolved","abandoned","expired"]},"skillName":{"type":"string","nullable":true,"description":"The skill this fix produced, once it has."},"blockedRuns":{"type":"integer","description":"How many runs hit this wall while it was open. Triage by it: biggest first."},"createdAt":{"type":"string","format":"date-time"}}}}}}}},"404":{"description":"Not yours, or not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/v1/skills":{"get":{"summary":"What has been learned that helps with a task","description":"Call BEFORE your agent attempts something it has failed at before. Put a returned skill's `instructions` in the agent's context.","parameters":[{"name":"task","in":"query","required":true,"schema":{"type":"string"},"description":"The task, phrased the way you phrase it in requestFix."}],"responses":{"200":{"description":"Your learned skills that match, best first.","content":{"application/json":{"schema":{"type":"object","properties":{"skills":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"instructions":{"type":"string","description":"The steps, as prose. Put this in your agent's context."},"timesWorked":{"type":"integer","description":"Raw counts, not a rate: 5 for 5 is worth following, 1 for 1 is a guess that worked once."},"timesFailed":{"type":"integer"}}}}}}}}}}}},"/v1/skills/{name}/outcome":{"post":{"summary":"Say whether a skill worked","description":"Closes the loop. One boolean, wired to whatever already tells you a run succeeded. A skill followed three times that never works retires itself.","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["worked"],"properties":{"worked":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Recorded; `retired` is true when this failure was the skill's third strike.","content":{"application/json":{"schema":{"type":"object","properties":{"recorded":{"type":"boolean"},"retired":{"type":"boolean"}}}}}},"404":{"description":"No skill of yours by that name.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/v1/skills/{name}/retire":{"post":{"summary":"Stop serving a skill immediately","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string"}}}}}},"responses":{"200":{"description":"Retired. Your agents stop being told about it now."},"404":{"description":"No skill of yours by that name.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/v1/me":{"get":{"summary":"Your fleet's dashboard, in one read","description":"Counts, the learning trend, recent interventions, your skill library — and the bill before it is one: plan, usage this month, and what overage would cost.","responses":{"200":{"description":"`billing.usedThisMonth` counts opened interventions only — deflections and duplicates are never metered."}}}}}}