{"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":[]},{"bearer":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"x-api-key","description":"Your key. Starts with oo_live_."},"bearer":{"type":"http","scheme":"bearer","description":"The same key as `Authorization: Bearer <key>`, for clients that only send the standard header."}},"schemas":{"Skill":{"type":"object","properties":{"systemHint":{"type":"string","description":"The skill as one block of context for a model: boundary first, then the steps, then how to report. Paste it verbatim."},"authority":{"type":"object","nullable":true,"properties":{"requiresHuman":{"type":"array","items":{"type":"string"}},"never":{"type":"array","items":{"type":"string"}}}},"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","answered","refused","abandoned","expired"]},"answer":{"type":"object","nullable":true,"description":"Once a person answered: read `approved` first (true: go ahead; false: do not do it). `kind` is decision, corrected_call, manual_done, stop or refused, and `value` carries it. `value.reason` is the person's why (always there for decision and corrected_call). A screen fixed by hand is manual_done with `value.result`: what the person says you need to know (a link, a code). Apply it; do not retry the same call.","properties":{"kind":{"type":"string"},"value":{"type":"object"},"approved":{"type":"boolean","description":"The person's yes or no. Never infer it from the words: a corrected call or manual_done is true, stop and refused are false, a decision says."},"approvedAmount":{"type":"object","description":"On a yes to a wall that asked an amount: how much it covers, which may be less than asked. Never spend more.","properties":{"amountCents":{"type":"integer"},"cents":{"type":"integer","deprecated":true,"description":"Same as amountCents; kept for SDKs 0.2.2 and older."},"currency":{"type":"string"}}}}},"agent":{"type":"string","nullable":true,"description":"Which of the key's agents asked, when it said."},"agentName":{"type":"string","nullable":true,"description":"Verified: the agent this key belongs to (one key per agent). Null on a legacy key."},"claimedAgent":{"type":"string","nullable":true,"description":"A label the request sent that is not the key's agent (a legacy key's self-reported name, or another name a bound key sent on a read). Unverified."},"wallId":{"type":"string","description":"The wall's identity: retries of the same wall share it."},"wallUrl":{"type":"string","description":"The wall's page in the portal, where a person answers it."},"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","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}},"Packet":{"type":"object","description":"What the agent saw, shown to the person who answers: the call, what came back, its last steps, and the sentences it was held to.","properties":{"tool":{"type":"string"},"args":{"description":"The call as the agent would make it. An `args.amountCents` (with `args.currency`) is the amount asked, the same as `amountCents`; the two must agree."},"error":{"type":"string"},"steps":{"type":"array","items":{"type":"string"},"maxItems":10},"screenshot":{"type":"string","description":"Base64 JPEG, 1.5 MB at most."},"boundary":{"type":"object","properties":{"may":{"type":"array","items":{"type":"string"}},"needsPerson":{"type":"array","items":{"type":"string"}},"never":{"type":"array","items":{"type":"string"}}}},"amountCents":{"type":"integer","minimum":0,"description":"What you ask to spend, in minor units; needs currency. A yes covers this much at most, and a receipt opened with approvedBy on it may not exceed it."},"currency":{"type":"string","description":"ISO 4217, e.g. EUR."}}},"Receipt":{"type":"object","properties":{"id":{"type":"string"},"state":{"type":"string","enum":["pending","needs_person","confirmed","failed","unconfirmed","refused","approved"],"description":"approved: a person said yes; do it, then confirm. refused: a rule or a person said no; approval.reason says why when it was a person."},"tool":{"type":"string"},"target":{"type":"string","nullable":true},"action":{"type":"string"},"agent":{"type":"string","nullable":true,"description":"Who acted: the key's agent, else the label sent."},"agentName":{"type":"string","nullable":true,"description":"Verified: the agent this key belongs to (one key per agent). Null on a legacy key."},"claimedAgent":{"type":"string","nullable":true,"description":"A label the request sent that is not the key's agent (a legacy key's self-reported name, or another name a bound key sent on a read). Unverified."},"idempotencyKey":{"type":"string"},"amountCents":{"type":"integer","nullable":true},"currency":{"type":"string","nullable":true},"evidence":{"type":"object","nullable":true},"authority":{"type":"object","nullable":true,"properties":{"decision":{"type":"string"},"ruleId":{"type":"string"},"sentence":{"type":"string"},"pattern":{"type":"string","enum":["split"],"description":"split: this looks like one payment cut into smaller ones (several in a short time that together pass a limit). Limits count a running total per agent and currency over their window."}}},"approval":{"type":"object","nullable":true,"description":"When a person had to decide: their yes or no, why, who, when, and the intervention it was given on.","properties":{"approved":{"type":"boolean"},"reason":{"type":"string","nullable":true},"by":{"type":"string","nullable":true},"at":{"type":"string","format":"date-time"},"interventionId":{"type":"string"},"amountCents":{"type":"integer","nullable":true,"description":"How much the person approved, which may be less than the receipt's amountCents."},"currency":{"type":"string","nullable":true}}},"deadlineAt":{"type":"string","format":"date-time"},"confirmedAt":{"type":"string","format":"date-time","nullable":true},"interventionId":{"type":"string","nullable":true}}}}},"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. With no page to take over, send `mode: \"answer\"` and a `packet` instead of `url`: a person answers in words or a corrected call, and the agent reads it back from `waitUrl`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["task"],"properties":{"url":{"type":"string","description":"The public http(s) page the agent is stuck on. Private and loopback addresses are refused. Leave it out for an answer wall."},"mode":{"type":"string","enum":["screen","answer"],"description":"screen (default): a person takes over the page. answer: a person answers; implied when there is no url."},"packet":{"type":"object","description":"What the agent saw, shown to the person who answers: the call, what came back, its last steps, and the sentences it was held to.","properties":{"tool":{"type":"string"},"args":{"description":"The call as the agent would make it. An `args.amountCents` (with `args.currency`) is the amount asked, the same as `amountCents`; the two must agree."},"error":{"type":"string"},"steps":{"type":"array","items":{"type":"string"},"maxItems":10},"screenshot":{"type":"string","description":"Base64 JPEG, 1.5 MB at most."},"boundary":{"type":"object","properties":{"may":{"type":"array","items":{"type":"string"}},"needsPerson":{"type":"array","items":{"type":"string"}},"never":{"type":"array","items":{"type":"string"}}}},"amountCents":{"type":"integer","minimum":0,"description":"What you ask to spend, in minor units; needs currency. A yes covers this much at most, and a receipt opened with approvedBy on it may not exceed it."},"currency":{"type":"string","description":"ISO 4217, e.g. EUR."}}},"agent":{"type":"string","maxLength":100,"description":"Which of your agents is asking, e.g. \"ops-bot\". Shown to the person (\"asked by ops-bot\"); walls from different agents never merge."},"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":{"systemHint":{"type":"string","description":"The skill as one block of context for a model: boundary first, then the steps, then how to report. Paste it verbatim."},"authority":{"type":"object","nullable":true,"properties":{"requiresHuman":{"type":"array","items":{"type":"string"}},"never":{"type":"array","items":{"type":"string"}}}},"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."},"wallId":{"type":"string","description":"Stable id of this wall (key, site, task words). Log it; retries and rephrasings map to the same id."},"waitUrl":{"type":"string","description":"GET it: holds up to 55 seconds and returns when the status changes."},"expectedSeconds":{"type":"integer","description":"Typical time for a person to reach the fix."},"next":{"type":"string","description":"The next move, written for the program reading it."}}}}}}}},"400":{"description":"Bad input, a refused target URL, or `agent_mismatch`: this key belongs to another agent than the `agent` sent.","content":{"application/json":{"schema":{"type":"object","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}}}}},"402":{"description":"Free plan cap reached, or only the reserve kept for approvals is left (the last 10%; `reservedForApprovals`). The meter is the organisation's: every agent's key counts toward one plan. Learned skills keep working.","content":{"application/json":{"schema":{"type":"object","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}}}}},"429":{"description":"`rate_limited`: too many calls, or too many new walls from this agent (default 6 a minute, 60 an hour; approvals have their own budget); carries `retryAfterSeconds`, `limit`, and for walls `per` and `agent`. `agent_paused`: a person paused this agent; carries `agent` and `retryAfterSeconds`. `retry-after` says when to try again.","content":{"application/json":{"schema":{"type":"object","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}}}}}}},"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","answered","refused","abandoned","expired"]},"answer":{"type":"object","nullable":true,"description":"Once a person answered: read `approved` first (true: go ahead; false: do not do it). `kind` is decision, corrected_call, manual_done, stop or refused, and `value` carries it. `value.reason` is the person's why (always there for decision and corrected_call). A screen fixed by hand is manual_done with `value.result`: what the person says you need to know (a link, a code). Apply it; do not retry the same call.","properties":{"kind":{"type":"string"},"value":{"type":"object"},"approved":{"type":"boolean","description":"The person's yes or no. Never infer it from the words: a corrected call or manual_done is true, stop and refused are false, a decision says."},"approvedAmount":{"type":"object","description":"On a yes to a wall that asked an amount: how much it covers, which may be less than asked. Never spend more.","properties":{"amountCents":{"type":"integer"},"cents":{"type":"integer","deprecated":true,"description":"Same as amountCents; kept for SDKs 0.2.2 and older."},"currency":{"type":"string"}}}}},"agent":{"type":"string","nullable":true,"description":"Which of the key's agents asked, when it said."},"agentName":{"type":"string","nullable":true,"description":"Verified: the agent this key belongs to (one key per agent). Null on a legacy key."},"claimedAgent":{"type":"string","nullable":true,"description":"A label the request sent that is not the key's agent (a legacy key's self-reported name, or another name a bound key sent on a read). Unverified."},"wallId":{"type":"string","description":"The wall's identity: retries of the same wall share it."},"wallUrl":{"type":"string","description":"The wall's page in the portal, where a person answers it."},"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","description":"With `wait`, the request holds up to that many seconds (55 at most) and returns as soon as the status changes: one call instead of a polling loop. The answer carries `next`, and `waitUrl` while still open.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"wait","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":55},"description":"Seconds to hold before answering if nothing changed."}],"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","answered","refused","abandoned","expired"]},"answer":{"type":"object","nullable":true,"description":"Once a person answered: read `approved` first (true: go ahead; false: do not do it). `kind` is decision, corrected_call, manual_done, stop or refused, and `value` carries it. `value.reason` is the person's why (always there for decision and corrected_call). A screen fixed by hand is manual_done with `value.result`: what the person says you need to know (a link, a code). Apply it; do not retry the same call.","properties":{"kind":{"type":"string"},"value":{"type":"object"},"approved":{"type":"boolean","description":"The person's yes or no. Never infer it from the words: a corrected call or manual_done is true, stop and refused are false, a decision says."},"approvedAmount":{"type":"object","description":"On a yes to a wall that asked an amount: how much it covers, which may be less than asked. Never spend more.","properties":{"amountCents":{"type":"integer"},"cents":{"type":"integer","deprecated":true,"description":"Same as amountCents; kept for SDKs 0.2.2 and older."},"currency":{"type":"string"}}}}},"agent":{"type":"string","nullable":true,"description":"Which of the key's agents asked, when it said."},"agentName":{"type":"string","nullable":true,"description":"Verified: the agent this key belongs to (one key per agent). Null on a legacy key."},"claimedAgent":{"type":"string","nullable":true,"description":"A label the request sent that is not the key's agent (a legacy key's self-reported name, or another name a bound key sent on a read). Unverified."},"wallId":{"type":"string","description":"The wall's identity: retries of the same wall share it."},"wallUrl":{"type":"string","description":"The wall's page in the portal, where a person answers it."},"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","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}}}}}}}},"/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."},{"name":"url","in":"query","required":false,"schema":{"type":"string"},"description":"The page. Scopes the answer to the site the skill was learned on; pass it whenever you have it."}],"responses":{"200":{"description":"Your learned skills that match, best first.","content":{"application/json":{"schema":{"type":"object","properties":{"skills":{"type":"array","items":{"type":"object","properties":{"systemHint":{"type":"string","description":"The skill as one block of context for a model: boundary first, then the steps, then how to report. Paste it verbatim."},"authority":{"type":"object","nullable":true,"properties":{"requiresHuman":{"type":"array","items":{"type":"string"}},"never":{"type":"array","items":{"type":"string"}}}},"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. When a served skill was not for your task (another field, tab or intent), send `{worked: false, reason: \"not_applicable\", task}`: it is not counted as a failure, and the task is remembered so the skill is not served for it again.","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"},"reason":{"type":"string","enum":["not_applicable"],"description":"With worked: false, the skill did not fit this task. Not a failure."},"task":{"type":"string","maxLength":500,"description":"With not_applicable: the task it did not fit. Defaults to the task it was last served for."}}}}}},"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"},"notApplicable":{"type":"boolean"},"learnedFrom":{"type":"boolean","description":"not_applicable: whether a task was known to remember as a negative example."}}}}}},"404":{"description":"No skill of yours by that name.","content":{"application/json":{"schema":{"type":"object","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}}}}}}}},"/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","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}}}}}}}},"/v1/receipts":{"post":{"summary":"Open a receipt before a side effect","description":"Rules are checked first. 201: allowed, do it and confirm. 200 with `duplicate: true`: this idempotency key was already used, do not do it again. 202: a person must approve first, wait on `waitUrl`; when they answer, the receipt becomes `approved` (do it, then confirm) or `refused`. 402 `quota_exceeded`: it needs a person and the plan has no fixes left; the receipt is recorded as needs_person, do not do it. 403 `authority_refused`: a rule forbids it. 409 `not_approved`: `approvedBy` does not cover this action. Unconfirmed past `deadlineAt`, a person is asked to check. The same idempotencyKey after `failed` reopens the same receipt (201, `retried: true`), keeping its approval; `refused` is final. Limits count a running total per agent and currency over their window (a day unless the rule says otherwise); several small ones that pass it together come back with `authority.pattern: \"split\"`. 429: a person must decide but this agent may not open another wall now (`rate_limited`, `agent_paused`); the receipt is recorded as needs_person, do not do it, retry after `retryAfterSeconds`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tool","action"],"properties":{"tool":{"type":"string"},"action":{"type":"string","description":"What it does, in one sentence."},"args":{},"target":{"type":"string"},"agent":{"type":"string","description":"Optional. The key's own agent wins; another name on a key bound to an agent is 400 agent_mismatch."},"idempotencyKey":{"type":"string","description":"One per real-world action, the same on every retry. Defaults to tool + args hash + the minute."},"amountCents":{"type":"integer"},"currency":{"type":"string"},"confirmWithinSeconds":{"type":"integer","minimum":1,"maximum":86400},"approvedBy":{"type":"string","description":"An intervention id a person answered with approved: true in the last hour, on this key, asked by the same agent, for the same tool and action (and site, when it had one), and for at least this amount in the same currency (a receipt with an amount needs a yes that had one, and a yes with an amount needs the receipt to send it). One approval backs exactly one receipt; a second use is 409 not_approved. The receipt opens as approved, with no new wall and no second page."}}}}}},"responses":{"200":{"description":"Duplicate: already done or in progress.","content":{"application/json":{"schema":{"type":"object","properties":{"receipt":{"type":"object","properties":{"id":{"type":"string"},"state":{"type":"string","enum":["pending","needs_person","confirmed","failed","unconfirmed","refused","approved"],"description":"approved: a person said yes; do it, then confirm. refused: a rule or a person said no; approval.reason says why when it was a person."},"tool":{"type":"string"},"target":{"type":"string","nullable":true},"action":{"type":"string"},"agent":{"type":"string","nullable":true,"description":"Who acted: the key's agent, else the label sent."},"agentName":{"type":"string","nullable":true,"description":"Verified: the agent this key belongs to (one key per agent). Null on a legacy key."},"claimedAgent":{"type":"string","nullable":true,"description":"A label the request sent that is not the key's agent (a legacy key's self-reported name, or another name a bound key sent on a read). Unverified."},"idempotencyKey":{"type":"string"},"amountCents":{"type":"integer","nullable":true},"currency":{"type":"string","nullable":true},"evidence":{"type":"object","nullable":true},"authority":{"type":"object","nullable":true,"properties":{"decision":{"type":"string"},"ruleId":{"type":"string"},"sentence":{"type":"string"},"pattern":{"type":"string","enum":["split"],"description":"split: this looks like one payment cut into smaller ones (several in a short time that together pass a limit). Limits count a running total per agent and currency over their window."}}},"approval":{"type":"object","nullable":true,"description":"When a person had to decide: their yes or no, why, who, when, and the intervention it was given on.","properties":{"approved":{"type":"boolean"},"reason":{"type":"string","nullable":true},"by":{"type":"string","nullable":true},"at":{"type":"string","format":"date-time"},"interventionId":{"type":"string"},"amountCents":{"type":"integer","nullable":true,"description":"How much the person approved, which may be less than the receipt's amountCents."},"currency":{"type":"string","nullable":true}}},"deadlineAt":{"type":"string","format":"date-time"},"confirmedAt":{"type":"string","format":"date-time","nullable":true},"interventionId":{"type":"string","nullable":true}}},"duplicate":{"type":"boolean"},"interventionId":{"type":"string","nullable":true,"description":"Always present: the wall this receipt waits on or was approved through, else null."},"waitUrl":{"type":"string","description":"When it is still waiting on a person."},"confirmUrl":{"type":"string"},"next":{"type":"string"}}}}}},"201":{"description":"Allowed: do it, then POST confirmUrl.","content":{"application/json":{"schema":{"type":"object","properties":{"receipt":{"type":"object","properties":{"id":{"type":"string"},"state":{"type":"string","enum":["pending","needs_person","confirmed","failed","unconfirmed","refused","approved"],"description":"approved: a person said yes; do it, then confirm. refused: a rule or a person said no; approval.reason says why when it was a person."},"tool":{"type":"string"},"target":{"type":"string","nullable":true},"action":{"type":"string"},"agent":{"type":"string","nullable":true,"description":"Who acted: the key's agent, else the label sent."},"agentName":{"type":"string","nullable":true,"description":"Verified: the agent this key belongs to (one key per agent). Null on a legacy key."},"claimedAgent":{"type":"string","nullable":true,"description":"A label the request sent that is not the key's agent (a legacy key's self-reported name, or another name a bound key sent on a read). Unverified."},"idempotencyKey":{"type":"string"},"amountCents":{"type":"integer","nullable":true},"currency":{"type":"string","nullable":true},"evidence":{"type":"object","nullable":true},"authority":{"type":"object","nullable":true,"properties":{"decision":{"type":"string"},"ruleId":{"type":"string"},"sentence":{"type":"string"},"pattern":{"type":"string","enum":["split"],"description":"split: this looks like one payment cut into smaller ones (several in a short time that together pass a limit). Limits count a running total per agent and currency over their window."}}},"approval":{"type":"object","nullable":true,"description":"When a person had to decide: their yes or no, why, who, when, and the intervention it was given on.","properties":{"approved":{"type":"boolean"},"reason":{"type":"string","nullable":true},"by":{"type":"string","nullable":true},"at":{"type":"string","format":"date-time"},"interventionId":{"type":"string"},"amountCents":{"type":"integer","nullable":true,"description":"How much the person approved, which may be less than the receipt's amountCents."},"currency":{"type":"string","nullable":true}}},"deadlineAt":{"type":"string","format":"date-time"},"confirmedAt":{"type":"string","format":"date-time","nullable":true},"interventionId":{"type":"string","nullable":true}}},"confirmUrl":{"type":"string"},"next":{"type":"string"}}}}}},"202":{"description":"Needs a person: wait on waitUrl.","content":{"application/json":{"schema":{"type":"object","properties":{"receipt":{"type":"object","properties":{"id":{"type":"string"},"state":{"type":"string","enum":["pending","needs_person","confirmed","failed","unconfirmed","refused","approved"],"description":"approved: a person said yes; do it, then confirm. refused: a rule or a person said no; approval.reason says why when it was a person."},"tool":{"type":"string"},"target":{"type":"string","nullable":true},"action":{"type":"string"},"agent":{"type":"string","nullable":true,"description":"Who acted: the key's agent, else the label sent."},"agentName":{"type":"string","nullable":true,"description":"Verified: the agent this key belongs to (one key per agent). Null on a legacy key."},"claimedAgent":{"type":"string","nullable":true,"description":"A label the request sent that is not the key's agent (a legacy key's self-reported name, or another name a bound key sent on a read). Unverified."},"idempotencyKey":{"type":"string"},"amountCents":{"type":"integer","nullable":true},"currency":{"type":"string","nullable":true},"evidence":{"type":"object","nullable":true},"authority":{"type":"object","nullable":true,"properties":{"decision":{"type":"string"},"ruleId":{"type":"string"},"sentence":{"type":"string"},"pattern":{"type":"string","enum":["split"],"description":"split: this looks like one payment cut into smaller ones (several in a short time that together pass a limit). Limits count a running total per agent and currency over their window."}}},"approval":{"type":"object","nullable":true,"description":"When a person had to decide: their yes or no, why, who, when, and the intervention it was given on.","properties":{"approved":{"type":"boolean"},"reason":{"type":"string","nullable":true},"by":{"type":"string","nullable":true},"at":{"type":"string","format":"date-time"},"interventionId":{"type":"string"},"amountCents":{"type":"integer","nullable":true,"description":"How much the person approved, which may be less than the receipt's amountCents."},"currency":{"type":"string","nullable":true}}},"deadlineAt":{"type":"string","format":"date-time"},"confirmedAt":{"type":"string","format":"date-time","nullable":true},"interventionId":{"type":"string","nullable":true}}},"waitUrl":{"type":"string","nullable":true},"wallUrl":{"type":"string","nullable":true,"description":"The portal page where a person answers."},"confirmUrl":{"type":"string"},"next":{"type":"string"}}}}}},"400":{"description":"Bad input, or `agent_mismatch`: this key belongs to another agent.","content":{"application/json":{"schema":{"type":"object","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}}}}},"402":{"description":"`quota_exceeded`: needs a person and the organisation has no human fixes left. Carries `upgradeUrl` and the recorded `receipt`.","content":{"application/json":{"schema":{"type":"object","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}}}}},"403":{"description":"A rule forbids it.","content":{"application/json":{"schema":{"type":"object","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}}}}},"409":{"description":"`not_approved`: approvedBy does not cover this action; `differs` names what does not match, and `approved` the amount it did cover.","content":{"application/json":{"schema":{"type":"object","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}}}}},"429":{"description":"`rate_limited` or `agent_paused`: it needs a person and this agent may not open a wall now. Carries `retryAfterSeconds` and the recorded `receipt`; do not do it.","content":{"application/json":{"schema":{"type":"object","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}}}}}}},"get":{"summary":"Recent receipts for this key","parameters":[{"name":"state","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer"}}],"responses":{"200":{"description":"Newest first.","content":{"application/json":{"schema":{"type":"object","properties":{"receipts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"state":{"type":"string","enum":["pending","needs_person","confirmed","failed","unconfirmed","refused","approved"],"description":"approved: a person said yes; do it, then confirm. refused: a rule or a person said no; approval.reason says why when it was a person."},"tool":{"type":"string"},"target":{"type":"string","nullable":true},"action":{"type":"string"},"agent":{"type":"string","nullable":true,"description":"Who acted: the key's agent, else the label sent."},"agentName":{"type":"string","nullable":true,"description":"Verified: the agent this key belongs to (one key per agent). Null on a legacy key."},"claimedAgent":{"type":"string","nullable":true,"description":"A label the request sent that is not the key's agent (a legacy key's self-reported name, or another name a bound key sent on a read). Unverified."},"idempotencyKey":{"type":"string"},"amountCents":{"type":"integer","nullable":true},"currency":{"type":"string","nullable":true},"evidence":{"type":"object","nullable":true},"authority":{"type":"object","nullable":true,"properties":{"decision":{"type":"string"},"ruleId":{"type":"string"},"sentence":{"type":"string"},"pattern":{"type":"string","enum":["split"],"description":"split: this looks like one payment cut into smaller ones (several in a short time that together pass a limit). Limits count a running total per agent and currency over their window."}}},"approval":{"type":"object","nullable":true,"description":"When a person had to decide: their yes or no, why, who, when, and the intervention it was given on.","properties":{"approved":{"type":"boolean"},"reason":{"type":"string","nullable":true},"by":{"type":"string","nullable":true},"at":{"type":"string","format":"date-time"},"interventionId":{"type":"string"},"amountCents":{"type":"integer","nullable":true,"description":"How much the person approved, which may be less than the receipt's amountCents."},"currency":{"type":"string","nullable":true}}},"deadlineAt":{"type":"string","format":"date-time"},"confirmedAt":{"type":"string","format":"date-time","nullable":true},"interventionId":{"type":"string","nullable":true}}}}}}}}}}}},"/v1/receipts/{id}":{"get":{"summary":"One receipt","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The receipt.","content":{"application/json":{"schema":{"type":"object","properties":{"receipt":{"type":"object","properties":{"id":{"type":"string"},"state":{"type":"string","enum":["pending","needs_person","confirmed","failed","unconfirmed","refused","approved"],"description":"approved: a person said yes; do it, then confirm. refused: a rule or a person said no; approval.reason says why when it was a person."},"tool":{"type":"string"},"target":{"type":"string","nullable":true},"action":{"type":"string"},"agent":{"type":"string","nullable":true,"description":"Who acted: the key's agent, else the label sent."},"agentName":{"type":"string","nullable":true,"description":"Verified: the agent this key belongs to (one key per agent). Null on a legacy key."},"claimedAgent":{"type":"string","nullable":true,"description":"A label the request sent that is not the key's agent (a legacy key's self-reported name, or another name a bound key sent on a read). Unverified."},"idempotencyKey":{"type":"string"},"amountCents":{"type":"integer","nullable":true},"currency":{"type":"string","nullable":true},"evidence":{"type":"object","nullable":true},"authority":{"type":"object","nullable":true,"properties":{"decision":{"type":"string"},"ruleId":{"type":"string"},"sentence":{"type":"string"},"pattern":{"type":"string","enum":["split"],"description":"split: this looks like one payment cut into smaller ones (several in a short time that together pass a limit). Limits count a running total per agent and currency over their window."}}},"approval":{"type":"object","nullable":true,"description":"When a person had to decide: their yes or no, why, who, when, and the intervention it was given on.","properties":{"approved":{"type":"boolean"},"reason":{"type":"string","nullable":true},"by":{"type":"string","nullable":true},"at":{"type":"string","format":"date-time"},"interventionId":{"type":"string"},"amountCents":{"type":"integer","nullable":true,"description":"How much the person approved, which may be less than the receipt's amountCents."},"currency":{"type":"string","nullable":true}}},"deadlineAt":{"type":"string","format":"date-time"},"confirmedAt":{"type":"string","format":"date-time","nullable":true},"interventionId":{"type":"string","nullable":true}}}}}}}},"404":{"description":"Not yours, or not found.","content":{"application/json":{"schema":{"type":"object","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}}}}}}}},"/v1/receipts/{id}/confirm":{"post":{"summary":"Confirm with the target system's evidence","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"evidence":{"type":"object","properties":{"providerId":{"type":"string"},"status":{"type":"string"},"url":{"type":"string"},"note":{"type":"string"}},"additionalProperties":true,"description":"Any other fields are kept under evidence.extra (4000 characters of JSON at most), never refused."},"ok":{"type":"boolean","description":"false when the target system said it did not happen."}}}}}},"responses":{"200":{"description":"Confirmed (or failed, with ok false).","content":{"application/json":{"schema":{"type":"object","properties":{"receipt":{"type":"object","properties":{"id":{"type":"string"},"state":{"type":"string","enum":["pending","needs_person","confirmed","failed","unconfirmed","refused","approved"],"description":"approved: a person said yes; do it, then confirm. refused: a rule or a person said no; approval.reason says why when it was a person."},"tool":{"type":"string"},"target":{"type":"string","nullable":true},"action":{"type":"string"},"agent":{"type":"string","nullable":true,"description":"Who acted: the key's agent, else the label sent."},"agentName":{"type":"string","nullable":true,"description":"Verified: the agent this key belongs to (one key per agent). Null on a legacy key."},"claimedAgent":{"type":"string","nullable":true,"description":"A label the request sent that is not the key's agent (a legacy key's self-reported name, or another name a bound key sent on a read). Unverified."},"idempotencyKey":{"type":"string"},"amountCents":{"type":"integer","nullable":true},"currency":{"type":"string","nullable":true},"evidence":{"type":"object","nullable":true},"authority":{"type":"object","nullable":true,"properties":{"decision":{"type":"string"},"ruleId":{"type":"string"},"sentence":{"type":"string"},"pattern":{"type":"string","enum":["split"],"description":"split: this looks like one payment cut into smaller ones (several in a short time that together pass a limit). Limits count a running total per agent and currency over their window."}}},"approval":{"type":"object","nullable":true,"description":"When a person had to decide: their yes or no, why, who, when, and the intervention it was given on.","properties":{"approved":{"type":"boolean"},"reason":{"type":"string","nullable":true},"by":{"type":"string","nullable":true},"at":{"type":"string","format":"date-time"},"interventionId":{"type":"string"},"amountCents":{"type":"integer","nullable":true,"description":"How much the person approved, which may be less than the receipt's amountCents."},"currency":{"type":"string","nullable":true}}},"deadlineAt":{"type":"string","format":"date-time"},"confirmedAt":{"type":"string","format":"date-time","nullable":true},"interventionId":{"type":"string","nullable":true}}}}}}}},"404":{"description":"Not yours, or not found.","content":{"application/json":{"schema":{"type":"object","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}}}}},"409":{"description":"`already_settled`: a settled receipt cannot change. `not_approved`: ok true on a receipt still waiting for a person, or refused.","content":{"application/json":{"schema":{"type":"object","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}}}}}}}},"/v1/authority/check":{"post":{"summary":"May this agent do this","description":"Checked against this key's rules, written as sentences, and the defaults that are always on. When nothing covers the action, the organisation's setting decides: by default an action that moves money (any amountCents above 0), deletes something or contacts someone needs a person, and anything else is allowed. Every answer is recorded.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tool"],"properties":{"tool":{"type":"string"},"target":{"type":"string"},"action":{"type":"string"},"amountCents":{"type":"integer"},"currency":{"type":"string","description":"ISO 4217, e.g. USD. Send it with amountCents: a limit in one currency never grants another."},"agent":{"type":"string"}}}}}},"responses":{"200":{"description":"The decision and the rule that made it.","content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["allow","needs_person","never"]},"ruleId":{"type":"string"},"sentence":{"type":"string"},"pattern":{"type":"string","enum":["split"],"description":"split: with this agent's earlier amounts in the window, this looks like one payment cut into parts."},"next":{"type":"string"}}}}}},"400":{"description":"Bad input.","content":{"application/json":{"schema":{"type":"object","description":"A refusal an agent can act on: the sentence a person reads, a stable code, and the next move.","properties":{"error":{"type":"string"},"code":{"type":"string","enum":["key_required","rate_limited","bad_request","target_refused","computer_required","quota_exceeded","not_found","unavailable","authority_refused","already_settled","not_approved","agent_paused","agent_mismatch"],"description":"agent_mismatch (400): this key belongs to another agent than the `agent` sent; use that agent's key or leave `agent` out. agent_paused (429): a person paused this agent. rate_limited (429): wait `retryAfterSeconds`."},"next":{"type":"string","description":"What to do about it, written for the program reading it."},"retryAfterSeconds":{"type":"integer","description":"rate_limited and agent_paused: seconds to wait before trying again (also the `retry-after` header)."},"limit":{"type":"integer","description":"rate_limited: how many were allowed."},"per":{"type":"string","description":"rate_limited on new walls: the window the limit counts, e.g. \"minute\" or \"hour\"."},"agent":{"type":"string","nullable":true,"description":"rate_limited on new walls and agent_paused: which agent."},"reservedForApprovals":{"type":"integer","description":"quota_exceeded: fixes kept back for approvals (receipts that need a person). A plain wall is refused once only these are left; an approval may still use them."},"upgradeUrl":{"type":"string","description":"quota_exceeded: where a person upgrades."},"used":{"type":"integer","description":"quota_exceeded: human fixes used this month by the whole organisation (all its agents' keys)."},"included":{"type":"integer","description":"quota_exceeded: fixes the plan includes."},"differs":{"type":"string","enum":["intervention","answer","age","agent","tool","target","action","amount","spent"],"description":"not_approved: which part of the approval does not match this action. An approval is bound to the action, the agent that asked, the target and the amount, and backs one receipt."}}}}}}}}},"/v1/authority/rules":{"get":{"summary":"The rules this agent works under","parameters":[{"name":"agent","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"`systemPrompt` is the rules as plain sentences, ready for the agent's context.","content":{"application/json":{"schema":{"type":"object","properties":{"rules":{"type":"array","items":{"type":"object","properties":{"sentence":{"type":"string"},"effect":{"type":"string"},"concepts":{"type":"array","items":{"type":"string"}},"limit":{"type":"string","nullable":true,"description":"The amount limit in words, with its window: \"up to $500 a day\". A rule's match.window is hour, day, week or transaction; an \"up to\" limit counts a day unless it says otherwise, a running total per agent and currency."}}}},"unknownActions":{"type":"string","enum":["risky","ask","allow"],"description":"What happens to an action no rule covers: risky (a person decides when it moves money, deletes something or contacts someone), ask (a person always decides), allow."},"systemPrompt":{"type":"string"}}}}}}}}},"/v1/quickstart":{"get":{"summary":"The loop, ready to run, for the key that is calling","description":"Returns the four steps and copy-ready snippets for Python, TypeScript, curl and MCP, plus the refusal codes. No key is echoed.","responses":{"200":{"description":"Snippets and the next move.","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/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":"`me.agent` is the agent this key belongs to (null on a legacy key). Plan and usage are the organisation's: every agent's key shares one plan and one meter. `billing.usedThisMonth` counts opened interventions; `billing.deflectedThisMonth` counts walls the fleet handled from a learned skill. Both are included in a plan up to its thresholds, then billed as overage; duplicates are never counted."}}}}}}