Multisig approvals
Create, inspect, and sign weighted multisig approvals for smart wallet user operations that need more signer weight before submission.
When a wallet has a multisig threshold configured, submitting a user operation immediately is not allowed. Instead, the integration creates an approval record that accumulates signatures from each required signer until the collected weight meets the threshold. The record stores the user operation hash, the call data to submit, the required weight, the collected weight, the lifecycle status, the optional deadline, and each collected signature.
Requires: advanced accounts enabled for the deployment.
This page is a reference for integration developers who already build smart wallet user operations. For changing the threshold itself, see Smart wallet multisig thresholds.
Prerequisites
Before creating or signing an approval:
- The authenticated participant must have an active organisation.
- The wallet must exist in the current system scope.
- The wallet must have an installed weighted multisig validator.
- The wallet must have a non-zero threshold configured.
- The caller must sign as an active signer on that wallet.
- The organisation must have a provisioned bundler wallet for account-abstraction submission.
Approval lifecycle
A multisig approval represents one pending user operation. You create the approval with the user operation hash and encoded call data. DALP records the initiator signature immediately, then stores the approval as pending unless the collected weight already meets the threshold.
Co-signers add signatures to the same approval. Each signature contributes the signer's configured weight. When the cumulative weight meets or exceeds the approval threshold, DALP marks the approval as submitted and submits the user operation automatically.
Approval statuses are:
| Status | Meaning |
|---|---|
pending | The approval exists and still needs more signer weight, or it is waiting for submission. |
submitted | The collected weight met the threshold and DALP submitted the user operation. |
executed | The submitted user operation completed successfully. |
expired | The approval deadline passed before completion. |
cancelled | The approval was cancelled without reaching the threshold. |
failed | Submission or execution failed. |
Create an approval
POST /api/v2/smart-wallets/{address}/approvals
Create an approval when your integration has built a user operation and needs co-signer weight before DALP submits it.
curl -X POST "https://your-platform.example.com/api/v2/smart-wallets/0x1234567890AbcdEF1234567890aBcdef12345678/approvals" \
-H "X-Api-Key: YOUR_DALP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"userOpHash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"callData": "0xabcdef",
"description": "Approve signer rotation for the treasury smart wallet",
"expiresAt": "2026-06-01T12:00:00Z"
}'The userOpHash must be a 32-byte hex hash. DALP rebuilds the operation preview from the supplied call data and wallet state, then rejects the request if the supplied hash does not match that preview.
The threshold request field is optional. DALP reads the current on-chain threshold from the indexed wallet state when it starts the approval workflow.
Use orderingScope only when the operation needs explicit submission ordering. The default is wallet-level ordering. When you set orderingScope to group, you must also provide a non-empty orderingKey; DALP rejects an orderingKey for any other scope.
List and read approvals
Use the list endpoint to show pending approvals and approval history for a wallet:
GET /api/v2/smart-wallets/{address}/approvals
The list endpoint is paginated. It supports filtering by status, initiatorAddress, operationKind, createdAt, and expiresAt. It supports sorting by status, operationKind, createdAt, and expiresAt; the default sort is newest first by createdAt.
Use the read endpoint when you already know the user operation hash:
GET /api/v2/smart-wallets/{address}/approvals/{userOpHash}
Both endpoints return approval records with collected signatures.
| Field | Type | Description |
|---|---|---|
id | string | Approval record ID. |
userOpHash | string | User operation hash for the pending operation. |
walletAddress | Ethereum address | Smart wallet contract address. |
chainId | number | Chain ID for the approval. |
organizationId | string | Organization that owns the approval record. |
initiatorAddress | Ethereum address | Signer that created the approval. |
threshold | string | Required cumulative signer weight as a decimal string. |
currentWeight | string | Collected signer weight as a decimal string. |
callData | hex string | Encoded call data for the operation. |
description | string or null | Optional operation description. |
status | enum | Approval lifecycle status. |
expiresAt | ISO 8601 string or null | Optional approval deadline. |
createdAt | ISO 8601 string | Creation timestamp. |
updatedAt | ISO 8601 string | Last update timestamp. |
signatures | array | Collected signer signatures with signer address, signature bytes, signer weight, and signing timestamp. |
List responses use the standard { data, meta, links } collection envelope. Single approval reads use { data, links }.
Sign an approval
POST /api/v2/smart-wallets/{address}/approvals/{userOpHash}/sign
A co-signer signs an existing approval with an empty request body. DALP resolves the caller's signing address from the authenticated participant, verifies that the caller is an active signer on the wallet, records the signature once, and adds the signer's weight to the approval.
curl -X POST "https://your-platform.example.com/api/v2/smart-wallets/0x1234567890AbcdEF1234567890aBcdef12345678/approvals/0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/sign" \
-H "X-Api-Key: YOUR_DALP_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'If the signer already submitted a signature for that approval, DALP does not add duplicate weight. If the approval is expired or no longer pending, the sign request is rejected instead of reopening it. A submitted approval can still be signalled again while the platform continues the user operation submission. The sign endpoint returns the current record and does not create a second approval for the same hash.
Operational notes
- Read the wallet and signer list before creating approvals so your integration can display the current threshold and signer weights.
- Treat
thresholdandcurrentWeightas decimal strings because signer weights are integer values that can exceed JavaScript's safe number range. - Store
userOpHashas the approval lookup key. The read and sign endpoints use it in the path. - Set
expiresAtwhen the operation should not remain open indefinitely. Use an ISO 8601 date-time string. - Use group ordering only for operations that must share a sequencing lane. For ordinary wallet operations, omit
orderingScopeandorderingKey. - Do not ask co-signers to call owner-only wallet configuration endpoints directly. Route co-signer participation through the approval sign endpoint.
Error codes
When an approval operation fails, the API returns a stable DALP-NNNN error code. Use the code to decide whether the caller can correct the request and retry, whether to wait for the indexer to catch up, or whether the failure needs operator follow-up. Each code below maps to a canonical entry in the platform API error reference.
The tables list each code with its category, what triggers it, and the retry and idempotency semantics. idempotent means the same request can be sent again without side effects beyond the first attempt. retry once means the condition may clear on a subsequent call, such as after the indexer catches up. no retry means the caller must change the request, the signer, or the wallet state before the call will succeed. operator means the caller cannot fix the condition and should contact the operator.
Create an approval
These codes surface while you create an approval. Most are correctable from the caller side: select an organisation, sign in with an active signer, or rebuild the preview, then resend.
| Code | Category | Retry / idempotency | When it happens |
|---|---|---|---|
| DALP-0034 | permission | no retry | No active organisation on the session. Select an organisation before you create approvals. |
| DALP-0191 | permission | no retry | The session has no signer wallet configured. Sign in with a session that carries a valid signer wallet. |
| DALP-0209 | client | no retry | The wallet was not found. Verify the address and confirm the wallet has finished indexing. |
| DALP-0207 | client | no retry | The wallet has no multisig threshold configured. Set a threshold before you create approvals. |
| DALP-0178 | operational | no retry | The wallet has no installed weighted multisig validator. Install one before you create approvals. |
| DALP-0080 | client | no retry | callData or userOpHash did not match the API contract. callData must be a 0x-prefixed hex string, and userOpHash must be a 66-character 0x-prefixed hex hash. Correct the field and retry. |
| DALP-0196 | permission | no retry | The caller is not an active signer on the wallet's multisig validator. Only multisig signers can create approvals. This also fires when the active signer differs from the session's signing address; sign in with that signer to continue. |
| DALP-0204 | domain | no retry | userOpHash does not match the preview DALP rebuilt from the supplied call data and wallet state. Rebuild the preview and retry. |
| DALP-0189 | client | no retry | The organisation has no provisioned bundler wallet. Complete system deployment first, because the provisioning phase creates the bundler wallet. |
| DALP-0201 | dependency | operator | No RPC URL is configured for the current chain. This needs operator follow-up on network configuration. |
| DALP-0281 | dependency | operator | The directory contract address is not configured in network config. This needs operator follow-up. |
| DALP-0282 | client | retry once | The entry point was not found in the indexer for this system. Retry once the indexer has processed the directory state. |
| DALP-0013 | dependency | retry once | The approval submission failed against a platform dependency. Retry the request; if it persists, contact support. |
| DALP-0185 | operational | retry once | The approval workflow finished without enough data to build the response. Retry the request. |
List and read approvals
These codes surface when you list a wallet's approvals or read a single approval. Both endpoints are restricted to wallet signers, so a non-signer cannot view approval data.
| Code | Category | Retry / idempotency | When it happens |
|---|---|---|---|
| DALP-0197 | permission | no retry | The caller is not a signer on the wallet. Only signers can list or view approval details. |
| DALP-0080 | client | no retry | userOpHash did not match the API contract. It must be a 66-character 0x-prefixed hex hash. Correct it and retry. (read only) |
| DALP-0181 | client | no retry | No approval exists for the supplied user operation hash. Verify the hash. (read only) |
| DALP-0182 | permission | no retry | The approval exists but does not belong to the wallet in the path. Read it under its own wallet address. (read only) |
Sign an approval
These codes surface when a co-signer signs an approval. The sign route records each signer's weight once and never adds duplicate weight for a repeated signature.
| Code | Category | Retry / idempotency | When it happens |
|---|---|---|---|
| DALP-0080 | client | no retry | userOpHash did not match the API contract. It must be a 66-character 0x-prefixed hex hash. Correct it and retry. |
| DALP-0034 | permission | no retry | No active organisation on the session. Select an organisation before you sign approvals. |
| DALP-0190 | client | no retry | The session has no wallet ID configured. Sign in with a session that carries a valid wallet. |
| DALP-0208 | client | no retry | The wallet was not found. Verify the address and confirm the wallet has finished indexing. |
| DALP-0180 | operational | no retry | The wallet has no installed weighted multisig validator. |
| DALP-0195 | permission | no retry | The caller is not an active signer on the wallet's multisig validator, or the active signer differs from the session's signing address. Sign in with that signer. |
| DALP-0181 | client | no retry | No approval exists for the supplied user operation hash, or its stored preview state no longer reproduces the hash. Recreate the approval if the preview has drifted. |
| DALP-0184 | permission | no retry | The approval exists but does not belong to the wallet in the path. Cross-wallet signature submission is not allowed. |
| DALP-0024 | client | idempotent | The signature was not accepted. The approval may have already been signed by this signer, expired, or moved out of the pending state. This code also returns when the hash belongs to the bundler approval flow, which you co-sign through the bundler SDK client or UserOperation REST resource instead. |
| DALP-0281 | dependency | operator | The directory contract address is not configured in network config. This needs operator follow-up. |
| DALP-0282 | client | retry once | The entry point was not found in the indexer for this system. Retry once the indexer has processed the directory state. |
Fix client and permission codes from the caller side: correct the request, the signer identity, or the wallet scope, then retry. DALP-0024 on a repeat signature is expected and idempotent. DALP records each signer's weight only once and re-signals submission for an already-submitted approval rather than reopening it. DALP-0282 clears once the indexer catches up. DALP-0013, DALP-0201, and DALP-0281 are platform-side conditions that need operator follow-up rather than a request change.
Related
Smart wallet integration tutorial
A step-by-step tutorial that takes you from confirming advanced accounts is active to submitting your first transaction through a participant's smart wallet.
Smart wallet multisig threshold API
Update and validate the approval threshold for a DALP smart wallet that uses weighted multisig signing.