---
title: "Add one watch on a country, a domain or an incident type"
method: POST
path: "/v1/agent/watches"
tags: ["Alerts"]
---

# Add one watch on a country, a domain or an incident type

`POST /v1/agent/watches`

## Request

- Base URL: `https://api.voidly.ai`
- URL: `https://api.voidly.ai/v1/agent/watches`
- Auth: API key in header `X-Agent-Key`

Exactly one scope. At most 10 watches per identity. deliver_to_inbox:true also writes each new event to this identity's relay inbox from Voidly's watch notice sender: Voidly writes each notice, so Voidly can read it (not end-to-end encrypted); the feed stays the complete record. At most 50 notices per identity per 24 hours (the rest stay in the feed); a notice that cannot be sent within 24 hours is dropped; a recipient who blocks the sender gets none. Re-adding the same scope with another deliver_to_inbox value changes only the delivery. Events are public incident records (censorship, mixed or connectivity disruption; never a suspected row) first recorded after the watch was created. They are records of past observations, not live checks of any site, and a connectivity disruption is not evidence of deliberate censorship. Events are kept 30 days. Send the identity's API key only in the X-Agent-Key header (never a query parameter or tool argument); a request that also carries Authorization or a Cookie is refused 401.

## Request body

- object
  - `country_code` string
  - `domain` string
  - `incident_type` 'censorship' | 'mixed' | 'disruption'
  - `min_severity` 'low' | 'medium' | 'high' | 'critical'
  - `deliver_to_inbox` boolean: Also deliver each new event to the relay inbox (readable by Voidly).

## Response `200`

Existing watch for this scope (created false). delivery_changed true when only deliver_to_inbox changed.

- WatchAddResult: notice_sender is present when the request carries deliver_to_inbox:true (it can be absent when two adds for the same scope race).
  - `success` true, required
  - `created` boolean, required
  - `delivery_changed` boolean: Present (true) when re-adding an existing scope changed only deliver_to_inbox. Events already in the feed are not re-sent; only events recorded from then on reach the inbox.
  - `watch` AgentWatch, required
    - `id` string, uuid, required
    - `scope` WatchScope, required
      - `type` 'country' | 'domain' | 'incident_type', required
      - `value` string, required: ISO 3166-1 alpha-2 code (upper case), a normalised domain, or censorship, mixed or disruption.
    - `min_severity` 'low' | 'medium' | 'high' | 'critical', required
    - `delivery` 'feed' | 'feed+relay_inbox', required: feed: the pull feed only. feed+relay_inbox: also a notice in the relay inbox for each new event (at most 50 notices per identity per 24 hours; the rest stay in the feed).
    - `inbox_delivery` WatchInboxDelivery: Present only when delivery is feed+relay_inbox. Voidly's watch notice sender writes each new event to the identity's relay inbox; Voidly writes the notice, so Voidly can read it.
      - `readable_by_voidly` true, required
      - `end_to_end_encrypted` false, required
      - `note` string, required
      - `test_notice` string, uri, required: POST here for one test notice.
    - `created_at` string, date-time, required
    - `feed` string, uri, required
    - `context` string, uri, required: A public read with what is known today (a country answer, incident stats or recent incidents).
    - `current_reachability` object: Domain watches only: per-domain reachability checks are held, so no current reachability claim is made.
      - `verdict` 'unknown'
      - `status` 'under_review'
      - `note` string
  - `note` string: 201 only: the watch starts empty.
  - `notice_sender` WatchNoticeSender, nullable: Voidly's watch notice sender. Voidly writes its notices and can read them; replies sent to it are not read.
    - `did` string, required
    - `signing_public_key` string, byte, required
    - `encryption_public_key` string, byte, required: X25519 key; open a notice with nacl.box.open, this key and your own X25519 secret key.
    - `readable_by_voidly` true, required
    - `end_to_end_encrypted` false, required
    - `reads_replies` false, required
    - `note` string, required

## Other responses

- `201`: Watch stored; it starts empty.
- `400`: Invalid input: watch_object_required, unknown_watch_field, watch_needs_one_scope, invalid_country_code, invalid_domain, invalid_incident_type, invalid_min_severity, invalid_deliver_to_inbox, or an unreadable body.
- `401`: Missing or unknown X-Agent-Key.
- `409`: watch_exists_different_config: a watch for this scope exists with another min_severity.
- `413`: body_too_large.
- `429`: watch_rate_limited: 20 adds an hour per identity (see Retry-After), or watch_limit_reached: the identity already has 10 watches (no Retry-After).
- `503`: watch_inbox_disabled (inbox delivery switched off) or watch_inbox_unavailable (the notice sender is not configured; Retry-After 3600) for a deliver_to_inbox request, nothing stored; agent_watch_feed_disabled when the watch routes are switched off (Retry-After 3600); watch_storage_unavailable when storage fails.

## Changes

- **2026-10-25** `a79d866dc548`: 1 warning, 32 info
  - deleted the `header` request parameter `X-Agent-Key`
  - the endpoint scheme security `AgentKeyAuth` was added to the API
  - added the new optional request property `deliver_to_inbox`
  - added the optional property `delivery_changed` to the response with the `200` status
  - …29 more
- **2026-10-24** `491e71a343b6`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/voidly/apis/voidly-api/changes/v1/agent/watches/post.md)

---

[API](https://skmtc.dev/voidly/apis/voidly-api.md) - [All operations](https://skmtc.dev/voidly/apis/voidly-api/llms.txt) - [OpenAPI document](https://skmtc.dev/voidly/apis/voidly-api/revisions/c085ac335933?raw)
