Skip to content

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.

  • 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

Before setting up Keystation, you need:

  1. A Flex vault with your user as a signer
  2. A Personal Access Token (PAT) — see Authentication
  3. An MPC backup file exported from the Tholos mobile app
  4. The decryption password you set when creating the backup

Keystation exposes two endpoints:

EndpointPurpose
POST /signLow-level MPC signing — signs a single hash using your key share
POST /flex-signFull Flex vault flow — approve, sign, and broadcast a transaction

The /flex-sign endpoint handles the complete Flex vault lifecycle:

  1. Get a challenge from the Tholos API for the transaction
  2. Sign the challenge and approve concurrently — Keystation signs the challenge using its EdDSA key share while the API verifies the approval
  3. Check the threshold — if not enough approvals yet, return the current count
  4. Initiate signing — request Sodot rooms for each unsigned transaction hash
  5. Sign all hashes — sign using ECDSA or EdDSA depending on the chain
  6. Broadcast — submit the signed transaction to the blockchain
  1. Export your MPC backup from the Tholos mobile app. This produces a file containing your encrypted ECDSA and EdDSA key shares for the vault.

  2. Place the backup file named backup in the Keystation working directory.

  3. Configure environment variables:

    VariableRequiredDescription
    DECRYPTION_PASSWORDYesPassword to decrypt the MPC backup file
    THOLOS_API_URLFor FlexTholos API base URL (https://api.tholos.app)
    THOLOS_API_TOKENFor FlexYour Personal Access Token (tholos_pat_...)
    TLS_CERT_FILENoTLS certificate file path (enables HTTPS)
    TLS_KEY_FILENoTLS key file path (enables HTTPS)
    AWS_SECRET_ARNNoAWS 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 the DECRYPTION_PASSWORD environment variable.

  4. Start Keystation:

    Terminal window
    DECRYPTION_PASSWORD="your-password" \
    THOLOS_API_URL="https://api.tholos.app" \
    THOLOS_API_TOKEN="tholos_pat_your_token" \
    ./keystation

    Keystation starts on port 8080 (HTTP) or 443 (HTTPS if TLS is configured). The /flex-sign endpoint is only registered when both THOLOS_API_URL and THOLOS_API_TOKEN are set.

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.

Terminal window
curl -X POST http://localhost:8080/flex-sign \
-H "Content-Type: application/json" \
-d '{
"transactionId": 12345,
"roomId": "abc123-room-id"
}'

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
}

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.

Terminal window
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).

Keystation auto-generates an OpenAPI specification with full request/response schemas:

  • Spec: GET /openapi.json
  • Interactive docs: GET /docs
  • Run Keystation in a private network — it should not be publicly accessible
  • Use TLS in production (TLS_CERT_FILE and TLS_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