Skip to content
Source: docs/api.md
Commit: 0f07a57e4ba3721f23cb629e32ee325c7146ecc4
Source updated:  ·  Edit this page

Synchronization API

Node observation, policy, signal, and web-candidate API reference.

Sync API

Observation upload:

POST /v1/observations/batch?instance_id=mail-tls
{
  "instance_id": "mail-tls",
  "observations": [
    {
      "fingerprint": "abc123",
      "status": "blocked",
      "first_seen": "2026-07-01T10:00:00Z",
      "last_seen": "2026-07-01T10:01:00Z",
      "ips": ["203.0.113.10"],
      "ports": [993],
      "sightings": [
        {"ip": "203.0.113.10", "port": 993, "last_seen": "2026-07-01T10:01:00Z"}
      ],
      "count": 2,
      "metadata": {
        "sni": "mail.example.com",
        "ja3": "...",
        "ja4": "..."
      }
    }
  ]
}

Timestamped sightings preserve the IP/port pairing needed for later event correlation. Gatehub retains them for eight days by default; configure --sighting-retention to change the bounded retention window. Aggregate fingerprint records and decisions are not removed by sighting cleanup.

Policy pull:

GET /v1/policy?instance_id=mail-tls&since=2026-07-01T10:00:00Z
{
  "cursor": "2026-07-01T10:05:00Z",
  "decisions": [
    {
      "scope_type": "instance",
      "scope_id": "mail-tls",
      "fingerprint": "abc123",
      "status": "approved",
      "label": "Alice iPhone",
      "updated_at": "2026-07-01T10:05:00Z",
      "actor": "admin"
    }
  ]
}

When trusted-source discovery is configured, policy responses also contain a trusted_ranges array of CIDR strings. Gates atomically replace only their control-plane-managed bypasses with this list; locally configured static ranges remain in force. Gatehub omits the field when discovery is disabled so an older deployment cannot accidentally clear local state.

Web signal nodes registered with kind gatesignal may upload aggregate scanner evidence to POST /v1/signals/batch?instance_id=<id>. The legacy log_watcher kind remains accepted during migration. The schema intentionally has no raw request-target or user-agent field because access-log values can contain credentials and personal data:

{
  "instance_id": "central-logs",
  "signals": [{
    "event_id": "01example",
    "observed_at": "2026-08-21T15:00:00Z",
    "host": "web-1",
    "site": "example",
    "ip": "203.0.113.10",
    "trigger": "suspicious_uri",
    "connections": 20,
    "errors": 18,
    "successes": 2,
    "window_seconds": 120
  }]
}

The authenticated admin endpoint GET /api/web-candidates correlates signals with TLS sightings from the same host within five minutes and returns report-only candidates grouped by gate instance and fingerprint. When the shadow policy is enabled, each candidate also includes shadow_status, shadow_reasons, the measured error_ratio, cross-site/node evidence, and a proposed expiry. would_block is simulation output only: this endpoint never creates a decision. The response's enforcement_mode reports whether the separate background controller is disabled, canary, or enforce.

An existing manual approved decision protects the matching fingerprint from shadow automation; an existing manual blocked decision is reported as already_blocked. Configure scoring with --web-shadow-enabled, --web-shadow-min-networks, --web-shadow-min-signals, --web-shadow-min-error-ratio, --web-shadow-require-multi-scope, and --web-shadow-proposed-ttl. Optional window (maximum 30m) and RFC3339 since parameters select the correlation interval.

Automated promotion is disabled by default. --web-enforcement-mode=canary creates expiring, instance-scoped blocks only for node IDs in --web-enforcement-canary-nodes; enforce permits every eligible TLSGate node. --web-enforcement-interval controls reconciliation frequency. Switching the mode to disabled is the kill switch: Gatehub emits explicit pending decisions for effective automated blocks so gates cannot retain stale local blocks. A block is renewed only when evidence newer than the previous block is present. Decision records retain their source, expiry, and aggregate evidence; raw request targets are never stored.

SMTP correlation reports

POST /v1/smtp/reports?instance_id=<node> accepts a bounded rolling-window SMTP correlation report from an authenticated active tlsgate node. The JSON body identifies the same instance_id, an SMTP namespace, exact listener, coverage interval, generation time, content-derived replay ID, aggregate counts, and bounded evidence. Gatehub stores only the newest generation for each node/SMTP namespace/listener. An exact replay succeeds idempotently; a different report with an older or equal generation returns 409 Conflict.

Reports are isolated from decisions and policy responses. They cannot approve or block a fingerprint. Authenticated administrators can list current reports with GET /api/smtp-reports or review their summaries on the dashboard.