AI assistance API
| Method | Path | Auth | Purpose |
|---|---|---|---|
| POST | /watches/draft | Token | Turn a plain-English description into a draft watch. Nothing is saved. |
| POST | /watches/draft/check-domains | Token | Best-effort liveness check for suggested domains. |
| POST | /watches/draft/preview | Token | Dry-run a search source and return the top candidate titles and URLs. |
| POST | /watches/:id/explain | Token | Explain an existing watch in plain English. Read-only. |
| POST | /watches/:id/revise | Token | Propose a field-level change set from one instruction. Nothing is saved. |
All of them are rate-limited to 10 requests per minute per owner, and all return
503 when the instance has no model key configured.
Draft a watch
Section titled “Draft a watch”curl -s -X POST https://<your-host>/watches/draft \ -H "authorization: Bearer $TOKEN" \ -H 'content-type: application/json' \ -d '{"description":"Tell me when version 2.0 of the framework is released as stable"}'{ "draft": { "name": "Framework 2.0 stable release", "condition": "Alert when version 2.0 is released as stable…", "sources": [ { "type": "search", "value": "framework 2.0 stable release", "recencyDays": 30, "rationale": "…" } ], "schedule": "0 */6 * * *", "threshold": 0.6, "notes": "Assumed you want stable releases only." }}Refine a previous draft in one round by sending it back with an instruction:
{ "description": "…", "refine": { "previousDraft": { "...": "..." }, "instruction": "only official sources" }}rationale and notes are display-only and are never stored on a watch.
Revise an existing watch
Section titled “Revise an existing watch”curl -s -X POST https://<your-host>/watches/framework-releases/revise \ -H "authorization: Bearer $TOKEN" \ -H 'content-type: application/json' \ -d '{"instruction":"check twice a day instead, and stop sending unconfirmed alerts"}'Returns a field-level change set — only what should change:
{ "revision": { "schedule": "0 */12 * * *", "weakThreshold": null, "reasons": [ { "field": "schedule", "why": "twice a day" } ] }}| Convention | Meaning |
|---|---|
| Field absent | Leave it exactly as it is |
| Field present | Proposed new value |
Field null |
Remove this optional field |
Send the panel’s current (possibly unsaved) form state as base so the diff is
computed against what the user is actually looking at. A base whose id does not
match the path is ignored, and ownership is always enforced on the path id.
Apply what you approve with a normal PUT /watches/:id.
Explain a watch
Section titled “Explain a watch”curl -s -X POST https://<your-host>/watches/framework-releases/explain \ -H "authorization: Bearer $TOKEN"{ "explanation": "Every six hours this checks the official blog feed and a web search for…" }Read-only, and useful for confirming that a watch says what you think it says.
Preview a search source
Section titled “Preview a search source”curl -s -X POST https://<your-host>/watches/draft/preview \ -H "authorization: Bearer $TOKEN" \ -H 'content-type: application/json' \ -d '{"value":"framework 2.0 stable release","hints":{"recencyDays":30}}'Runs the search once and returns up to five candidate titles and URLs.
Nothing is stored and no evaluation happens — it is the fastest way to see
whether a query finds the right pages before committing to it. Returns 503 when
no search key is configured.
Check suggested domains
Section titled “Check suggested domains”curl -s -X POST https://<your-host>/watches/draft/check-domains \ -H "authorization: Bearer $TOKEN" \ -H 'content-type: application/json' \ -d '{"domains":["example.gov","not-a-real-domain.test"]}'{ "liveness": { "example.gov": true, "not-a-real-domain.test": false } }A best-effort reachability check so a hallucinated domain can be flagged
rather than silently pinned. It never throws: an unverifiable domain is simply
reported as false.