Utility Applications
Screen utility applications, record package-bound decisions, and manage reviewed notices through REST, the SDK, and CLI.
last-updated: "2026-10-27"
Public plugin scope and processing
The public plugin exposes only the utility tools in its curated customer catalog after exact-session workspace confirmation and current direct-member authorization. Its presence does not expose the human decision or notice-write operations documented for existing integrations below; public-plugin users perform those actions in the website.
Trial and prepaid screening uses the reviewing utility's processing allowance and the exact submitted package. Applicant private results do not replace that review or fund it. See processing allowances.
The utility lane uses the same application, package, review, and decision services as the utility console. Your credential selects the organization; requests cannot select another utility or supply an actor, organization, or provenance record.
Screening starts are available to authorized automation, including MCP. Manual freeze, finding adjudication, screening completion, and study requirements remain human decisions. They are available through REST, the SDK, and CLI, but excluded from both hosted and local MCP.
Package versions and migration
The examples on this page target the published, aligned 0.4.0 release of @gridwonk/sdk,
@gridwonk/cli, and @gridwonk/mcp-server. Install the components your integration uses from
GitHub Packages with an account that has package access. Local installs require a classic
personal access token with read:packages; see
GitHub's registry authentication guidance.
See the CLI installation instructions for registry setup.
Check the installed CLI with gridwonk --version; a website deployment does not update local packages.
When moving from 0.3.x, replace legacy base64 uploads (uploadDocument, docs upload, and
upload_document) with storage-native packet intake.
The 0.4.0 release also removes AX optimization and Queue Analytics methods, commands, and
tools. Those removals have no replacement GridWonk operation. Review existing automation before
upgrading; MCP still excludes the human decisions described below.
Access
- An owner or administrator creates a runtime organization key at
/utility/api-keysafter ordinary invite-and-login onboarding. Organization suspension and billing restrictions still apply. - Exchange the key at
POST /api/v1/oauth/tokenfor a short-lived token withpartner.read,partner.write, or both. The scopes are independent: write does not imply read. See authentication. - Reads require current authorized membership. Writes also require a current writer role, the matching utility identity, and an eligible application state. An expired membership, viewer seat, or consultant grant does not confer utility decision authority.
For first-key setup through the CLI, sign in with gridwonk auth login --browser, identify the
organization with gridwonk orgs list, and use auth bootstrap-status --org <id> followed by
auth bootstrap-key --org <id> --name "Initial Management Key". The bootstrap command requires
an explicit --org; switching the stored active organization is insufficient. Bootstrap creates
a management key for key lifecycle operations; use it to provision the
runtime key for application traffic. Key role, partner scopes, and the creator's current
organization role are separate checks.
Keep keys and bearer tokens private. Ordinary packet operations do not create webhook subscriptions; use the management-key lane described in webhooks. Notice REST/SDK/CLI operations and read-only MCP bindings are implemented in the released utility-notice stack. Schema and provider setup were separately activated for this release; each new integration should still verify its own live behavior. The five utility event families use existing webhook subscriptions; see Webhooks API. Notice writes remain human decisions and are excluded from MCP.
Read before deciding
Use GET /api/v1/utility/applications to find applications, then
GET /api/v1/utility/applications/{submissionId} for the selected application.
Its /packages, /packages/{packageId}/findings, and /history reads expose the immutable
package, pinned review and findings, current adjudication versions, and application history.
The application, package, run, and finding identifiers are related identities, not interchangeable
strings. Take them from the same current package read.
When point-of-interconnection review is enabled for the packet owner, the existing authorized packet report may also contain geographic evidence. Coordinate observations and their coverage do not create deficiency findings or approve the package. Human POI decisions use authenticated review actions; this addition does not introduce a REST, SDK, CLI, or MCP mutation endpoint.
Start screening
Use the existing POST /api/v1/packets/{submissionId}/review endpoint with an empty JSON object
for the default start. A direct utility credential selects utility authority. The equivalent
CLI command is gridwonk packets review start --submission <id>; MCP uses
start_packet_review. See packet review for the complete start contract.
Eligible utility-owned packets and developer-submitted packets can be screened. An unsubmitted developer draft cannot. Active, unexpired upload batches block screening until they settle, are abandoned, or expire.
For a formal application in pending, queued, or resubmitted, the queued review and its
move to screening commit together before work is dispatched. This applies to console, REST,
SDK, CLI, and MCP starts. A completed run moves it to screened; a failed start or run restores
the prior status once no other utility review is active. An exact retry reuses the active run.
Re-screening does not reset an existing screened, notice, or complete state. Utility-owned
drafts keep their separate package-freeze transition, and completed automated screening still
requires the human decisions below.
The reviewing utility pays through the shared review budget, including when the applicant owns
the documents. Concurrent or repeated starts of the same eligible work reuse the existing run
and job instead of charging again. Reuse does not require another budget reservation even when
the daily cap has been reached. New work remains subject to the current organization limits;
429 responses include Retry-After. Do not change a budget to make a retry succeed.
Automatic package freeze continues to follow the utility screening policy. A manual freeze is a separate human operation and cannot request the automatic path.
Record human decisions
Every route below uses POST, requires partner.write, and accepts a strict JSON object.
Unknown fields are refused. All paths start with /api/v1/utility/applications/{submissionId}.
| Operation | Path | Body |
|---|---|---|
| Manual freeze | /freeze | {} |
| Adjudicate one finding | /packages/{packageId}/adjudications | runId, findingId, decision, expectedVersion; optional rationale and editAfter |
| Complete screening | /screening/complete | packageId |
| Set or replace a study requirement | /study-requirement | scopeDescription, requirementText; optional caseReference |
Manual freeze
Only a utility-owned draft can be manually frozen. The shared core checks current ownership, visibility, membership, upload completion, and packet readiness under the application lock. An applicant-owned draft or already-submitted application cannot use this operation. The response identifies the frozen package; use that package's reads before making a finding decision.
Adjudication
The package must be the latest package, and its pinned run and finding must match the request.
The decision is accept, dismiss, defer, or edit. Dismiss, defer, and edit require a written
reason. An edit supplies editAfter; the server derives the original values. expectedVersion
is the version you read, or 0 if the finding has no decision. A competing decision returns a
conflict; refresh the package findings before trying again.
The original review is not overwritten. Decisions are recorded in a versioned ledger, including the authenticated actor and the originating surface.
Completion
Completion checks the exact latest package and the current decision state. Repeating a successful completion for that package is idempotent: the response reports that it was already complete, without another transition. A wrong or older package is still refused after completion. Completed screening is not approval to interconnect.
Study requirement
Record a study requirement after automated screening while the human decision round is still
open (screened or notice_draft). Closed screening is refused. The requirement applies to the
next submission only. Setting or replacing it does not alter the existing frozen package,
its evidence pins, or its saved report. A later submission must satisfy the then-current
requirement. The evidence version and its history entry are committed together.
Package-bound notices
Every notice belongs to the application named in its URL. A notice ID from another application
is refused even when both applications belong to the same utility. All paths below begin with
/api/v1/utility/applications/{submissionId}/notices.
| Method | Path | Scope | Strict request body |
|---|---|---|---|
GET | Collection | partner.read | None; optional status, round, query, sort and paging filters |
GET | /{noticeId} | partner.read | None |
POST | Collection | partner.write | packageId from the current immutable package |
PATCH | /{noticeId} | partner.write | One or more of subject, body, deficiencyItems, responseDueAt |
POST | /{noticeId}/submit | partner.write | {}; draft to review |
POST | /{noticeId}/approve | partner.write | {}; review to approved, bound to the exact content revision |
POST | /{noticeId}/return | partner.write | {}; review to draft |
POST | /{noticeId}/revoke | partner.write | {}; approved to review when safe to cancel |
POST | /{noticeId}/send | partner.write | recipientEmail |
POST | /{noticeId}/acknowledge | partner.write | {}; sent to acknowledged |
The optional notice round list filter accepts integers from 1 through 2,147,483,647.
Larger values fail request validation before a database query.
The programmatic lane requires direct, current utility membership. A write scope does not replace a write-capable role, application access, or current state checks. Console consultant grants and applicant acknowledgment remain separate existing permissions; they do not create an applicant or consultant notice API. Source-managed applications do not gain notice-write authority from this interface.
Draft creation derives findings and their provenance from the package. Edits cannot supply a new actor, organization, approval, or adjudication identity. Notice reads include content, revision and package identity, canonical status, and a bounded delivery summary; they do not return contact addresses, internal edit history, actor identities, or provider payloads.
Send and retry behavior
recipientEmail must match the recorded applicant address or an active, unexpired
owner/admin/member address in the applicant organization. The server proves eligibility at
the mutation boundary; it does not publish a contact directory. This restriction applies to
REST, SDK, and CLI. Existing authorized console free-text recipients remain supported.
Send commits an immutable recipient, approved revision, payload and delivery key before any
provider attempt. A pending request returns 202; the canonical notice can still be
approved. Repeating it reuses the same intent. A finalized send returns 200 with
changed: false; an existing held result can also return 200 with its explicit delivery
state, not a sent claim. Held or uncertain delivery is not a new-send invitation. There are at most
eight automatic attempts within 23 hours; a failed queue hint does not erase the committed
request. Provider acceptance, canonical sent, and inbox delivery are different facts.
A successful acknowledgment returns acknowledged; repeating it returns changed: false
without a second history entry or event. Refresh state after a conflict instead of substituting
another notice or resetting a delivery key.
SDK, CLI, and provenance
The SDK methods are freezeUtilityPackage, adjudicateUtilityFinding,
completeUtilityScreening, and setUtilityStudyRequirement. The matching commands are
utility applications freeze, utility adjudicate, utility screening complete, and
utility study-requirement set. See the CLI reference
for flags and examples.
Notice methods are listUtilityNotices, getUtilityNotice, createUtilityNotice,
updateUtilityNotice, transitionUtilityNotice, and sendUtilityNotice.
transitionUtilityNotice selects the named submit, approve, return, revoke, or
acknowledge action; it cannot assign an arbitrary status. CLI commands are
utility notices list/get/create/edit/submit/approve/return/revoke/send/acknowledge.
CLI mutations require confirmation or --yes. --dry-run prints the intended operation without
an HTTP request; it is not proof of authorization or readiness. The normal SDK identifies a REST
origin; the CLI identifies a CLI origin. The server derives actor and credential identity, and
console actions retain their console origin. A client cannot submit its own provenance object.
Refusals and MCP boundary
An unresolved notice delivery also blocks conflicting freeze, finding, screening-completion and study-requirement decisions. Resolve pending, held or accepted-but-unfinalized delivery through the authorized notice workflow; do not reset its key or retry with another notice. The notice interfaces retain this guard and do not grant MCP write permission.
Malformed request bodies return 400; malformed path identifiers and missing or unauthorized
application/package/run/finding identities return 404; stale versions, incompatible states, and unfinished upload
batches return 409. Authentication, scope, request-rate, and shared-budget checks also apply.
No refusal should be worked around by changing production membership, flags, or budget settings.
MCP catalogs omit all four earlier human-decision operations and every notice write.
list_utility_notices and get_utility_notice require partner.read and use the same scoped,
slim notice reads as REST. A direct call to an excluded operation is
refused before its mutation core executes, regardless of partner scope or supported protocol
revision. MCP may start screening and read the resulting package and findings; it cannot make
the utility's decision. These REST-only decisions appear in the authenticated full OpenAPI
document, not the public agent-facing OpenAPI projection.
Corrected applicant packages
An applicant resubmission creates its corrected immutable package and returns the application
to Pending for the same receiving utility. It does not start legacy per-document screening
or assume utility authority. A current authorized utility writer starts the shared packet
review through the endpoint above or Screen Selected in the queue; the shared core selects
utility_rescreen after the earlier utility round. Package-bound decisions and historical
package reads retain their existing authorization and version checks.