Skip to content

client.approvals

View as Markdown

client.approvals — the approvals operations.

On AsyncKindgi every method is the same, awaited.

list(
*,
limit: int | None = None,
cursor: str | None = None,
scope_kind: Literal['tenant', 'org', 'project'] | None = None,
scope_id: str | UUID | None = None,
status: Literal['pending', 'assigned', 'in_review', 'approved', 'rejected', 'escalated', 'expired', 'withdrawn'] | list[Literal['pending', 'assigned', 'in_review', 'approved', 'rejected', 'escalated', 'expired', 'withdrawn']] | None = None,
assigned_to: Literal['me'] | None = None,
decided_by: Literal['me'] | None = None,
order: Literal['asc', 'desc'] | None = None,
required_role: Literal['standard', 'senior', 'admin'] | None = None,
created_after: str | None = None,
wait_token_id: str | UUID | list[str | UUID] | None = None,
run_id: str | UUID | None = None,
include_descendants: bool | None = None,
timeout: float | None = None,
) -> ApprovalCollectionPage
Signature

List approvals visible to the caller. GET /v1/approvals

Requires a reviewer: a token that carries a reviewerRole, or whose user is a registered reviewer (the roster gives the role). With authorization on, a person who is the tenant's admin (through a session or an admin key not limited to a project) reads at every tier: with no roster entry, as an admin reviewer; with a lower role, their own tier, and any tier they ask for with requiredRole. The roster doesn't show such a reader, but the access audit records the tenant-admin check (authz-decision), made only where it changes what the roster gives. Role-scoped: reviewers only see approvals whose requiredRole rank ≤ their rank (standard < senior < admin). With authorization on, only approvals whose project the caller may read. scopeKind/scopeId narrow to one project's approvals, or every project's in an org; approvals from before Kindgi 0.1.3 have no project and are listed only without a scope.

get(approval_id: str | UUID, /, *, timeout: float | None = None) -> Approval
Signature

Fetch a single approval. GET /v1/approvals/{approvalId}

Requires a reviewer, or (with authorization on) a person who is the tenant's admin, as the list does; the tenant's admin reads an approval of any tier. Returns 404 for ids that exist but require a higher role than the caller (avoids cross-tier existence leaks — see API-ROUTE-CONVENTIONS.md §2.4), or that are in a project the caller may not read. A decided approval carries its decision: what the reviewer decided, why, and who (decidedBy, user:<userId>).

complete(
approval_id: str | UUID,
body: CompleteApprovalBody | Mapping[str, Any] | None = None,
/,
*,
idempotency_key: str | None = None,
timeout: float | None = None,
**fields: Any,
) -> CompleteApprovalResult
Signature

Submit a decision on an approval. POST /v1/approvals/{approvalId}/complete

Records the decision (HitlBinding.submitReview). When the approval carries a waitTokenId and the decision is approve or reject, also completes the waitpoint so the suspended run resumes, with { decided, rationale?, decidedBy, approvalId }: the run's journal records who decided which approval (decidedBy is user:<userId>).

audit_bundle(
approval_id: str | UUID,
body: ExportAuditBundleBody | Mapping[str, Any] | None = None,
/,
*,
idempotency_key: str | None = None,
timeout: float | None = None,
**fields: Any,
) -> ExportAuditBundleResult
Signature

Export a signed audit bundle for a decided approval. POST /v1/approvals/{approvalId}/audit-bundle

Signs the approval, its decision and its evidence with the deployment's export key, and records the export (an export-signed audit event). The same envelope as the other signed exports, so one verifier reads all three; check publicKey against GET /v1/export-signing-keys. For a decided approval only (approved, rejected, escalated, expired, withdrawn): a pending one is 409 approval-not-decided. A deployment with no export key answers 404 signing-not-configured.