Partner Packets
Partner-scoped REST and hosted MCP access to active Storage-native packet intake, documents, review, status, and screening.
Restricted test credentials
A temporary application-scoped test credential can further restrict the operations below.
Its allowed application IDs and expiry are checked on every request, including requests
using an existing bearer token or MCP session. A partner.write scope does not override
those restrictions. Revocation blocks new token exchanges and subsequent API requests.
An already issued storage upload link has its own expiry; it only writes its reserved
object and cannot read or overwrite files. Ordinary partner credentials and endpoint
contracts are unchanged.
Trial and prepaid intake
For trial and prepaid workspaces, supported uploads require a current processing allowance before an upload authorization or background processing starts. The trial source allowance includes the ZIP container and each expanded source entry; resuming that same entry does not count it twice. Native DWG processing is unavailable in this rollout, including DWG entries inside archives. A format listed for an existing integration does not override this workspace restriction. See processing allowances and recovery.
Workspace format restrictions are enforced before upload authorization and File Library attachment. If a workspace is limited to PDF review, only standalone PDFs are supported; images, ZIP containers, and native CAD files are refused. Review starts recheck stored packet sources, so an earlier upload or a different client cannot widen eligibility. These restrictions do not waive utility evidence requirements or change the endpoints, credential scopes, or request schemas below.
Partner review starts reserve against the reviewing organization's shared review budget. Utility screening charges the reviewing utility, including when it screens a developer-submitted packet.
Console partial reports are read views over current document checks, not completed packet-run resources. The partner review endpoint still returns real run records; partial results do not satisfy submission eligibility. Required CAD is resolved from the published utility/process policy, not a global capacity threshold.
The partner packet lane exposes the production packet-intake and review
capabilities under /api/v1/packets/*. It is a binding of the existing
console services — the same cores, cohorts, authorization predicates, and
shared role-decision writer — never a second processing or authorization
system.
For resumable intake, use the server-returned uploadAuth.endpoint exactly: signed uploads
use /storage/v1/upload/resumable/sign with the token in x-signature, not the ordinary
bearer-authenticated resumable route. This shared transport also serves CAD and ZIP reservations;
their authorization, size limits and finalize contracts remain distinct and unchanged.
The outbound-only Salesforce installed application uses those same intake and acceptance cores
through a separate certificate-signed API. Its durable receipt pins the exact field values,
program mapping, file version IDs, sizes and checksums selected in Salesforce. That private API is
not part of /api/v1/packets/*, partner OAuth, the SDK, CLI, or MCP, and its processing gate remains
off until a later activation approval.
For an applicant packet, create or locate the owning developer record through the Projects API before starting intake. Utility-owned drafts use the utility creation routes below. Developer project submission and resubmission remain console-only safety transactions; packet intake does not bypass them.
Packet JSON requests use the same bounded parsing and generic error contract as the other API v1 routes. The server rejects oversized or malformed input before packet state, document content, or review work is loaded.
The review-start and human role-decision mutations use a 16 KiB JSON body cap. A body over that
route-specific limit receives 413 PAYLOAD_TOO_LARGE before authorization-dependent write work.
A review-start request may omit its body when no optional review fields are supplied.
Authentication: partner-scoped tokens only
The console's Cancel Packet Review control is a session-authenticated action with exact review-lane authorization, not a new partner packet endpoint. Existing partner scopes, endpoint paths and start/read contracts below are unchanged. Ordinary job cancellation retains its own job-organization scope; it is not an alternative grant of partner packet access.
Every packet REST endpoint and hosted MCP packet tool requires an access token
minted with an explicit partner scope (see
Authentication → Partner Scopes). Raw API keys
and scope-less tokens receive 403 insufficient_scope on packet REST routes
and cannot discover or call packet MCP tools. Partner-scoped tokens are refused
on ordinary non-packet endpoints (partner_token_confined) and capped at one
hour. The MCP gateway accepts them only for the packet tools granted by the
token's exact scope. A platform-admin suspension of the organization's API and MCP
access, or an account billing suspension, refuses packet REST routes and MCP packet
tools before the scope check with 403 FORBIDDEN and reason: api_access_suspended
or reason: billing_suspended.
curl -X POST https://gridwonk.com/api/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_secret=$GRIDWONK_API_KEY" \
--data-urlencode "resource=https://gridwonk.com/api/v1/mcp" \
--data-urlencode "scope=partner.read partner.write"The resource parameter is required only when the caller wants an MCP-bound audience. Omit it for packet REST calls, which continue to use the legacy API audience.
On every request the acting user's active organization membership is
re-verified, and access is confined to the key organization's own reach:
its applicant projects, its utility submissions, or submissions covered by an
active organization-access grant. For a delegated MCP session, the delegated
user—not the API-key owner—governs membership and private-document visibility.
Every refusal — absence, denial, off-cohort — is the same 404.
Endpoints
The mixed-upload batch coordinator is available to partner clients under a submission. It reserves one immutable ordered selection without replacing the document, CAD, or archive intake identities. The existing session-authenticated console route uses the same service. Utility credentials can read and mutate only utility-owned batch manifests, not applicant-owned manifests. Utility writes require the utility application's write-membership checks; applicant callers retain their own membership or applicant-issued grant checks. A grant from the reviewing utility is insufficient.
An unfinished, unexpired upload batch blocks both automatic and manual full-packet review.
Manual REST, SDK, CLI, and MCP starts return 409 CONFLICT until the batch finishes, is canceled
or abandoned, or naturally expires. Individual document reviews remain available. Canceling a
batch does not remove accepted documents or waive any other packet-readiness requirement. The
manual start checks before budget/job work and again under the packet lock before creating its
review run; if a new batch wins that race, no review workflow starts and reserved spend is released.
| Method + Path | Scope | Purpose |
|---|---|---|
POST /api/v1/packets/intake | partner.write | Create a Storage-native intake; returns server-selected upload authorization (signed upload ≤6MB, resumable TUS above). Retries with the same idempotencyKey deduplicate. A batch item supplies both batchId and batchItemId; supplying only one is refused, and a batch-bound retry deduplicates on the item plus its declaration rather than on idempotencyKey. |
POST /api/v1/packets/intake/{intakeId}/finalize | partner.write | Prove the uploaded object, enter processing, start the durable pipeline. Idempotent. |
GET /api/v1/packets/intake/{intakeId} | partner.read | Safe acceptance / sanitization / OCR / searchable-PDF status projection, including nullable batchId and batchItemId. |
POST /api/v1/packets/{submissionId}/intake-batches | partner.write | Reserve one ordered manifest of 1–12 loose files, or one ZIP placeholder. An identical idempotencyKey replay returns the original batch with 200; a new reservation returns 201. |
GET /api/v1/packets/{submissionId}/intake-batches/{batchId} | partner.read | Read batch and item status after proving the exact packet and owner organization. |
POST /api/v1/packets/{submissionId}/intake-batches/{batchId}/heartbeat | partner.write | Extend an active batch's idle deadline without exceeding its fixed 24-hour lifetime. |
POST /api/v1/packets/{submissionId}/intake-batches/{batchId}/pair | partner.write | Applicant-only: pair one inspected DWG item to an exact current site-plan version, or request the server's unambiguous match. |
POST /api/v1/packets/{submissionId}/intake-batches/{batchId}/items/{itemId}/cancel | partner.write | Cancel one not-yet-uploading item (reserved, registering, or rate_limited). |
POST /api/v1/packets/{submissionId}/intake-batches/{batchId}/abandon | partner.write | Abandon unfinished items and settle the batch. |
GET /api/v1/packets/{submissionId}/documents | partner.read | Document list with current roles and pinned classifier lineage. Two lanes: the applicant organization (and applicant-issued grants) under per-document visibility; a utility organization runs the utility lane's ladder (cohort, utility identity, formally submitted or utility-owned draft — never a developer draft) and then sees every linked document. Utility-issued grants stay console-only. |
POST /api/v1/packets/{submissionId}/documents | partner.write | Attach an owner-organization File Library asset. Returns 201 when created or 200 when the exact attachment already exists; only PDF, PNG, and JPEG assets are accepted. |
DELETE /api/v1/packets/{submissionId}/documents/{documentId} | partner.write | Permanently delete a document only while every linked packet is a draft or resubmission under development. Submitted history, package pins, foreign ownership, and mismatched IDs are refused. This destructive operation is not available through MCP. |
POST /api/v1/packets/{submissionId}/documents/{documentId}/review | partner.write | Start or reuse review for the exact packet/document pair. Optional { "retryFailed": true } is available on REST, SDK, and CLI. Returns 429 with Retry-After when the request limit or the paying organization's review budget is exhausted. |
GET /api/v1/packets/documents/{documentId}/pdf | partner.read | Preview or download the accepted sanitized rendition: a 302 to a signed URL valid for at most five minutes, never the original upload. Requires exact submissionId + versionId (+ packageId for utility package context); 202 with Retry-After while the rendition is preparing, 409 on a package pin integrity conflict. |
GET /api/v1/packets/documents/{documentId}/text | partner.read | Sanitized OCR text + document-coordinates-v1 locations. Requires exact submissionId + versionId (+ packageId for utility package context). |
POST /api/v1/packets/documents/{documentId}/role | partner.write | Confirm or correct a document content role. This route always records a human decision; when it supersedes an automatic assignment, the human role remains authoritative and the analysis applicable to the corrected type runs again. A stale suggestion or concurrent update returns 409 CONFLICT — refresh and retry. A linked document with no accepted sanitized version returns 422 UNPROCESSABLE — re-upload the document first; retrying will not help. |
POST /api/v1/packets/{submissionId}/review | partner.write | Start an applicant or utility packet review (an active automatic review is reused, never double-billed; 50 starts/hour per user+organization). Utility calls also require the utility application lane and current write membership. |
Each declared item keeps its own intake identity. For a document item, pass the returned batchId
and itemId as batchId and batchItemId when creating the single-file intake, then upload and
finalize normally. The server verifies the batch, item, submission, owner, actor, file declaration,
state, and expiry under the packet lock. The pair cannot be used to move an existing intake to a
different batch. Repeating the same batch or item request does not create a second intake or charge
quota again.
Creating a new document link through intake or File Library attachment recounts the packet's active documents in the same transaction. A failed transaction rolls back both the link and the count; replaying an existing intake or attachment does not add another link or increment the count.
An exact attachment retry also reuses a document retained in that packet's version history.
It returns that document's version identity with reused: true and viewable: false when the
version is no longer current. The retry does not restore the old version, promote a replacement,
or create another attachment or audit record.
While the upload attempt is active, retrying creation returns the original intake with fresh
upload authorization. Once processing has begun or the attempt is terminal, creation can return
409; poll that intake instead of generating a new item. Batch declarations are immutable.
Native-CAD declarations and pairing on utility-owned packets are excluded and return 404.
Pairing an applicant-owned item may return 200 needs_selection with authorized candidates;
retry with one exact version ID. A stale target returns 409. These routes can continue an
existing console mixed selection but do not add target-free CAD creation. ZIP creation uses the
separate archive protocol below.
Creation records preserve authenticated provenance — who acted and through which interface. Later human mutations add audit records in the same transaction as the state change; they do not overwrite the origin. No-change retries add no second mutation record. These records never accept actor or organization IDs from request bodies and are not part of public status payloads.
When batch cancellation or abandonment starts an automatic packet review, the job retains that
request's authenticated user, credential, interface and correlation ID. Background item completion
and batch expiry use the batch's validated creation record instead. Automatic freeze adds the
executing job ID to that record. Missing or invalid legacy records stay explicitly unknown;
they are not reconstructed from a different caller. No request or response fields change.
An unfinished batch blocks automatic packet review and package freeze. Completing every item, cancelling unfinished items, or abandoning the batch removes only that batch's block; all other readiness checks still apply. A heartbeat extends the two-hour idle deadline, capped at 24 hours from reservation. File limits remain 30 MiB per item, 120 MiB per batch, and 12 items.
When the applicant packet-review readiness check refuses an incomplete packet, REST returns
400 INVALID_INPUT with an instruction to complete the packet requirements. Hosted MCP returns
the same INVALID_INPUT outcome. This expected refusal starts no review and is not a server error.
The utility lane also returns INVALID_INPUT when an uploaded document has not finished
processing or role classification; finish those steps before requesting review again.
A human-confirmed PDF split also pauses new document/packet reviews and submission while it is
pending or failed. Resolve it in the console with Retry split or Keep original; review
starts return the existing INVALID_INPUT outcome. More actions → Split PDF is console-only,
including for assigned or previously reviewed PDFs; no REST, SDK, CLI, or MCP split operation is
introduced. Successful children need their own reviews; retained parent findings are historical.
Attaching a document also fires an automatic packet-review check in the background. That check
is best-effort by design and never affects the attach response — but it is no longer silent when
its own infrastructure is broken: a failed review reservation (an unapplied migration, a dead
connection) is logged at error level with its SQLSTATE rather than read as "nothing to do". The
hourly reconciliation sweep remains the durable backstop either way. The check adds no work to
a healthy attach: the reporting path is loaded only when there is an error to report.
| GET /api/v1/packets/{submissionId}/review/{runId} | partner.read | Review run detail with the cited deficiency report. |
| GET /api/v1/packets/{submissionId}/status | partner.read | Canonical workflow status (never implies utility approval) + immutable submitted-package list. |
| GET /api/v1/packets/{submissionId}/screening | partner.read | Utility-organization-only package-bound screening status. This GET is read-only; adjudication uses the separate utility decision endpoints, not MCP. |
ZIP intake and recovery
ZIP uploads use a separate reservation, not the single-file intake endpoint (which refuses ZIP).
The packet owner is the applicant organization when present, otherwise the utility organization.
Utility credentials cannot change a developer-owned packet, even when their creator also belongs
to the developer. Every operation checks the current actor and owner; unavailable or foreign
resources return the same 404.
| Operation | Route | Scope |
|---|---|---|
| Create | POST /api/v1/packets/{submissionId}/archive-intake | partner.write |
| Status | GET /api/v1/packets/{submissionId}/archive-intake/{archiveId} | partner.read |
| Finalize or resume processing | POST /api/v1/packets/{submissionId}/archive-intake/{archiveId}/finalize | partner.write |
| Abandon an incomplete upload | POST /api/v1/packets/{submissionId}/archive-intake/{archiveId}/abandon | partner.write |
| Cancel a document intake | POST /api/v1/packets/intake/{intakeId}/cancel | partner.write |
| Restart a document upload from byte zero | POST /api/v1/packets/intake/{intakeId}/reauthorize | partner.write |
| Retry failed document processing | POST /api/v1/packets/intake/{intakeId}/retry-processing | partner.write |
Create accepts declaredFileName (ending in .zip) and integer declaredSizeBytes.
Supply idempotencyKey, or both batchId and batchItemId from an archive batch reservation.
The response contains archiveId, uploadAuth, and deduped; new reservations return 201,
identical retries while uploading return 200. Changed declarations conflict. Upload bytes using
the returned authorization, then finalize the archive. Never send a chosen storage path.
The limits are 30 MiB compressed, 12 supported files, 30 MiB per file, 120 MiB expanded, and a maximum compression ratio of 100. Nested archives, unsafe paths, encrypted entries, and unsupported files are rejected. Utility ZIPs accept PDF, PNG and JPEG, not native CAD. Applicant-owned batch-linked ZIPs retain the existing DWG rules and pairing requirements.
Status returns archive progress and safe entry states. If processing fails or finalize returns
503 WORKFLOW_START_FAILED, retry finalize with the same archive ID. Accepted children
retain their identities. A live run is not restarted; a processing row untouched for over
15 minutes can claim a restart. Concurrent child handoffs reconcile the same authorized child;
an accepted document whose error-free initial processing was interrupted resumes without consuming a user
recovery cycle. Completed processing is not repeated. Handoff retries quota pressure at most five times, one minute
apart. Abandon applies only while uploading, returns status: abandoned, and stores
rejected with upload_abandoned; cleanup waits for outstanding upload authorization to expire.
Individual recovery is separate: cancel refuses accepted documents; reauthorize supersedes the
old attempt and returns a new upload authorization for the same intake, starting from byte zero.
Both remain creator-only and require current owner write access. Processing retry requires an
accepted document with an internal processing failure, no valid current artifact, and owner write
access. It permits three user recovery cycles. A startup failure restores the previous counter;
replaying a fresh queued or running reservation does not start another workflow or consume another
cycle. An inactive reservation may be reclaimed after 15 minutes in the same cycle, without another
retry audit or upload quota reservation. Successful processing records completion and keeps the same
accepted identities. State refusals, including retries after a valid current artifact exists, return 409.
Document recovery does not handle native CAD.
Upload observations and safe recovery
The document-list response separately adds optional ocrState for the authorized current
document version: not_enqueued, queued, running, using_fallback, ready, retryable, or
terminally_failed. It is independent of reviewStatus, legacy digitizationStatus, and
reviewArtifactReady. Omission means OCR status is unavailable, not that OCR failed or completed.
A failed text-recognition sidecar does not turn a completed review into a failed review.
Document intake status may include optional uploadState: pending, uploading, failed,
expired, or complete. Keep it separate from acceptance, sanitization, OCR, and review.
A browser-reported transfer failure is an observation, not proof that the stored file is invalid.
Server-verified bytes take precedence: a delayed failure report cannot downgrade an upload that
has already advanced to processing or acceptance. Older responses may omit this field.
For an interrupted transfer, use the existing reauthorize operation on the same intake. It
creates a new attempt and storage path, starts from byte zero, and preserves previous attempts
as history. It does not overwrite an accepted document. Current creator/owner authorization and
editable-packet checks still apply. If expiry cleanup already released the previous attempt's
reservation, a new attempt must reacquire quota and can return 429 RATE_LIMITED; otherwise the
live reservation remains in force. A reported failure alone never frees quota.
The original creator can also cancel a pending intake after a reported transfer failure,
with current owner write access. Cancellation schedules its pending object for cleanup and
records one cancellation audit; repeating it is a no-op. A batch item already settled as
failed / upload_failed retains that terminal history instead of being reopened or rewritten.
Accepted source documents cannot be cancelled.
Finalization verifies the exact uploaded object and declared byte length before changing state.
The matching attempt and intake advance together with an eligible batch item in one transaction.
A concurrent retry that replaces that attempt returns 409 CONFLICT: refresh the intake status
before deciding whether to retry. Successful or cancelled batch-item history is not reopened.
A failed loose-file item reopens with its own upload or processing retry. Its batch reopens only
within the batch's fixed lifetime; neither recovery extends that lifetime. An expired or abandoned
batch stays closed history while its file finishes, so reporting a transfer failure never makes a
file less retryable than an unreported interruption. Finalization also completes an older attempt
already marked uploaded whose intake was never advanced, after the same verification.
The browser's failure-report callback is session-only. There is no corresponding partner REST, SDK, CLI, or MCP report-failure operation; integrations use the existing status and recovery calls.
Archive creation provenance is immutable and is carried to child intakes. Subsequent human archive and recovery changes record their own authenticated provenance in the same transaction. Feature enablement, upload quotas and all other readiness checks still apply.
Utility lane reads
A utility organization's partner key (org type utility, inside the UTILITY_APPLICATIONS_V2
cohort) also reads its own Applications workspace under /api/v1/utility/applications. The
organization and its utility identity come from the key's own organization row; no request value
can select another organization, and every refusal is the same 404.
| Method + Path | Scope | Purpose |
|---|---|---|
GET /api/v1/utility/applications | partner.read | The Applications queue: formally submitted applications pinned to the key organization (add includeDrafts=true for utility-owned drafts), each with its canonical workflow status. Filters query, screeningStatus, generationType, minCapacityMw, maxCapacityMw, sortBy, sortOrder, limit (max 200), offset; an unusable value returns 400. |
GET /api/v1/utility/applications/{submissionId} | partner.read | One application: summary, workflow status, package list, and — bound to the latest package or ?packageId= — the frozen document list, review summary, evidence, communications, and active study requirement. A utility-owned draft with no package yet returns package: null. |
GET /api/v1/utility/applications/{submissionId}/packages | partner.read | Every immutable submitted package, newest first, with pinnedReview. |
GET /api/v1/utility/applications/{submissionId}/packages/{packageId}/findings | partner.read | The pinned run, its report snapshot, the append-only adjudication ledger, the CAD-revision comparison, and the screening summary (latest-package flag, open notices, blocking-finding counts) for one exact package. Read-only; the console's decision controls are not part of the payload. |
GET /api/v1/utility/applications/{submissionId}/history | partner.read | The immutable application history, newest first, in a closed vocabulary (package, stage, screening, external, notice, adjudication, study requirement). |
For mixed application lists, a temporary Salesforce permission-check outage can return 200
with salesforceReadUnavailable: true. Rows and total include ordinary applications and only
Salesforce applications whose current access checks succeeded; the list and count are partial.
The field is absent when no such outage occurred. Retry to recheck live source permissions.
This does not relax direct application, package, finding, history, or artifact authorization.
Screening completion in any of these payloads is a screening decision, never utility approval. Manual freeze, adjudication, screening completion, and study requirements are available through the human-decision routes below. Notice writes remain a later layer.
Utility lane writes (partner.write)
A utility organization's partner key with the partner.write scope creates its own draft
applications and shapes them before documents arrive. The key creator must hold a write-capable
seat (owner, admin, or member); a viewer's key reads but never writes. Every write records the
key and the request surface in the row's change provenance.
| Method + Path | Scope | Purpose |
|---|---|---|
POST /api/v1/utility/applications | partner.write | Create one utility-owned draft. Nothing is required up front; a blank applicationNumber is generated. Send requestKey to make the call retry-safe: an identical replay returns the same draft with 200, a changed replay is refused with 409. |
POST /api/v1/utility/applications/batch | partner.write | Create a manifest of drafts in one retry-safe call. applicationNumber is required on every row (unique within the batch) and is never generated; the other fields are optional. |
PATCH /api/v1/utility/applications/{submissionId}/shape | partner.write | Set a utility-owned draft's capacityMw, interconnectionLevel, and declaredTierSlug (null clears it). Drafts only; the program follows the utility's published shapes. A developer's packet is never edited by the utility. A 409 CONFLICT means another request changed the application at the same moment; retry. |
POST /api/v1/utility/applications/{submissionId}/freeze | partner.write | Manually freeze an eligible utility-owned draft through the console's shared core; body {}. |
POST /api/v1/utility/applications/{submissionId}/packages/{packageId}/adjudications | partner.write | Record a version-checked human decision for the exact latest package, pinned run, and finding. |
POST /api/v1/utility/applications/{submissionId}/screening/complete | partner.write | Complete the exact current packageId; repeating a completed decision is idempotent, but older or wrong packages still refuse. |
POST /api/v1/utility/applications/{submissionId}/study-requirement | partner.write | Record study evidence for the next submission while the screened round remains open; never rewrite the frozen package. |
The four manual decisions have SDK and confirmed CLI bindings but are excluded from hosted and local MCP, including direct invocation. Bodies are strict and bounded to 32 KiB. See the utility lane guide for body fields, receipts, and lifecycle rules.
When supplied, capacityMw must be between 0.000001 and 99999999.999999 MW in
whole-watt increments (at most six decimal places). Creation and shape changes reject values
that would round or overflow storage with 400. An application number already used by the
organization returns 409. Request bodies are strict: an unknown field anywhere in the body is
refused with 400 and the message names the field, so a misspelled field is never silently
dropped.
Uploading documents into a utility-owned draft uses the same single-file intake endpoints as the applicant lane. Upload batches, ZIP intake and recovery are also available. Draft document deletion, library attachment and explicit per-document review are available through the document operations on this page; deletion remains excluded from MCP.
To screen a utility-owned draft or a formally submitted developer application, call
POST /api/v1/packets/{submissionId}/review with { "reviewAuthority": "utility" }, or use
the existing start_packet_review MCP tool, SDK startPacketReview, or CLI packets review start.
Utility callers may omit reviewAuthority; the server selects utility authority. The same
utility cohort, organization identity, application-stage and current write-membership checks
apply to REST and MCP. Developer drafts, foreign applications and utility-issued consultant
grants do not enter this lane. The shared review core permits genuinely missing required
documents for utility screening, but requires every uploaded document's processing and role
classification to be settled. Completion may freeze a utility-owned draft into an immutable
package; it does not approve the application or send an applicant notice.
The review body accepts only the documented reviewAuthority field; unknown fields return
400 INVALID_INPUT before review starts. Applicant and consultant credentials cannot select
utility authority. A new review job reserves the reviewing organization's budget atomically
with enqueueing. An exact active-job retry reuses that job without another charge, including
when the organization has reached its review cap; the request-rate limit still applies.
GET /api/v1/packets/{submissionId}/documents reports readyForReview and missingRequiredRoles
from the packet's published lane roster (not a fixed role list). When the roster cannot be
determined, readyForReview is false with an empty missingRequiredRoles — the gate is closed,
not satisfied. POST …/review returns the readiness reason verbatim when the packet's lane cannot
be resolved (for example, a utility that publishes several programs needs the submitted
application form to select one).
A partner review start records a change-provenance record in the job's metadata: the acting user, the
credential (api_key:<key id> or oauth_client:<client id>), the surface, and the request
correlation id. A REST start is recorded as surface rest; the GridWonk CLI sends the
x-gridwonk-client-surface: cli header (SDK option clientSurface: 'cli') so its starts are
recorded as cli; the hosted start_packet_review tool records mcp. The record is built from the
server's own authentication and cannot be supplied in the request body. When a review's terminal
edge settles the screening status or freezes a utility package automatically, whether from the job's
own completion or from the recovery sweep, the resulting status-history rows carry that job's
provenance plus the job id.
Salesforce-owned packets: disabled connector
The retained credentialed Salesforce connector is implemented but disabled. Its four scoped REST/MCP/SDK operations and automatic service-owned package freezing are implemented; the existing utility review binding does not activate that workflow or close sandbox acceptance.
Source-owned copies have additional safeguards. Ordinary intake, replacement, role correction, shape changes, and review starts cannot change or recapture their source evidence. A new review requires a complete connector capture of the approved field mapping and exact file versions; pending, failed, expired, or changed captures do not open the review gate.
Packet, package, report, history, and document reads require the effective human user's current Salesforce record and field permissions, including when reading an older package. A service credential does not stand in for that viewer. Queue filtering applies the same permission decision to rows and totals before pagination; queries matching more than 200 source-owned applications must use narrower filters. A permission-service outage fails the read instead of returning an incomplete successful result.
Historical reads now require current permission for all committed captures, including old-only fields and previous-package comparisons. Foreign selected runs, malformed snapshots, and more than 200 revisions fail closed. A revoked older field can also deny a current view.
The current document list contains only the committed source revision's files. Historical packages retain their captured files and findings. Structured application-field evidence is separate from PDF evidence: reports identify the captured snapshot and field citations identify the source record, field, and capture time. These citations do not invent a PDF, page number, or document count.
The separate outbound-only installed application does not use the partner credentials or linked-human remote checks above. Its Layer 1 foundation preserves the installation and Salesforce reviewer through the existing packet pipeline; both its API and processing authorizer remain hard-disabled. Ordinary packet/document/result readers and direct authenticated database reads deny installed content, even for staff. The retained connector's result delivery and recovery sweeps skip installed imports entirely, and CAD companion replays reauthorize installed imports through their own installation lane rather than a saved service credential. No new packet submission or results operation is enabled by merging that foundation.
Native CAD companion intake
These utility-neutral endpoints attach one private DWG companion to an existing current site-plan PDF version. They use the ordinary signed direct-upload transport and the same organization authorization and packet-locking core as packet intake. For partner packets, the applicant organization owns the packet and controls upload availability, not the selected utility; utility-specific review requires a reviewed CAD procedure profile. Finalization and background acceptance, rejection, or failure updates recheck that same owner before changing packet state.
The target-free awaiting_target state belongs only to a session-authenticated console batch. The
console first tries an exact normalized filename match to a current site plan and otherwise pairs
only when the submission has one unambiguous current site plan. An ambiguous drawing remains
private and asks an authorized user to select a site plan. None of those console semantics widens
this partner contract.
| Method + Path | Scope | Purpose |
|---|---|---|
POST /api/v1/packets/cad-intake | partner.write | Reserve a DWG-only intake for an exact current site-plan version and return signed standard or resumable TUS upload authorization. |
POST /api/v1/packets/cad-intake/{intakeId}/finalize | partner.write | Prove and inspect the upload, then attach the accepted immutable source to the selected current site-plan version. |
GET /api/v1/packets/cad-intake/{intakeId} | partner.read | Return separate upload, inspection, attachment, rejection, and internal-failure states without private storage metadata. |
POST /api/v1/packets/cad-intake/{intakeId}/reauthorize | partner.write | Supersede an expired attempt and issue fresh upload authorization from byte zero. |
POST /api/v1/packets/cad-intake/{intakeId}/cancel | partner.write | Cancel an incomplete intake and schedule its provisional object for cleanup. |
An idempotency key may be retried only for the same declared filename, byte count, and site-plan
target. Reusing it for a different upload returns 409. If accepted finalization cannot start its
durable workflow, the route returns 503 workflow_start_failed with Retry-After: 5; retry the
same finalization. Processing attempt numbers and atomic claims fence duplicate workflow starts.
Only .dwg is accepted, with a separate 30 MB ceiling. The first source binds to the existing
site-plan version. Replacing it with different bytes creates a new logical version, preserves the
sanitized PDF artifacts, and invalidates stale readiness and review identity. Submitted packages pin
the exact companion asset and SHA-256 hash. Upload and attachment do not require Autodesk. Separately
gated APS processing can create a browser-safe derivative and structured evidence after acceptance;
native bytes are never exposed through MCP or loaded into the browser.
Operational telemetry records only the intake stage, safe outcome, elapsed time, and whether a new logical version was created. It never records native bytes, signed upload authorization, storage paths, or source hashes.
Packet reruns prefer exact current stored extractions and read changed or unmatched documents again. The partner route cannot request the internal forced-fresh synthetic QA mode; that control is limited to authorized platform administrators reviewing eligible editable demo packets in the console.
Hosted MCP tools
Connect to POST https://gridwonk.com/api/v1/mcp with the same scoped OAuth
token. MCP means Model Context Protocol: a standard way for an AI client to
discover and call named tools. Discovery and execution use one policy, so a
tool hidden from tools/list is also refused by tools/call.
| MCP tool | Scope | REST-equivalent capability |
|---|---|---|
create_packet_intake | partner.write | Create intake |
finalize_packet_intake | partner.write | Finalize intake |
get_packet_intake_status | partner.read | Intake status |
reserve_packet_intake_batch | partner.write | Reserve an ordered upload manifest |
get_packet_intake_batch | partner.read | Read batch and item status |
heartbeat_packet_intake_batch | partner.write | Extend the idle deadline |
pair_packet_intake_batch_item | partner.write | Pair a DWG item to a site plan |
cancel_packet_intake_batch_item | partner.write | Cancel one unfinished item |
abandon_packet_intake_batch | partner.write | Abandon an unfinished batch |
list_packet_documents | partner.read | Document list (applicant lane, or the pinned utility organization) |
attach_packet_document_from_library | partner.write | Attach an owner-organization File Library asset; exact retries are reused |
start_packet_document_review | partner.write | Start or reuse review for one exact packet document; MCP does not expose failed-run retry |
get_packet_document_text | partner.read | Sanitized text and coordinates |
start_packet_review | partner.write | Start or reuse review |
get_packet_review_run | partner.read | Review-run detail |
get_packet_workflow_status | partner.read | Canonical workflow status |
get_packet_screening_status | partner.read | Utility package screening status |
get_packet_document_rendition | partner.read | Signed URL for the sanitized rendition |
list_utility_applications | partner.read | Utility Applications queue |
create_utility_application | partner.write | Create one utility-owned draft |
create_utility_application_batch | partner.write | Create a manifest of drafts |
update_utility_application_shape | partner.write | Set a draft's capacity, level, and program |
get_utility_application | partner.read | One application with package-bound detail |
list_utility_application_packages | partner.read | Submitted packages of an application |
list_utility_package_findings | partner.read | Pinned review, ledger, and screening decision |
get_utility_application_history | partner.read | Application history |
The Confirm/Correct role operation is deliberately not model-facing. Use the console, REST API, SDK, or CLI when a human must confirm or correct a role.
What is never exposed
Raw original files, signed storage references, service-only descriptors, provider errors, and internal identifiers never cross this surface. There is no request-selectable resolver context: version, package, and organization context are proved server-side on every call.
Feature availability
There is no packet-specific rollout flag on this surface. Each operation obeys
the same authoritative server-side cohorts as the console (for example,
Storage-native intake creation and the utility screening read are enabled per
organization — the env dial merged with per-organization feature states, which platform
admins manage from the organization's admin Features tab); outside a cohort the endpoint
behaves as 404.
Native-CAD intake is available to every applicant organization by default. The server-only
NATIVE_CAD_INTAKE_COHORT setting is an operational kill switch or temporary narrowing control,
not an NES-only entitlement. A utility procedure profile controls which deterministic review rules
may use accepted evidence; no profile means upload, visualization, and evidence summaries can still
work while utility-specific automated CAD findings stay unavailable.
The classifier's owner-approved automatic policy is a separate internal rollout under the
server-only CLASSIFIER_AUTO_APPLY role/organization cohort. Positive v1 results in that cohort can
become authoritative and start review without a partner call. The partner API cannot change the
cohort; its role endpoint always records a human Confirm or Correct decision. Historical v1
suggestions remain valid without a score, while the optional confidence-v2 contract remains a
separate internal identity.
The optional Combined-PDF split is a session-authenticated console capability, on by default per
applicant organization (the server-only COMBINED_SPLIT dial and per-org feature states can narrow
or disable it). It is not a new endpoint on this partner REST surface. After a person confirms a split in the console, the derived children appear through
the ordinary document and review endpoints; the immutable source container does not count as a
reviewable packet document. The packet status endpoint's documentCount excludes the retained
source, and assigning a content role to it through the role endpoint returns a clear conflict
message ("assign roles on its derived documents instead") rather than a database error.
The optional ZIP container intake is available through the archive protocol above. An expired idempotent upload retry must reacquire an organization slot under the same database lock as a new upload; it is refused when all three slots are live and does not charge the rolling file/byte quota twice.
SDK and CLI
Every endpoint has a first-class binding in @gridwonk/sdk
(createPacketIntake, finalizePacketIntake, getPacketIntakeStatus,
reservePacketIntakeBatch, getPacketIntakeBatch, heartbeatPacketIntakeBatch,
pairPacketIntakeBatchItem, cancelPacketIntakeBatchItem, abandonPacketIntakeBatch,
createPacketArchiveIntake, getPacketArchiveIntake, finalizePacketArchiveIntake,
abandonPacketArchiveIntake, cancelPacketIntake, reauthorizePacketIntake,
retryPacketIntakeProcessing, attachPacketDocumentFromLibrary, deletePacketDocument,
startPacketDocumentReview, listPacketDocuments, getPacketDocumentText, setPacketDocumentRole,
startPacketReview, getPacketReviewRun, getPacketWorkflowStatus,
getPacketScreeningStatus, getPacketDocumentRenditionUrl, and for utility organizations
listUtilityApplications, getUtilityApplication, listUtilityApplicationPackages,
listUtilityPackageFindings, getUtilityApplicationHistory, createUtilityApplication,
createUtilityApplicationBatch, updateUtilityApplicationShape — mint a scoped token with
getOAuthToken(expiresIn, scope)) and the gridwonk packets … CLI group
(intake create/finalize/status/cancel/reauthorize/retry-processing, archive-intake create/status/finalize/abandon, intake-batches reserve/status/heartbeat/pair/cancel-item/abandon, documents list/attach/delete/review/text/pdf/set-role,
review start/get, status, screening) plus gridwonk utility applications list/get/packages/findings/history/create/batch-create/shape.
The SDK methods hang off GridWonkClient (exported as GridBoostClient too, a deprecated alias
of the same class).
Both client surfaces default to the canonical https://gridwonk.com API origin. Legacy
production hosts remain accepted for compatibility and are normalized to the canonical
origin before authenticated packet requests are sent.
Relationship to the legacy document endpoints
The generic classify and digitize document endpoints are deprecated
compatibility adapters for pre-packet integrations. Packet workflows use this
lane instead: classification arrives as a pinned model result followed by an automatic or human
authoritative role decision, and digitization/sanitization/OCR run inside Storage-native intake.
The adapters remain unchanged until the scheduled legacy retirement.
The separate legacy GET /api/v1/requirements read permanently returns typed 410 Gone with the
published replacement. Its SDK, CLI, and public MCP wrappers have also been removed. That does not
affect any endpoint on this page. Packet review uses the
separate effective-analysis requirement tier, so the state of a utility's requirement review does
not gate an authorized packet review (the review's reject decisions and edits apply where analysis
enforcement is activated). See
Requirements API — Retirement Stages.
Corrected submissions and intake reservation clocks
Corrected applicant resubmission returns to Pending after its immutable package commits.
The receiving utility starts the shared whole-packet review through the existing review
endpoint or queue action. The core selects utility_rescreen after an earlier utility round;
the applicant action does not invoke the legacy per-document screening lane. Partner scopes,
request schemas, budget reservations and provenance checks remain those documented above.
Intake batch creation records its creation, last-activity and expiry timestamps from the same application-clock instant. The configured idle and maximum lifetime windows remain unchanged, avoiding disagreement between database and application clocks at reservation.
Interpreting review completeness
A review-run response retains the existing verdict enum. incomplete means declared checks remain unresolved or coverage was not recorded; it does not convert missing evidence into a technical failure. Deficiency severity and blocking counts remain independently visible. scope-inapplicable requires an affirmative applicability decision and does not keep the review incomplete.
report.coverage.checksIncomplete is optional and lists a check, a reason (context-missing or not-built) and a reviewer-facing note when the check ran on some evidence but could not finish its declared scope. The same check remains in checksPerformed; valid findings are retained. checksNotPerformed explains checks that did not run. When available, its optional note identifies the missing prerequisite and a next action. Older records may have only a reason code. Missing coverage on older reports means unknown, not all checks passed. No review result is utility approval.
When report.coverage.results is present, it has one row per declared check. The stable machine values mean:
| Machine outcome | Meaning |
|---|---|
deficiency | Deficiency identified: required information is missing or a technical problem is demonstrated. Inspect the cited finding to distinguish them. |
could-not-verify | Unable to verify: the check was attempted but could not conclude, including partially evaluated evidence. A partial check may carry a reason and note without inventing a finding. |
not-applicable | Not applicable: evidence establishes that the rule does not apply. |
not-performed | Not evaluated: the check did not run; its reason explains why. |
no-deficiency-found | No deficiency identified in this completed check. This is not utility approval. |
Partial checks retain any valid findingIds alongside their unfinished reason and note. Reports without results have no per-check record; their absence does not mean every check passed. This API contract does not assert delivery of the separately planned full Checks table.