Xiber NetOS — API & Integrations Guide
REST API endpoints, MCP tools, and external system integration map.
REST API
| Setting | Value |
|---|---|
| Base URL | http://localhost:8000/api/v1 |
| Production Base URL | https://netos.xiberian.net/api/v1 |
| Docs (Swagger) | https://netos.xiberian.net/docs-api/ |
| OpenAPI Schema | https://netos.xiberian.net/openapi.json |
| Content Type | application/json |
Authentication
Browser users authenticate through Microsoft SSO. Machine users and coding agents should use NetOS API access tokens.
Use either header format:
Authorization: Bearer ntos_live_...or:
X-NetOS-API-Key: ntos_live_...API tokens are bound to an internal NetOS user. The token authenticates the machine, then NetOS applies that user's normal RBAC roles, scopes, and field-level permissions. Frontend visibility is irrelevant for machine access; backend permissions are still authoritative.
Development environments may also allow dev headers when ALLOW_DEV_AUTH=true:
x-user-email: dev@example.com
x-user-role: execDo not use dev headers in production.
Creating Machine Access Tokens
Only users with users_edit can create or revoke API tokens.
POST /api/v1/authz/api-tokens{
"user_id": "00000000-0000-0000-0000-000000000000",
"name": "agent01 quote importer",
"expires_at": "2026-09-01T00:00:00Z"
}The response includes the full token once:
{
"api_token_id": "11111111-1111-1111-1111-111111111111",
"user_id": "00000000-0000-0000-0000-000000000000",
"user_email": "agent-netos@xiber.net",
"name": "agent01 quote importer",
"token_prefix": "ntos_live_abcd...",
"expires_at": "2026-09-01T00:00:00+00:00",
"token": "ntos_live_full_secret_value_returned_once"
}Store the token immediately in the calling system's secret manager. NetOS stores only a hash and cannot display the full token again.
List tokens:
GET /api/v1/authz/api-tokensRevoke a token:
DELETE /api/v1/authz/api-tokens/{api_token_id}Rotate a token:
POST /api/v1/authz/api-tokens/{api_token_id}/rotateRotation keeps the same token record but replaces the secret. The previous token stops working immediately, and the new token is returned once.
Machine Access Example
export NETOS_API_TOKEN='ntos_live_...'
curl -sS \
-H "Authorization: Bearer $NETOS_API_TOKEN" \
https://netos.xiberian.net/api/v1/authz/mePrompt For Another Coding Agent
You are integrating with Xiber NetOS.
Base URL:
https://netos.xiberian.net/api/v1
API docs:
https://netos.xiberian.net/docs-api/
OpenAPI schema:
https://netos.xiberian.net/openapi.json
Authenticate every API request with:
Authorization: Bearer <NETOS_API_TOKEN>
The token is bound to an internal NetOS user. Do not try to bypass RBAC. If an endpoint returns 401 or 403, report the missing permission or authorization failure.
Useful endpoints:
- GET /authz/me
- GET /search
- GET /quotes
- POST /quotes/extract
- GET /quotes/drafts
- POST /quotes/drafts
- PATCH /quotes/drafts/{draft_id}
- POST /quotes/drafts/{draft_id}/reject
- POST /quotes/drafts/{draft_id}/commit
- POST /quotes
- POST /quotes/{quote_id}/documents
- POST /quotes/{quote_id}/documents/text
- POST /quotes/{quote_id}/documents/{document_id}/reanalyze
- GET /circuits
- GET /infrastructure
- GET /customers
- GET /rf-links
- GET /electrical-services
Vendor quote model:
- One quote represents one vendor/path/service.
- Term pricing is stored in pricing_options.
- NNI is a valid quote service type and represents an EVPL landing point.
- `target_type` identifies the quote scope. Use `circuit` for transport/path quotes with A and Z endpoints. Use values such as `infrastructure`, `tower`, `rooftop`, `datacenter`, `electrical`, `rf_link`, or `other` for single-site/service quotes that only need a target site/location.
- Quote attachments are stored on the quote record. Uploaded vendor PDFs, images, order forms, and proposals are analyzed in the background when an AI provider is configured; AI summaries and notes are searchable at low search priority.
- Pasted vendor emails or unstructured quote notes can be saved as text quote attachments through `POST /quotes/{quote_id}/documents/text`. NetOS persists the text as a quote document, preserves line breaks for later viewing, queues AI analysis, and includes the text/AI notes in search.
- Claude Desktop and other MCP users should create quote drafts, not committed quotes. NetOS users review drafts in Vendor Quotes -> Draft Inbox, edit the form, then commit or reject them.Endpoints
Health Check
GET /healthz{"status": "ok"}No authentication required.
List Circuits
GET /api/v1/circuitsQuery Parameters:
| Param | Type | Description |
|---|---|---|
carrier | string | Filter by carrier name |
status | string | Filter by status enum |
search | string | Full-text search across circuit label, carrier circuit ID, carrier name |
Response: Array of circuit objects with nested carrier, contract, A endpoint, and Z endpoint data.
Example:
curl -H "x-user-role: exec" \
"http://localhost:8000/api/v1/circuits?status=active&carrier=Lumen"Get Circuit Detail
GET /api/v1/circuits/{circuit_id}Response includes:
- Circuit attributes (label, carrier circuit ID, service type, bandwidth, status, MRC, NRC)
- Carrier details (name, NOC phone, portal URL)
- Contract details (term dates, renewal type, ETF, escalator)
- A and Z endpoints (name, address, coordinates)
- Exact monitoring URL and generated monitoring search fallback
- Provider portal URL
- Lifecycle events (ordered by date)
Create Circuit
POST /api/v1/circuitsRequires: Write role (exec, finance, network_eng, operations, pm)
Request Body:
{
"xiber_circuit_label": "XIB-LUM-0042",
"carrier_circuit_id": "DHEC.123456",
"carrier_name": "Lumen",
"service_type": "wave",
"bandwidth_mbps": 10000,
"status": "active",
"monitoring_url": "https://librenms.xiber.local/device/123",
"mrc_usd": 2500.00,
"nrc_usd": 5000.00,
"a_endpoint_name": "Xiber HQ",
"z_endpoint_name": "Cologix COL1"
}The manual UI now uses Infrastructure and Customer site selectors for circuit A/Z locations. The REST API still accepts endpoint fields so imports and integrations can create endpoint snapshots. For attribution, creating a circuit is not enough by itself; create a subtended_links relationship to state which infrastructure asset is the upstream donor and which downstream structure or customer endpoint is served over that circuit.
For DIA and broadband services, NetOS treats the circuit as single-site and clears the Z endpoint.
Customer, RF Link, Electrical, and Attribution APIs
Customers
GET /api/v1/customers
POST /api/v1/customers
GET /api/v1/customers/{customer_id}
PATCH /api/v1/customers/{customer_id}
DELETE /api/v1/customers/{customer_id}Customer records represent commercial and MFC customer sites. They can be selected by circuits, RF Links, and subtended links. Customer detail responses include associated circuits, RF Links, serving paths, inherited donor cost, customer revenue, attributed cost, and gross margin.
RF Links
GET /api/v1/rf-links
POST /api/v1/rf-links
PATCH /api/v1/rf-links/{rf_link_id}
DELETE /api/v1/rf-links/{rf_link_id}
POST /api/v1/rf-links/{rf_link_id}/documentsRF Links are built from existing infrastructure and customer sites. Links between two infrastructure assets are backhaul. Links from infrastructure to a customer site are customer endlinks. When a customer endlink is saved, NetOS synchronizes the matching subtended customer endpoint relationship so attribution can show RF transport.
RF System Catalog
GET /api/v1/rf-systems
POST /api/v1/rf-systems
PATCH /api/v1/rf-systems/{rf_system_id}
DELETE /api/v1/rf-systems/{rf_system_id}RF systems define selectable defaults such as name, description, frequency used, capacity, cost, PTP/PtMP type, equipment role, and PtMP compatibility. PtMP source nodes must reference RF systems with role ptmp_base. PtMP customer RF Links must reference a subscriber/client RF system with role ptmp_subscriber; if the subscriber has compatible base system IDs, the selected PtMP source node's base system must be included.
Electrical Services
GET /api/v1/electrical-services
POST /api/v1/electrical-services
PATCH /api/v1/electrical-services/{electrical_service_id}
DELETE /api/v1/electrical-services/{electrical_service_id}
POST /api/v1/electrical-services/{electrical_service_id}/documentsElectrical services attach to exactly one Infrastructure or Customer site. They store provider, service type, account and meter numbers, voltage, amperage, phase, delivery location, service address, average monthly cost, start date, monitoring URL, notes, and supporting documents.
Infrastructure Subtended Links
POST /api/v1/infrastructure/{infrastructure_id}/subtended-links
PATCH /api/v1/infrastructure/{infrastructure_id}/subtended-links/{link_id}
DELETE /api/v1/infrastructure/{infrastructure_id}/subtended-links/{link_id}Subtended links explicitly define the financial hierarchy. Use them to attach customer endpoints, downstream structures, existing circuits, or RF Links to a parent infrastructure asset. This is what drives the attribution tree, dashboard attribution cards, customer inherited-cost drilldowns, and infrastructure financial summaries.
Bulk Update Circuits
PATCH /api/v1/circuits/bulkRequires: Write role (exec, finance, network_eng, operations, pm)
Request Body:
{
"circuit_ids": ["8d8e4333-8182-4443-8e0d-f2307276db52"],
"updates": {
"status": "active",
"carrier_name": "Lumen",
"service_type": "dia",
"mrc_usd": 1850.00,
"nrc_usd": 0,
"contract_term_end_date": "2027-12-31",
"notes": "Updated through bulk action"
}
}Only fields included in updates are changed. Each affected circuit receives an audit entry.
Response:
{"updated": 1, "requested": 1}Bulk Delete Circuits
POST /api/v1/circuits/bulk-deleteSoft-deletes circuits by setting deleted_at. Records remain available for audit and historical reporting.
Request Body:
{
"circuit_ids": ["8d8e4333-8182-4443-8e0d-f2307276db52"]
}Response:
{"deleted": 1, "requested": 1}Map Data
GET /api/v1/circuits/mapQuery Parameters:
| Param | Type | Description |
|---|---|---|
carrier | string | Filter by carrier |
service_type | string | Filter by service type enum |
status | string | Filter by status enum |
state | string | Filter by endpoint state (US state) |
Response:
{
"circuits": [
{
"id": "uuid",
"label": "XIB-LUM-0042",
"carrier": "Lumen",
"service_type": "wave",
"bandwidth_mbps": 10000,
"status": "active",
"a_endpoint": {"name": "...", "lat": 39.96, "lng": -82.99},
"z_endpoint": {"name": "...", "lat": 39.95, "lng": -83.00},
"geometry": {"type": "LineString", "coordinates": [[-82.99, 39.96], [-83.00, 39.95]]}
}
],
"endpoints": [
{
"id": "uuid",
"name": "Xiber HQ",
"type": "pop",
"geometry": {"type": "Point", "coordinates": [-82.99, 39.96]}
}
],
"infrastructure": [
{
"id": "uuid",
"name": "Cologix COL1",
"type": "data_center",
"geometry": {"type": "Point", "coordinates": [-83.00, 39.95]}
}
],
"filters": {
"carriers": ["Lumen", "Zayo", "Cogent"],
"service_types": ["wave", "dia", "dark_fiber"],
"statuses": ["active", "ordered"],
"states": ["OH", "GA", "IL"]
}
}Dashboard Summary
GET /api/v1/dashboard/summaryResponse includes:
| Section | Fields |
|---|---|
kpis | total_circuits, active_circuits, infrastructure_count, circuit_mrc, facility_mrc, total_mrc, modeled_mrr, modeled_margin, renewal_window_count |
spend_by_carrier | Array of {carrier, mrc, circuit_count} |
service_mix | Array of {service_type, count} |
state_mix | Array of {state, count} |
renewal_pipeline | Array of {state, count} |
margin_histogram | Array of {bucket, count} |
at_risk_circuits | Array of circuit summaries |
top_expensive | Array of circuit summaries |
lowest_margin | Array of circuit summaries |
Import Preview
POST /api/v1/imports/circuits/preview
Content-Type: multipart/form-dataUpload a CSV or XLSX file. Returns import job ID, detected column mapping, headers, sample rows, and validation summary.
Example:
curl -H "x-user-role: exec" \
-F "file=@examples/sample_circuits.csv" \
http://localhost:8000/api/v1/imports/circuits/previewImport Commit
POST /api/v1/imports/circuits/{import_job_id}/commitCommits all valid staged rows. Returns insert/update/invalid counts.
Example:
curl -H "x-user-role: exec" \
-X POST \
http://localhost:8000/api/v1/imports/circuits/{import_job_id}/commitList Service Providers
GET /api/v1/service-providersReturns carrier records with circuit count, infrastructure count, and total spend.
Get Service Provider
GET /api/v1/service-providers/{carrier_id}Returns provider detail with related circuits and infrastructure assets.
List Infrastructure Assets
GET /api/v1/infrastructureReturns infrastructure asset records with facility type, provider, costs, terms, and monitoring_url.
Bulk Update Infrastructure Assets
PATCH /api/v1/infrastructure/bulkRequest Body:
{
"infrastructure_ids": ["ae30e22f-565d-46f3-be94-9d0e001a59de"],
"updates": {
"status": "active",
"provider_name": "American Tower",
"site_type": "tower",
"mrc_usd": 2200.00,
"price_escalator_pct": 3.0,
"term_end_date": "2028-12-31",
"notes": "Updated through bulk action"
}
}Only fields included in updates are changed. Each affected asset receives an audit entry.
Response:
{"updated": 1, "requested": 1}Bulk Delete Infrastructure Assets
POST /api/v1/infrastructure/bulk-deleteSoft-deletes infrastructure assets by setting deleted_at.
Request Body:
{
"infrastructure_ids": ["ae30e22f-565d-46f3-be94-9d0e001a59de"]
}Response:
{"deleted": 1, "requested": 1}Audit Activity
GET /api/v1/audit/activityReturns recent request/write activity including user, role, IP, event type, action, entity, changed fields, and response status.
Feedback Queue
GET /api/v1/feedback
POST /api/v1/feedback
PATCH /api/v1/feedback/{feedback_id}
POST /api/v1/feedback/{feedback_id}/commentsFeedback requests support priority, status, and progress comments. Public comments attempt to notify the requester by email when SMTP is configured.
MCP Server
Location: apps/mcp/
The MCP server exposes NetOS data to XOS agents (ExecOS, department agents, Claude Desktop users).
Current Tools
The MCP server is intentionally a thin, permission-aware layer over the NetOS REST API. It does not read the database directly. API-token RBAC controls which rows and fields are returned.
| Tool | Description |
|---|---|
netos_auth_me | Verify the configured NetOS API identity, roles, and permissions |
search_netos | Universal search across inventory, sites, customers, documents, and providers |
list_circuits | List wholesale circuits with optional API filters |
get_circuit | Get a circuit detail record |
list_infrastructure | List infrastructure sites, with simple client-side filters |
get_infrastructure_context | Get full infrastructure context, relationships, economics allowed by RBAC, and compact document/photo metadata |
list_customers | List customer sites, with simple client-side filters |
get_customer_context | Get customer context including contacts, access notes, service paths, and compact document/photo metadata |
get_site_documents | Return metadata, user notes, and AI summaries for site documents/photos |
list_rf_links | List RF links, including PTP/PtMP path metadata |
get_rf_link | Get one RF link by UUID via list filtering |
list_quotes | List vendor quotes using supported API filters |
get_quote | Get quote detail, pricing options, and status history when permitted |
quote_aggregation | Site-level vendor quote aggregation for NNI/port planning signals |
create_quote_draft | Create a vendor quote draft for human review without writing to quote history |
list_quote_drafts | List vendor quote drafts by review status |
get_quote_draft | Get one vendor quote draft by UUID |
update_quote_draft | Correct a draft payload before review/commit |
reject_quote_draft | Reject a duplicate, stale, or invalid draft with a reason |
get_carrier_summary | Provider/carrier summary with circuit count, MRC totals, ETF exposure, contacts, portals, circuits, and infrastructure |
get_renewal_pipeline | Circuit and infrastructure renewal deadlines by state for a lookahead window |
get_field_record | Field-oriented context by kind: circuit, infrastructure, customer, or rf_link |
Planned Tools
| Tool | Description |
|---|---|
get_circuit_pl | Per-circuit P&L with revenue attribution |
get_outage_history | Outage events for a circuit |
| Write tools | Create/update with explicit agent confirmation flow and audit trail |
Authentication
Production MCP deployments should use a NetOS API token generated in Admin. Configure the MCP process with:
NETOS_API_BASE_URL=http://10.10.67.118:8010
NETOS_API_TOKEN=ntos_live_...Use the protected internal API endpoint for machine clients. The public browser hostname https://netos.xiberian.net is fronted by Microsoft SSO through oauth2-proxy and will return an HTML sign-in page before NetOS can validate an API token.
Every MCP request is sent to the REST API with:
Authorization: Bearer <NETOS_API_TOKEN>The token user's RBAC permissions determine what the tools can see. Financial fields, executive summaries, document metadata, and search results follow the same field-level masking rules as the REST API.
For local development only, the MCP server can fall back to trusted dev headers:
NETOS_MCP_AGENT_EMAIL=xos-agent@xiber.com
NETOS_MCP_AGENT_ROLE=agentThis fallback should not be used for production gateway access.
Registration with XOS Gateway
The MCP server should be registered with the Xiber MCP Gateway (gateway.xiberian.net) so it's available to all XOS agents and Claude Desktop users via the SSE bridge. This is not yet configured.
External System Integration Map
| System | Direction | Purpose | Status |
|---|---|---|---|
| Sonar | Pull | Customer accounts, MRR, revenue attribution per circuit | Planned |
| Monday.com | Bidirectional | Renewal tasks, variance tasks, circuit order workflow | Planned |
| Wisdm | Pull | Tower and network site geometry for map overlays | Planned |
| LibreNMS / Prometheus / Loki | Pull | Utilization data, outage detection, monitoring deep links | Planned |
| DocuSeal | Push | Generate termination notices and contract execution envelopes | Planned |
| Microsoft 365 / Entra ID | Pull | SSO, user identity, calendar/Teams/SharePoint references | Planned |
| XOS (MCP Gateway) | Expose | Agent-readable circuit tools for automated reporting and decisions | Skeleton |
| Lumen Control Center | Pull | Circuit status sync from carrier portal | Not started |
| Zayo Tranzact | Pull | Circuit status sync from carrier portal | Not started |
| Cogent Portal | Pull | Circuit status sync from carrier portal | Not started |
Planned Webhooks (Outbound)
| Event | Trigger | Destination |
|---|---|---|
circuit.installed | Circuit status → active | Monday.com, Slack |
circuit.decommissioned | Circuit status → decommissioned | Monday.com, Slack |
renewal.state_changed | Renewal state transition | Monday.com, Email, Slack |
invoice.variance_detected | Invoiced MRC ≠ contracted MRC | Monday.com (task for finance) |
*Webhooks are not yet implemented.*
