Python
Async-first. Typed dataclasses. Generator-based streaming interface. Targets Python 3.11+.
pip install omnitwin Developers
API reference, SDKs, and integration guides for the agent-native network twin.
REST · gRPC · MCP · SSE streaming · OpenAPI
Three steps from zero to your first streaming agent response.
Create a key in your workspace settings at Settings → API Keys.
Keys are scoped to a workspace and can be restricted to read-only.
export OMNITWIN_API_KEY=ot_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx List subnets in your workspace. Pagination defaults to 50 per page.
curl -X GET \
https://api.myomnitwin.com/v1/subnets \
-H "Authorization: Bearer $OMNITWIN_API_KEY" \
-H "Accept: application/json" {
"data": [
{
"id": "sn_01HX7K2M3N4P5Q6R7S8T9U0V",
"cidr": "10.128.0.0/16",
"status": "allocated",
"purpose": "prod-us-east"
}
],
"meta": { "total": 142, "page": 1, "per_page": 50 }
}
The POST /agents/command endpoint returns a Server-Sent Events stream.
Each line is a typed JSON envelope.
curl -N -X POST \
https://api.myomnitwin.com/v1/agents/command \
-H "Authorization: Bearer $OMNITWIN_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{"command":"Find available /24 blocks in 10.128.0.0/16"}' data: { "type": "agent_status", "body": { "message": "Searching intent database..." } }
data: { "type": "data_chunk", "body": { "matches": 3 } }
data: { "type": "agent_tool_call", "body": { "fn": "ipam_search" } }
data: { "type": "final_result", "body": { "available_blocks": 2 } }
data: [DONE]
All API requests must be authenticated. Include your API key in the
Authorization header on every request.
Authorization: Bearer ot_live_xxxxxxxxxxxx X-OmniTwin-Key: ot_live_xxxxxxxxxxxx Never expose API keys in client-side code. For browser integrations, proxy requests through your backend.
https://api.myomnitwin.com/v1 https://sandbox.myomnitwin.com/v1 No real data. Safe for integration testing. Manage IP address allocations. All writes are identity-bound — every mutation records the actor, timestamp, and intent in the immutable audit trail.
/subnets List subnets Returns a paginated list of subnets. Filter by CIDR prefix, status, or purpose tag.
cidr string Filter to subnets within this CIDR block. e.g. 10.0.0.0/8 status string One of allocated · reserved · available · deprecated purpose string Free-text purpose tag. Supports partial match. page integer Page number. Default: 1 per_page integer Results per page. Max: 200. Default: 50 {
"data": [
{
"id": "sn_01HX7K2M3N4P5Q6R7S8T9U0V",
"cidr": "10.128.0.0/16",
"status": "allocated",
"purpose": "prod-us-east",
"vlan_id": 128,
"owner": "team:platform",
"created_at": "2024-11-03T14:22:00Z"
}
],
"meta": { "total": 142, "page": 1, "per_page": 50 }
} /subnets/:id Get subnet detail Returns a single subnet with full metadata, child allocations, and current utilization.
{
"id": "sn_01HX7K2M3N4P5Q6R7S8T9U0V",
"cidr": "10.128.0.0/16",
"status": "allocated",
"purpose": "prod-us-east",
"total_ips": 65536,
"used_ips": 18943,
"utilization": 0.289,
"children": ["sn_01HX...", "sn_01HY..."],
"tags": { "region": "us-east-1", "env": "prod" }
} /subnets Create subnet allocation Allocates a new subnet. The math engine validates the CIDR, checks for overlap, and records intent in Postgres.
cidr required string CIDR notation. e.g. 10.128.16.0/20 purpose required string Human-readable purpose label. Used for search and audit. parent_id string ID of the parent subnet. Enforces hierarchy. vlan_id integer VLAN association. 1–4094. tags object Arbitrary key-value metadata. {
"id": "sn_01HZ9A3B4C5D6E7F8G9H0I1J",
"cidr": "10.128.16.0/20",
"status": "allocated",
"created_at": "2024-11-03T15:00:00Z"
} /subnets/:id Update subnet Update mutable fields on an existing subnet. Writes are identity-bound: the actor is recorded and the change is appended to the immutable audit trail. CIDR itself cannot be changed — allocate a new subnet instead.
purpose string Update the purpose label. status string Transition status: allocated · reserved · deprecated owner string Owner reference. e.g. team:platform or user:alice tags object Merged (not replaced) with existing tags. /subnets/:id/audit Get immutable audit trail Returns the full immutable audit log for a subnet. Every mutation — create, update, agent action — is recorded with actor identity and timestamp. Append-only; records cannot be deleted.
{
"subnet_id": "sn_01HX7K2M3N4P5Q6R7S8T9U0V",
"events": [
{
"seq": 1,
"action": "created",
"actor": "user:alice@acme.com",
"at": "2024-11-03T14:22:00Z"
},
{
"seq": 2,
"action": "status_changed",
"actor": "agent:ipam-allocator",
"at": "2024-11-04T09:15:32Z"
}
]
} Physical and virtual infrastructure objects. Each device carries two parallel states: twin state (what OmniTwin believes is true) and detected state (what was last observed via discovery). The gap between them is drift.
/devices List devices Returns a paginated list of devices. Filterable by site, rack, role, or drift status.
site string Site slug or ID. role string Device role: switch · router · server · firewall · pdu has_drift boolean Filter to devices with unresolved drift. Default: false /devices/:id Get device with twin + detected state
Returns the full device object including both twin state (Postgres intent) and
detected state (graph observed). The drift_score is a normalized float
from 0 (aligned) to 1 (fully diverged).
{
"id": "dv_01HX9B3C4D5E6F7G8H9I0J1K",
"hostname": "spine-01.nyc1",
"role": "switch",
"drift_score": 0.17,
"twin_state": { "interfaces": 48, "mgmt_ip": "10.0.1.1" },
"detected_state": { "interfaces": 46, "last_seen": "2024-11-03T18:42:11Z" }
} /devices/:id/drift Get drift events for a device Returns the time-ordered list of drift events for a device. Each event records what diverged, when it was detected, and whether it has been reconciled.
{
"device_id": "dv_01HX9B3C4D5E6F7G8H9I0J1K",
"events": [
{
"id": "dr_01HZA1B2C3",
"field": "interfaces",
"twin_value": 48,
"actual_value": 46,
"detected_at": "2024-11-03T18:42:11Z",
"status": "open"
}
]
} /devices/:id/reconcile Trigger one-click reconcile Launches a reconciliation job for the device. The agent computes the diff between twin state and detected state, applies the resolution strategy, and updates both databases. Returns immediately with a job ID.
strategy string trust_twin · trust_detected · interactive. Default: interactive fields string[] Limit reconciliation to specific fields. Omit to reconcile all drift. {
"job_id": "job_01HZA1B2C3D4E5F6G7H8I9J",
"status": "queued",
"stream": "/v1/agents/sessions/sess_xxx/events"
}
The agent API is the primary interface to the platform. POST /agents/command
accepts natural-language or structured commands and returns a streaming SSE response.
Every session is persisted with full telemetry.
The command endpoint is streaming-first. Set Accept: text/event-stream
to receive typed events as they arrive. Omit the header to receive a single JSON
response after the agent finishes.
/agents/command Execute a command · main API SSE Executes a command against the OmniTwin agent runtime. Accepts natural language ("Find available /24 blocks in the prod VPC") or deterministic CIDR/hardware queries. Returns a Server-Sent Events stream of typed JSON envelopes.
command required string The command to execute. Natural language or deterministic query. session_id string Continue an existing session. Omit to start a new session. context object Additional context keys: subnet_id, device_id, scope model string Override the workspace default LLM. e.g. anthropic/claude-3-5-sonnet curl -N -X POST \
https://api.myomnitwin.com/v1/agents/command \
-H "Authorization: Bearer $OMNITWIN_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{"command":"Allocate a /24 for the payments service in us-east"}' data: { "type": "agent_status", "seq": 1, "body": { "message": "Parsing intent..." } }
data: { "type": "data_chunk", "seq": 2, "body": { "source": "ipam", "matches": 2 } }
data: { "type": "agent_tool_call", "seq": 3, "body": { "fn": "ipam_allocate" } }
data: { "type": "final_result", "seq": 4, "body": { "committed": true } }
data: [DONE] /agents/sessions List active agent sessions Returns active and recent sessions for the workspace. Sessions expire after 24 hours of inactivity.
/agents/sessions/:id Get session with telemetry Returns a session object including full telemetry: model used, token counts, tool calls made, latency per step, and final status.
{
"id": "sess_01HZ9A3B4C5D6E7F",
"command": "Allocate a /24 for the payments service",
"status": "completed",
"model": "anthropic/claude-3-5-sonnet",
"telemetry": { "input_tokens": 842, "output_tokens": 316, "tool_calls": 2, "duration_ms": 1840 }
} /agents/sessions/:id/events SSE stream of agent events SSE Subscribe to the live event stream for a session. If the session is still active, this is a live stream. If the session has completed, the full event history is replayed and the stream closes.
Ingest data from existing IPAM tools. Supported sources: Infoblox, BlueCat, phpIPAM, and CSV. Import jobs run asynchronously; conflicts are surfaced for human or agent review before committing to the intent database.
/import Start import job
Starts an import job. For file-based sources (CSV, export files), upload using
multipart/form-data. For API-connected sources, provide credentials
in the request body.
source required string One of: infoblox · bluecat · phpipam · csv file file CSV or export file. Required when source is csv. credentials object API credentials for connected sources. Shape varies by source. dry_run boolean Validate and surface conflicts without committing. Default: false {
"job_id": "imp_01HZ9A3B4C5D6E7F8G9H0I",
"source": "infoblox",
"status": "queued",
"dry_run": false
} /import/:jobId Get import job status Returns the current status of an import job including progress, counts, and any fatal errors.
{
"job_id": "imp_01HZ9A3B4C5D6E7F8G9H0I",
"status": "processing",
"progress": { "processed": 1240, "total": 3817 },
"conflicts": 14,
"committed": 1226
} /import/:jobId/conflicts List import conflicts Returns a list of conflicts detected during import — overlapping CIDRs, duplicate hostnames, mismatched ownership. Each conflict has a suggested resolution that can be accepted via the command bar or API.
{
"conflicts": [
{
"id": "cf_01HZB1C2D3",
"type": "cidr_overlap",
"import_cidr": "10.128.0.0/20",
"existing_id": "sn_01HX...",
"suggestion": "mark_as_child"
}
]
} Graph queries against the live network topology. The topology layer is backed by a graph database and reflects observed physical and logical connections. Use it to find paths, understand blast radius, and navigate the network graph programmatically.
/topology/graph Get topology subgraph Returns a subgraph from the topology. Scope the query with a device ID, subnet ID, or site to avoid full-graph responses. The response is a node-edge graph suitable for rendering with D3, Cytoscape, or similar.
scope_id string Center the subgraph on this node (device, subnet, or site ID). depth integer Hop depth from the scope node. Default: 2. Max: 5 include_drift boolean Annotate edges with drift status. Default: false {
"nodes": [
{ "id": "dv_01HX...", "type": "switch", "label": "spine-01.nyc1" },
{ "id": "dv_01HY...", "type": "server", "label": "rack-a-01" }
],
"edges": [
{ "from": "dv_01HX...", "to": "dv_01HY...", "type": "connected_to" }
]
} /topology/path/:from/:to Find path between nodes Finds the shortest path between two nodes in the topology graph (Dijkstra over the graph database). Useful for blast-radius analysis, cable tracing, and network segmentation review.
{
"from": "dv_01HX...",
"to": "dv_01HZ...",
"hops": 3,
"path": ["dv_01HX...", "dv_01HY...", "dv_01HZ..."],
"edges": [
{ "port_a": "eth1/1", "port_b": "eth1/24", "cable": "lc-01482" }
]
} The agent runtime is gRPC/MCP-streaming-first. The REST API surface exposes this via Server-Sent Events (SSE). Every message in the stream is a typed JSON envelope with a consistent shape.
interface StreamEvent {
type: EventType;
seq: number; // monotonic per session
session: string; // session ID
ts: string; // ISO 8601
body: unknown; // typed per EventType
}
type EventType =
"agent_status" // status update, reasoning step
| "data_chunk" // partial result data
| "agent_tool_call" // tool invocation + args
| "final_result" // terminal event with result
| "error"; // fatal error, stream closes agent_status Reasoning step or status message. body.message is display-safe prose. data_chunk Partial result data. Shape varies by query type. Safe to render incrementally. agent_tool_call Tool invocation. body.fn is the tool name; body.args are the call arguments. final_result Terminal event. Always the last data event before [DONE]. Contains the committed result. error Fatal error. body.code and body.message. Stream closes after this event.
The stream always terminates with data: [DONE] on a line by itself.
Treat the absence of final_result before [DONE] as an
error condition.
Native client libraries are in development for pre-beta release. The REST API is stable now — build against it directly while the SDKs land.
Async-first. Typed dataclasses. Generator-based streaming interface. Targets Python 3.11+.
pip install omnitwin Idiomatic Go client. Context-aware. Channel-based streaming. First-class gRPC support.
go get github.com/omnitwin/sdk-go Full types for all endpoints and event envelopes. AsyncIterable streaming. Node + edge runtime compatible.
npm install @omnitwin/sdk Every response includes rate limit state. The default limit is 1,000 requests per minute per workspace.
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 842
X-RateLimit-Reset: 1730654460 # Unix timestamp
Retry-After: 12 # seconds, if 429
All errors return a consistent JSON body with a machine-readable code
and a human-readable message.
{
"error": {
"code": "cidr_overlap",
"message": "10.128.0.0/20 overlaps existing sn_01HX...",
"request_id": "req_01HZB1C2D3E4F5G6H7"
}
} 200 OK — request succeeded. 201 Created — resource was created. Body contains the new resource. 202 Accepted — async job queued. Poll the returned job_id for status. 400 Bad Request — validation failed. Check error.code for specifics. 401 Unauthorized — missing or invalid API key. 403 Forbidden — authenticated but insufficient scope. 404 Not Found — resource does not exist or is not accessible to this key. 409 Conflict — CIDR overlap, duplicate hostname, or state transition conflict. 429 Too Many Requests — rate limit exceeded. Respect Retry-After. 500 Server Error — includes a request_id for support escalation. Sandbox
The sandbox environment mirrors the production API with isolated data. Use it for integration testing, demos, and experimenting with the streaming agent interface.
https://sandbox.myomnitwin.com/v1
All sandbox keys are prefixed ot_sandbox_. Data resets every 24 hours.