External API (v1)
Route index for GridWonk partner integrations over /api/v1.
External API (v1)
This page is the endpoint index for the GridWonk partner API.
Base URL
https://gridwonk.com/api/v1Authentication
Most routes require a Bearer token — either an API key or a JWT obtained via OAuth 2.0:
Authorization: Bearer gw_live_... (API key)
Authorization: Bearer eyJhbGci... (JWT from /oauth/token)Legacy gb_live_/gb_test_ keys are no longer accepted. Use a gw_live_... or gw_test_... key.
See Authentication & Rate Limiting for details on both methods.
Auth exceptions: /oauth/token accepts client credentials by body or HTTP Basic auth, bootstrap routes require an approved GridWonk user session, and /api/v1/openapi.json returns the complete discovery document directly to raw API-key and scope-less OAuth callers. The app-host /openapi.json and /.well-known/openapi.json routes would serve the curated partner packet projection, but anonymous publication is off and both return 404. The machine-token issuer advertises client credentials, and its optional resource parameter can bind a JWT to /api/v1/mcp. The separately gated public plugin uses user OAuth and exact-session browser confirmation; its curated tools do not grant general REST access. Machine tokens do not authorize admin MCP. Its separately gated administrator-OAuth lane requires an approved client, exact audience and current administrator authority; implementation does not establish activation. A platform-admin suspension of an organization's API and MCP access, or an account billing suspension, refuses every API-key and MCP request with 403 FORBIDDEN and reason: api_access_suspended or reason: billing_suspended before endpoint and profile checks run.
The project routes use the underlying organization key authority; projects:* scopes are not a
live grant vocabulary.
Request bodies are bounded before route parsing. General JSON requests are limited to 1 MiB and the
OAuth token body to 32 KiB. Oversized requests return 413 PAYLOAD_TOO_LARGE. Document bytes are
never sent as JSON: packet intake issues a signed upload target (files up to 30 MB; formats per
the packets page) and validates the stored object before it is accepted.
The partner packet review and role-decision mutations and project PATCH updates use a stricter
16 KiB JSON cap because their request contracts are small.
The complete authenticated partner OpenAPI document covers every exported /api/v1 HTTP operation except four deliberate
omissions: the two session-only bootstrap routes and the authenticated route that serves the
OpenAPI document itself, plus the hard-disabled Salesforce installed-app endpoint. That separate
certificate-signed contract is not callable using partner API keys or OAuth tokens; it returns
503 {"error":"disabled"} without accepting work. Each omission has an owner, documentation
link, and rationale in the checked registry. CI rejects undocumented live operations, missing
methods, stale omissions, and advertised operations with no route.
A smaller curated contract is built for https://gridwonk.com/openapi.json and
https://gridwonk.com/.well-known/openapi.json, but it is not published — both routes return
404 while PUBLIC_OPENAPI_DISCOVERY is unset. It includes only active partner packet operations
that also have hosted MCP bindings, plus the OAuth token exchange. Every operation has a unique
function-safe operationId, exact partner.read or partner.write security, and a named schema
for every declared status — success and error alike — with no payload left as an open object. Human
role decisions and the broader operator surface remain outside that document.
The two documents differ in wording as well as in coverage. The complete document is written for operators and names internal rollout gates, quota figures, and processing vendors; the curated document's prose is authored separately, and a contract fails the build if any of that vocabulary reaches it. Ask for the complete document when you need those operational details.
Key management responses include role, endpoint restriction, cost limit, expiration, and usage fields. Create/update requests cap rateLimitPerMinute at 1000, and cross-organization key operations are restricted to GridWonk platform management keys.
OAuth token exchange is protected by a shared production rate limiter and does not accept a caller-supplied forwarded IP as its security identity. Use the client ID bucket for predictable automation behavior.
Endpoint Index
| Method | Path | Purpose |
|---|---|---|
| POST | /oauth/token | Exchange API key for a short-lived JWT (OAuth 2.0 client credentials), optionally bound to an MCP resource |
| POST | /utilities/match | Match utility names to EIA-backed utility records |
| GET | /utilities/list | Browse and search utilities with filters |
| POST | /documents/classify | Classify document type from raw markdown |
| POST | /documents/digitize | Synchronous document digitization |
| POST | /documents/validate | Retired tombstone; returns authenticated HTTP 410 |
| GET | /documents/{documentId}/working-draft | Fetch editable working-copy spans (always on — no feature gate) |
| PATCH | /documents/{documentId}/working-draft/spans/{spanId} | Update one working-copy span |
| GET | /applications/query | Query organization-scoped application sessions |
| GET, POST | /projects | List developer projects or create a real customer draft |
| GET, PATCH | /projects/{projectId} | Read or update an organization-owned editable draft |
| POST | /agents/chat | Stream chatbot responses (SSE). Opt in to citation events with includeSources: true |
| POST | /agents/execute | Run supported agents asynchronously |
| POST | /assist | Run enabled one-shot or streaming text assistance with resolved model/provider/usage metadata |
| GET | /jobs | List async jobs |
| POST | /jobs | Create async job |
| GET | /jobs/{jobId} | Fetch one job |
| DELETE | /jobs/{jobId} | Cancel active job |
| GET | /jobs/{jobId}/stream | Stream job progress/completion (SSE) |
| GET | /published-requirements | Query customer-released utility requirements |
| GET | /requirements | Retired. Returns typed HTTP 410 with /published-requirements as the replacement |
| POST | /packets/intake | Start partner-scoped packet intake; see Partner Packets for the full intake, document, role-decision, review, status, and screening surface |
| POST | /packets/{submissionId}/intake-batches | Reserve a declared upload selection; GET .../{batchId} reads it, and nested heartbeat, pair, items/{itemId}/cancel, and abandon routes coordinate its lifecycle |
| GET, POST | /packets/{submissionId}/documents | List packet documents or attach an owner-organization File Library asset |
| DELETE | /packets/{submissionId}/documents/{documentId} | Delete a document only from an editable draft or resubmission working set; excluded from MCP and public OpenAPI |
| POST | /packets/{submissionId}/documents/{documentId}/review | Start or reuse one exact document review; budget exhaustion is 429 RATE_LIMITED with Retry-After |
| POST | /packets/{submissionId}/review | Start or reuse an applicant or eligible utility review through the shared review core; requires partner.write |
| POST | /utility/applications/{submissionId}/freeze | Human-requested freeze of an eligible utility-owned draft |
| POST | /utility/applications/{submissionId}/packages/{packageId}/adjudications | Record a human decision for the exact package, run, finding, and expected version |
| POST | /utility/applications/{submissionId}/screening/complete | Complete screening for the exact latest package; repeated completion is idempotent |
| POST | /utility/applications/{submissionId}/study-requirement | Set or replace a human study requirement for the next submission only |
| GET, POST | /utility/applications/{submissionId}/notices | List application-bound notices or draft from an exact frozen package |
| GET, PATCH | /utility/applications/{submissionId}/notices/{noticeId} | Read safe notice detail or edit allowed draft content |
| POST | /utility/applications/{submissionId}/notices/{noticeId}/{operation} | Named submit, approve, return, revoke, or acknowledge transition; not an arbitrary status write |
| POST | /utility/applications/{submissionId}/notices/{noticeId}/send | Request durable delivery to an on-file applicant/member address; pending work returns 202 |
| POST | /packets/cad-intake | Start private DWG companion intake for an exact current site-plan version; finalize, status, reauthorization, and cancellation use nested intake-ID routes |
| GET | /deficiency-reports | Query scoped findings by findingState (open, resolved, superseded); remediationStatus separately tracks fix progress |
| POST | /remediation/exports | Create clean/redline/evidence remediation bundle |
| GET | /remediation/exports/{exportId} | Poll remediation export status |
| GET | /webhooks | List webhook subscriptions |
| POST | /webhooks | Create webhook subscription |
| GET | /webhooks/{id} | Get one subscription and recent attempts |
| PATCH | /webhooks/{id} | Update subscription |
| DELETE | /webhooks/{id} | Delete subscription |
| GET | /usage | Usage and performance rollups |
| GET | /mcp | Discover the credential-filtered MCP catalog: broad tools for raw/scope-less credentials, or exact-scope packet tools for partner OAuth tokens |
| POST | /mcp | Execute MCP JSON-RPC calls with the same per-tool discovery and authorization policy |
| DELETE | /mcp | Close a stateful MCP session |
| GET | /openapi.json | Return OpenAPI metadata to raw API-key or scope-less OAuth callers |
The MCP discovery GET and the optional event-stream GET are different contracts. A normal JSON
GET returns discovery metadata; a GET advertising text/event-stream (matched case-insensitively)
returns 405, so clients must not open a reconnect loop for a standalone stream.
The four utility human-decision writes require partner.write and current utility writer
authority. They have SDK and CLI bindings but are excluded from MCP and the curated public
OpenAPI document. See Utility Applications for strict request
bodies and lifecycle restrictions.
The separate notice routes implement the package-bound notice workflow. Notice list/detail reads
require partner.read and have REST, SDK, CLI, and read-only MCP bindings. All notice writes
require partner.write and current direct utility writer membership; they are absent from MCP
and the curated public OpenAPI document. JSON write bodies are strict and capped at 32 KiB.
Creation returns 201; ordinary updates/transitions return 200. Send returns 202 for
unfinished pending, retrying, or provider-accepted delivery and 200 for finalized, held, or
canceled delivery; inspect its separate canonical status and delivery fields. Neither a 2xx
response nor provider acceptance proves inbox delivery. These implemented contracts do not
activate the held schema or production release.
The existing webhook subscription routes also accept the five utility.* event families for
receiving-utility organizations. This is an event-contract extension, not another notice mutation
route; schema activation and production release remain held. The signed Resend receipt endpoint
is a provider callback outside /api/v1, not an API-key operation. See
Webhooks API for the utility event contract.
Four Salesforce-specific REST/MCP/SDK operations are implemented but default-disabled; see the connector section below. Existing packet routes do not grant permission to import or overwrite Salesforce-owned evidence. Salesforce acceptance remains separate.
The OpenAPI document includes the complete native-CAD intake family, not only its create route.
Those routes are utility-neutral: availability is controlled by the applicant organization's
server-side cohort, while utility-specific drawing checks require a separately reviewed procedure
profile. The server proves packet write access before revealing cohort or workflow state.
The batch coordinator and applicant-only pairing also have REST, SDK, CLI, and MCP bindings.
They can continue a console-created mixed selection and pair an inspected drawing once its PDF
becomes a current site plan. Standalone partner CAD creation still requires that exact version
up front; the batch bindings do not expose a target-free CAD upload. ZIP creation, status,
finalization, and abandonment use the separate packet archive-intake routes, with document
cancel, reauthorize, and retry-processing under the intake resource. See
ZIP intake and recovery for all seven operations.
Utility-owned batches accept ordinary document uploads, not native-CAD declarations or pairing.
Requirement Reads
GET /published-requirements, SDK queryPublishedRequirements(), CLI gridwonk requirements published, and MCP query_published_requirements share one server reader. It serves every published row except the ones a utility reviewer explicitly rejected; rejected rows are omitted server-side and never appear. Each returned row carries reviewStatus: approved (utility reviewers signed off) or pending (awaiting a current utility decision, including a verdict made stale by a later change). An unknown utility or uncovered category returns an explicit honest state rather than technical rows, legacy rows, or a fuzzy-matched neighbour. The typed releaseStatus (released, partially_released, review_incomplete, not_published) reports utility-review progress and is not a serving gate — a review_incomplete scope still returns its rows. category=fees is always empty. Utility resolution is exact.
GET /requirements is a permanent 410 Gone / ENDPOINT_GONE tombstone with
/published-requirements as the replacement. The old SDK method, CLI aliases, and public MCP tool
have been removed. The internal common-tools tool still uses the short name query_requirements,
but it always reads the published Packet Intake store. See
Retirement Stages.
Async Job Handle Contract
DELETE /api/v1/jobs/{jobId} also settles the linked review for an authorized packet-review
job, preserving completed document findings. Its success response may include runtime and
warning; do not interpret status settlement as an immediate stop of an external provider call.
See Cancel Job for authority and retry boundaries.
Routes that queue long-running work return 202 with:
{
"jobId": "uuid",
"status": "pending",
"pollUrl": "/api/v1/jobs/{jobId}",
"streamUrl": "/api/v1/jobs/{jobId}/stream"
}Quick Start
# Match a utility
curl -X POST https://gridwonk.com/api/v1/utilities/match \
-H "Authorization: Bearer $GRIDBOOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Duke Energy","state":"NC"}'
# Poll a job returned by document upload or a supported job creation request
curl https://gridwonk.com/api/v1/jobs/<jobId> \
-H "Authorization: Bearer $GRIDBOOST_API_KEY"Next References
Salesforce connector operations
The authenticated specification includes four operations under
/api/v1/integrations/salesforce/{connectionId}: application search, mapped-answer/file manifest,
acknowledged idempotent import, and progress. They are implemented but default-disabled, and require
partner scopes or connection-bound REST-audience tokens. Import returns 202; progress is not
report access. See exact inputs and activation gates.