HTTP REST API server for the multisig coordinator, powered by the multisig engine.
The server is built with axum and wraps the multisig engine to expose HTTP endpoints for multisig operations. All business logic is handled by the engine - the server layer simply handles HTTP request/response serialization and validation.
On startup, the server:
- Establishes a PostgreSQL connection pool.
- Creates and starts a
MultisigEnginewith a dedicated Miden runtime thread. - Wraps the engine in an
Appstate accessible to all route handlers. - Binds to the configured TCP listener.
Configuration is loaded from base_config.ron and can be overridden via environment variables with the prefix MIDENMULTISIG_.
Config(
app: AppConfig(
listen: "localhost:59059",
network_id_hrp: "mtst",
cors_allowed_origins: ["*"],
),
db: DbConfig(
db_url: "postgres://multisig:multisig_password@localhost:5432/multisig",
max_conn: 10,
),
miden: MidenConfig(
node_url: "https://rpc.testnet.miden.io:443",
store_path: "./store",
keystore_path: "./keystore",
timeout: "30s",
),
)The cors_allowed_origins field controls which origins can make cross-origin requests to the server:
- Empty array
[]: CORS is disabled - Specific origins: Only listed origins are allowed, e.g.,
["http://localhost:3000", "https://example.com"] - Wildcard
["*"]: All origins are allowed (permissive mode, default for development)
By default, the base configuration uses ["*"] to allow all CORS requests for local development convenience. For production deployments, it's recommended to override this with specific allowed origins.
Use double underscores (__) to override nested configuration fields:
# override app config
export MIDENMULTISIG_APP__LISTEN="0.0.0.0:8080"
export MIDENMULTISIG_APP__NETWORK_ID_HRP="mtst"
# configure CORS allowed origins for specific origins
export MIDENMULTISIG_APP__CORS_ALLOWED_ORIGINS='["http://localhost:3000", "http://example.com"]'
# override database config
export MIDENMULTISIG_DB__DB_URL="postgres://user:pass@db-host:5432/multisig"
export MIDENMULTISIG_DB__MAX_CONN="20"
# override miden config
export MIDENMULTISIG_MIDEN__NODE_URL="https://rpc.testnet.miden.io:443"
export MIDENMULTISIG_MIDEN__STORE_PATH="./miden-store.sqlite3"
export MIDENMULTISIG_MIDEN__KEYSTORE_PATH="./keystore"
export MIDENMULTISIG_MIDEN__TIMEOUT="60s"Before starting the server, ensure database migrations have been run. See the database migrations section for detailed instructions.
# using cargo
cargo run --bin miden-multisig-coordinator-server --releaseCheck if the server is running.
curl -X GET http://localhost:59059/healthResponse: 200 OK
Creates a new multisig account with specified approvers and threshold.
Endpoint: POST /api/v1/multisig-account/create
curl -X POST http://localhost:59059/api/v1/multisig-account/create \
-H "Content-Type: application/json" \
-d '{
"threshold": 2,
"approvers": [
"mtst1abc...",
"mtst1def...",
"mtst1ghi..."
],
"pub_key_commits": [
"<base64_encoded_public_key_1>",
"<base64_encoded_public_key_2>",
"<base64_encoded_public_key_3>"
]
}'Response:
{
"address": "mtst1xyz...",
"created_at": "2025-10-19T12:00:00Z",
"updated_at": "2025-10-19T12:00:00Z"
}Proposes a new transaction for a multisig account.
Endpoint: POST /api/v1/multisig-tx/propose
curl -X POST http://localhost:59059/api/v1/multisig-tx/propose \
-H "Content-Type: application/json" \
-d '{
"multisig_account_address": "mtst1xyz...",
"tx_request": "<base64_encoded_transaction_request>"
}'Response:
{
"tx_id": "550e8400-e29b-41d4-a716-446655440000",
"tx_summary": "<base64_encoded_transaction_summary>"
}Submits an approver's signature for a pending transaction. If the signature threshold is met, the transaction is automatically processed.
Endpoint: POST /api/v1/signature/add
curl -X POST http://localhost:59059/api/v1/signature/add \
-H "Content-Type: application/json" \
-d '{
"tx_id": "550e8400-e29b-41d4-a716-446655440000",
"approver": "mtst1abc...",
"signature": "<base64_encoded_signature>"
}'Response:
{
"tx_result": "<base64_encoded_transaction_result_if_threshold_met>"
}Note: tx_result is either null if threshold is not yet met, or contains the base64-encoded transaction result if the transaction was executed.
Retrieves consumable notes' note-ids for an account tracked by the coordinator.
Endpoint: POST /api/v1/consumable-notes/list
# get consumable notes for a specific account
curl -X POST http://localhost:59059/api/v1/consumable-notes/list \
-H "Content-Type: application/json" \
-d '{
"address": "mtst1xyz..."
}'
# get all consumable notes (across all accounts)
curl -X POST http://localhost:59059/api/v1/consumable-notes/list \
-H "Content-Type: application/json" \
-d '{
"address": null
}'Response:
{
"note_ids": [
{
"note_id": "0xabc123...",
"note_id_file_bytes": "<base64_encoded_note_file>"
},
{
"note_id": "0xdef456...",
"note_id_file_bytes": "<base64_encoded_note_file>"
},
{
"note_id": "0x789ghi...",
"note_id_file_bytes": "<base64_encoded_note_file>"
}
]
}Retrieves details of a multisig account.
Endpoint: POST /api/v1/multisig-account/details
curl -X POST http://localhost:59059/api/v1/multisig-account/details \
-H "Content-Type: application/json" \
-d '{
"multisig_account_address": "mtst1xyz..."
}'Response:
{
"multisig_account": {
"address": "mtst1xyz...",
"kind": "public",
"threshold": 2,
"created_at": "2025-10-19T12:00:00Z",
"updated_at": "2025-10-19T12:00:00Z"
}
}Lists all approvers for a specific multisig account.
Endpoint: POST /api/v1/multisig-account/approver/list
curl -X POST http://localhost:59059/api/v1/multisig-account/approver/list \
-H "Content-Type: application/json" \
-d '{
"multisig_account_address": "mtst1xyz..."
}'Response:
{
"approvers": [
{
"address": "mtst1abc...",
"pub_key_commit": "<base64_encoded_public_key_1>"
},
{
"address": "mtst1def...",
"pub_key_commit": "<base64_encoded_public_key_2>"
},
{
"address": "mtst1ghi...",
"pub_key_commit": "<base64_encoded_public_key_3>"
}
]
}Retrieves transaction statistics for a multisig account.
Endpoint: POST /api/v1/multisig-tx/stats
curl -X POST http://localhost:59059/api/v1/multisig-tx/stats \
-H "Content-Type: application/json" \
-d '{
"multisig_account_address": "mtst1xyz..."
}'Response:
{
"tx_stats": {
"total": 42,
"last_month": 15,
"total_success": 38
}
}Lists all transactions for a multisig account, optionally filtered by status.
Endpoint: POST /api/v1/multisig-tx/list
# list all transactions
curl -X POST http://localhost:59059/api/v1/multisig-tx/list \
-H "Content-Type: application/json" \
-d '{
"multisig_account_address": "mtst1xyz...",
"tx_status_filter": null
}'
# filter by status (pending/success/failure)
curl -X POST http://localhost:59059/api/v1/multisig-tx/list \
-H "Content-Type: application/json" \
-d '{
"multisig_account_address": "mtst1xyz...",
"tx_status_filter": "pending"
}'Response:
{
"txs": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"multisig_account_address": "mtst1xyz...",
"status": "pending",
"tx_request": "<base64_encoded_transaction_request>",
"tx_summary": "<base64_encoded_transaction_summary>",
"tx_summary_commit": "<base64_encoded_transaction_summary_commitment>",
"input_note_ids": [
{
"note_id": "0xabc123...",
"note_id_file_bytes": "<base64_encoded_note_file>"
}
],
"signature_count": 1,
"created_at": "2025-10-19T12:00:00Z",
"updated_at": "2025-10-19T12:00:00Z"
}
]
}Note: signature_count is omitted if zero.