Docs
API Reference

Projects API

List, read, create, and update developer projects.

capacityMw remains MW on the API. The approval-gated precision migration widens storage to six decimal places, preserving 11.4 kW as 0.0114 MW. Extraction reads the utility's registered field mapping and keeps AC and DC capacity separate; existing values are not silently corrected.

Projects API

The Projects API manages the same developer project records shown in the GridWonk console. Every read and write is limited to the developer organization that owns the API key. Utility and platform organizations cannot use these customer endpoints.

Authentication uses the authority of the organization API key or its short-lived legacy-audience JWT. Fine-grained projects:* OAuth grants are not advertised or enforced yet.

Use packet intake to add documents after creating a project. Submission and resubmission remain console workflows while their full package-integrity transaction is extracted for headless use; the API does not bypass that safety boundary.

You can create a private project by default and review its packet for a utility with a released, complete packet setup, even if that utility has not joined the platform. Creating or reviewing a project does not send the packet to the utility. Formal submission is available only after GridWonk and the utility have accepted submissions for the selected state and program and an active utility reviewer is available. Private Review remains available after that activation; there is no automatic submission. Explicit Submit shares the frozen documents and the one packet report pinned to the package, not other unpinned private reviews or private document-review history. Project creation does not require a receiving utility organization or an environment flag.

Project create JSON bodies use the general 1 MiB API cap. Project PATCH bodies use a stricter 16 KiB cap because updates contain only a few fields. A malformed or oversized update is rejected before any project lookup or write occurs.

List projects

GET /api/v1/projects

Optional query parameters: utilityName, state, limit (1–100), and offset.

curl "https://gridwonk.com/api/v1/projects?state=TN&limit=20" \
  -H "Authorization: Bearer $GRIDBOOST_API_KEY"

Get a project

GET /api/v1/projects/{projectId}

An unknown project, a project in another organization, and an archived synthetic demo project all return 404.

Create a project

POST /api/v1/projects

{
  "utilityName": "nashville-electric-service",
  "projectName": "River Solar",
  "capacityMw": 12.5,
  "state": "TN",
  "interconnectionLevel": "distribution"
}

Creation requires the exact canonical utility record and an available packet-review lane for the requested state and connection type. It does not require a receiving utility organization. A missing utility returns 404; demo project markers and synthetic applicant organizations return 403. Missing state or an unavailable review lane returns 400 INVALID_INPUT. Creation stores the utility's canonical EIA identifier so readiness and automatic-review workflows use the same utility identity as the console. Formal submission separately checks the receiving utility's acceptance and reviewer setup.

Program declaration

capacityMw remains megawatts on the API; no API unit selector is introduced. Console input may use kW and converts before calling the server. Database precision is six decimal places after the approved precision migration, preserving 11.4 kW as 0.0114 MW. AC and DC application ratings remain distinct; a mismatch is surfaced rather than silently overwriting the stored project capacity.

Some utilities publish more than one interconnection program for the same track — for example Maryland Level 2, Level 3, and Level 4 for distribution. The console's project dialog asks for the program in that case, and the API enforces the same rule through the optional declaredTierSlug field:

  • The utility publishes two or more programs for interconnectionLevel: declaredTierSlug is required and must be the slug of one of them.
  • The utility publishes zero or one program: declaredTierSlug must be omitted.

A missing, unpublished, or unexpected declaredTierSlug returns 400 INVALID_INPUT. The message lists the valid programs as slug (label), and error.details.programs carries the same list as { slug, label } objects, so a client can discover the programs from the refusal and retry. There is no separate list-programs endpoint yet; this payload is the discovery mechanism.

{
  "error": {
    "code": "INVALID_INPUT",
    "message": "This utility publishes 3 interconnection programs for the distribution track; declaredTierSlug is required. Valid programs: maryland-level-2 (Maryland Level 2), maryland-level-3 (Maryland Level 3), maryland-level-4 (Maryland Level 4).",
    "details": {
      "programs": [
        { "slug": "maryland-level-2", "label": "Maryland Level 2" },
        { "slug": "maryland-level-3", "label": "Maryland Level 3" },
        { "slug": "maryland-level-4", "label": "Maryland Level 4" }
      ]
    }
  },
  "requestId": "req_a1b2c3d4e5f6g7h8"
}

Resend with the chosen program:

{
  "utilityName": "delmarva-power",
  "projectName": "Asilomar II",
  "capacityMw": 0.25,
  "state": "MD",
  "interconnectionLevel": "distribution",
  "declaredTierSlug": "maryland-level-2"
}

The accepted program is stored on the project, returned as declaredTierSlug on every project read (null for an undeclared project), and selects the rulebook the review runs against. A stored declaration that cannot be read returns 409 rather than reporting the project as undeclared. It cannot be changed through PATCH. If the utility's published programs cannot be read, or the publication is misconfigured, the API returns 503 SERVICE_UNAVAILABLE and creates nothing — a project is never created without the declaration its utility requires. error.reason says which case it is: program_lookup_failed is transient and carries retryAfter plus a Retry-After header; program_publication_invalid means the utility's publication needs correction and retrying will not help. The SDK exposes both as reason and retryAfter on the thrown error, and the CLI includes them in --json output.

Update a project

PATCH /api/v1/projects/{projectId}

You may change projectName, capacityMw, state, or interconnectionLevel while the project is an editable draft. After authorization, a project that is no longer an editable draft returns 409 before checking the proposed field changes. The utility and the declared program cannot be changed, and a track change has to leave the project in a state creation would have accepted: moving a project that declared a program to another track returns 409 INVALID_STATE, and moving an undeclared project onto a track where the utility publishes two or more programs returns 400 INVALID_INPUT with the valid programs in error.details.programs — create a new project with declaredTierSlug instead. A state or track change must also land on a released packet-review lane within the utility's service states, as creation requires; otherwise it returns 400 INVALID_INPUT. A draft created before state was required can still change only its track under the original program rule; add state before submitting. The update and stage check happen in one database statement, so a concurrent submission cannot be overwritten by a stale edit.

SDK and CLI

const created = await client.createProject({
  utilityName: 'nashville-electric-service',
  projectName: 'River Solar',
  capacityMw: 12.5,
  state: 'TN',
  interconnectionLevel: 'distribution',
  // declaredTierSlug: 'maryland-level-2', // only when the utility publishes 2+ programs
});

When the API refuses an undeclared or mismatched program, the SDK throws a ValidationError whose details is a ProjectProgramDeclarationDetails — programs lists the valid { slug, label } options. Every SDK error also exposes reason and retryAfter, so a 503 can be told apart as program_lookup_failed (wait retryAfter seconds, then retry) or program_publication_invalid (do not retry) without parsing the message.

gridwonk projects list --state TN --json
gridwonk projects create \
  --utility nashville-electric-service \
  --name "River Solar" \
  --capacity-mw 12.5 \
  --state TN \
  --interconnection-level distribution \
  --yes
# Multi-program utilities: add --declared-tier-slug <slug>. A refusal lists the
# valid slugs, and --json output includes them under error.details.programs.

On this page