Server-Side Signing
Run MPC signing on a server using Keystation, replacing the mobile app as the user party in Flex vault transactions.
Keystation is a lightweight signing service that loads your MPC key shares and participates in Sodot MPC ceremonies on the server. It replaces the Tholos mobile app as the user party, enabling fully programmatic transaction approval and signing for Flex vaults.
When to use server-side signing
Section titled “When to use server-side signing”- Automated treasury operations (scheduled transfers, payroll)
- Trading bots and DeFi strategies
- Backend services that need to sign on behalf of a vault member
- CI/CD pipelines that deploy or interact with smart contracts
Prerequisites
Section titled “Prerequisites”Before setting up Keystation, you need:
- A Flex vault with your user as a signer
- A Personal Access Token (PAT) — see Authentication
- An MPC backup file exported from the Tholos mobile app
- The decryption password you set when creating the backup
How it works
Section titled “How it works”Keystation exposes two endpoints:
| Endpoint | Purpose |
|---|---|
POST /sign | Low-level MPC signing — signs a single hash using your key share |
POST /flex-sign | Full Flex vault flow — approve, sign, and broadcast a transaction |
The /flex-sign endpoint handles the complete Flex vault lifecycle:
- Get a challenge from the Tholos API for the transaction
- Sign the challenge and approve concurrently — Keystation signs the challenge using its EdDSA key share while the API verifies the approval
- Check the threshold — if not enough approvals yet, return the current count
- Initiate signing — request Sodot rooms for each unsigned transaction hash
- Sign all hashes — sign using ECDSA or EdDSA depending on the chain
- Broadcast — submit the signed transaction to the blockchain
-
Export your MPC backup from the Tholos mobile app. This produces a file containing your encrypted ECDSA and EdDSA key shares for the vault.
-
Place the backup file named
backupin the Keystation working directory. -
Configure environment variables:
Variable Required Description DECRYPTION_PASSWORDYes Password to decrypt the MPC backup file THOLOS_API_URLFor Flex Tholos API base URL ( https://api.tholos.app)THOLOS_API_TOKENFor Flex Your Personal Access Token ( tholos_pat_...)TLS_CERT_FILENo TLS certificate file path (enables HTTPS) TLS_KEY_FILENo TLS key file path (enables HTTPS) AWS_SECRET_ARNNo AWS Secrets Manager ARN for the password The decryption password is loaded from (in order): AWS Secrets Manager, a Docker secret at
/run/secrets/decryption_password, or theDECRYPTION_PASSWORDenvironment variable. -
Start Keystation:
Terminal window DECRYPTION_PASSWORD="your-password" \THOLOS_API_URL="https://api.tholos.app" \THOLOS_API_TOKEN="tholos_pat_your_token" \./keystationKeystation starts on port
8080(HTTP) or443(HTTPS if TLS is configured). The/flex-signendpoint is only registered when bothTHOLOS_API_URLandTHOLOS_API_TOKENare set.
Approve and sign a Flex vault transaction
Section titled “Approve and sign a Flex vault transaction”The /flex-sign endpoint handles transactions that already exist on the Tholos API. Create the transaction first using the Send a Transaction flow, then use Keystation to approve and sign it.
curl -X POST http://localhost:8080/flex-sign \ -H "Content-Type: application/json" \ -d '{ "transactionId": 12345, "roomId": "abc123-room-id" }'const response = await fetch("http://localhost:8080/flex-sign", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ transactionId: 12345, roomId: "abc123-room-id", }),});const result = await response.json();console.log(result.status); // "approved" or "broadcast"If the threshold is met, Keystation automatically signs and broadcasts:
{ "status": "broadcast", "currentApprovals": 2, "approvalsRequired": 2, "transactionHash": "0x1234567890abcdef..."}If more approvals are needed, it returns the current count:
{ "status": "approved", "currentApprovals": 1, "approvalsRequired": 2}Sign a raw hash
Section titled “Sign a raw hash”The /sign endpoint performs low-level MPC signing without interacting with the Tholos API. Use this when you need to sign arbitrary data as part of a custom workflow.
curl -X POST http://localhost:8080/sign \ -H "Content-Type: application/json" \ -d '{ "unsignedHash": "32c0436983f80b26220bb3f266ce1bc1d73f589ce3ed1e0ea419f8e4b1787d1a", "signingScheme": "ECDSA", "sodotRoomID": "8e04ee8f5e085ce8ecca24fb67235e58" }'ECDSA is used for EVM chains, Bitcoin, and TRON. The hash must be exactly 64 hex characters (32 bytes).
curl -X POST http://localhost:8080/sign \ -H "Content-Type: application/json" \ -d '{ "unsignedHash": "a1b2c3d4e5f6...", "signingScheme": "EDDSA", "sodotRoomID": "8e04ee8f5e085ce8ecca24fb67235e58" }'EdDSA is used for Solana, Cosmos, and SUI chains. The hash can be any length.
OpenAPI spec
Section titled “OpenAPI spec”Keystation auto-generates an OpenAPI specification with full request/response schemas:
- Spec:
GET /openapi.json - Interactive docs:
GET /docs
Security considerations
Section titled “Security considerations”- Run Keystation in a private network — it should not be publicly accessible
- Use TLS in production (
TLS_CERT_FILEandTLS_KEY_FILE) - Store the decryption password in AWS Secrets Manager or Docker secrets, not as a plaintext environment variable
- The PAT carries your account’s full permissions — restrict the token’s scope and set an expiration date
- Rotate your PAT regularly using the token rotation endpoint
Next steps
Section titled “Next steps”- Send a Transaction — create transactions to approve with Keystation
- Vaults — understand Flex vault architecture
- Authentication — manage Personal Access Tokens
- API Reference — browse all Tholos API endpoints