Sign Service is a lightweight, stateless Bitcoin signing microservice built on top of BDK (Bitcoin Dev Kit) and Axum.
It provides HTTP APIs to:
- Derive Bitcoin keys and addresses from a mnemonic and derivation path
- Sign Bitcoin PSBTs (Partially Signed Bitcoin Transactions) using a mnemonic
- Run without persistent storage (in-memory only)
The service is designed for backend systems, wallets, and automation services that require deterministic Bitcoin key derivation and transaction signing.
This service can be used to:
- Act as a remote Bitcoin signer
- Derive xprv / xpub / address from a BIP-39 mnemonic
- Sign PSBTs generated by external systems (wallets, indexers, trading systems)
- Integrate Bitcoin signing logic into backend services without embedding wallet logic everywhere
Typical use cases include:
- Custody or semi-custodial signing services
- Automated Bitcoin transaction pipelines
- Backend services that separate transaction construction and signing
- Multi-account or multi-derivation-path key management systems
| Module | Description |
|---|---|
| Axum HTTP Server | Provides REST APIs |
| BDK Wallet | Used for descriptor-based signing |
| BIP-39 | Mnemonic parsing |
| BIP-32 | HD key derivation |
| Miniscript | Descriptor parsing and validation |
- Stateless: No wallet or database persistence
- Descriptor-based: Uses
wpkh()descriptors - In-memory wallet: Wallet is created per request
- Network-aware: Supports different Bitcoin networks via config
GET /health
Returns service health status.
Response
ok
POST /get_pubkey_addres
Derives xprv, xpub, and a Bitcoin address from a mnemonic and derivation path.
{
"mnemonic": "abandon abandon abandon ...",
"derivation_path": "m/84h/827166h/0h"
}{
"xprv": "wpkh(tprv...)",
"xpub": "wpkh(tpub...)",
"address": "bc1q..."
}derivation_pathis the account-level path- The service internally derives the first external address (
/0/0) - Returned
xprvandxpubare descriptor-formatted
POST /sign_tx
Signs a PSBT using the provided mnemonic.
{
"mnemonic": "abandon abandon abandon ...",
"psbt": "cHNidP8BA..."
}
psbtmust be base64-encoded.
{
"tx_hex": "0200000001...",
"txid": "abcdef1234..."
}- The PSBT must be constructed using the same derivation path as the signer
- The signer derives keys using a fixed internal derivation path
- If derivation paths do not match exactly, signing will fail
curl -X POST http://127.0.0.1:8080/get_pubkey_addres \
-H "Content-Type: application/json" \
-d '{
"mnemonic": "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
"derivation_path": "m/84h/827166h/0h"
}'curl -X POST http://127.0.0.1:8080/sign_tx \
-H "Content-Type: application/json" \
-d '{
"mnemonic": "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
"psbt": "cHNidP8BAFICAAAA...",
"derivation_path": "m/84h/827166h/0h"
}'Create a config.toml file:
port = 8080
network = "bitcoin"Supported networks:
bitcointestnetregtestsignet
cargo run --release -- config.tomlThe service will start listening on:
0.0.0.0:<port>
- Call
/get_pubkey_addres - Receive address
- Use this address to receive BTC
-
Use your own wallet, indexer, or library
-
Construct PSBT spending UTXOs from the derived address
-
Ensure:
- Correct
bip32_derivation - Correct derivation path
- Correct network
- Correct
- Send PSBT to
/sign_tx - Service signs and finalizes the transaction
- Receive raw transaction hex and txid
- Broadcast using your preferred Bitcoin node or API
-
Never expose mnemonics over public networks
-
This service assumes a trusted internal environment
-
Consider:
- TLS termination
- Request authentication
- Network isolation
- Hardware-backed key management for production
- Single-key
wpkhonly - No multisig support
- No descriptor wildcard support in signing
- Stateless (no UTXO tracking)
- Not a full wallet implementation
Private / Internal use only.