How to Document Power Sources, Panels, Breakers, and Feeds
A working procedure for building a power distribution record from source to rack: the order to create each record, the API calls, the fields that matter, and the checks that catch gaps.

On this page
Power documentation usually stops at the rack. The rack has a name, the devices have power draw, and somewhere in a spreadsheet there is a number for the circuit. The part that disappears is the path between the utility feed and the equipment: which panel feeds the rack, which breaker protects the feed, which feed lands on which inlet, and which source sits upstream of the panel. When a breaker trips or a maintenance window closes a panel, that missing path turns a simple question into a walk through an electrical room with a clipboard.
This procedure builds the record from the top down. You will create the site reference, the sources, the panel, the source links, the breakers, and the feeds in the order the power actually flows. Each step uses the Obelinf API so the same commands can become a script, and each step finishes with a check that the record is complete before you move to the next one. The goal is not a perfect single line diagram on day one. The goal is a chain that can answer which breaker feeds this rack and what else is on the same panel.
Start with the site and the naming scheme
The API resolves a site by ID, and every record below carries that ID, so the site is the anchor for the whole chain. Pull the site you intend to document and keep its ID in an environment variable for the rest of the session.
export OBELINF_API_KEY="your_read_write_key"
export OBELINF_ORG="acme-netops"
export API="https://api.obelinf.com/${OBELINF_ORG}"
curl --fail --silent --show-error \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
"${API}/sites?q=nyc" \
| jq -r '.sites[] | [.id, .name, .slug] | @tsv'
Pick a naming scheme before the first write. A useful pattern is site code, panel code, breaker position, and feed role: nyc1-pnl-a3-42-r07-a for the feed, nyc1-pnl-a3 for the panel, and nyc1-ups-a for the source. The exact pattern matters less than keeping it stable across panels. Breaker positions come from the physical panel, so store the label exactly as the electrician wrote it, including any letter suffix.
Create the source before the panel
A source is the utility feed, UPS, generator, ATS, busway, or other supply that sits upstream of a panel. Create the utility feed and the UPS separately even if the utility is the only active input today, because the path will be incomplete if the UPS has no upstream record.
cat > source-utility.json <<JSON
{
"name": "Utility feed A",
"slug": "nyc1-utility-a",
"site_id": "${SITE_ID}",
"type": "utility",
"status": "active",
"rated_capacity_w": 100000
}
JSON
curl --fail --silent --show-error -X POST \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
-H "Content-Type: application/json" \
--data @source-utility.json \
"${API}/power/sources" \
| jq '.power_source | {id, name, type, status, rated_capacity_w}'
Repeat the call for the UPS with "type": "ups" and the name of the unit. The valid source types are utility, ups, generator, ats, busway, and other. The source capacity is optional, but record it when the nameplate or the contract gives you a number, because it becomes the ceiling for every downstream panel and feed.
cat > source-ups.json <<JSON
{
"name": "UPS A",
"slug": "nyc1-ups-a",
"site_id": "${SITE_ID}",
"type": "ups",
"status": "active",
"rated_capacity_w": 20000
}
JSON
curl --fail --silent --show-error -X POST \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
-H "Content-Type: application/json" \
--data @source-ups.json \
"${API}/power/sources" \
| jq '.power_source | {id, name, type, rated_capacity_w}'
Save the returned id values as UTILITY_ID and UPS_ID. Link the utility source to the UPS before moving downstream, so the UPS has a documented upstream path. If the source is planned rather than installed, set status to planned and fill the rest of the record when the unit arrives.
curl --fail --silent --show-error -X POST \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"upstream_source_id\":\"${UTILITY_ID}\",\"downstream_source_id\":\"${UPS_ID}\",\"role\":\"output\",\"priority\":10,\"is_active\":true}" \
"${API}/power/source-links" \
| jq '{id, role, upstream_source_name, downstream_source_name, priority}'
Create the panel and link it to the source
The panel is the point where the record changes from a supply to a distribution board. Create it with the voltage, amperage, phase, and maximum utilization that are printed on the panel or stated in the electrical schedule. The max_utilization value is applied to the capacity calculation, so a 100 amp panel at 80 percent does not advertise the full 100 amps as usable.
cat > panel-a3.json <<JSON
{
"name": "PNL A3",
"slug": "nyc1-pnl-a3",
"site_id": "${SITE_ID}",
"location": "Electrical room, wall A",
"status": "active",
"rated_voltage_v": 208,
"rated_amperage_a": 100,
"phase": "single",
"max_utilization": 80
}
JSON
curl --fail --silent --show-error -X POST \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
-H "Content-Type: application/json" \
--data @panel-a3.json \
"${API}/power/panels" \
| jq '.power_panel | {id, name, rated_voltage_v, rated_amperage_a, phase, max_utilization}'
Save the returned id as PANEL_ID. Now connect the source to the panel with a source link. The upstream side is always a source. The downstream side is either another source or a panel, never both. Use input-a and input-b for the two inputs of a redundant panel, and output for a source that feeds another source.
curl --fail --silent --show-error -X POST \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"upstream_source_id\":\"${UPS_ID}\",\"downstream_panel_id\":\"${PANEL_ID}\",\"role\":\"input-a\",\"priority\":10,\"is_active\":true}" \
"${API}/power/source-links" \
| jq '{id, role, upstream_source_name, downstream_panel_name, priority, is_active}'
The link is directional. The upstream source feeds the downstream panel, and the priority value orders multiple inputs. If you have a second independent UPS, create a second link to the same panel with role set to input-b and a different priority. Do not create both inputs from the same source unless that is the actual design, because the redundancy report will read them as one failure domain.
Add the breakers with the real panel positions
Breakers belong to one panel, and the position must be unique inside that panel. The position is a string, not a number, so values such as 42, 42A, and A-12 are all valid. Record the rating in amps and the number of poles from the panel schedule, then set the initial status to available or reserved until a feed uses it.
curl --fail --silent --show-error -X POST \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"position":"42","rating_a":30,"poles":2,"status":"reserved","description":"Rack R07 primary"}' \
"${API}/power/panels/${PANEL_ID}/breakers" \
| jq '{id, position, rating_a, poles, status, is_used}'
Save the returned id as BREAKER_ID. The valid breaker statuses are available, in-use, reserved, and failed. A feed creation changes the breaker to in-use automatically, which is why the initial value here is only a staging state. If two people are working on the panel, the unique position constraint is what prevents a duplicate record, not a naming convention.
Create the feed and attach it to a rack
A feed is the named circuit from the panel to a rack or device. Create it with the panel, the breaker, and the rack in the same call. The rack must be in the same site as the panel. Resolve the rack ID before the feed write, and save it as RACK_ID.
curl --fail --silent --show-error \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
"${API}/racks?q=R07" \
| jq -r '.racks[] | [.id, .name, .site_id] | @tsv'
If the rack is not known yet, leave rack_id out and attach it later, but do not leave the field blank after the rack is installed.
cat > feed-r07-a.json <<JSON
{
"name": "R07-A",
"power_panel_id": "${PANEL_ID}",
"power_breaker_id": "${BREAKER_ID}",
"rack_id": "${RACK_ID}",
"status": "active",
"role": "primary",
"redundancy_group": "R07",
"supply": "ac",
"phase": "single",
"voltage": 208,
"amperage": 30,
"max_utilization": 80,
"mark_connected": true,
"description": "Rack R07 primary feed from panel A3"
}
JSON
curl --fail --silent --show-error -X POST \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
-H "Content-Type: application/json" \
--data @feed-r07-a.json \
"${API}/power/feeds" \
| jq '.power_feed | {id, name, power_panel_name, breaker_position, rack_name, role, capacity_w, load_w}'
Save the returned id as FEED_ID. The feed inherits voltage from the panel and amperage from the breaker when those fields are omitted, but the explicit values are easier to audit. Feed names must be unique inside a panel, and the API rejects an amperage above the breaker rating. The redundancy_group is free text that pairs the A and B feeds for the same rack, and role records which side of that pair the feed represents. Use primary and redundant, not free text.
The capacity calculation is visible in the response, and it follows the panel utilization limit rather than the raw breaker rating. For a single phase 208 volt feed on a 30 amp breaker at 80 percent, the working number is 4,992 watts. For a three phase feed, the phase factor changes the result, so set phase to three explicitly instead of relying on the default.
| Input | Value | Why it matters |
|---|---|---|
| Voltage | 208 V | Nominal feed voltage from the panel schedule |
| Amperage | 30 A | Breaker rating, not the panel main rating |
| Phase | Single | Three phase multiplies capacity by 1.732 |
| Max utilization | 80% | Continuous load limit, not a suggestion |
| Calculated capacity | 4,992 W | 208 x 30 x 0.8, rounded |
Connect the feed when the device inlet exists
The feed to rack assignment is enough to show capacity, but the device level path needs a cable endpoint. Resolve the device ID, save it as DEVICE_ID, then list the inlets and save the inlet you intend to use as INLET_ID.
curl --fail --silent --show-error \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
"${API}/devices?rack_id=${RACK_ID}&limit=100" \
| jq -r '.devices[] | [.id, .name] | @tsv'
curl --fail --silent --show-error \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
"${API}/power/devices/${DEVICE_ID}/power-inlets" \
| jq -r '.power_inlets[] | [.id, .name, .type, .status] | @tsv'
Now create the connection between the feed and the inlet. The API accepts power_feed and power_inlet as endpoint types, and it rejects a second connection on either side.
curl --fail --silent --show-error -X POST \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"endpoint_a_type\":\"power_feed\",\"endpoint_a_id\":\"${FEED_ID}\",\"endpoint_b_type\":\"power_inlet\",\"endpoint_b_id\":\"${INLET_ID}\",\"cable_type\":\"power\",\"label\":\"R07-A to web-prod-01 PSU A\",\"status\":\"connected\"}" \
"${API}/power/connections" \
| jq '{cable_id, endpoint_a, endpoint_b}'
Now the feed has a physical endpoint and the device power summary can calculate the downstream load. If the device has two inlets, connect the A feed to inlet A and the B feed to inlet B. If both cords land on the same feed or the same panel, the connection record will show it, and the redundancy check will have something real to test.
Verify the chain in one read
The panel detail endpoint is the fastest completeness check because it returns the panel, its breakers, its feeds, and the source links that feed it. Read it after every panel is built, not only when something breaks.
curl --fail --silent --show-error \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
"${API}/power/panels/${PANEL_ID}" \
| jq '{
panel: .power_panel | {name, capacity_w, load_w, utilization_pct},
breakers: [.breakers[] | {position, rating_a, status, is_used, feed_name}],
feeds: [.feeds[] | {name, breaker_position, rack_name, role, capacity_w, load_w}],
sources: [.source_links[] | {upstream_source_name, role, is_active, priority}]
}'
A clean result has a source link, at least one breaker, at least one feed, and no feed without a breaker. The check below turns the gaps into a worklist across the site.
curl --fail --silent --show-error \
-H "Authorization: Bearer ${OBELINF_API_KEY}" \
"${API}/power/feeds?site_id=${SITE_ID}&all=true" \
| jq -r '.power_feeds[]
| select(.power_breaker_id == null or .capacity_w == null)
| [.name, .power_panel_name, (.breaker_position // "NO BREAKER"), (.capacity_w // "NO CAPACITY")]
| @tsv'
Keep the chain current
Power records go stale in the same places every time: a breaker is replaced but the rating stays, a feed is moved to another rack, a panel is retired while its feeds remain active, or a new UPS is installed without a source link. Put the completeness query in the change process for every new rack and every panel modification, and review it quarterly with the same discipline you apply to IP and device records.
The review does not need to start with the whole site. Pick one panel, check its source link, list its breakers, confirm each active breaker has a feed and each active feed has a rack, then fix the blanks. One panel completed properly is more useful than a site full of half filled rows, because the next panel has a pattern to copy.
Obelinf keeps these records in the same API used above, so the commands can become the documentation process instead of a separate audit. Start with the panel that caused the last unexpected outage, and rebuild that chain first.
Frequently Asked Questions
What records do you need to document a power distribution chain?
Should I create the power source or the panel first?
Why does a breaker need both a position and a rating?
What is the difference between a breaker and a power feed in Obelinf?
How do I know a power feed record is complete?
Can a power feed exist without a breaker?
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

How to Draw a Power Topology Diagram from Utility to Server
Build a power topology diagram that stays readable: the node and edge schema, a TSV worklist, validation checks, and a Graphviz script that renders the same graph every time.
Read more
What Is a Power Feed? Panels, Breakers, and Rack Power Explained
A plain explanation of power feeds, panels, breakers, circuits, and PDUs, with the fields to record, the capacity math, and a checklist you can use at the rack.
Read more
Common Mistakes When Documenting Data Centers
Data center documentation fails for predictable reasons. Here are the most common mistakes teams make and how to avoid them.
Read more