Shuttle Docs

Approvals

Get, list, approve and reject — without duplicating action creation.

GroupBusiness-action authorization
RuntimesTypeScript browser/server, React client adapter, Python/Go server
Updated2026-09-15

Status and boundary

Proposed target SDK domain based on the verified public activity/decision surface. “Approval” is the application-facing name for authorization progress on one protected business action. It is not a smart wallet, blockchain multisignature transaction, account-abstraction object or delegation mechanism.

The underlying protected business call creates the durable action and, when review is required, its approval record. There is no redundant createApproval: creation through both paths could duplicate or detach authorization from the action it controls.

Public methods#

TypeScript browser TypeScript server React adapter Python server Go server
Scoped review actions only Proposed target Calls the TypeScript core in a client component; no approval hook is implied Proposed server target Proposed server target
sdk.approvals.get({ approvalId }, options?)
sdk.approvals.list({ states?, actionKinds?, cursor? }, options?)
sdk.approvals.approve({ approvalId, response }, options?)
sdk.approvals.reject({ approvalId, response, reason? }, options?)

Every call is organization/account scoped by authenticated context. get requires one approval ID. list supports bounded pagination plus state/action filters. approve and reject require fresh response evidence from an allowed participant, bound to the approval fingerprint. A free-form reason is metadata only and never authorization.

Approval object#

Field Meaning
approvalId stable approval identity
requestId caller-stable identity of the underlying business action
actionKind wallet, policy, user, organization, signing, sending, treasury funding, export or recovery action class
resource exact resource kind and identifier
actor safe initiating requester/service identity and wallet control mode
payloadFingerprint canonical identity of immutable protected material
state actionRequired, awaitingApprovals, approved, denied, expired, executing, succeeded, failed or unknown
requiredApprovals / receivedApprovals threshold and distinct accepted participants when multi-party review applies
canApprove / canReject current caller capability after server-side policy evaluation
createdAt / expiresAt issuance and expiry boundaries

The response never exposes signing secrets, raw session credentials or reusable authorization material. Participant detail is limited to safe references needed by the caller's granted scope.

Lifecycle and correlation#

Text
business call -> action recorded -> approval not required | awaiting approvals
awaiting approvals -> approved | denied | expired
approved -> executing -> succeeded | failed | unknown

An action may complete immediately under valid grants, so not every operation waits. Embedded approvals use owner-authorized participants; server-wallet approvals use its named service/admin participants, policies and limits. End-user login cannot count as treasury service authority. Thresholds count distinct approvals over one fingerprint. This off-chain logic changes no wallet bytecode or signing format.

Three states remain distinct:

  1. Approval state answers whether the required actors authorized the protected action.
  2. Operation state answers whether the backend action executed and what durable result it produced. getOperation(requestId) remains the restart and unknown-outcome facade.
  3. Chain transaction status answers whether a submitted transaction was broadcast, included, executed or finalized.

An approved send may still fail before submission or on chain. A chain hash does not prove approval, execution success or finality.

Continuation and duplicate safety#

The existing authorization handler and getOperation({ requestId, authorization }) continuation submit response evidence to the same backend record represented here. They are not an independent vote store. Automatic handler submission and explicit sdk.approvals.approve or getOperation continuation cannot both submit the same response.

Every response binds approval ID, request ID, original action kind/resource/requester, authorized approving actor, payload fingerprint and expiry. The initiating actor and approving actor remain distinct and need not be the same person. Exact replay of the same approver response returns the recorded vote without adding another approval. A second response from the same participant cannot count twice. Changed response proof, changed action material, unauthorized participant, expiry, stale policy/resource version or foreign scope fails without advancing the action.

No actor may approve a membership, policy or ownership change using authority obtained only from that pending change. Root or owner changes are authorized by the current valid authority at the effect boundary. Approval never bypasses the underlying wallet, policy, user or organization rules.

Denial, expiry and failures#

Denial, expiry and insufficient approvals are explicit terminal authorization outcomes and produce no protected effect. A read is effect-free. Transport timeout after an approve/reject submission makes the response outcome unknown; recover the same approval or operation identity. Do not create a replacement action, blind-repeat a decision or rebroadcast a transaction.

Acceptance#

See getOperation, Policies, Transactions, Users, and Organizations.