Docs

API reference

The full route-by-route reference is generated directly from the live gateway — every request/response shape you see there is the real, current contract, not documentation that can drift out of sync with it.

Both links point at the full gateway, which serves every domain listed on/domains — routes are tagged by domain, so filter to a domain (for example overhead) in the interactive docs for just that part of the API.

Quickstart

Every route takes a typed request body and returns a typed, cited result — here's the real request/response shape for one function, /overhead/determine_nesc_grade:

Request
curl -X POST https://vertical-ai-api-593424780294.us-central1.run.app/overhead/determine_nesc_grade \
  -H "Authorization: Bearer vaico_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "inp": {
      "max_supply_voltage_v": 14400,
      "crosses_railroad": true,
      "auto_deenergized_at_crossing": false
    },
    "source_ref": "job-4471"
  }'
Response
{
  "grade": "B",
  "rationale": "Supply >22kV crossing a railroad without automatic de-energization requires Grade B.",
  "rule_refs": ["NESC Rule 242", "NESC Table 242-1"],
  "provenance": {
    "method": "determine_nesc_grade",
    "source_ref": "job-4471",
    "engine_version": "0.8.0",
    "computed_at": "2026-08-24T19:00:00Z",
    "notes": []
  }
}

Authentication

Every request needs your key, either as a query param or a bearer token:

# Authorization header (recommended)
curl -H "Authorization: Bearer vaico_live_..." \
  https://vertical-ai-api-593424780294.us-central1.run.app/overhead/determine_nesc_grade

# or query param
curl "https://vertical-ai-api-593424780294.us-central1.run.app/overhead/determine_nesc_grade?key=vaico_live_..."

Design workflow

The Substation (usm), Transmission Structure (utm) and Generation (ugm) domains have a staged design workflow: routes that start a design, report its status, run one stage, summarize it, propose fixes for failed stages, and record your decision on a proposal. A stage can only run once the stages it depends on exist, and a stage that could not evaluate something says so instead of passing. Every route is a POST.

Call shape

The routes are stateless: nothing is stored on the server. …_design_start takes the design_basis and returns { state, status }. Every later route takes that state back verbatim; the routes that change it return the new state to send next. The loop is:

  1. start with the design basis; you get the state and the status.
  2. run_stage with the state and a stage_id; you get the new state and the status. To change the design basis, re-run design_basis with new_design_basis; every stage that depends on it goes stale.
  3. status or summary with the state; you get a report (per-stage status, stale stages, the next stage that can run; the summary adds open items and the standards cited). Neither changes the state.
  4. propose with the state; you get { proposals, unfixable, dismissed }. Only failed stages get proposals.
  5. decide with the state, a proposal_id and decision of apply or dismiss; you get the new state and status. Dismissing needs a non-empty reason and is remembered in the state. A stale or already-decided proposal, or a stage run out of dependency order, returns 422.

Response bodies are untyped objects in the OpenAPI schema; the shapes above are abridged from the harness code, and the interactive reference shows the request models.

Substation: start, then run one stage (design_basis fields not shown)
curl -X POST https://vertical-ai-api-593424780294.us-central1.run.app/usm/substation_design_start \
  -H "Authorization: Bearer vaico_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "design_basis": { ... } }'
# -> { "state": { ... }, "status": { ... } }

curl -X POST https://vertical-ai-api-593424780294.us-central1.run.app/usm/substation_design_run_stage \
  -H "Authorization: Bearer vaico_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "state": { ... }, "stage_id": "equipment_ratings" }'
# state = the object start returned, sent back unmodified
Transmission: run a stage. Generation: propose, then decide
POST https://vertical-ai-api-593424780294.us-central1.run.app/utm/transmission_design_run_stage
{ "state": { ... }, "stage_id": "sag_tension" }

POST https://vertical-ai-api-593424780294.us-central1.run.app/ugm/generation_design_propose
{ "state": { ... } }

POST https://vertical-ai-api-593424780294.us-central1.run.app/ugm/generation_design_decide
{ "state": { ... }, "proposal_id": "<id from propose>", "decision": "dismiss", "reason": "Deferred to the selection review" }

