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 (Neo4j 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 Neo4j 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 on Neo4j). 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.