Skip to content

Latest commit

 

History

History
93 lines (74 loc) · 3.86 KB

File metadata and controls

93 lines (74 loc) · 3.86 KB

Owner identity for the intelligence surfaces

Watchlists, developer keys, webhooks, saved queries, graph cases, knowledge submissions and node RPC execution belong to an owner. The owner is the holder of an API key issued by this backend. There is no user_id anywhere: a body or query field with that name is ignored, and a resource that belongs to another owner answers 404.

Creating an owner

POST /api/v1/intelligence/developer/owners
{ "name": "Ingestion service" }

Answers 201 with the first key. secret_key is shown once and is never stored in clear. The owner id is generated by the server. Creation is bounded per caller address (10 per hour).

{ "key_id": "...", "owner_id": "...", "name": "Ingestion service",
  "scopes": ["read", "watchlists", "webhooks", "queries", "cases", "knowledge", "node:rpc", "keys:manage"],
  "secret_key": "uip_live_...", "storage": "durable" }

Signing a request

Authorization: Bearer uip_live_...

X-Api-Key is accepted too. A missing or unknown key answers 401; a key without the needed scope answers 403.

Scopes

Scope Grants
read Reads that are owner scoped
watchlists /api/v1/intelligence/watchlists/*
webhooks /api/v1/intelligence/developer/webhooks*
queries /api/v1/intelligence/query/saved
cases /api/v1/intelligence/graph/cases*
knowledge POST /api/v1/intelligence/knowledge/labels, challenges
node:rpc POST /api/v1/node/rpc (still bounded by the read-only allowlist and per-method budget)
keys:manage Minting and revoking further keys for the same owner, with a subset of the caller's scopes

* cannot be minted through the API. An operator key with every scope can be provided out of band through UNIVERSE_INTELLIGENCE_LEGACY_MASTER_KEY; nothing is seeded from source.

Storage

Keys are stored as an HMAC-SHA256 of the secret under a pepper that is either UNIVERSE_INTELLIGENCE_KEY_PEPPER or, when unset, generated once and kept in intelligence_settings. Webhook signing secrets are AES-256-GCM encrypted with UNIVERSE_INTELLIGENCE_SECRET_KEY (32 bytes hex) or a key derived from the pepper. All owner rows carry owner_id and network; the network is the backend's own.

Without a database (DATABASE.ENABLED=false) the same contract runs in memory and every owner response reports storage: "memory"; nothing survives a restart.

Webhooks and delivery

POST /api/v1/intelligence/developer/webhooks
{ "target_url": "https://hooks.example.org/universe", "events": ["watchlist.notification"] }

Targets must be https, must not carry credentials, and must resolve only to public addresses; every resolved address is checked again at delivery time and the connection is pinned to it. A delivery is one HTTPS POST with headers X-Universe-Event-Id, X-Universe-Timestamp and X-Universe-Signature: v1=<hex> where the signature is HMAC-SHA256(secret, timestamp.body). Only a 2xx is a success; redirects, timeouts, connection errors and other statuses are failures that are retried from a leased outbox with capped backoff, up to eight attempts. GET /api/v1/intelligence/developer/webhooks/:id/attempts lists what actually happened.

Watchlists

Entities are stored as SHA-256 of the raw identifier. Pass "blinded": true to submit a hash you computed yourself. Rules: confirmation, value_transfer (optional threshold_value in sats), rbf_replacement, feerate_cross (threshold_value in sat/vB), reorg_displaced. The matcher runs on every block the backend processes and on every replacement the RBF cache records; a notification is unique per rule and event, a re-observed block produces nothing new, and a reorg marks displaced confirmations. GET /api/v1/intelligence/watchlists/notifications lists the owner's notifications; POST .../notifications/:id/ack acknowledges one.