What you can build
The example sidecar validates Aptos signing requests, which Turnkey does not currently parse natively. Other use cases require extending the example.
Architecture
Your application submits activities as an initiator user. Turnkey evaluates the applicable policies and collects approvals. The sidecar runs your custom checks inside a TVC enclave and votes as a separate service user. For signing, the transaction signing key stays in Turnkey. The sidecar uses an API credential derived from its long-lived TVC Quorum Key to approve or reject the activity.TVC quorum keys: Turnkey supports creating and storing quorum key shares in its key management platform. Hosted quorum keys are secured by Turnkey: key generation, signing, and share re-encryption are all inside enclaves. See the hosted-operator example for setup.
Activity approval flow
The sidecar verifies the webhook signature, freshness, and organization before evaluating the activity.- Your application submits a request; its submission counts as the initiator’s approval.
- Turnkey records the activity as awaiting consensus and sends a signed webhook.
- The sidecar evaluates the activity and submits an approval or rejection for supported requests.
- Turnkey evaluates the vote and completes the activity, rejects it, or continues waiting for approvals.
Choosing an approval model
The same API credential, webhook verification, and voting mechanism provide the foundation for either model. Changes to root membership and threshold require approval from the current root quorum.
The example sidecar ignores administrative activities. Before making it a required root member, add explicit validation for the administrative actions it must approve, including root-quorum updates where needed.
Implementation steps
Explore the complete implementation in the TVC policy sidecar example.
1
Deploy the policy sidecar
Follow the example’s deployment instructions. They use hosted operators to create and provision a private Quorum Key. Replace the publicly known quorum key: the sidecar uses the quorum key as a Turnkey credential.Configure the sidecar for your Turnkey organization, approve the deployment, and provision its shares after verification. Once live, keep its public URL for registration.
2
Register the sidecar in Turnkey
Retrieve the deployed sidecar’s public key from
GET /turnkey/api_public_key and register it, with the returned curve type, on a dedicated non-root service user. Use the returned key rather than generating another keypair.Create a separate non-root initiator user with its own credential and a Turnkey-owned Ed25519 signing key with an Aptos address. Two credentials on the same user do not provide two independent approvals.3
Require the sidecar's approval
Create a policy requiring both users, scoped to the intended wallet:Replace the placeholders with your wallet and user IDs. Keep the policy’s scope aligned with the activities the sidecar can validate.
4
Connect activity webhooks
Create a webhook endpoint in the same organization, using your deployed app’s URL with the path
/webhooks/turnkey/activity. Subscribe it to ACTIVITY_UPDATES so the sidecar receives pending activities and can vote.5
Submit and check a request
Submit a supported Aptos raw-signing request with the initiator’s credential. Confirm that the activity enters
ACTIVITY_STATUS_CONSENSUS_NEEDED, then inspect the sidecar’s vote and final activity result.Ignored activities can remain pending. An API submission failure is separate from a policy rejection. Successful signing returns a signature; it does not fund or broadcast the transaction.
Extending the example to Sui and Stellar
Some signing flows submit a transaction digest rather than the full transaction. To apply custom checks, the sidecar needs the original transaction data and must verify that it produces the digest being signed. This requires extending both the client and the example sidecar. Turnkey preserves extra top-level fields in an API-key-stamped activity request. Your application can include a field such assuiContext or stellarContext alongside type, timestampMs, organizationId, and parameters. Turnkey does not interpret this context; your TVC sidecar defines its format and validation rules.
- Include the transaction context. For Sui, include the serialized transaction bytes needed to reconstruct the intent message. For Stellar, include the transaction envelope XDR and network passphrase. Add this context before stamping the request, and send the exact body that was stamped. Update the client’s request construction so the extra field is preserved.
- Compute the digest as usual. Use your existing signing flow to compute the transaction digest and submit it in
parameters.payload, with the additional context alongside the request’s standard fields. - Read the context in the sidecar. After verifying the webhook, fetch the activity in your sidecar logic. The original request is available as a JSON string in the initiating vote’s
messagewithinactivity.votes, rather than in the parsedintent. Identify the original request by checking that the SHA-256 hash of its exact message bytes matches the activity’ssha256:fingerprint, then read your context field. - Validate before voting. Parse the supplied transaction and independently reconstruct its signing digest, including Sui’s intent prefix or Stellar’s network-specific signature base. Your sidecar should require an exact match with the activity’s signing payload in addition to evaluating the rest of the policies.