How to Track ISP Circuit IDs, Demarcs, and Terminations Across Providers
A working procedure for circuit records: the fields to capture, API calls to write them, the commands that verify a handoff, and the queries that find incomplete circuits before the next outage.

On this page
- At a Glance: Where Circuit Identity Lives
- The fields to capture, and where each one comes from
- Look up the IDs before you write the record
- Record the circuit when the order is placed
- Add the carrier reference the day it is issued
- Attach the terminations when the handoff is made
- Verify the handoff before you call it done
- Find incomplete records before the next outage
- What to have open before you call support
A circuit outage starts with a specific kind of delay. The link is down, the team knows the internal name, and the carrier needs a reference nobody can find quickly. The carrier reference exists on the invoice, the demarc exists on the floor plan, and the port exists on a router, and the outage would be ten minutes shorter if all three were recorded together. That is the entire case for treating a circuit as structured data rather than a line in a spreadsheet.
This is the working version of that idea. It covers the exact fields to capture, the API calls that write them at each stage of an order, the commands that confirm a handoff is healthy before you call it done, and the queries that surface the circuits still missing a reference or a termination. The order of operations matters as much as the fields, because the details are cheapest to record while the install is still fresh.
At a Glance: Where Circuit Identity Lives
| Obelinf | Spreadsheet | Carrier portal only | |
|---|---|---|---|
| Provider circuit ID | Searchable field on the circuit | Free text column, inconsistent | One portal per carrier |
| Order and service reference | Kept in the circuit description | Another column, rarely updated | Order history if findable |
| Demarc and cross connects | Linked to the interfaces they reach | Notes cells that go stale | Usually absent |
| Endpoint equipment | A and Z ends point at real interfaces | Two device name columns | Absent |
| Cross carrier view | One query across every provider | One file, if maintained | One login per provider |
| Change history | Immutable and per field | Manual or none | Carrier side only |
The fields to capture, and where each one comes from
Every value on a circuit record traces back to a person, a contract, or a device, and knowing the source makes the record fill itself in a predictable order. Keep this list as the definition of done for a new circuit.
| Field | API name | Example | Source |
|---|---|---|---|
| Internal name | name |
NYC to DC1 primary | Your team |
| URL slug | slug |
nyc-dc1-primary | Your team |
| Provider | provider_id |
Zayo | Contract |
| Circuit type | type_id |
DIA | Contract |
| Carrier reference | cid |
carrier string, verbatim | Carrier portal or invoice |
| Provisioned rate | bandwidth |
1000 (Mbps) |
Contract |
| A and Z sites | site_a_id, site_b_id |
NYC, DC1 | Design |
| Terminations | interface_a_id, interface_b_id |
Gi0/0/0 on rtr-nyc-01 | Handoff |
| Status | status |
planned, active, decommissioned | Lifecycle |
| Order details | description |
order number, contract ID | Procurement |
The first four are known before the carrier issues anything, which is why the record should exist from the day the order is placed. The last three are only known once the service is live, and those are the ones that get skipped when nobody owns the step.
Look up the IDs before you write the record
The API takes IDs rather than names, so the first step is resolving the provider, type, site, and interface you intend to reference. Save the results in environment variables for the session and keep the commands in a small script so the next circuit takes seconds.
export OBELINF_API_KEY="your_read_write_key"
export OBELINF_ORG="acme-netops"
# Provider and type IDs
curl --fail --silent --show-error -H "Authorization: Bearer ${OBELINF_API_KEY}" \
"https://api.obelinf.com/${OBELINF_ORG}/circuit-providers?q=zayo" \
| jq -r '.circuit_providers[] | [.id, .name] | @tsv'
curl --fail --silent --show-error -H "Authorization: Bearer ${OBELINF_API_KEY}" \
"https://api.obelinf.com/${OBELINF_ORG}/circuit-types?q=dia" \
| jq -r '.circuit_types[] | [.id, .name] | @tsv'
# Sites at each end
curl --fail --silent --show-error -H "Authorization: Bearer ${OBELINF_API_KEY}" \
"https://api.obelinf.com/${OBELINF_ORG}/sites?q=nyc" \
| jq -r '.sites[] | [.id, .name] | @tsv'
The terminations are resolved the same way, and the interface list filters by device so you can find the exact port that the handoff reaches.
curl --fail --silent --show-error -H "Authorization: Bearer ${OBELINF_API_KEY}" \
"https://api.obelinf.com/${OBELINF_ORG}/device-interfaces?device_id=${ROUTER_ID}&limit=200" \
| jq -r '.interfaces[] | [.id, .device_name, .name, (.description // "")] | @tsv'
Copy the interface ID for the port the circuit lands on, not the port you wish it landed on. If the handoff is still a patch panel and no device interface exists yet, leave the termination empty and come back to it, because a placeholder ID is worse than an honest gap.
Record the circuit when the order is placed
Create the record with everything known on day one, status set to planned, and no carrier reference yet. This is the step that most teams skip, and it is the reason circuit IDs end up in email.
cat > circuit.json <<JSON
{
"name": "NYC to DC1 primary",
"slug": "nyc-dc1-primary",
"provider_id": "${PROVIDER_ID}",
"type_id": "${TYPE_ID}",
"site_a_id": "${SITE_A_ID}",
"site_b_id": "${SITE_B_ID}",
"status": "planned",
"bandwidth": 1000,
"description": "Order 88412, 2 year term, A end rtr-nyc-01"
}
JSON
curl --fail --silent --show-error -X POST \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
-H "Content-Type: application/json" \
--data @circuit.json \
"https://api.obelinf.com/${OBELINF_ORG}/circuits" \
| jq '.circuit | {id, name, cid, bandwidth, status}'
Save the returned id as CIRCUIT_ID. From here the record grows by patch as each milestone passes, rather than being created once at the end from memory.
Add the carrier reference the day it is issued
When the carrier confirms the order it issues the circuit ID, the reference that every support call will start with. Store it exactly as written, including punctuation and letter case, because support engineers read it back character by character into a system that will reject a close match.
curl --fail --silent --show-error -X PATCH \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"cid\":\"${CARRIER_CID}\",\"status\":\"active\"}" \
"https://api.obelinf.com/${OBELINF_ORG}/circuits/${CIRCUIT_ID}" \
| jq '.circuit | {name, cid, status, bandwidth}'
If the carrier gives you more than one reference, keep the primary circuit ID in cid and put the order number, the service ID, and the account number in description as labeled text. Two identifiers in one field is the fastest way to lose both.
Attach the terminations when the handoff is made
The terminations are the part of the record that pays off during an incident, because they turn a question about a carrier reference into a query about a cable you can go find. Patch them in as soon as the ports are assigned.
curl --fail --silent --show-error -X PATCH \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"interface_a_id\":\"${IF_A_ID}\",\"interface_b_id\":\"${IF_B_ID}\"}" \
"https://api.obelinf.com/${OBELINF_ORG}/circuits/${CIRCUIT_ID}" \
| jq '.circuit | {name, interface_a_device_name, interface_a_name, interface_b_device_name, interface_b_name}'
The response returns the resolved device and interface names, which is worth reading back to confirm you attached the right end to the right site. A circuit whose A end resolves to a device in the wrong site is a copy and paste error that is trivial to catch here and expensive to catch during a failover.
Verify the handoff before you call it done
The record is not complete until the port is known to be healthy, because a circuit documented as active on a flapping interface is worse than one documented as planned. Read the link state, the error counters, and the optical levels on the terminating device.
show interfaces Gi0/0/0
show interfaces Gi0/0/0 | include error|CRC|drops
show interfaces Gi0/0/0 transceiver
show lldp neighbors GigabitEthernet0/0/0 detail
On Juniper the same checks come from the interface and the optics diagnostics, and on a Linux host from the link statistics and the module DOM data.
show interfaces ge-0/0/0 extensive | match "Input errors|CRC|Link mode"
show interfaces diagnostics optics ge-0/0/0 | match "Laser output|Receiver signal"
ethtool eth0 | grep -E "Speed|Duplex|Link detected"
ethtool -S eth0 | grep -iE "crc|error|drop"
ethtool -m eth0
Three readings decide whether you close the ticket. The link should be up at the speed the contract expects and the interface should be full duplex where the optic supports it. Error counters should be flat across a second reading a few minutes later. The receive optical level should sit inside the range the transceiver publishes, not at either extreme, because a level near the edge is a failure waiting for a temperature change. Write the known good numbers into the circuit description or a note, so the next engineer has a baseline instead of a guess.
Find incomplete records before the next outage
A circuit inventory drifts quietly, and the fix is a short set of queries you run on a schedule. Pull the whole list once and keep the JSON, then filter it locally.
curl --fail --silent --show-error -H "Authorization: Bearer ${OBELINF_API_KEY}" \
"https://api.obelinf.com/${OBELINF_ORG}/circuits?limit=500" > circuits.json
# Active circuits with no carrier reference
jq -r '.circuits[] | select(.status == "active" and .cid == null)
| [.name, .provider_name, .site_a_name, .site_b_name] | @tsv' circuits.json
# Circuits missing a termination at either end
jq -r '.circuits[] | select(.interface_a_id == null or .interface_b_id == null)
| [.name, .status, (.interface_a_name // "A missing"), (.interface_b_name // "Z missing")] | @tsv' circuits.json
# Circuits with no provisioned rate recorded
jq -r '.circuits[] | select(.bandwidth == null) | [.name, .provider_name, .type_name] | @tsv' circuits.json
# A provider with no circuit type suggests a rushed record
jq -r '.circuits[] | select(.provider_id != null and .type_id == null)
| [.name, .provider_name, .cid] | @tsv' circuits.json
Run these quarterly and after any migration. An active circuit with no carrier reference is the highest priority, because that is the record that will slow down a support call. A missing termination means nobody can say which port to check. A blank rate means nobody can answer a capacity question without opening the contract.
What to have open before you call support
Most of the elapsed time in a circuit incident is spent assembling facts that should already be on one screen. Before you dial, have these four things visible, and read the circuit ID off the record rather than from memory.
The habit that keeps all of this honest is unglamorous. Write the carrier reference down exactly as issued at the moment it is issued, point both ends at the ports they touch as soon as those ports are assigned, and run four queries a quarter to find what drifted. Circuits that live in one structured list, with the carrier reference beside the interfaces they feed and edges rendered between multi site networks in the network topology, are the ones that turn the next outage into a ticket instead of a translation exercise.
Frequently Asked Questions
What is an ISP circuit ID?
What is a demarcation point on a WAN circuit?
How do I find the device interface a circuit terminates on?
Should I store the carrier circuit ID exactly as the carrier writes it?
How do I check whether a circuit handoff is healthy?
How do I keep WAN circuit records current across several providers?
Free Tools
Put this into practice with the free calculators, reference tables, and checklists in the Obelinf toolkit.
Stop reaching for a spreadsheet
Obelinf keeps every subnet, device, circuit, and rack in one live source of truth, with audit logs and a topology view. Free for personal use.
Related Articles

Committed Bandwidth vs Port Speed: Sizing and Auditing Circuit Capacity
Where to read committed bandwidth and port speed, how to measure the 95th percentile properly, a worked sizing example, and the API queries that flag capacity mismatches across a circuit inventory.
Read more
Introducing Wireless Links to Obelinf
Obelinf now models point to point wireless links between two wireless interfaces, alongside wireless interface types, access point and station roles, and a native SSID to VLAN link. Document the bridges that were living in a spreadsheet.
Read more
How to Document a Wireless Network: SSIDs and Groups
A practical guide to documenting wireless networks: what to record for every SSID, how to group them by site and purpose, and how to keep the records from drifting.
Read more