> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getpara.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrate conditional approvals

> Coordinate human approval decisions or collect signatures for a policy-bound transaction

The policy defines the approval workflow and which settings may be adjusted. Your application initiates requests, collects decisions or signatures, and displays progress; Para checks eligibility and enforces the workflow before signing can continue.

Use authenticated decisions when people need to authorize a transaction. Use signature collection when the transaction itself needs signatures from multiple wallets.

| Evidence                 | What a participant contributes                        | What completion means                                                                                |
| ------------------------ | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `authenticated_approval` | An authenticated approve/reject decision.             | The request has the required human authorization; normal guarded signing still follows.              |
| `transaction_signature`  | A verified signature over the case's signing payload. | The required signatures have been collected; chain-specific assembly and submission remain separate. |

Neither replaces wallet-owner consent for user-owned wallets. A server secret manages authority and configuration; it cannot impersonate a person's approval or wallet signature.

## Configure the workflow

Author a `require_approval` rule through the [CLI](/v3/cli/permissions) or work with Para. The [JSON reference](/v3/references/permissions/policy-json#conditional-approval-requirements) includes an ordered three-stage EVM treasury requirement: two finance reviewers, one compliance reviewer, then every eligible owner.

For that treasury, your backend binds the wallet to an authorization scope and assigns the corresponding roles to Para users. Provision distinct people across stages: a person counts only once in a case, and an authenticated initiator cannot approve their own request. A simple M-of-N workflow uses one stage with a numeric count; unanimous approval uses `requiredApprovals: "all"`.

<Card title="Configure trusted approval authority" icon="server" href="/v3/rest/permissions-administration">
  Bind wallets, assign roles or attributes, and manage declared configuration from your backend.
</Card>

The same authenticated workflow can govern a Stellar treasury by using its transaction selector and chain-appropriate facts. This does not turn the treasury into an onchain multisig: participants are authorizing Para's subsequent signing operation.

```json theme={null}
{
  "walletType": "STELLAR",
  "requestRoute": "stellar.sign_transaction",
  "requestType": "stellar_transaction",
  "chainId": "Test SDF Network ; September 2015"
}
```

This selector targets Stellar testnet. Keep amounts in the network's base units and test the actual transaction encoding; changing the selector alone does not translate EVM-specific conditions.

## Track the initiator's request

Submit the transaction through the existing signing integration. A matching authenticated approval requirement creates a case tied to that exact request. App-owned REST signing can report `POLICY_REVIEW_REQUIRED` with an `approvalCaseId`; the user SDK integration also exposes case discovery for the authenticated initiator.

```typescript theme={null}
const { cases } = await para.listInitiatedApprovalCases({ limit: 20 });
const current = await para.getInitiatedApprovalCase(caseId);
```

Use the case for the operation your UI is tracking, rather than choosing an arbitrary pending case. These reads let the initiator track progress without granting them approver authority.

## Let an approver act

The signed-in approver discovers cases they can access:

```typescript theme={null}
const { cases } = await para.listAccessibleApprovalCases();
const current = await para.getAccessibleApprovalCase(caseId);
```

For the hosted experience, generate and open the Portal URL:

```typescript theme={null}
const url = await para.getApprovalCaseReviewUrl({ caseId });
window.open(url, "para-approval", "popup,width=480,height=720");
```

Your application opens the URL using its normal browser handling. Para may ask the user to authenticate before showing the review. Read the current case after the user returns; closing the window does not establish an approval result.

A custom authenticated UI can submit decisions directly:

```typescript theme={null}
const current = await para.getAccessibleApprovalCase(caseId);
if (current.decision.canDecide) {
  const updated = await para.approveApprovalCase(caseId);
}
```

Use `rejectApprovalCase(caseId)` for rejection. Para checks the authenticated user, current eligibility, stage, and case state on each mutation. Display returned capabilities and status rather than trusting role names in browser state.

Stages progress in order; eligible decisions within a stage may arrive in any order. Eligibility is snapshotted as a stage opens. A rejection ends the case. Expiry or changes to the relevant policy, authority, or request can prevent the case from authorizing signing.

## Continue signing

A completed authenticated case is approval evidence, not a signature response. Continue or retry the original operation through its signing integration. Para rechecks current policy and authorization before signing; the case does not grant blanket permission for another transaction.

Keep the user's transaction review and consent separate from other people's approval decisions. Never display “transaction sent” merely because the approval case completed.

## Collect transaction signatures

For a policy with `evidence: "transaction_signature"`, initiate a collection using the original encoded transaction. Para derives the signing context; the client does not supply trusted policy facts.

```typescript theme={null}
const collection = await para.createApprovalSignatureCollection({
  requestId,
  walletId,
  transaction: {
    format: "solana_transaction",
    transactionBase64,
  },
});
```

Use a unique request ID for the operation and retain the returned case ID. Supported payload formats also include EVM transactions/typed data, Safe typed data, Cosmos sign documents, Stellar XDR, and Sui transaction bytes; see the [method reference](/v3/references/core/permissions/createapprovalsignaturecollection) for their exact shapes.

For an eligible participant using a Para wallet, the convenience method fetches the case payload, signs with the selected wallet, and submits the signature:

```typescript theme={null}
const updated = await para.signApprovalTransaction({
  caseId,
  walletId: approverWalletId,
});
```

The wallet ID is the participant's signing wallet. It must be compatible with the case's transaction format, owned by the signed-in participant, and bound to the collection's authorization scope. Existing signing/Portal authorization still applies. The signature-collection initiator may contribute if eligible, unlike an authenticated-approval initiator.

If your integration supplies signatures separately, read `getApprovalSigningPayload(caseId)` and submit through `submitApprovalSignature(caseId, { walletId, signature })`. Sign the exact returned payload with the required encoding; signing an arbitrary message with the same case ID is not equivalent.

After the case completes, the collection initiator retrieves the signature bundle using their authenticated client. Other participants cannot retrieve it. The case must remain unexpired and valid against the current authorization context.

```typescript theme={null}
const bundle = await para.getApprovalSignatures(caseId);
```

The bundle contains the transaction payload and verified contributions. Your chain integration remains responsible for assembling the multisig transaction, satisfying the onchain account's own signer/threshold rules, and broadcasting it. Policy roles are not a substitute for the multisig account's onchain membership.

<CardGroup cols={2}>
  <Card title="Sui multisig signer" icon="pen" href="/v3/references/hooks/useParaSuiMultiSigSigner">
    Read the existing chain-specific signer contract before assembling a Sui multisig transaction.
  </Card>

  <Card title="Signature lifecycle methods" icon="code" href="/v3/references/core/permissions/getapprovalsignatures">
    Inspect the payload, signatures, and supported result types.
  </Card>
</CardGroup>

## Let authorized managers adjust a workflow

A policy may expose named settings through `safeKnobs`. Use the authenticated manager's capabilities to determine what their UI can offer:

```typescript theme={null}
const capabilities = await para.getUserApprovalCapabilities(authorizationScopeId);
const requirements = await para.listConfigurableApprovalRequirements(authorizationScopeId);
const effective = await para.getEffectiveApprovalConfiguration(reference);
```

`reference` contains `authorizationScopeId`, `policyId`, `policyVersion`, and `requirementId`. Use `effective.configuration?.revision ?? 0` as `expectedRevision` when calling `updateApprovalConfiguration`. A null configuration means the authored defaults apply and no settings have been saved yet. Only declared settings may change; the manager cannot add arbitrary stages or assign themselves a role. Backend assignment management is a separate authority.

These workflow settings are also separate from [personal spending parameters](/v3/react/guides/permissions#adjust-personal-limits). A policy can use both: the user chooses their amount limit, while authorized managers configure the declared approval workflow.

<CardGroup cols={2}>
  <Card title="React hooks" icon="react" href="/v3/references/hooks/permissions">
    Read cases, submit decisions, and update configuration with React hooks.
  </Card>

  <Card title="Policy lifecycle" icon="rotate" href="/v3/general/permissions-lifecycle">
    Handle version changes, expiry, and production publication.
  </Card>
</CardGroup>
