Your organization’s configured signer must generate the Turnkey approval stamp outside Ground’s servers. Ground receives the stamp and validates it against the pending activity before forwarding the vote to Turnkey.
When approvals happen
Set up signing before you need to withdraw. In production, a request that
would take your organization’s cumulative withdrawals above 200 is allowed without signing. The total includes
pending withdrawals across all organization wallets; cancelled and failed
withdrawals do not count. Set up signing in
Ground Portal → Settings → Signing.
Organizations with limited self-serve access have a separate $100 cumulative
production withdrawal limit.
- Withdrawals (
POST /v2/wallets/{id}/withdrawals): when signing is enabled, each payout leg transitions topending_customer_approvalwhen it’s ready for signing. - Stellar deposit setup (
POST /v2/wallets/{id}/deposit-addresses/{chain}/enable): Ground creates astellar_trustlineactivity that authorizes the wallet to receive Circle USDC.
walletId + chain. If multiple activities become ready on the same chain, later activities queue behind the earlier approval automatically.
What does not require approval
Strategy updates (PATCH /v2/wallets/{id}/strategy) do not require this organization approval flow. They are API-authenticated requests; later rebalances may still be executed by Ground under the wallet’s configured policy.
Detecting a pending approval
When a withdrawal payout needs approval,payoutLegs[].status and the external payout step state become pending_customer_approval. Poll GET /v2/wallets/:id/withdrawals/:withdrawalId or subscribe to portfolio_wallet.withdrawal.status_changed to detect this state.
For Stellar deposit setup, subscribe to portfolio_wallet.approval.status_changed. A pending event includes the activityId, activityKind, chain, and validity window.
After receiving either signal, call GET /v2/turnkey/activities/pending to fetch the approval details and activity fingerprint for the authenticated organization.
Approving an activity
- Capture the pending activity from the relevant webhook, withdrawal response, or withdrawal status response.
- Fetch the matching activity from
GET /v2/turnkey/activities/pending. - Verify the transaction details (see best practice below).
- Request the Turnkey approval or rejection payload from
POST /v2/turnkey/activity-approval-request. - Stamp
stampPayloadwith your organization signer in infrastructure you control. - Submit the stamp with
POST /v2/turnkey/activities/{activityId}/vote. - Processing continues automatically once approved.
turnkeyRequest object and a stampPayload string. Stamp stampPayload locally with the organization signer, then submit the resulting Turnkey stamp:
Stamping the approval payload
Ground does not stamp the Turnkey approval for you. Your integration must createcustomerApprovalStamp by passing the exact stampPayload string to your organization’s Turnkey-compatible stamper. The API field retains the name customerApprovalStamp.
For a machine signer, stamp the payload from your own backend or signing service:
Enable signing and register a machine signing key at Ground Portal → Settings → Signing. See dashboard and signer setup for enrollment and the exact controls. Ground API keys authenticate API requests. Approval signing keys authorize activities and must be stored separately.
The Portal displays a compressed public key as hex and exports the private key as PKCS#8 PEM. ApiKeyStamper expects the private scalar as hex. If using the Portal export, convert it locally in your Node.js signing service when loading the secret:
apiPrivateKey from this conversion. If your secret is already the hexadecimal private scalar, set apiPrivateKey from TURNKEY_API_PRIVATE_KEY instead. TURNKEY_API_PUBLIC_KEY is the matching public hex value from the Portal. Never log either private-key representation.
TURNKEY_API_PRIVATE_KEY, raw passkey material, or any other signing secret to Ground. Ground only needs the customerApprovalStamp object, the original turnkeyRequest, and the intended action.
Verify before you approve
When your system receives a pending approval, verify the activity before signing. Once an approved transaction is broadcast, it cannot be reversed.Withdrawal payouts
- Destination address — confirm the pending activity’s
destinationAddressmatches the address your system originally submitted in the withdrawal request. Reject it if the address does not match. - Amount — confirm the displayed amount is reasonable for the withdrawal and yield source. Asynchronous sources may not exactly match the originally requested amount.
- Chain and token — confirm
destinationChainanddestinationTokenmatch your request, including the exact sandbox network. Validate the destination using the network’s address format. - Withdrawal correlation — match the pending approval to a withdrawal your system initiated. Reject orphaned, expired, or unexpected approvals.
Stellar deposit setup
For astellar_trustline activity, confirm the wallet ID, activity ID, activity kind, stellar or stellar_testnet chain, and activity fingerprint match a deposit setup your system initiated. This activity has no withdrawal destination or payout amount. Reject orphaned, expired, or unexpected approvals.
Example verification flow:
Automation patterns
Two patterns work well for handling approvals:- Webhook-driven — subscribe to
portfolio_wallet.withdrawal.status_changedfor withdrawal payouts andportfolio_wallet.approval.status_changedfor Stellar setup. When an approval becomes pending, fetchGET /v2/turnkey/activities/pending, verify the details, requestPOST /v2/turnkey/activity-approval-request, stamp the returnedstampPayloadlocally, and submit the vote. - Polling-driven — for withdrawals, poll
GET /v2/wallets/:id/withdrawals/:withdrawalIdand checkpayoutLegs[].statusandpayoutLegs[].steps[].state. PollGET /v2/turnkey/activities/pendingas the approval backstop.
Status updates
Subscribe to these events to monitor progress:portfolio_wallet.withdrawal.status_changedportfolio_wallet.withdrawal.payout.status_changedportfolio_wallet.approval.status_changed
failed with a failureReason.
Approval authorizes signing. Continue tracking each payout and its withdrawal until completed; see Withdraw Funds.