9 min read

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.

ByAndré Ribeiro· Founder, Obelinf
How to Document Power Sources, Panels, Breakers, and Feeds
How to Document Power Sources, Panels, Breakers, and Feeds · October 26, 2026
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.

The six records in a documented power chain, from source to device RECORD TYPES IN THE POWER CHAIN Source utility or UPS Source link upstream path Panel bus and enclosure Breaker position and rating Feed circuit to rack Rack or device Six record types answer six different questions. The source link carries the upstream path, the breaker carries the protective device, and the feed carries the rack assignment. If you can walk this chain in both directions, an outage question becomes a lookup instead of a room visit.

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}'

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.

InputValueWhy it matters
Voltage208 VNominal feed voltage from the panel schedule
Amperage30 ABreaker rating, not the panel main rating
PhaseSingleThree phase multiplies capacity by 1.732
Max utilization80%Continuous load limit, not a suggestion
Calculated capacity4,992 W208 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'
Four completeness checks for a documented power chain, with the field that proves each one WHAT A COMPLETE CHAIN PROVES Question Evidence Field to check What feeds this panel? Upstream source link source_links Which breaker protects this feed? Breaker position and rating breaker_position Which rack does it serve? Rack assignment rack_name Can it carry the load safely? Derated capacity against draw capacity_w / load_w A record that cannot answer all four questions is an inventory entry, not a power path.

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?
You need one record per real asset and one record per electrical path: sources such as utility feeds, UPS units, generators, ATS units, and busways, panels, breakers inside each panel, and power feeds that connect a breaker to a rack or device. If you stop at the rack and never record the panel and breaker behind it, you have a power inventory without a power path.
Should I create the power source or the panel first?
Create the source first, then the panel, then the breaker, then the feed. That order follows the physical path and lets you link each record to the record above it while the details are still in front of you. It also means a panel is never left without an upstream source in the documentation.
Why does a breaker need both a position and a rating?
The position is how a technician finds the breaker on the panel, and it must be unique inside that panel. The rating in amps is the capacity limit that the downstream feed inherits. A breaker record without a position is hard to find in an electrical room, and a record without a rating makes the feed capacity impossible to calculate.
What is the difference between a breaker and a power feed in Obelinf?
A breaker is the protective switch inside a panel. A power feed is the named electrical path from that breaker to a rack or device. The breaker owns the position and rating, while the feed owns the rack assignment, role, phase, voltage, utilization limit, and physical connection. Keeping them separate means one bad breaker record does not silently corrupt every downstream path.
How do I know a power feed record is complete?
A complete feed has a panel, a breaker, a rack or a connected endpoint, a role, a supply type, a phase, a voltage, an amperage, and a utilization limit. If any of those are blank, the record can still be stored, but capacity and redundancy reporting will be weaker. Treat the blanks as a worklist rather than as acceptable defaults.
Can a power feed exist without a breaker?
Yes in the data model, but it should be treated as a documentation gap. A feed without a breaker cannot inherit a rating, cannot show which protective device feeds it, and cannot be traced back to a panel position during an outage. Use an empty breaker field for staged work, then close it before the feed goes live.

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