{"openapi":"3.0.3","info":{"title":"Aemulus Protocol API","version":"1.0.0","description":"Run browser-automation skills, read their extracted output, and verify their on-chain receipts. Authenticate with an API key (Bearer); receipt verification is public."},"servers":[{"url":"https://aemulusai.com"}],"security":[{"ApiKey":[]}],"components":{"securitySchemes":{"ApiKey":{"type":"http","scheme":"bearer","description":"An Aemulus API key, e.g. `aem_live_…`."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"RunRequest":{"type":"object","properties":{"skillId":{"type":"string","example":"skl_8c…"},"input":{"type":"object","additionalProperties":{"type":"string"},"description":"Field key → value for the skill's inputs."}},"required":["skillId"]},"Run":{"type":"object","properties":{"id":{"type":"string"},"skillId":{"type":"string"},"status":{"type":"string","enum":["running","awaiting_input","completed","needs_review","failed"]},"result":{"type":"string","nullable":true},"output":{"type":"object","nullable":true,"additionalProperties":{"type":"string"}},"receiptHash":{"type":"string","nullable":true},"steps":{"type":"integer"},"createdAt":{"type":"integer"}}},"RunListItem":{"type":"object","description":"List items omit `result` and `steps` (fetch a single run for those).","properties":{"id":{"type":"string"},"skillId":{"type":"string"},"status":{"type":"string","enum":["running","awaiting_input","completed","needs_review","failed"]},"output":{"type":"object","nullable":true,"additionalProperties":{"type":"string"}},"receiptHash":{"type":"string","nullable":true},"createdAt":{"type":"integer"}}},"RunStarted":{"type":"object","description":"POST /runs returns only these two fields (the run starts async).","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["running","awaiting_input","completed","needs_review","failed"]}}},"SkillSummary":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"version":{"type":"integer"},"runCount":{"type":"integer"},"inputs":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"}}}}}},"Verification":{"type":"object","properties":{"found":{"type":"boolean"},"runId":{"type":"string"},"status":{"type":"string"},"steps":{"type":"integer"},"hash":{"type":"string","nullable":true},"matches":{"type":"boolean"},"batch":{"type":"object","properties":{"id":{"type":"string"},"root":{"type":"string"},"index":{"type":"integer"},"leafCount":{"type":"integer"},"proofValid":{"type":"boolean"},"anchor":{"type":"object","nullable":true,"properties":{"sig":{"type":"string"},"cluster":{"type":"string"},"url":{"type":"string"},"memoMatches":{"type":"boolean","nullable":true}}}}}}},"VerificationNotFound":{"type":"object","properties":{"found":{"type":"boolean","enum":[false]},"runId":{"type":"string"}}}}},"paths":{"/api/v1/runs":{"post":{"summary":"Run a skill","description":"Starts a run; returns immediately with status \"running\". Send an `Idempotency-Key` header to make retries safe - the same key returns the original run instead of starting a new one.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Replay-safe key; identical retries return the first response."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunRequest"}}}},"responses":{"200":{"description":"Run started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunStarted"}}}},"400":{"description":"Invalid body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient $AEMU balance for access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Skill not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"An identical Idempotency-Key request is in progress","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Daily quota reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"summary":"List your runs","description":"Your runs, newest first. Cursor-paginated.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size (max 100)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a prior response's nextCursor."}],"responses":{"200":{"description":"A page of runs","content":{"application/json":{"schema":{"type":"object","properties":{"runs":{"type":"array","items":{"$ref":"#/components/schemas/RunListItem"}},"nextCursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/runs/{id}":{"get":{"summary":"Get a run","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The run","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Run"}}}},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/runs/{id}/disclose":{"get":{"summary":"Prove one field of a run","description":"A selective-disclosure bundle for a single field, provable against the run's committed root (which is anchored on chain) without revealing any other field. Owner-only. Verify one with POST /api/disclosures/verify, which needs no key.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"field","in":"query","required":true,"description":"Which committed field to prove.","schema":{"type":"string"}}],"responses":{"200":{"description":"The disclosure bundle","content":{"application/json":{"schema":{"type":"object","properties":{"disclosure":{"type":"object","properties":{"runId":{"type":"string"},"field":{"type":"string"},"value":{"type":"string"},"salt":{"type":"string"},"root":{"type":"string"},"proof":{"type":"object"}}}}}}}},"400":{"description":"No field given","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Run not found, no commitment, or unknown field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/watches":{"get":{"summary":"List your watches","responses":{"200":{"description":"Your watches, with each one's current value and whether it runs a skill when it fires"},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create a watch","description":"A schedule plus the rule that reads its output, created together — a schedule with no rule burns the watch allowance every cadence and reports nothing. The cadence is checked against your tier first: an unaffordable one is refused, with the list you can sustain, rather than accepted and silently skipped. Optionally pass action:{kind:\"run_skill\",skillId} to run one of your skills when the rule fires, handed the value that fired it; it is metered against your daily run quota like any other run.","responses":{"201":{"description":"The watch"},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cadence your tier cannot sustain, or missing scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Skill not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Schedule limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/watches/{id}":{"get":{"summary":"Get one watch","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The watch, with its failure streak and mute state"},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Watch not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Pause, resume, or disarm a watch","description":"Send active to pause or resume. Send action:\"alert\" to stop it running a skill while leaving the watch and its baseline intact — deleting and recreating would lose the baseline, so the replacement stays quiet through the first real change. Either field alone is enough.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The new state"},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Watch not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a watch","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Watch not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/skills":{"get":{"summary":"List published skills","description":"The published catalog, newest first. Cursor-paginated.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size (max 100)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a prior response's nextCursor."}],"responses":{"200":{"description":"A page of the catalog","content":{"application/json":{"schema":{"type":"object","properties":{"skills":{"type":"array","items":{"$ref":"#/components/schemas/SkillSummary"}},"nextCursor":{"type":"string","nullable":true}}}}}},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/verify/{runId}":{"get":{"summary":"Verify a receipt (public)","security":[],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Verification result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Verification"}}}},"404":{"description":"No receipt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerificationNotFound"}}}}}}},"/api/batch/{id}/bundle":{"get":{"summary":"Download a proof bundle (public)","security":[],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Self-contained, content-addressed proof bundle"},"404":{"description":"Batch not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}