{"openapi":"3.1.0","info":{"title":"ApexDiagram API","version":"1.0.0","description":"Network diagrams as data. Every diagram is one graph rendered as five views; this API reads and writes that graph. Authenticate with an API key created at Settings → API keys."},"servers":[{"url":"/api/v1"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Diagrams"},{"name":"Devices"},{"name":"Links"},{"name":"Inventory","description":"VLANs, subnets and locations are organisation-wide."},{"name":"Analysis","description":"Linter, bill of materials, auto-layout."},{"name":"Versions"},{"name":"Governance","description":"Audit trail."},{"name":"Templates"}],"paths":{"/diagrams":{"get":{"tags":["Diagrams"],"summary":"List diagrams","description":"Requires an API key with role VIEWER or higher.","responses":{"200":{"description":"Diagram list","content":{"application/json":{"schema":{"type":"object","properties":{"diagrams":{"type":"array","items":{"$ref":"#/components/schemas/DiagramListItem"}}}}}}}}},"post":{"tags":["Diagrams"],"summary":"Create a diagram","description":"Blank, from a template id, or from a full DiagramSnapshot. Requires an API key with role EDITOR or higher.","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"templateId":{"type":"string"},"snapshot":{"$ref":"#/components/schemas/DiagramSnapshot"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}}}}},"402":{"$ref":"#/components/responses/PlanLimit"}}}},"/diagrams/{id}":{"parameters":[{"$ref":"#/components/parameters/id"}],"get":{"tags":["Diagrams"],"summary":"Get a diagram as a DiagramSnapshot","responses":{"200":{"description":"Snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiagramSnapshot"}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"tags":["Diagrams"],"summary":"Rename","description":"Requires an API key with role EDITOR or higher.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}}}}},"responses":{"200":{"description":"Renamed"},"403":{"$ref":"#/components/responses/Forbidden"}}},"delete":{"tags":["Diagrams"],"summary":"Delete","description":"Requires an API key with role EDITOR or higher.","responses":{"204":{"description":"Deleted"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/diagrams/{id}/devices":{"parameters":[{"$ref":"#/components/parameters/id"}],"get":{"tags":["Devices"],"summary":"List a diagram's devices","responses":{"200":{"description":"Devices","content":{"application/json":{"schema":{"type":"object","properties":{"devices":{"type":"array","items":{"$ref":"#/components/schemas/Device"}}}}}}}}},"post":{"tags":["Devices"],"summary":"Create a device","description":"Requires an API key with role EDITOR or higher.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceInput"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Device"}}}},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/devices":{"get":{"tags":["Devices"],"summary":"Search devices across diagrams","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"},"description":"Matches name, hostname, IP, serial or asset tag."}],"responses":{"200":{"description":"Matches","content":{"application/json":{"schema":{"type":"object","properties":{"devices":{"type":"array","items":{"$ref":"#/components/schemas/Device"}}}}}}}}}},"/devices/{id}":{"parameters":[{"$ref":"#/components/parameters/id"}],"get":{"tags":["Devices"],"summary":"Get a device","responses":{"200":{"description":"Device","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Device"}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"tags":["Devices"],"summary":"Update a device","description":"Only fields sent change; null clears nullable fields. Requires an API key with role EDITOR or higher.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceInput"}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Device"}}}},"403":{"$ref":"#/components/responses/Forbidden"}}},"delete":{"tags":["Devices"],"summary":"Delete a device","description":"Requires an API key with role EDITOR or higher.","responses":{"204":{"description":"Deleted"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/diagrams/{id}/links":{"parameters":[{"$ref":"#/components/parameters/id"}],"get":{"tags":["Links"],"summary":"List cables and data flows","responses":{"200":{"description":"Links","content":{"application/json":{"schema":{"type":"object","properties":{"links":{"type":"array","items":{"$ref":"#/components/schemas/Link"}}}}}}}}},"post":{"tags":["Links"],"summary":"Create a link","description":"Requires an API key with role EDITOR or higher.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkInput"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Link"}}}},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/links/{id}":{"parameters":[{"$ref":"#/components/parameters/id"}],"patch":{"tags":["Links"],"summary":"Update link metadata","description":"Merged with the existing metadata and validated per link type. Requires an API key with role EDITOR or higher.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["metadata"],"properties":{"metadata":{"$ref":"#/components/schemas/LinkMetadata"}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Link"}}}},"403":{"$ref":"#/components/responses/Forbidden"}}},"delete":{"tags":["Links"],"summary":"Delete a link","description":"Requires an API key with role EDITOR or higher.","responses":{"204":{"description":"Deleted"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/diagrams/{id}/lint":{"parameters":[{"$ref":"#/components/parameters/id"}],"get":{"tags":["Analysis"],"summary":"Diagram assistant findings","responses":{"200":{"description":"Findings","content":{"application/json":{"schema":{"type":"object","properties":{"findings":{"type":"array","items":{"$ref":"#/components/schemas/LintFinding"}},"counts":{"type":"object","additionalProperties":{"type":"integer"}}}}}}}}}},"/diagrams/{id}/bom":{"parameters":[{"$ref":"#/components/parameters/id"}],"get":{"tags":["Analysis"],"summary":"Bill of materials","responses":{"200":{"description":"BOM","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/diagrams/{id}/layout":{"parameters":[{"$ref":"#/components/parameters/id"}],"post":{"tags":["Analysis"],"summary":"Auto-layout one view","description":"Writes a safety version first. Requires an API key with role EDITOR or higher.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"viewType":{"$ref":"#/components/schemas/ViewType"}}}}}},"responses":{"200":{"description":"Positioned","content":{"application/json":{"schema":{"type":"object","properties":{"viewType":{"$ref":"#/components/schemas/ViewType"},"positioned":{"type":"integer"}}}}}}}}},"/diagrams/{id}/versions":{"parameters":[{"$ref":"#/components/parameters/id"}],"get":{"tags":["Versions"],"summary":"List versions","responses":{"200":{"description":"Versions","content":{"application/json":{"schema":{"type":"object","properties":{"versions":{"type":"array","items":{"$ref":"#/components/schemas/Version"}}}}}}}}},"post":{"tags":["Versions"],"summary":"Save a checkpoint","description":"Requires an API key with role EDITOR or higher.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}}}}}}},"/diagrams/{id}/activity":{"parameters":[{"$ref":"#/components/parameters/id"}],"get":{"tags":["Governance"],"summary":"Audit trail for a diagram","parameters":[{"name":"before","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","schema":{"type":"integer","maximum":200}}],"responses":{"200":{"description":"Newest first","content":{"application/json":{"schema":{"type":"object","properties":{"activity":{"type":"array","items":{"$ref":"#/components/schemas/AuditEntry"}}}}}}}}}},"/activity":{"get":{"tags":["Governance"],"summary":"Export the organisation's audit trail as NDJSON","description":"Oldest first, one JSON object per line, each with prevHash and hash so the receiver can verify the chain. Requires an API key with role ADMIN or higher.","parameters":[{"name":"since","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"diagramId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"application/x-ndjson"}}}},"/vlans":{"get":{"tags":["Inventory"],"summary":"List VLANs and subnets","responses":{"200":{"description":"VLANs"}}},"post":{"tags":["Inventory"],"summary":"Create a VLAN with a subnet","description":"Requires an API key with role EDITOR or higher.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","vlanTag","cidr"],"properties":{"name":{"type":"string"},"vlanTag":{"type":"integer","minimum":1,"maximum":4094},"cidr":{"type":"string","example":"10.10.0.0/24"}}}}}},"responses":{"201":{"description":"Created"}}}},"/locations":{"get":{"tags":["Inventory"],"summary":"Location tree","responses":{"200":{"description":"Locations"}}},"post":{"tags":["Inventory"],"summary":"Create a location","description":"Requires an API key with role EDITOR or higher.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","kind"],"properties":{"name":{"type":"string"},"kind":{"type":"string","enum":["SITE","BUILDING","FLOOR","ROOM","RACK"]},"parentId":{"type":"string"},"rackUnits":{"type":"integer"}}}}}},"responses":{"201":{"description":"Created"}}}},"/templates":{"get":{"tags":["Templates"],"summary":"Built-in and organisation templates","responses":{"200":{"description":"Templates"}}}},"/openapi.json":{"get":{"summary":"This document","security":[],"responses":{"200":{"description":"OpenAPI 3.1 JSON"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key starting with ad_ (older keys start with pb_). Created at Settings → API keys."}},"parameters":{"id":{"name":"id","in":"path","required":true,"schema":{"type":"string"}}},"responses":{"NotFound":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Role too low, or the diagram requires change approval","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"PlanLimit":{"description":"Plan limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"},"details":{}},"required":["error"]},"ViewType":{"type":"string","enum":["NETWORK","PHYSICAL","LOGICAL","DATA","PURDUE"]},"DeviceType":{"type":"string","enum":["ROUTER","SWITCH","FIREWALL","LOAD_BALANCER","ACCESS_POINT","WIRELESS_CONTROLLER","PATCH_PANEL","SERVER","WORKSTATION","LAPTOP","PRINTER","CLOUD","STORAGE","PLC","RTU","SAFETY_CONTROLLER","DCS_CONTROLLER","HMI","SCADA_SERVER","HISTORIAN","SENSOR_ACTUATOR","ACTUATOR","INSTRUMENT","INDUSTRIAL_SWITCH","INDUSTRIAL_FIREWALL","PROTOCOL_GATEWAY","OTHER"]},"DiagramListItem":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"devices":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"DiagramSnapshot":{"type":"object","description":"The universal interchange format: the same shape the JSON export produces and the importer accepts. See docs/features/versions.md.","required":["name","devices","links","vlans","locations"],"properties":{"name":{"type":"string"},"documentation":{"type":["string","null"]},"devices":{"type":"array","items":{"type":"object","additionalProperties":true,"required":["key","name","type"],"properties":{"key":{"type":"string"},"name":{"type":"string"},"type":{"$ref":"#/components/schemas/DeviceType"}}}},"links":{"type":"array","items":{"type":"object","additionalProperties":true,"required":["key","srcDeviceKey","dstDeviceKey"]}},"vlans":{"type":"array","items":{"type":"object","additionalProperties":true}},"locations":{"type":"array","items":{"type":"object","additionalProperties":true}},"annotations":{"type":"array","items":{"type":"object","additionalProperties":true}},"layers":{"type":"array","items":{"type":"object","additionalProperties":true}},"backgrounds":{"type":"array","items":{"type":"object","additionalProperties":true}},"symbols":{"type":"array","items":{"type":"object","additionalProperties":true}},"locationFrames":{"type":"array","items":{"type":"object","additionalProperties":true}},"locationDistances":{"type":"array","items":{"type":"object","additionalProperties":true}}}},"DeviceInput":{"type":"object","properties":{"name":{"type":"string","maxLength":120},"type":{"type":"string","description":"DeviceType enum value, or free text such as \"core switch\" which is inferred."},"hostname":{"type":"string"},"make":{"type":"string"},"model":{"type":"string"},"serial":{"type":"string"},"assetTag":{"type":"string"},"description":{"type":"string"},"docUrl":{"type":"string","format":"uri"},"status":{"type":"string","enum":["ACTIVE","PLANNED","DECOMMISSIONED"]},"purdueLevel":{"type":["string","null"],"enum":["L0","L1","L2","L3","DMZ","L4","L5",null]},"ipAddress":{"type":["string","null"],"description":"Primary port IP."},"vlanTag":{"type":["integer","null"],"description":"Must already exist (POST /vlans)."},"locationId":{"type":["string","null"]},"rackUnit":{"type":["integer","null"]},"portCount":{"type":"integer","minimum":1,"maximum":96},"unitCost":{"type":["number","null"]},"complianceTags":{"type":"array","items":{"type":"string"}},"position":{"type":"object","properties":{"viewType":{"$ref":"#/components/schemas/ViewType"},"x":{"type":"number"},"y":{"type":"number"}},"required":["viewType","x","y"]}},"required":["name"]},"Device":{"type":"object","properties":{"id":{"type":"string"},"diagramId":{"type":"string"},"name":{"type":"string","maxLength":120},"type":{"type":"string","description":"DeviceType enum value, or free text such as \"core switch\" which is inferred."},"hostname":{"type":"string"},"make":{"type":"string"},"model":{"type":"string"},"serial":{"type":"string"},"assetTag":{"type":"string"},"description":{"type":"string"},"docUrl":{"type":"string","format":"uri"},"status":{"type":"string","enum":["ACTIVE","PLANNED","DECOMMISSIONED"]},"purdueLevel":{"type":["string","null"],"enum":["L0","L1","L2","L3","DMZ","L4","L5",null]},"ipAddress":{"type":["string","null"],"description":"Primary port IP."},"vlanTag":{"type":["integer","null"],"description":"Must already exist (POST /vlans)."},"locationId":{"type":["string","null"]},"rackUnit":{"type":["integer","null"]},"portCount":{"type":"integer","minimum":1,"maximum":96},"unitCost":{"type":["number","null"]},"complianceTags":{"type":"array","items":{"type":"string"}},"position":{"type":"object","properties":{"viewType":{"$ref":"#/components/schemas/ViewType"},"x":{"type":"number"},"y":{"type":"number"}},"required":["viewType","x","y"]},"positions":{"type":"array","items":{"type":"object","properties":{"viewType":{"$ref":"#/components/schemas/ViewType"},"x":{"type":"number"},"y":{"type":"number"}}}}}},"LinkInput":{"type":"object","required":["srcDeviceId","dstDeviceId"],"properties":{"srcDeviceId":{"type":"string"},"dstDeviceId":{"type":"string"},"linkType":{"type":"string","enum":["CABLE","VLAN_TRUNK","LOGICAL","DATA_FLOW"]},"srcPortLabel":{"type":"string"},"dstPortLabel":{"type":"string"},"metadata":{"$ref":"#/components/schemas/LinkMetadata"}}},"LinkMetadata":{"type":"object","description":"CABLE: cableType (Cat5e, Cat6, Cat6a, Fiber-SM, Fiber-MM, Other), connector (RJ45, LC, SC, Other), lengthMeters, cableNumber, color, strokeWidth, routing. DATA_FLOW: protocol (required), port, direction (UNIDIRECTIONAL, BIDIRECTIONAL), label.","additionalProperties":true},"Link":{"type":"object","properties":{"id":{"type":"string"},"linkType":{"type":"string"},"metadata":{"$ref":"#/components/schemas/LinkMetadata"}}},"LintFinding":{"type":"object","properties":{"ruleId":{"type":"string"},"severity":{"type":"string","enum":["error","warning","info"]},"message":{"type":"string"},"deviceKey":{"type":["string","null"]},"linkKey":{"type":["string","null"]}}},"Version":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["MANUAL","AUTO"]},"label":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"summary":{"type":"object","additionalProperties":{"type":"integer"}}}},"AuditEntry":{"type":"object","properties":{"id":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"actor":{"type":"string"},"action":{"type":"string","example":"device.update"},"entityType":{"type":"string"},"entityId":{"type":["string","null"]},"summary":{"type":"string"},"diff":{},"seq":{"type":"integer"},"prevHash":{"type":["string","null"]},"hash":{"type":["string","null"]}}}}}}