Routes and stage ids

  • /usm: substation_design_{start,status,run_stage,summary,propose,decide}, plus substation_propose_fix for a single failing check. Stage ids: design_basis, electrical_topology, fault_study, bus_clearances, transformer, lv_fault_study, equipment_ratings.
  • /utm: transmission_design_{start,status,run_stage,summary,propose,decide}. Stage ids: design_basis, conductor_ampacity, sag_tension, structure_span, wire_loads, structure_span_loaded.
  • /ugm: generation_design_{start,status,run_stage,summary,propose,decide}, plus generation_propose_fix for a single failing check. Stage ids: design_basis, generator, gsu, station_service, grid_interface.

Statuses

Each stage record carries one of five statuses: missing (not run), valid, incomplete (ran, but could not evaluate something, and says what), failed or stale (an input or an upstream stage changed since it ran). In the transmission and generation workflows failed is definitional: the result fails the comparison against the inputs you stated, which is not the same as failing the code.

Some stages can never report valid, because part of what they would check is not evaluated: equipment_ratings (usm: asymmetry), sag_tension, structure_span and structure_span_loaded (utm), and station_service and grid_interface (ugm). A fully entered design therefore still reports that not every stage is valid. A stage result is a screening result, not a design approval.

Sibling harnesses and the hand-off

The usm fault_study and lv_fault_study stages call the circuit harness, and the utm sag_tension stage calls the overhead harness. If that sibling is unreachable the stage returns incomplete and records the reason; it never invents a number. The generation design builds a versioned hand-off object (contract version 1) that you can pass to the substation design as design_basis.ugm_handoffs. It is a JSON object you carry between the two designs, not a pipeline. There is no hand-off from the transmission design to the substation design.

Scoping and the SDK

Each route requires its domain’s bare scope (usm, utm or ugm); an unrestricted key reaches all of them. Inthe SDK (v0.14.0) the routes are methods of the same names, each taking one request (a dict or the generated model):

r = client.usm.substation_design_start({"design_basis": {...}})
r = client.usm.substation_design_run_stage({"state": state, "stage_id": "bus_clearances"})
client.utm.transmission_design_propose({"state": state})
client.ugm.generation_design_decide({"state": state, "proposal_id": pid, "decision": "apply"})

See each domain’s research page (Substation,Transmission Structure,Generation) for each stage, what it validates and what it does not. All of it is draft, with AI-assisted review only.

Verified fixes

You do not have to ask for a fix. When a check fails and a verified fix exists, the result itself says so: it carries a fix_offer (the finding, the fix options with their side effects, and a question to put to the user) and aFIX AVAILABLE note. A design status lists failed stages that have fixes under propose_available. Nothing is applied until the user decides. A proposal route returns the full fix. A proposal is not a suggestion: it is the smallest change to an adjustable input that makes the same check or stage pass when it is re-run, and the response records that the re-run happened. Each proposal carries the patch (from, to, unit), the finding it fixes with its citation, andconsequences — a fix for one rule can worsen another, for example a lower conductor tension raises sag. When the answer is a minimum rather than a product (a breaker rating, a transformer size, a pole strength) it says so inneeds_selection.

  • Single checks: /usm/substation_propose_fix, /ugm/generation_propose_fix, /ubm/nec_propose_fix, /ada/prowag_propose_fix, /uvm/propose_underground_fix. Send the check name and the same input you gave the check.
  • Design stages: …_design_propose and …_design_decide under /usm, /utm and /ugm. Applying a proposal changes the design basis and marks dependent stages stale; dismissing needs a reason and is remembered in the state.

A proposal never changes a fact that decides whether a rule applies (is it a dwelling, is the fence metallic), a fixed condition (voltage, altitude, materials) or a measured result. Only failed findings get proposals; an incomplete stage reports what is missing instead.

Scoping

Your key is scoped to exactly the domains (and, for Overhead, jurisdictions) granted to it. A route outside your key's scope returns 403, not a silent partial result.