# Authentication
Source: https://docs.mpcvault.com/api-reference/authentication
How to authenticate with the MPCVault API.
All API requests require the `x-mtoken` header with your API token.
## Getting Your Token
1. Log in to your MPCVault Dashboard
2. Navigate to **Settings > API**
3. Generate a new API token
4. Store it securely - it won't be shown again
## Using Your Token
Include the token in the `x-mtoken` header:
```bash theme={null}
curl -X POST https://api.mpcvault.com/v1/getWalletList \
-H "Content-Type: application/json" \
-H "x-mtoken: YOUR_API_TOKEN" \
-d '{"vaultUuid": "your-vault-uuid","page":"0","limit":"10"}'
```
## Security Best Practices
* **TLS Required** - All requests must use TLS 1.2+
* **IP Allowlist** - Restrict API access to specific IPs in the Dashboard
* **Token Safety** - Never expose tokens in client-side code or version control
* **Rotate Regularly** - Generate new tokens periodically and revoke old ones
# Data types and encodings
Source: https://docs.mpcvault.com/api-reference/data-types
How every field of the REST and gRPC APIs is encoded.
The REST API is a JSON mapping of the gRPC API. Both expose the same messages, so every field has one type and two encodings: its protobuf type over gRPC, and the JSON value described below over REST.
## JSON conventions
* Requests and responses use `Content-Type: application/json` and UTF-8.
* Responses use `lowerCamelCase` field names (`vaultUuid`). Requests also accept the `snake_case` name (`vault_uuid`). Unknown request fields are ignored without an error, so a misspelled optional field is read as omitted: for example, a misspelled `callbackClientSignerPublicKey` sends a transaction or structured message request to the MPCVault app for manual signing.
* Every field of a message is present in a response. A scalar that is unset has its zero value (`""`, `"0"`, `false`, the first enum value, `[]`). A message or wrapper that is unset is `null`.
* A field that belongs to a `oneof` is present only when it is set, so a response contains at most one of the members.
* Field order is not significant.
* The OpenAPI schemas list the canonical form: `lowerCamelCase` names, enum names and decimal strings for 64-bit integers. The other forms in the table below are accepted but not listed.
## Types
| Protobuf type | JSON in responses | JSON accepted in requests | gRPC |
| - | - | - | - |
| `string` | UTF-8 string | string | UTF-8 string |
| `bool` | `true` or `false` | boolean | bool |
| `int32`, `uint32` | number | number or decimal string | varint |
| `int64`, `uint64` | **decimal string**, for example `"1759400600000"` | decimal string or number | varint (64-bit) |
| `bytes` | **base64**, standard alphabet (`A-Z a-z 0-9 + /`) with `=` padding | base64, standard or URL-safe, padded or not | raw bytes |
| enum | the value name, for example `"STATUS_PENDING"` | the value name or its number | varint |
| message | object; `null` when unset | object, or omitted | nested message |
| `repeated` | array; `[]` when empty | array | repeated field |
| `google.protobuf.StringValue` | string, or `null` when unset | string or `null` | wrapper message |
| `google.protobuf.Int64Value` | decimal string, or `null` when unset | decimal string, number or `null` | wrapper message |
| `google.protobuf.BoolValue` | `true`, `false` or `null` when unset | boolean or `null` | wrapper message |
An enum can gain values. Treat a name you do not recognize as unknown instead of failing.
## Field conventions
These conventions hold across the API. A field that follows another rule says so in its description.
* **Timestamps** are Unix time in milliseconds, in a 64-bit integer (a decimal string in JSON).
* **UUIDs** are hyphenated strings in the form `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`.
* **Amounts** are decimal strings in the unit stated by the field (for example wei, satoshi or lamports), never floating-point numbers. A request created through the API holds an integer in that unit. For a request created in the MPCVault app, the stored amount is returned scaled to that unit without rounding, so it can have a fractional part if more precision was entered than the unit has. The stored amount can differ from the amount entered (for example, a Bitcoin send is capped to the value of the first 30 spendable outputs less a reserve for the fee).
* **Addresses** use the address format of the field's network. The signing request payloads state the format of each address field.
* **Hex strings** are stated as such in the field description, with or without the `0x` prefix as that field specifies.
# API Errors
Source: https://docs.mpcvault.com/api-reference/errors
Understanding and handling MPCVault API errors.
## Error Response Format
All errors return a JSON object with an `error` field:
```json theme={null}
{
"error": {
"code": "INVALID_ARGUMENT",
"message": "vaultUuid is required"
}
}
```
## Common Error Codes
| Code | Description |
| - | - |
| `INVALID_ARGUMENT` | Missing or invalid request parameters |
| `NOT_FOUND` | Resource (wallet, signing request) not found |
| `PERMISSION_DENIED` | API token lacks required permissions |
| `UNAUTHENTICATED` | Missing or invalid API token |
| `ALREADY_EXISTS` | Resource already exists (e.g., duplicate ref) |
| `FAILED_PRECONDITION` | Operation not allowed in current state |
| `RESOURCE_EXHAUSTED` | Rate limit exceeded |
| `INTERNAL` | Internal server error |
## HTTP Status Codes
| Status | Meaning |
| - | - |
| `200` | Success |
| `400` | Bad request - check your parameters |
| `401` | Unauthorized - check your API token |
| `403` | Forbidden - insufficient permissions |
| `404` | Not found |
| `429` | Rate limited - slow down requests |
| `500` | Server error - retry later |
## Handling Errors
```python theme={null}
import requests
response = requests.post(
"https://api.mpcvault.com/v1/createWallet",
headers={"x-mtoken": "YOUR_API_TOKEN"},
json={"vaultUuid": "..."}
)
if response.status_code != 200:
error = response.json().get("error", {})
print(f"Error: {error.get('code')} - {error.get('message')}")
```
# gRPC vs REST
Source: https://docs.mpcvault.com/api-reference/grpc
Choose the right protocol for your integration.
MPCVault supports both gRPC and REST with identical functionality.
## Comparison
| | gRPC | REST |
| - | - | - |
| Endpoint | `api.mpcvault.com:443` | `https://api.mpcvault.com/v1` |
| Performance | Faster (binary protocol) | Standard HTTP/JSON |
| Client libraries | Auto-generated from Protobuf | Use any HTTP client |
| Best for | High-frequency operations | Simple integrations |
## REST Example
```bash theme={null}
curl -X POST https://api.mpcvault.com/v1/getWalletList \
-H "Content-Type: application/json" \
-H "x-mtoken: YOUR_API_TOKEN" \
-d '{"vaultUuid": "your-vault-uuid","page":"0","limit":"10"}'
```
## gRPC Example
```python theme={null}
import grpc
from mpcvault import wallet_pb2, wallet_pb2_grpc
# Create secure channel
channel = grpc.secure_channel(
'api.mpcvault.com:443',
grpc.ssl_channel_credentials()
)
# Create stub
stub = wallet_pb2_grpc.WalletServiceStub(channel)
# Make request with metadata
metadata = [('x-mtoken', 'YOUR_API_TOKEN')]
response = stub.GetWalletList(
wallet_pb2.GetWalletListRequest(vault_uuid="your-vault-uuid"),
metadata=metadata
)
```
## Protobuf Definitions
Full Protobuf definitions and examples are available at:
[github.com/mpcvault/mpcvaultapis](https://github.com/mpcvault/mpcvaultapis/)
# Idempotency
Source: https://docs.mpcvault.com/api-reference/idempotency
Safely retry API requests without duplicate operations.
For state-changing operations (creating wallets, signing requests), add an `idempotency-key` header to safely retry failed requests.
## Usage
```bash theme={null}
curl -X POST https://api.mpcvault.com/v1/createWallet \
-H "Content-Type: application/json" \
-H "x-mtoken: YOUR_API_TOKEN" \
-H "idempotency-key: 550e8400-e29b-41d4-a716-446655440000" \
-d '{"vaultUuid": "...", "networkType": "NETWORK_TYPE_ETHEREUM"}'
```
## Requirements
| Requirement | Description |
| - | - |
| Format | Client-generated unique value (UUID v4 recommended) |
| Max Length | 255 characters |
| Expiration | Keys expire after 24 hours |
## How It Works
1. Include a unique `idempotency-key` header with your request
2. If the request fails due to network issues, retry with the same key
3. MPCVault returns the cached response if the key was already used
4. This prevents duplicate wallet creation or transaction signing
## When to Use
* `createWallet` - Prevent duplicate wallet creation
* `createSigningRequest` - Prevent duplicate transaction requests
* `createBatchPayment` - Prevent duplicate batch payments
Read-only operations like `getWalletList` don't require idempotency keys.
# Introduction
Source: https://docs.mpcvault.com/api-reference/overview
Integrate MPCVault into your applications with our REST and gRPC APIs.
## Base URL
```
https://api.mpcvault.com/v1
```
For gRPC, connect to `api.mpcvault.com:443` with TLS.
## What You Can Build
* **Automated Transactions** - Create and execute transactions programmatically with API client signing
* **Deposit Addresses** - Generate unique deposit addresses for customer deposits across multiple chains
* **Batch Payments** - Process payroll, airdrops, and bulk transfers efficiently
* **Message Signing** - Sign messages and typed data for DeFi interactions and authentication
## Signing Flow
The signing process involves creating a request and then executing it:
```mermaid theme={null}
sequenceDiagram
participant App as Your Application
participant API as MPCVault API
participant Signer as Client Signer
participant Chain as Blockchain
App->>API: Create Signing Request
API-->>App: Request UUID + Details
App->>Signer: Execute Signing Request
Signer->>API: MPC Signing Protocol
API-->>Signer: Signature
Signer->>Chain: Broadcast Transaction
Chain-->>App: Transaction Hash
```
| Method | Use Case | How It Works |
| - | - | - |
| **Manual** | Human approval required | Request appears in MPCVault mobile app |
| **Programmatic** | Automated operations | API Client Signer executes automatically |
# CreateBatchPayment
Source: https://docs.mpcvault.com/api-reference/rest/create-batch-payment
openapi.json POST /v1/createBatchPayment
Create a batch payment to send tokens to multiple recipients. Complete the batch payment in the MPCVault web app.
Creates a batch payment in a single request. Complete and send the batch payment in the **MPCVault web app**. In the Try It playground, select a batch type from the tabs and fill in the required fields.
| Type | Use case |
| - | - |
| **EVM Batch Native / ERC20** | Batch send ETH or ERC20 tokens to multiple addresses |
| **BTC Batch Native** | Batch send BTC to multiple addresses |
| **Sui Batch Native / Coin** | Batch send SUI or Sui coins to multiple addresses |
# CreateSigningRequest
Source: https://docs.mpcvault.com/api-reference/rest/create-signing-request
openapi.json POST /v1/createSigningRequest
Create a signing request for a transaction or message. Complete it in the MPCVault app or via the API client signer.
Creates a signing request that can be completed in the **MPCVault mobile app** (manual) or with the **API client signer** (programmatic). In the Try It playground, select a transaction type from the tabs and fill in the required fields.
| Type | Use case |
| - | - |
| **EVM Send Native / ERC20 / Custom** | Send ETH, ERC20 tokens, or custom EVM transactions |
| **EVM Message** | Sign messages (e.g., dApp authentication) |
| **Tron / Solana / Sonic / Aptos / Sui / TON** | Native tokens, custom transactions, or message signing |
| **BTC Send Native** | Send BTC |
| **Raw Message** | Sign raw bytes |
# CreateWallet
Source: https://docs.mpcvault.com/api-reference/rest/create-wallet
openapi.json POST /v1/createWallet
Create a new EOA wallet in a vault for a given network.
Creates a new wallet in the specified vault. Use the returned `address` in the response (do not derive it yourself). Run your own sanity checks before using the wallet in production.
# ExecuteSigningRequests
Source: https://docs.mpcvault.com/api-reference/rest/execute-signing-requests
openapi.json POST /v1/executeSigningRequests
Execute a pending signing request with the API client signer.
Signs and executes a pending signing request. Only supported for **API wallets** that have a client signer configured. The response includes the signed transaction ready to broadcast.
# GetBalance
Source: https://docs.mpcvault.com/api-reference/rest/get-balance
openapi.json POST /v1/getBalance
Get native or token balance for a wallet address.
Returns the balance for a wallet address—native token or a specific ERC-20/SPL token. Balance is a string for precision; use the token’s decimals to convert (e.g. ETH 18, USDC 6, SOL 9).
# GetBatchPaymentDetails
Source: https://docs.mpcvault.com/api-reference/rest/get-batch-payment-details
openapi.json POST /v1/getBatchPaymentDetails
Get details and status of a batch payment.
Returns batch payment details by UUID, including status, recipient list, and associated signing requests. Use this endpoint to check progress or confirm completion.
# GetSigningRequestDetails
Source: https://docs.mpcvault.com/api-reference/rest/get-signing-request-details
openapi.json POST /v1/getSigningRequestDetails
Get a signing request: status, failure reason, transaction hash and payload.
Returns the signing request with the given UUID. Any request of a vault the API token can access is returned, whatever its status and however it was created: through the API, in the MPCVault app, or by a connected dApp (WalletConnect, plugin or MetaMask Institutional). Reading a request does not require a client signer.
The call fails with HTTP 400 (`InvalidArgument`, message `Invalid uuid`) when the request does not exist or the token cannot access its vault.
The response is a [SigningRequest object](/api-reference/signing-request): the common fields and one payload field whose name says what the request is, their encodings, and notes on `source` and `simulation`.
Everything MPCVault returns about a request, including `simulation` and `evmInputDataDecode`, is reference information, not a verification. See [Verify independently](/api-reference/signing-request#verify-independently).
# GetSigningRequestList
Source: https://docs.mpcvault.com/api-reference/rest/get-signing-request-list
openapi.json POST /v1/getSigningRequestList
List the signing requests of a vault, in any status, with pagination.
Returns the signing requests of a vault: pending, succeeded and failed, whether they were created through the API, in the MPCVault app or by a connected dApp. There is no status filter. Results are newest first by default.
Paginate with `page` (starting at 1) and `limit` (1 to 100, default 10). Set `sortOrder` to `SORT_ORDER_ASC` for oldest first. The call fails with HTTP 400 (`InvalidArgument`, message `Invalid uuid`) when the vault does not exist or the API token cannot access it.
Each element of `signingRequests` is a [SigningRequest object](/api-reference/signing-request): the common fields and at most one payload field, with their encodings. [Data types and encodings](/api-reference/data-types) lists the conventions that apply to all fields.
Every request in the response carries its full payload and simulation. A page of very large requests, for example 100 requests with about 128 KiB of calldata each (about 13 MB), exceeds the 10 MiB limit on the protobuf message that the REST gateway accepts from the gRPC server, and most gRPC clients accept 4 MiB by default. The call then fails with `RESOURCE_EXHAUSTED` (HTTP 429): request a smaller `limit`. A single request with very large calldata or simulation can exceed these limits on its own.
# GetWalletInfo
Source: https://docs.mpcvault.com/api-reference/rest/get-wallet-info
openapi.json POST /v1/getWalletInfo
Get a single wallet by address or customer reference.
Returns one wallet by its blockchain **address** or your **ref** (customer reference). Provide either `address` or `ref`, not both.
# GetWalletList
Source: https://docs.mpcvault.com/api-reference/rest/get-wallet-list
openapi.json POST /v1/getWalletList
List all wallets in a vault with pagination.
Returns all wallets in a vault. Use `page` and `limit` to paginate (e.g. `limit` 100, max 100 per page).
# RejectSigningRequest
Source: https://docs.mpcvault.com/api-reference/rest/reject-signing-request
openapi.json POST /v1/rejectSigningRequest
Reject a pending signing request.
Rejects a signing request. Once rejected, it cannot be reopened or executed. This action is irreversible.
# Resimulation
Source: https://docs.mpcvault.com/api-reference/rest/resimulation
openapi.json POST /v1/resimulation
Re-run the simulation of a pending signing request.
Re-runs the simulation of a pending signing request and returns the stored simulation. The encoding of `simulation` is described under [Simulation](/api-reference/signing-request#simulation): base64 in JSON, decoding to UTF-8 JSON text in a network-specific form, for reference only.
A successful re-run replaces the stored simulation with the result of the run. If the simulation provider returns an error, or the organization's simulation allowance is used up, the call still succeeds and `simulation` is empty. A simulation that does not finish within 5 seconds fails a custom transaction with an error, and returns the earlier stored simulation for a dApp transaction. A returned simulation therefore does not show that it was just re-run.
The request must be pending, belong to a vault the API token can access, and have been created by the same API user. Only custom transactions and EVM dApp transactions are simulated; for any other request `simulation` is empty.
| Failure | HTTP status | Message |
| - | - | - |
| `signingRequestUuid` is empty | 400 (`FailedPrecondition`) | `Signing request uuid required` |
| The request does not exist, is in another organization or an inaccessible vault, or was created by another API user | 400 (`InvalidArgument`) | `Invalid uuid` |
| The request is not pending | 400 (`FailedPrecondition`) | `Signing request already done` |
# SigningRequest object
Source: https://docs.mpcvault.com/api-reference/signing-request
The fields, payloads and encodings of a signing request.
A signing request is the object returned by [GetSigningRequestDetails](/api-reference/rest/get-signing-request-details) and [GetSigningRequestList](/api-reference/rest/get-signing-request-list). It has the common fields, which are always present, and at most one payload field. The name of the payload field says what the request is, and its body holds the details: the transfer, transaction or message the request asks the vault to sign.
Every field is listed below with its type and encoding. The conventions that apply to all of them are in [Data types and encodings](/api-reference/data-types).
## Fields
## Payload fields
At most one payload field is set on a request, and its name says what the request is. Names are given as in REST JSON; gRPC uses the snake\_case names (`evmSendNative` is `evm_send_native`).
| Request | Payload field |
| - | - |
| Transfer of a native coin | `evmSendNative`, `btcSendNative`, `tronSendNative`, `solanaSendNative`, `sonicSvmSendNative`, `suiSendNative`, `aptosSendNative`, `tonSendNative`, `stellarSendNative` |
| Transfer of a token | `evmSendErc20`, `tronSendTrc10`, `tronSendTrc20`, `solanaSendSplToken`, `sonicSvmSendSplToken`, `suiSendCoin`, `aptosSendCoin`, `tonSendToken`, `stellarSendAsset` |
| Custom transaction, including a transaction from a dApp | `evmSendCustom`, `solanaSendCustom`, `sonicSvmSendCustom`, `suiSendCustom`, `aptosSendCustom`, `tonSendCustom`, `stellarSendCustom` |
| Message to sign, including a message from a dApp | `evmMessage`, `solanaMessage`, `suiMessage`, `aptosMessage`, `tonMessage` |
| Raw message | `rawMessage` |
| Wallet creation | `createWallet` |
| Stellar trustline | `stellarChangeTrust` |
| Aptos account setup | `aptosRegisterCoin`, `aptosOpenToken` |
| Swap | `swapApproval`, `swapSend` |
| Batch payment | `batchPaymentApproval`, `batchPaymentSend` |
| Fiat payment | `fiatPayment` |
| Vault and keys | `vaultCreation`, `vaultSettingUpdate`, `rootKeyGeneration`, `rootKeyBackup`, `keyAccessGrant` |
A request from a dApp uses the same payload fields as a request created through the API or in the MPCVault app. `source` tells them apart: it is set only for dApp requests. The payload of a dApp request is the request as the dApp submitted it and MPCVault stored it; MPCVault does not check it again when it returns it.
### Payloads without fields
The payload fields in the last five rows have an empty body, for example `"fiatPayment": {}`. The field name is all the API returns about the request. Use the MPCVault app to view its details.
A kind of request added to MPCVault appears as a payload field of its own. Treat a request whose payload field you do not recognize as a kind you cannot inspect.
### Requests without a payload field
A request is returned without a payload field when the API has no body for it:
* a dApp message other than the ones listed above: an EVM `eth_sign` message, and Stellar messages and authorization entries;
* an Aptos dApp request to sign a transaction without submitting it, and a Stellar SEP-10 challenge transaction;
* a dApp transaction that arrived without a request method, or whose stored data cannot be returned, for example calldata that is not hex;
* a Stellar transfer or trustline whose asset is not an asset code and issuer, for example a token that is identified by a contract address.
Such a request is not fully supported by the API yet. Use the MPCVault app to view its details. `source` is set when the request came from a dApp.
## Source
`source` is set only for requests that arrived from a dApp, and is `null` for every other request.
* `source.type` is the channel through which MPCVault received the request: `TYPE_WALLET_CONNECT`, `TYPE_PLUGIN` or `TYPE_MMI`. MPCVault sets it and the dApp cannot choose it. It does not identify the dApp, plugin or person behind the request: any member of the vault can create a plugin request, for example.
* `source.website` is the website the dApp reports for itself. It is unverified text supplied by the dApp, with no validated format, and is `null` when the dApp reported none.
Do not use either field to decide whether to trust a request.
### By connection type
What a dApp request can carry depends on the channel it arrived through.
| `source.type` | Networks | A transaction is returned as | A message is returned as | Returned without a payload field |
| - | - | - | - | - |
| `TYPE_WALLET_CONNECT` | EVM | `evmSendCustom` | `evmMessage` (`personal_sign` or typed data) | `eth_sign` messages |
| `TYPE_MMI` | EVM | `evmSendCustom` | `evmMessage` (`personal_sign` or typed data) | None |
| `TYPE_PLUGIN` | EVM, Solana, Sui, Aptos, TON and Stellar networks | `evmSendCustom`, `solanaSendCustom`, `sonicSvmSendCustom`, `suiSendCustom`, `aptosSendCustom`, `tonSendCustom` or `stellarSendCustom`, by network | `evmMessage`, `solanaMessage`, `suiMessage`, `aptosMessage` or `tonMessage`, by network | `eth_sign` messages; Aptos requests to sign without submitting; Stellar messages, authorization entries and SEP-10 challenges |
On every channel, a transaction whose stored data cannot be returned has no payload field either.
The other fields of a dApp request:
| Field | dApp transaction | dApp message |
| - | - | - |
| `source` | Set | Set |
| `notes` | The note a signer added in the MPCVault app; `null` when none | `null` |
| `simulation` | The stored simulation, when there is one | `""` |
| `evmInputDataDecode` | EVM only, when the call could be decoded | `null` |
| `callbackClientSignerPublicKey` | `null` | `null` |
In `evmSendCustom`, a dApp transaction differs from one created through the API in three fields, on all three channels: `from` and `to` are EIP-55 checksummed, `nonce` is returned (from the dApp, or the one a signer set), and `gasFee` holds the fee a signer set in the app plus the gas limit. The fee the dApp proposed is not returned.
## Simulation
`simulation` is the result of simulating the transaction, returned for reference only. MPCVault stores it in a network-specific form (the provider's response, an MPCVault summary of it, or a synthetic result; see the table below) and does not vouch for it. Run your own simulation before you rely on the outcome.
**Encoding.** `simulation` is `bytes`: base64 (standard alphabet, padded) in REST JSON, raw bytes over gRPC. The bytes are UTF-8 JSON text. The JSON schema depends on the network (table below); MPCVault does not define or version it. The text is the JSON as stored, which can be re-serialized (key order, whitespace) compared with the provider's response.
```bash theme={null}
curl -s -X POST https://api.mpcvault.com/v1/getSigningRequestDetails \
-H 'x-mtoken: ' -H 'Content-Type: application/json' \
-d '{"uuid": ""}' \
| jq -r '.signingRequest.simulation' | base64 -d | jq .
```
**When it is set.** For custom transactions on EVM, Aptos, Sui, Solana and TON networks, and for dApp transactions that are returned with a payload (EVM, Solana, Sonic SVM, Sui, Aptos, TON and Stellar), once a simulation is stored. It is `""` for every other request, including plain transfers, messages, Bitcoin and TRON requests, and requests for which no simulation is stored (provider failure or timeout, quota exceeded, custom EVM networks). A Stellar simulation that failed is stored as a result with `success` false, not as an empty value. Resimulation ([REST](/api-reference/rest/resimulation), [gRPC](/api-reference/grpc/resimulation)) attempts to replace the stored value; see there for what a provider failure returns.
| Network | JSON content |
| - | - |
| EVM networks | The Tenderly Simulate API response without its `contracts` array. Top-level keys: `transaction`, `error`, `simulation`, `generated_access_list`. |
| HyperEVM | An envelope `{"result": […], "gas_price": "0x…", "nonce": "0x…", "from": "0x…"}`; `result` is the Alchemy `eth_simulateV1` result. |
| Aptos, Movement | MPCVault's summary of the transaction simulated through the node's `/transactions/simulate`, with snake\_case keys: `hash`, `sender`, `sequence_number`, `max_gas_amount`, `gas_unit_price`, `gas_currency_code`, `expiration_timestamp_secs`, `payload`, `signature`, `events`, `version`, `state_root_hash`, `event_root_hash`, `gas_used`, `accumulator_root_hash`, `changes`, `timestamp`, `status`, `error_message`; empty values are omitted. `payload`, `signature`, `changes` and each `events[].data` are themselves JSON-encoded strings, `status` is a number (`1` pending, `2` success, `3` fail) and `error_message` holds the VM status of a failed simulation. |
| Sui | The `sui_dryRunTransactionBlock` result. `transaction`, `effects`, `events`, `object_changes` and `balance_changes` are themselves JSON-encoded strings, and `status` is a number. |
| Solana, Sonic SVM | MPCVault's own summary of the `simulateTransaction` result, not the provider's response. Keys are snake\_case: `success`, `error`, `block_number`, `nonce`, `network_fee`, `change`, `approval`, `balance_change`, `contract_calls`, `events`, … |
| TON | A TonAPI account event from message emulation: `event_id`, `account`, `actions`, `lt`, … When the wallet balance does not cover the outgoing amounts, `event_id` is `"insufficient-funds"`. |
| Stellar | dApp transactions only: `{"success": …, "kind": "classic_preflight" or "soroban", "error": "…", "result": …}`, where `result` is the Soroban simulation result. |
| Bitcoin, TRON | Never set. |
## Verify independently
MPCVault returns a request as it holds it, together with its own view of it (`evmInputDataDecode`, `simulation`, `source`, `notes`). This is reference information, not a verification. To verify a request, run your own independent checks: decode the calldata yourself, simulate the transaction with your own provider, and compare addresses and amounts with your own records. Do not rely on these fields as your only check.
# Supported Networks
Source: https://docs.mpcvault.com/api-reference/supported-networks
Blockchain networks supported by the MPCVault API.
## Networks
| Network | Network Type | Features |
| - | - | - |
| Ethereum & EVM | `NETWORK_TYPE_ETHEREUM` | Native, ERC-20, ERC-721, Custom contracts |
| Bitcoin | `NETWORK_TYPE_BITCOIN` | Native BTC |
| Solana | `NETWORK_TYPE_SOLANA` | Native SOL, SPL tokens |
| Aptos | `NETWORK_TYPE_APTOS` | Native APT, Coins |
| Sui | `NETWORK_TYPE_SUI` | Native SUI, Coins |
| TRON | `NETWORK_TYPE_TRON` | TRX, TRC-10, TRC-20 |
| TON | `NETWORK_TYPE_TON` | Native GRAM (prev. TON), Jettons |
## EVM Chain IDs
For EVM-compatible networks, use these chain IDs:
| Chain ID | Network |
| - | - |
| `1` | Ethereum Mainnet |
| `137` | Polygon |
| `56` | BNB Chain |
| `42161` | Arbitrum One |
| `10` | Optimism |
| `8453` | Base |
| `43114` | Avalanche C-Chain |
Custom EVM networks can be added via the MPCVault Dashboard.
# AddWatchAddress
Source: https://docs.mpcvault.com/api-reference/sweep/add-watch-address
openapi.json POST /v1/sweep/addWatchAddress
Register a TRON address for monitoring.
Registers a TRON address for monitoring - see the [TRON Watch Address overview](/api-reference/sweep/tron-watch-address) for webhooks and push rules.
Re-adding the same address with the same API token is idempotent, so it is safe to retry.
## Errors
All errors return a JSON object with `code`, `error`, and `reason` fields:
```json theme={null}
{
"code": 400,
"error": "Bad Request",
"reason": "address invalid"
}
```
| Reason | Description |
| - | - |
| `network unsupported` | `network` is missing or not supported |
| `address required` / `address invalid` | Address is missing or not a valid TRON address |
| `unauthenticated` | `x-mtoken` is missing or invalid |
| `webhook not configured` | The API token has no webhook URL configured yet |
| `IP is not allowed` | The request IP is not in the allowlist |
| `internal server error` | Server-side error |
# CreateDepositWallet
Source: https://docs.mpcvault.com/api-reference/sweep/create-deposit-wallet
openapi.json POST /v1/sweep/wallets
Create a dedicated deposit address for a user.
Creates a deposit address bound to your business reference. Idempotent on `(API token, network, ref)`: repeated calls return the same address, so it is safe to retry. An EVM address works on all five chains.
If you only use one EVM chain, a `ref` like `arbitrum_` makes wallets easy to tell apart.
Sweep uses a separate API token issued by MPCVault - see the [Sweep Overview](/api-reference/sweep/overview).
## Errors
All errors return a JSON object with `code`, `error`, and `reason` fields:
```json theme={null}
{
"code": 400,
"error": "Bad Request",
"reason": "ref required"
}
```
| Reason | Description |
| - | - |
| `network required` / `network unsupported` | `network` missing or unsupported |
| `ref required` / `ref invalid` | `ref` missing, too long, or contains invalid characters |
| `unauthenticated` | `x-mtoken` missing or invalid |
| `IP is not allowed` | Request IP not allowlisted |
| `sweep config not configured` | Sweep parameters not configured; contact MPCVault |
| `wallet disabled` | Address disabled |
| `wallet address conflict; retry` | Address allocation conflict; retry |
| `internal server error` | Server-side error |
# Sweep Overview
Source: https://docs.mpcvault.com/api-reference/sweep/overview
Dedicated deposit addresses for your users, with real-time webhooks and automatic USDC/USDT sweeping.
Sweep creates dedicated on-chain deposit addresses for your users (one or more per user). Transfers on an address trigger real-time webhooks. USDC/USDT deposits are swept automatically to your configured sweep address.
Supported networks: EVM (Ethereum, Arbitrum, Base, Polygon, BSC) and Solana. For the product introduction, see [Deposit & Sweep](/guides/36-deposit-and-sweep).
Sweep uses a separate API token issued by MPCVault - not a token created from the web console. Contact your MPCVault account manager to enable Sweep and configure your sweep parameters.
## Preparation
You provide:
* Sweep address (one for EVM, one for Solana)
* Webhook URL
* Outbound IPs (if IP allowlisting is enabled)
MPCVault provides:
* API base URL: `https://api.mpcvault.com`
* API token, sent in the `x-mtoken` header
* Webhook verification public key ([see Webhooks](/api-reference/sweep/webhooks))
## How It Works
```mermaid theme={null}
sequenceDiagram
participant User as End User
participant App as Your Server
participant API as MPCVault
participant Chain as Blockchain
App->>API: Create Deposit Wallet (ref)
API-->>App: Deposit Address
User->>Chain: Deposit to Address
API-->>App: Webhook (CONFIRMED / FINALIZED)
App->>App: Credit User
API->>Chain: Sweep USDC/USDT to Your Sweep Address
```
1. [Create one or more deposit wallets](/api-reference/sweep/create-deposit-wallet) for each user.
2. The user deposits at any time; MPCVault sends [webhooks](/api-reference/sweep/webhooks) in real time for each transfer, and you credit users based on lifecycle events.
3. USDC/USDT deposits are transferred to your sweep address automatically per the [sweep rules below](#when-a-sweep-triggers), net of a small network fee.
Crediting users is driven entirely by webhooks and is independent of sweep progress.
## When a Sweep Triggers
Sweeps are evaluated hourly, per address per token. Only `FINALIZED` deposits count toward the balance; `CONFIRMED` does not.
| Condition | Result |
| - | - |
| Balance ≥ 100 USDC/USDT | Swept in the next hourly run |
| Balance ≥ 10 USDC/USDT, and no new deposit for 24 hours | Swept in the next hourly run |
| Balance \< 10 USDC/USDT | Not swept |
Only the USDC/USDT contracts below are swept; other assets (including native coins) are notified but not swept.
## Network Fees
The network fee covers the on-chain Gas of the sweep; it is deducted from the swept amount, per address per token.
| Network | Network Fee |
| - | - |
| Ethereum | 2 USDC/USDT |
| Arbitrum | 1 USDC/USDT |
| Base | 1 USDC/USDT |
| Polygon | 1 USDC/USDT |
| BSC | 1 USDC/USDT |
| Solana | 1 USDC/USDT |
A large-sweep fee of an extra 10 USDC/USDT applies on any network when a single sweep is ≥ 5,000.
Examples:
* Arbitrum address accumulates 120 USDC → sweep address receives 119 USDC
* Arbitrum address accumulates 6,000 USDC → sweep address receives 5,989 USDC
## Swept Token Contracts
| Network | USDC | USDT |
| - | - | - |
| ETHEREUM | `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48` | `0xdac17f958d2ee523a2206206994597c13d831ec7` |
| ARBITRUM | `0xaf88d065e77c8cc2239327c5edb3a432268e5831` | `0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9` |
| BASE | `0x833589fcd6edb6e08f4c7c32d4f71b54bda02913` | `0xfde4c96c8593536e31f229ea8f37b2ada2699bb2` |
| POLYGON | `0x3c499c542cef5e3811e1192ce70d8cc03d5c3359` | `0xc2132d05d31c914a87c6611c10748aeb04b58e8f` |
| BSC | `0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d` | `0x55d398326f99059ff775485246999027b3197955` |
| SOLANA | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` | `Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB` |
# TRON Watch Address
Source: https://docs.mpcvault.com/api-reference/sweep/tron-watch-address
Monitor TRON addresses you run yourself and receive signed webhooks for their transfers.
Watch Address monitors TRON addresses and notifies your server of their transfers - built for wallets you run yourself; both your own addresses and addresses on MPCVault can be registered. When a registered address sends or receives TRX or USDT on-chain, MPCVault POSTs a signed webhook to your configured URL.
* **Monitoring Only** - No wallet is created, MPCVault holds no keys, and no assets are moved
* **No Historical Backfill** - Only transfers that occur after registration are notified
Watch Address uses the same API token as Sweep, issued by MPCVault - not a token created from the web console. Contact your MPCVault account manager to enable it and configure your webhook URL.
## Preparation
You provide:
* Webhook URL
* Outbound IPs (if IP allowlisting is enabled)
MPCVault provides:
* API base URL: `https://api.mpcvault.com`
* API token, sent in the `x-mtoken` header
* Webhook verification public key (see below)
## How It Works
1. Register each address via [AddWatchAddress](/api-reference/sweep/add-watch-address).
2. MPCVault sends a signed webhook for every transfer on the address, by lifecycle stage.
3. Verify the signature, deduplicate, and apply your business logic.
## Webhook
### Push Rules
* Both incoming and outgoing transfers are notified; there is no minimum amount
* Currently monitored assets: TRX and USDT
* Only successful on-chain transactions are pushed; failed transactions are not
* Self-transfers (sender and recipient are the same address) are not pushed
* Each transaction is notified by lifecycle stage: `CONFIRMED` (19 blocks) then `FINALIZED` (38 blocks), strictly in order; TRX and USDT use the same thresholds, and TRON does not send `REVERTED`
Block thresholds are MPCVault's current operating standard, provided for reference only. They may change with network conditions and do not guarantee irreversibility: only `FINALIZED` is final. Crediting or releasing funds based on `CONFIRMED` is your own risk decision - MPCVault is not liable for losses caused by acting before `FINALIZED`. Apply stricter thresholds per your own risk requirements.
### Signature Verification
Request headers:
```
Content-Type: application/json
Signature:
Signature-Algorithm: Ed25519
```
Verification public key (Ed25519):
```
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOeJEPa2w1I10acMaQlng0BnGtfBwxDnM9lVHJGe+h5j
```
The signature covers the raw request body bytes, exactly as received - do not re-serialize the JSON before verifying:
```
Ed25519.Verify(public_key, raw_request_body, base64_decode(Signature))
```
```go Go theme={null}
package main
import (
"bytes"
"crypto/ed25519"
"encoding/base64"
"strings"
"golang.org/x/crypto/ssh"
)
const publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOeJEPa2w1I10acMaQlng0BnGtfBwxDnM9lVHJGe+h5j"
func verify(signatureB64 string, rawBody []byte) bool {
parsed, _, _, rest, err := ssh.ParseAuthorizedKey([]byte(publicKey))
if err != nil ||
parsed.Type() != ssh.KeyAlgoED25519 ||
len(bytes.TrimSpace(rest)) != 0 {
return false
}
cryptoKey, ok := parsed.(ssh.CryptoPublicKey)
if !ok {
return false
}
pub, ok := cryptoKey.CryptoPublicKey().(ed25519.PublicKey)
if !ok || len(pub) != ed25519.PublicKeySize {
return false
}
signature, err := base64.StdEncoding.DecodeString(
strings.TrimSpace(signatureB64),
)
if err != nil || len(signature) != ed25519.SignatureSize {
return false
}
return ed25519.Verify(pub, rawBody, signature)
}
```
```python Python theme={null}
import base64
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
from cryptography.hazmat.primitives.serialization import load_ssh_public_key
PUBLIC_KEY = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOeJEPa2w1I10acMaQlng0BnGtfBwxDnM9lVHJGe+h5j"
public_key = load_ssh_public_key(PUBLIC_KEY.encode())
assert isinstance(public_key, Ed25519PublicKey)
def verify(signature_b64: str, raw_body: bytes) -> bool:
try:
public_key.verify(base64.b64decode(signature_b64), raw_body)
return True
except (InvalidSignature, ValueError):
return False
```
```javascript Node.js theme={null}
const crypto = require("crypto");
const PUBLIC_KEY = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOeJEPa2w1I10acMaQlng0BnGtfBwxDnM9lVHJGe+h5j";
function parseSshEd25519(line) {
const blob = Buffer.from(line.split(" ")[1], "base64");
const algoLen = blob.readUInt32BE(0);
const algo = blob.subarray(4, 4 + algoLen).toString();
const keyLen = blob.readUInt32BE(4 + algoLen);
const raw = blob.subarray(8 + algoLen, 8 + algoLen + keyLen);
if (algo !== "ssh-ed25519" || raw.length !== 32) throw new Error("not an ssh-ed25519 key");
return crypto.createPublicKey({
key: Buffer.concat([Buffer.from("302a300506032b6570032100", "hex"), raw]),
format: "der",
type: "spki",
});
}
const publicKey = parseSshEd25519(PUBLIC_KEY);
function verify(signatureB64, rawBody) {
const signature = Buffer.from(signatureB64.trim(), "base64");
if (signature.length !== 64) return false;
return crypto.verify(null, rawBody, publicKey, signature);
}
```
### Request Body
Example (USDT incoming):
```json theme={null}
{
"uuid": "3f0a7c9e-5b21-5c58-9e0b-2f6d8a4c1e77",
"wallet_address": "TSvcVista6bxr7WFmDMWKLzTBnF4N34u9v",
"network": "TRON",
"unique_id": "tron:74123456:txhash:0",
"block_number": 74123456,
"block_hash": "0000000004...blockhash",
"hash": "7c2b...transactionhash",
"is_send": false,
"from_address": "TPayerAddress...",
"to_address": "TSvcVista6bxr7WFmDMWKLzTBnF4N34u9v",
"mint_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"decimals": 6,
"amount": "100.25",
"status": "SUCCESS",
"event_type": "CONFIRMED",
"timestamp": 1784515200000
}
```
| Field | Description |
| - | - |
| `uuid` | Unique ID of this transaction record, identical across lifecycle stages |
| `wallet_address` | The registered watch address |
| `network` | Always `TRON` |
| `unique_id` | On-chain event ID; shared by both notifications when both sides of a transfer are watched |
| `block_number` / `block_hash` / `hash` | On-chain block number, block hash, transaction hash |
| `is_send` | `false` = incoming (watch address is recipient); `true` = outgoing (watch address is sender) |
| `from_address` / `to_address` | Sender / recipient; omitted when empty |
| `mint_address` | Token contract address (USDT: `TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t`); empty for native TRX |
| `decimals` | Token decimals (TRX: 6) |
| `amount` | Human-readable amount, string, already scaled by decimals |
| `status` | Always `SUCCESS` |
| `event_type` | `CONFIRMED` (19 blocks; safe to credit) or `FINALIZED` (38 blocks; final, safe to release withdrawals) |
| `timestamp` | On-chain time in milliseconds; not for idempotency |
### Idempotency
Each transaction produces two notifications - `CONFIRMED` then `FINALIZED` - with the same `uuid`. If both sender and recipient of one transfer are watched, each side additionally gets its own pair: same `unique_id`, but different `wallet_address`, `is_send`, and `uuid`.
Use `uuid` + `event_type` for idempotency - `uuid` alone would drop the `FINALIZED` stage, and `unique_id` alone would drop one side of a watched-to-watched transfer.
After verifying and processing a webhook, return HTTP 200 (exactly; the response body is ignored). Any other status or a failed request is retried with exponential backoff, indefinitely - so your endpoint must be idempotent.
### Recommended Handling Steps
1. Read the raw request body and verify the signature with the public key.
2. Parse the JSON and check that `status` is `SUCCESS`.
3. Deduplicate by `uuid` + `event_type`.
4. Optionally re-verify the transaction hash, direction, token, and amount via TRON RPC.
5. Apply your business logic and return HTTP 200.
# Sweep Webhooks
Source: https://docs.mpcvault.com/api-reference/sweep/webhooks
Real-time notifications for transfers on deposit addresses.
Successful transactions on deposit addresses are notified by lifecycle stage. Both directions are notified: `is_send=false` incoming, `is_send=true` outgoing.
## Signature Verification
Request headers:
```
Content-Type: application/json
Signature:
Signature-Algorithm: Ed25519
```
Verification public key (Ed25519):
```
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOeJEPa2w1I10acMaQlng0BnGtfBwxDnM9lVHJGe+h5j
```
The signature covers the raw request body bytes, exactly as received - do not re-serialize the JSON before verifying:
```
Ed25519.Verify(public_key, raw_request_body, base64_decode(Signature))
```
```go Go theme={null}
package main
import (
"bytes"
"crypto/ed25519"
"encoding/base64"
"strings"
"golang.org/x/crypto/ssh"
)
const publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOeJEPa2w1I10acMaQlng0BnGtfBwxDnM9lVHJGe+h5j"
func verify(signatureB64 string, rawBody []byte) bool {
parsed, _, _, rest, err := ssh.ParseAuthorizedKey([]byte(publicKey))
if err != nil ||
parsed.Type() != ssh.KeyAlgoED25519 ||
len(bytes.TrimSpace(rest)) != 0 {
return false
}
cryptoKey, ok := parsed.(ssh.CryptoPublicKey)
if !ok {
return false
}
pub, ok := cryptoKey.CryptoPublicKey().(ed25519.PublicKey)
if !ok || len(pub) != ed25519.PublicKeySize {
return false
}
signature, err := base64.StdEncoding.DecodeString(
strings.TrimSpace(signatureB64),
)
if err != nil || len(signature) != ed25519.SignatureSize {
return false
}
return ed25519.Verify(pub, rawBody, signature)
}
```
```python Python theme={null}
import base64
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
from cryptography.hazmat.primitives.serialization import load_ssh_public_key
PUBLIC_KEY = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOeJEPa2w1I10acMaQlng0BnGtfBwxDnM9lVHJGe+h5j"
public_key = load_ssh_public_key(PUBLIC_KEY.encode())
assert isinstance(public_key, Ed25519PublicKey)
def verify(signature_b64: str, raw_body: bytes) -> bool:
try:
public_key.verify(base64.b64decode(signature_b64), raw_body)
return True
except (InvalidSignature, ValueError):
return False
```
```javascript Node.js theme={null}
const crypto = require("crypto");
const PUBLIC_KEY = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOeJEPa2w1I10acMaQlng0BnGtfBwxDnM9lVHJGe+h5j";
function parseSshEd25519(line) {
const blob = Buffer.from(line.split(" ")[1], "base64");
const algoLen = blob.readUInt32BE(0);
const algo = blob.subarray(4, 4 + algoLen).toString();
const keyLen = blob.readUInt32BE(4 + algoLen);
const raw = blob.subarray(8 + algoLen, 8 + algoLen + keyLen);
if (algo !== "ssh-ed25519" || raw.length !== 32) throw new Error("not an ssh-ed25519 key");
return crypto.createPublicKey({
key: Buffer.concat([Buffer.from("302a300506032b6570032100", "hex"), raw]),
format: "der",
type: "spki",
});
}
const publicKey = parseSshEd25519(PUBLIC_KEY);
function verify(signatureB64, rawBody) {
const signature = Buffer.from(signatureB64.trim(), "base64");
if (signature.length !== 64) return false;
return crypto.verify(null, rawBody, publicKey, signature);
}
```
## Request Body
```json theme={null}
{
"wallet_address": "0x59b4a4fd7bc1baa0e6bb65cbfe3e2e4dbfa5e0a1",
"network": "ETHEREUM",
"unique_id": "chain:block:hash:index",
"block_number": 123456789,
"block_hash": "0xabc...",
"hash": "0xdef...",
"is_send": false,
"from_address": "0x1234...",
"to_address": "0x59b4a4fd7bc1baa0e6bb65cbfe3e2e4dbfa5e0a1",
"mint_address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"decimals": 6,
"amount": "100.25",
"status": "SUCCESS",
"event_type": "CONFIRMED",
"timestamp": 1784515200000,
"uuid": "5f0c8f6e-..."
}
```
| Field | Description |
| - | - |
| `wallet_address` | Deposit address |
| `network` | `ETHEREUM` `ARBITRUM` `BASE` `POLYGON` `BSC` `SOLANA`; EVM deposits report the specific chain |
| `unique_id` | Unique on-chain event ID, shared across all stages of a transaction |
| `block_number` / `block_hash` | Block number (slot on Solana) / block hash |
| `hash` | Transaction hash (signature on Solana) |
| `is_send` | `true` when the transfer is outgoing from the deposit address |
| `from_address` / `to_address` | Omitted when empty |
| `mint_address` | Token contract / mint address; empty for native coins |
| `decimals` | Token decimals |
| `amount` | Human-readable amount string |
| `status` | Only `SUCCESS` is delivered |
| `event_type` | See [Lifecycle Events](#lifecycle-events) |
| `timestamp` | On-chain timestamp (ms) |
| `uuid` | Transaction record UUID, identical across stages |
## Lifecycle Events
* **`CONFIRMED`** - Crediting threshold reached; safe to credit the user
* **`FINALIZED`** - Final; safe to release withdrawals. No further changes
* **`REVERTED`** - A `CONFIRMED` transaction was rolled back by a reorg (EVM only); reverse the credit. `CONFIRMED` is sent again if re-included
Notifications for a transaction are delivered strictly in order. Thresholds:
| Network | `CONFIRMED` | `FINALIZED` |
| - | - | - |
| ETHEREUM | 6 confirmations | 64 confirmations |
| ARBITRUM | 128 L2 confirmations | Node finalized |
| BASE | 20 L2 confirmations | Node finalized |
| POLYGON | 60 confirmations | 300 confirmations |
| BSC | 60 confirmations | 300 confirmations |
| SOLANA | - | Transaction finalized |
Solana sends `FINALIZED` only; it serves as both the crediting and withdrawal basis.
These thresholds are MPCVault's current operating standard, provided for reference only. They may change with network conditions and do not guarantee irreversibility: a `CONFIRMED` transaction can still be rolled back by a reorg (delivered as `REVERTED`), and only `FINALIZED` is final. Crediting or releasing funds based on `CONFIRMED` is your own risk decision - MPCVault is not liable for losses caused by acting before `FINALIZED`. Apply stricter thresholds per your own risk requirements.
## Response and Retry
Return HTTP 200; only 200 counts as delivered (any response body is accepted). Otherwise MPCVault retries with exponential backoff (up to 1-hour intervals) until it receives 200. Suggested idempotency key:
```
mpcvault:sweep:::
```
All stages of a transaction share the same `unique_id`, so deduplicating on `unique_id` alone would drop later stages.
## Recommended Handling Steps
1. Read the raw request body and verify the signature with the public key.
2. Parse the JSON and check that `status` is `SUCCESS`.
3. Deduplicate by `uuid` + `event_type` + `block_hash`.
4. Apply by `event_type`: `CONFIRMED` → credit the user; `REVERTED` → reverse the credit; `FINALIZED` → allow withdrawal.
5. Return HTTP 200.
# Architecture
Source: https://docs.mpcvault.com/architecture
How MPCVault distributes key shares across multiple cloud environments.
## Key Share Distribution
MPCVault uses a 3-of-3 multi-party computation (MPC) setup:
| Share | Holder | Location | TEE |
| - | - | - | - |
| Share 1 | You | Your device | - |
| Share 2 | MPCVault | Google Cloud | AMD SEV |
| Share 3 | MPCVault | Microsoft Azure | Intel SGX |
All three shares are required for signing. No single party ever has access to the complete private key.
## Multi-Cloud Infrastructure
MPCVault operates across multiple cloud providers, each using a different Trusted Execution Environment (TEE):
| Cloud | TEE Technology | Description |
| - | - | - |
| Google Cloud | AMD SEV | Secure Encrypted Virtualization |
| Microsoft Azure | Intel SGX | Software Guard Extensions |
This orthogonal platform design reduces the risk of compromise - a vulnerability in one TEE technology doesn't affect the other.
## No Counterparty Risk
Unlike centralized custody providers, MPCVault never holds all your key shares. This eliminates counterparty risk - you always know where your assets are and maintain control over them.
You can:
* Request your key shares from MPCVault at any time
* Designate a Trust to hold encrypted backups for recovery independent of MPCVault
## Recovery Options
| Option | Description |
| - | - |
| Key Share Export | Request all three shares for full wallet recovery |
| Trust Backup | Store encrypted backup with a third-party trust |
| Standard Recovery | Use your device and MPCVault's shares together |
# Encryption
Source: https://docs.mpcvault.com/encryption
Zero-trust architecture with end-to-end encrypted communication.
## End-to-End Encryption
MPCVault adopts a zero-trust architecture. All traffic between computing nodes is peer-to-peer encrypted.
| Component | Protocol |
| - | - |
| Key Exchange | Noise Protocol IK |
| Encryption | ChaCha20-Poly1305 AEAD |
| Hashing | Blake2s |
The relay server is trustless - it has no knowledge of the actual messages transmitted.
## Personal Key Certificate
Each MPCVault user has a cryptographic identity defined by an Ed25519 key pair called the Personal Key Certificate. Only you know the private key.
## How Authentication Works
| Layer | Method |
| - | - |
| Platform | Traditional authentication (password, 2FA) |
| Cryptographic | Ed25519 signature verification |
In addition to standard authentication, MPCVault performs cryptographic attestation using your public key.
## Zero-Trust Benefits
Personal Key Certificates enable:
* **Trustless secret sharing** - Pass key shares between users without exposing them to MPCVault
* **End-to-end encryption** - Messages encrypted directly between participants
* **Cryptographic identity** - Actions are cryptographically signed and verifiable
# Back Up Your Key Certificate
Source: https://docs.mpcvault.com/guides/1-how-to-back-up-your-personal-key-certificate/index
Secure your personal key certificate to maintain access to your assets.
MPCVault is non-custodial. If you lose your key certificate, you will not be able to access your crypto assets. Back up your key certificate immediately after generating it.
## Backup Methods
We recommend using at least two backup methods.
### iCloud Backup (iOS Only)
If iCloud backup is enabled on your iPhone, your key certificate is automatically backed up. You can access it from any device logged into your iCloud account.
Disabling iCloud backup in settings will delete existing iCloud backups.
### Mnemonic Phrase
Write down the mnemonic phrase provided during setup and store it in a secure location. This phrase can recreate your key certificate.
### Download Key Files
Download your key certificate files and save them to iCloud or another secure storage location.
The password encrypting your backup is as important as the backup itself. Keep it secure for future device recovery.
## Creating Additional Backups
You can create a new backup anytime from **Me** > **Back up personal key certificate** in the mobile app.
# DeFi Access
Source: https://docs.mpcvault.com/guides/10-how-do-i-connect-my-wallet-to-a-dapp/index
Multiple ways to connect MPCVault to any DeFi protocol across all supported chains.
MPCVault is built for DeFi. Connect to any protocol on any chain we support—Ethereum, Polygon, Arbitrum, Optimism, Base, Solana, Aptos, Sui, TON, and more. Whether you're swapping, staking, lending, or interacting with custom contracts, MPCVault gives you multiple connection options:
* **Browser Extension** — Full support for EVM chains plus Aptos, Solana, Sui, TON, and Movement
* **Mobile In-App Browser** — Access dApps directly from the MPCVault app
* **WalletConnect** — Scan QR codes to connect from any device (EVM chains)
* **MetaMask Institutional** — For institutional users with MMI integration
There are no restrictions on which dApps you can connect to. You can even build your own private dApps and connect your wallet to them.
## Chrome browser extension
The browser extension method offers the most comprehensive network support and is ideal for desktop users. Follow the steps below to connect:
1. Download [browser plugin](https://chrome.google.com/webstore/detail/mpcvault/jgfmfplofjigjfokigdiaiibhonfnedj).
2. Open the plugin, click on "**Sign in**", and authorize the MPCVault account login.
3. Navigate to the dApp you want to connect to, click on the "**Connect**", the **wallet logo** or the "**Sign In**" button, typically located in the upper-right corner, and select MPCVault.
4. Select your vault and wallet, then click "**Confirm**" to establish the connection. You can also switch between connected wallets or disconnect on the home page.
5. Once connected, you can use the dApp for transactions or other activities.
## Mobile app
This method is perfect for users who prefer mobile access and want a seamless in-app connection. Here's how:
1. Open the MPCVault app on your mobile phone.
2. Navigate to the "**Home**" page, then click the **globe-shaped icon** in the top-right corner to access the dApp connection.
3. Use the search bar to find the website of the dApp you want to connect to. The dApp opens in the in-app browser.
4. In the dApp, select "**Connect**" or a similar button—often in the top-right corner, then choose the MPCVault. For dApps that don't offer an MPCVault option, you'll want to select 'MetaMask' from the list of options that appears.
5. A pop-up will appear in the mobile app. Select the network, the vault and the wallet you wish to connect to, then click "**Connect**".
6. Once connected, you can use the dApp to swap tokens, stake assets, or perform other activities as supported.
7. By clicking the wallet icon in the top-right corner, you can switch between connected wallets or disconnect from the dApp.
## WalletConnect
WalletConnect is a popular protocol for connecting wallets to dApps using QR codes. This method is limited to EVM chains. Please follow these steps to connect to a dApp:
1. Open the dApp you want to connect to. We will use Uniswap as an example. Most dApps have a "**Connect**" button in the top right corner. Please click that button.
2. A pop-up window will appear on the screen listing different wallet association options. Click "**WalletConnect**" and a QR code will be generated.
3. Open the MPCVault app, tap the icon similar to "**+**" in the top-right corner of the home page, select WalletConnect to activate the camera, and then scan the QR code.
4. After scanning the QR code, a page will appear to confirm the connection to the dApp. Select your wallet and click "**Confirm**" to authorize the dApp to connect to your wallet.
**Connecting on iOS via a mobile browser?** The connection can appear stuck after you confirm—iOS pauses the dApp page while you're in the MPCVault app.
**What to do:** Right after tapping "**Confirm**" in MPCVault, switch back to your dApp browser. This wakes the page, and the connection completes.
5. You can start using the dApp for transactions or other operations.
Please note that when the "**WalletConnect access**" button is closed in the vault settings, WalletConnect isn't supported in this vault.
## What to do if you can't connect?
If you are unable to connect to our plugin after selecting MetaMask on certain dApp websites, you can try the following solutions:
1. Check for Updates. Make sure you have the latest version of **plugin** installed or that your **browser** is up to date.
2. Refresh the dApp website.
3. If you have other active wallet extensions on your browser, you can try closing those wallets before connecting and using our plugin, e.g., [Uniswap](https://uniswap.org/).
# Custom Transactions
Source: https://docs.mpcvault.com/guides/11-how-to-set-custom-payload-for-your-transaction/index
Interact with contracts or deploy contracts using custom payloads.
Send custom transaction data to interact with contracts that have no frontend or to deploy contracts.
## Steps
1. Select the native token in your wallet and click **Send**.
2. Click **Advanced option** and enter hex data in the **Custom Data** field.
## Use Cases
| Action | Recipient | Amount | Custom Data |
| - | - | - | - |
| Deploy contract | Leave empty | Leave empty | Bytecode |
| Call contract | Contract address | 0 (or leave empty) | Function call data |
Custom data must be in hex format. Use [abi.hashex.org](https://abi.hashex.org/) to encode EVM function calls.
# Cancel Transactions
Source: https://docs.mpcvault.com/guides/12-how-to-cancel-a-transaction/index
Cancel pending transactions before they confirm on-chain.
Cancel transactions that are still pending on the network. Confirmed transactions cannot be reversed.
## When to Cancel
* **Stuck transactions** — Transaction pending too long due to low gas or congestion
* **Wrong details** — Incorrect recipient or amount
* **Changed plans** — No longer want to execute the transaction
## How It Works
Canceling sends a new transaction with the same nonce but higher gas, replacing the original. Check [Etherscan Gas Tracker](https://etherscan.io/gastracker) for current fees.
## Via Web Console
1. Go to [console.mpcvault.com](https://console.mpcvault.com/).
2. Navigate to **Transactions**.
3. Find the pending transaction, click **...** > **Cancel transaction**.
4. Click **Create signing request** and sign in the app.
## Via Mobile App
1. Open the app and tap **Transactions**.
2. Find the pending transaction and tap to open details.
3. Tap **...** > **Cancel transaction**.
4. Create and sign the cancellation request.
# Gas Fees & Nonce
Source: https://docs.mpcvault.com/guides/14-b-evm-txs-how-to-set-gad-fee-and-nonce/index
How to customize gas fees and nonce for EVM transactions, plus troubleshooting stuck transactions.
MPCVault automatically selects the optimal gas fees and nonce for your transactions. For advanced use cases, such as resolving stuck transactions or prioritizing specific actions, you can manually customize the gas fee and nonce.
## What are gas fees on EVM chains?
Gas fees are payments made to the network to execute a transaction. They incentivize miners or validators to process and validate transactions. Below is an explanation of the key parameters:
**Max Fee**: The maximum amount you’re willing to pay per unit of gas. After the transaction is processed, any unused portion will be refunded. The total amount of the transaction is calculated by multiplying the max fee by the gas limit.
**Max Priority Fee**: An optional tip paid to miners or validators to prioritize your transaction. Transactions with higher priority fees are more likely to be confirmed faster.
**Gas Limit**: The maximum amount of gas units your transaction can consume. Complex transactions (e.g., interacting with smart contracts) require higher gas limits.
## How to set gas fees
To manually set gas fees, you can use a blockchain explorer to check recent network activity and reference optimal gas prices. Here’s how to do it using Plasma as an example:
1. Visit Plasma blockchain explorer.
2. Find recent successful transactions of the **same type** (e.g., token transfer, contract interaction) to use as a reference.
3. Open the transaction details and scroll to the "**Click to see More**" section.
4. Locate the "**Gas Limit & Usage by Txn**" and "**Gas Price**" fields.
5. Use these values as a reference and set your gas fee slightly higher to ensure execution.
6. Use this value to set the gas fee in MPCVault when creating or editing your transaction.
## What is a nonce?
Nonce is a sequential number assigned to each transaction from your wallet. It ensures transactions are processed in the correct order and prevents duplication or replay attacks.
## How to set the nonce
To find and set the correct nonce for your transaction, you can use blockchain explorer. Below is an example using Plasma blockchain explorer:
1. Visit Plasma blockchain explorer.
2. Enter your **wallet address** in the search bar to view your account’s activity and transaction history.
3. Locate the most recent transaction sent from your wallet.
4. Open the transaction details and scroll to the “**Click to see More**” section. Locate the "**Nonce"** field, which indicates the last used nonce for your wallet.
5. Determine the next nonce. If the latest transaction’s nonce is 5, the next transaction should use a nonce of 6.
6. Use this value to set the nonce in MPCVault when creating or editing your transaction.
## Troubleshooting
If you encounter issues such as failed or stuck transactions, improper gas fee or nonce settings are often the cause. Below are common problems and how to resolve them.
### Transaction Stuck
Sometimes, a transaction can get stuck and fail to be confirmed due to insufficient gas fees, an incorrect nonce, or inadequate funds.
**Solution:**
* Replace with same nonce (if you want to proceed with the transaction):
* Create a new transaction using the same nonce as the stuck transaction.
* Significantly increase gas fees (recommendation: 20–30% higher).
* Sign and send the transaction to replace the stuck one.
* Cancel with same nonce (if you no longer wish to proceed with the transaction):
* Create a new transaction with the same nonce, setting the amount to **zero** or sending it to yourself.
* Significantly increase gas fees (recommend 20-30% higher)
* Sign and send the transaction to cancel the original stuck transaction.
### "Intrinsic gas too low" error
This error occurs when the gas fee is set too low to meet the network's minimum requirements.
**Solution:**
* Use a blockchain explorer to check recent gas fees for similar transactions.
* Set reasonable gas fees based on current network conditions.
### "Nonce too low" error
This error occurs when a transaction is submitted with a nonce that has already been used.
**Solution:**
* Use a blockchain explorer to find the next available nonce for your wallet.
* Re-initiate your transaction using this correct value.
### Nonce gap
If a transaction is submitted with a nonce higher than the next available value, it will remain pending until the gap is resolved.
**Solution:**
* Locate your last confirmed nonce via a blockchain explorer.
* Create a new transaction with the next correct nonce (last nonce + 1). A simple transfer to yourself with a standard gas fee is recommended.
* Once this transaction is confirmed, the original stuck transaction will be processed in sequence.
# Transaction Policies
Source: https://docs.mpcvault.com/guides/15-vault-transaction-policies/index
Configure approval rules to protect your vault's assets.
Transaction policies define who can approve transactions and under what conditions. Set up policies and [quorum](/guides/16-what-is-a-quorum/index) approvals to protect your assets.
## Simple Mode
One approval requirement for all transactions. New vaults default to Simple Mode requiring one manager approval.
## Advanced Mode
Customize approval rules by transaction type.
### Message Signing
Control approvals for dApp interactions (login, identity verification).
* Set to **0 managers** for low-risk signing (any member can approve)
* Permit2 and other contract authorizations fall under **unknown policy**
### Known Amount
Set policies based on daily, weekly, or monthly volume.
**Example:** Daily volume ≥ \$10,000 requires 3 managers
| Volume | Approval |
| - | - |
| \< \$10,000/day | Any member |
| ≥ \$10,000/day | 3 managers |
### Unknown Amount
For transactions where the amount is indeterminate (NFTs, custom transactions, dApp interactions).
Required managers cannot exceed the current quorum.
### Custom Policy (Whitelist)
Allow specific addresses to be approved by any member. Useful for:
* Hot wallet top-ups
* Restricting traders to specific protocols (e.g., Uniswap only)
Policies only trigger when chain and address match the whitelist.
## Whitelist Transfers Only
Restrict transactions to whitelisted accounts only. Supported on EVM chains, Bitcoin, and TRON.
Only vault managers can edit policies. Changes require manager quorum approval.
# Quorum
Source: https://docs.mpcvault.com/guides/16-what-is-a-quorum/index
The minimum number of approvers required for transactions and settings changes.
A quorum is the minimum number of participants required to complete an action.
## Transaction Quorum
The number of approvers needed to sign a transaction. If a vault requires a quorum of 3, at least 3 authorized members must participate.
## Manager Quorum
The number of managers required to approve changes to:
* [Vault members and policies](/guides/5-how-to-add-vault-members-and-set-up-multisig/index)
* [API Client Signer settings](/guides/17-how-to-use-api-client-signer/index)
Manager quorum cannot exceed the number of current managers. To increase quorum capacity, add managers or promote members to manager role.
# Client Signer Setup
Source: https://docs.mpcvault.com/guides/18-how-to-enable-api/client-signer
Set up the client signer for automated, programmatic transaction signing.
**Skip this page** if you only need manual transaction approval via the MPCVault app. The client signer is only required for automated signing.
The client signer is a Docker container that:
1. Maintains a secure connection to MPCVault
2. Receives signing callbacks when you call `ExecuteSigningRequests`
3. Approves transactions based on your callback server's response
## Prerequisites
* Docker (or Docker Compose) installed
* A server with a stable internet connection
* A callback endpoint on your backend to receive and approve signing requests
* An [API user already created](/guides/18-how-to-enable-api/index)
## Step 1: Generate an Ed25519 Key Pair
The client signer authenticates with MPCVault using an Ed25519 key pair. Generate one locally:
```bash theme={null}
# Generate the key pair
ssh-keygen -t ed25519 -C "mpcvault-client-signer" -f ./client-signer-key -N ""
# View the public key (you'll need this for MPCVault console)
cat ./client-signer-key.pub
# View the private key (you'll need this for config.yml)
cat ./client-signer-key
```
The public key looks like:
```
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0wmN/Cr3JXqmLW7u+g9pTh+wyqDHpSQEIQczXkVx9q mpcvault-client-signer
```
**No password:** The key must not have a passphrase for the client signer to use it automatically.
## Step 2: Register the Client Signer in Your Vault
1. Go to [console.mpcvault.com](https://console.mpcvault.com/)
2. Navigate to your vault's **Team & policies** page
3. Click **+ New Client Signer**
4. Enter the information:
| Field | Description |
| - | - |
| Name | Identifier for this signer (e.g., `production-signer`) |
| Public key | Paste the contents of `client-signer-key.pub` |
| IP Whitelist | (Optional) Your server's IP addresses |
5. Click **Continue** → **Confirm** to create a signing request
6. Approve the **Vault setting update** request in the MPCVault app
## Step 3: Grant Key Access
After creating the client signer, MPCVault automatically creates a **Key grant access** signing request. This grants the client signer permission to participate in MPC signing.
Approve this request in the MPCVault app to complete setup.
**One signer per vault:** Each vault requires its own client signer. You cannot reuse the same signer across multiple vaults.
## Step 4: Create the Configuration File
Create `config.yml` with your settings:
```yaml theme={null}
# Health check endpoint for monitoring
http-health:
listening-addr: 0.0.0.0:8080
# Your vault's UUID (find in vault settings)
vault-uuid: "350063e9-xxxx-xxxx-xxxx-aaf939821815"
# Authentication
ssh:
private-key: |
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtz
c2gtZWQyNTUxOQAAACCtMJjfwq9yV6pi1u7voPaU4fsMqgx6UkBCEHM15FcfagAA
AJgPBwb8DwcG/AAAAAtzc2gtZWQyNTUxOQAAACCtMJjfwq9yV6pi1u7voPaU4fsM
qgx6UkBCEHM15FcfagAAAEBKbCX7sP2Y3yL4H8Mz220wK0wmN/Cr3JXqmLW7u+g9
pTh+wyqDHpSQEIQczXkVx9qAAAAFW1wY3ZhdWx0LWNsaWVudC1zaWduZXI=
-----END OPENSSH PRIVATE KEY-----
password: ""
# Your callback endpoint
callback-url: "http://host.docker.internal:8088/api/mpcvault/callback"
```
**Configuration reference:**
| Field | Description | Example |
| - | - | - |
| `http-health.listening-addr` | Health check endpoint | `0.0.0.0:8080` |
| `vault-uuid` | UUID from vault settings page | `350063e9-...` |
| `ssh.private-key` | Full private key content | `-----BEGIN OPENSSH...` |
| `ssh.password` | Key passphrase (empty if none) | `""` |
| `callback-url` | Your backend endpoint for approvals | `http://your-server:8088/callback` |
## Step 5: Run the Client Signer
### Option A: Docker Run (Development)
```bash theme={null}
docker run -d \
--name mpcvault-signer \
--restart unless-stopped \
-p 8080:8080 \
-v $(pwd)/config.yml:/config.yml:ro \
ghcr.io/mpcvault/client-signer:latest \
--config-path=/config.yml
```
### Option B: Docker Compose (Recommended for Production)
Create `docker-compose.yml`:
```yaml theme={null}
version: '3.8'
services:
mpcvault-signer:
image: ghcr.io/mpcvault/client-signer:latest
container_name: mpcvault-signer
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./config.yml:/config.yml:ro
command: ["--config-path=/config.yml"]
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
```
Start with:
```bash theme={null}
docker-compose up -d
```
### Running on macOS (Apple Silicon)
The Client Signer image currently supports `linux/amd64` only. Docker Desktop can run the image on Apple Silicon Macs using `amd64` emulation.
You may see the platform mismatch warning below. The warning itself does not prevent the container from running.
```
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
```
If the container does not run correctly, try enabling **Use Rosetta for x86\_64/amd64 emulation on Apple Silicon** in Docker Desktop → Settings → General, then run it again.
You can also explicitly specify the platform if needed:
```bash Docker Run {2} theme={null}
docker run -d \
--platform linux/amd64 \
--name mpcvault-signer \
--restart unless-stopped \
-p 8080:8080 \
-v $(pwd)/config.yml:/config.yml:ro \
ghcr.io/mpcvault/client-signer:latest \
--config-path=/config.yml
```
```yaml Docker Compose {4} theme={null}
services:
mpcvault-signer:
image: ghcr.io/mpcvault/client-signer:latest
platform: linux/amd64
# ...rest unchanged
```
For production, we recommend a native `linux/amd64` host.
### Verify it's running
```bash theme={null}
# Check container status
docker ps | grep mpcvault-signer
# Check health endpoint
curl http://localhost:8080/health
# View logs
docker logs -f mpcvault-signer
```
Docker image: [ghcr.io/mpcvault/client-signer](https://github.com/orgs/mpcvault/packages/container/package/client-signer)
## Step 6: Implement Your Callback Handler
When you call `ExecuteSigningRequests`, MPCVault sends a callback to your `callback-url`. Your server must:
1. Receive the callback (POST request with protobuf body)
2. Validate the signing request against your business rules
3. Return HTTP 200 to approve, or 4xx/5xx to reject
**Example callback handler (Node.js/Express):**
```javascript theme={null}
const express = require('express');
const app = express();
// Parse raw protobuf body
app.use('/api/mpcvault/callback', express.raw({ type: '*/*' }));
app.post('/api/mpcvault/callback', async (req, res) => {
try {
// The body contains a serialized SigningRequest protobuf
const signingRequestData = req.body;
// Implement your validation logic here:
// - Check amount limits
// - Verify destination addresses
// - Apply rate limiting
// - Log for audit trail
const shouldApprove = await validateSigningRequest(signingRequestData);
if (shouldApprove) {
// Return 200 to approve the transaction
res.status(200).send('approved');
} else {
// Return 4xx to reject
res.status(403).send('rejected');
}
} catch (error) {
console.error('Callback error:', error);
res.status(500).send('error');
}
});
app.listen(8088, () => {
console.log('Callback server running on port 8088');
});
```
**Security:** Your callback endpoint should validate requests and implement appropriate access controls. Consider using request signing or IP whitelisting.
## Docker Networking
| Your Setup | Callback URL Format |
| - | - |
| Callback server on same host as Docker | `http://host.docker.internal:PORT/path` |
| Callback server in same Docker network | `http://service-name:PORT/path` |
| Callback server on remote host | `http://your-server.com:PORT/path` |
**`host.docker.internal`** is a special DNS name that resolves to the host machine from inside a Docker container. It works on Docker Desktop (Mac/Windows) and recent Docker Engine versions on Linux.
## How Signing Works
When you call `ExecuteSigningRequests`:
```mermaid theme={null}
sequenceDiagram
participant App as Your App
participant API as MPCVault API
participant Signer as Client Signer
participant Chain as Blockchain
App->>API: POST /signing-requests/execute
API->>Signer: Callback (SigningRequest protobuf)
Note over Signer: Your logic decides
Signer-->>API: HTTP 200 (approve)
API->>Chain: Broadcast Transaction
API-->>App: { tx_hash: "0x...", status: "completed" }
```
## Troubleshooting
| Issue | Cause | Solution |
| - | - | - |
| Container won't start | Invalid config.yml | Check YAML syntax and key format |
| Container doesn't run correctly on Apple Silicon Mac | `amd64` image needs emulation | Try enabling Rosetta in Docker Desktop (see [Running on macOS](#running-on-macos-apple-silicon)) |
| Platform mismatch warning on macOS | Image is `linux/amd64`, host is Apple Silicon | Safe to ignore; optionally add `--platform linux/amd64` |
| No callbacks received | Wrong callback URL | Use `host.docker.internal` for local |
| Connection refused | Port not exposed | Verify `-p 8080:8080` mapping |
| Auth failed | Key mismatch | Ensure public key matches private key |
| Key access denied | Missing approval | Approve **Key grant access** in app |
| Timeout | Callback too slow | Respond within 5 seconds |
| Transaction rejected | Non-200 response | Check your validation logic |
### Useful Commands
```bash theme={null}
# Check signer logs
docker logs -f mpcvault-signer
# Restart signer
docker restart mpcvault-signer
# Check health
curl http://localhost:8080/health
# Test callback endpoint
curl -X POST http://localhost:8088/api/mpcvault/callback \
-H "Content-Type: application/octet-stream" \
-d "test"
```
# API Setup Guide
Source: https://docs.mpcvault.com/guides/18-how-to-enable-api/index
Complete guide to setting up API access and programmatic signing with MPCVault.
This guide walks you through setting up API access for MPCVault. You can start with just an API token and add the client signer later if you need automated signing.
## Choose Your Setup
**Start here** — all integrations begin with an API token.
* Create and manage wallets
* Query balances and history
* Create signing requests
* Transactions approved manually in app
**Add later** — when you need automation.
* Everything from API Token, plus:
* Execute transactions programmatically
* Automated approval based on your logic
* No manual intervention required
```mermaid theme={null}
flowchart LR
A[Create API Token] --> B{Need automation?}
B -->|No| C[Done! Use manual approval]
B -->|Yes| D[Add Client Signer]
D --> E[Full automation]
```
***
## API Token Only (Manual Approval)
With just an API token, you can build integrations where transactions are approved manually by team members in the MPCVault mobile app.
**Capabilities:**
* Create and list wallets
* Query balances and transaction history
* Create signing requests
* Monitor transaction status
**Signing flow:**
```mermaid theme={null}
sequenceDiagram
participant App as Your App
participant API as MPCVault API
participant Mobile as MPCVault App
participant Chain as Blockchain
App->>API: POST /signing-requests (create)
API-->>App: { uuid: "abc-123", status: "pending" }
Note over Mobile: Team member reviews
Mobile->>API: Approve & Sign
API->>Chain: Broadcast Transaction
App->>API: GET /signing-requests/abc-123
API-->>App: { status: "completed", tx_hash: "0x..." }
```
**Best for:** Treasury operations, high-value transfers, or any workflow requiring human review.
***
## API Token + Client Signer (Automated Signing)
Adding a client signer enables fully automated transaction execution without manual approval. The client signer runs on your infrastructure and programmatically approves transactions based on your business logic.
**Additional capabilities:**
* Execute signing requests programmatically
* Build automated payment workflows
* Handle high-frequency operations
* Implement scheduled transactions
**Signing flow:**
```mermaid theme={null}
sequenceDiagram
participant App as Your App
participant API as MPCVault API
participant Signer as Client Signer
participant Chain as Blockchain
App->>API: POST /signing-requests/execute
API->>Signer: Callback (SigningRequest protobuf)
Note over Signer: Your logic decides
Signer-->>API: HTTP 200 (approve)
API->>Chain: Broadcast Transaction
API-->>App: { tx_hash: "0x...", status: "completed" }
```
**Best for:** Automated payroll, programmatic trading, deposit sweeping, or any high-volume operation.
***
## Part 1: Create an API User (Required)
Every API integration starts with creating an API user and obtaining a token.
### Step 1: Create the API user
1. Go to [console.mpcvault.com](https://console.mpcvault.com).
2. Navigate to the **API** page (org admin required).
3. Click **Create an API user**.
4. Fill in the required fields:
| Field | Description |
| - | - |
| Name | Unique identifier for this API user (must be unique within the organization) |
| Permission | Select which vaults this API user can access |
| IP Whitelist | (Optional) Restrict access to specific IP addresses (up to 3, comma-separated) |
5. Click **Create** to generate the API user.
### Step 2: Save your API token
After creation, a popup displays your API token. **Copy and save it immediately.**
You cannot retrieve the full API token again. If you lose it, you must generate a new one.
### Step 3: Test your token
Verify your token works by making a test request:
```bash theme={null}
curl -X POST https://api.mpcvault.com/v1/getWalletList \
-H "Content-Type: application/json" \
-H "x-mtoken: YOUR_API_TOKEN" \
-d '{"vaultUuid": "your-vault-uuid","page":"0","limit":"10"}'
```
### What you can do now
| Operation | Endpoint | Requires Client Signer? |
| - | - | - |
| List wallets | `GET /wallets` | No |
| Get balances | `GET /wallets/{id}/balance` | No |
| Create wallets | `POST /wallets` | No |
| Create signing requests | `POST /signing-requests` | No (approved manually) |
| Execute signing requests | `POST /signing-requests/execute` | **Yes** |
**Example code and SDKs:** [GitHub repository](https://github.com/mpcvault/mpcvaultapis/tree/main/examples)
If you only need manual approval for transactions, you're done here. Continue to [Part 2](#part-2-set-up-the-client-signer-optional) only if you need automated signing.
***
## Part 2: Set Up the Client Signer (Optional)
**Skip this section** if you only need manual transaction approval via the MPCVault app.
The client signer enables fully automated transaction signing without manual approval. It's a Docker container that runs on your infrastructure and programmatically approves transactions based on your business logic.
Complete guide to setting up the client signer, including key generation, Docker deployment, and callback handler implementation.
***
## Custom EVM Chains
To send transactions on custom EVM chains via API:
### 1. Add the chain to your vault
1. Go to [console.mpcvault.com](https://console.mpcvault.com/)
2. Navigate to the vault's **Custom EVM networks** menu
3. Add the chain with: chain ID, RPC URL, block explorer URL
### 2. Add ERC20 tokens (if needed)
1. Navigate to the vault's **Token list** menu
2. Add tokens by contract address
### 3. Set required parameters
For custom EVM chains, you **must** explicitly provide:
| Parameter | Description | Why Required |
| - | - | - |
| `nonce` | Transaction sequence number | MPCVault can't query custom RPCs |
| `gas_fee` | Gas price and limit | Network conditions vary |
```json theme={null}
{
"chain_id": "43114",
"to_address": "0x...",
"value": "1000000000000000000",
"nonce": 42,
"gas_fee": {
"gas_limit": "21000",
"max_fee_per_gas": "25000000000",
"max_priority_fee_per_gas": "1000000000"
}
}
```
***
## Troubleshooting
| Issue | Cause | Solution |
| - | - | - |
| `401 Unauthorized` | Invalid or expired token | Regenerate token in console |
| `403 Forbidden` | No access to vault | Check API user permissions |
| `404 Not Found` | Wrong endpoint or resource | Verify API endpoint and IDs |
For client signer troubleshooting, see the [Client Signer Setup](/guides/18-how-to-enable-api/client-signer#troubleshooting) guide.
# BTC Wallet
Source: https://docs.mpcvault.com/guides/19-btc-wallet/index
Understanding UTXOs and network congestion for Bitcoin transactions.
## What is UTXO?
UTXO (Unspent Transaction Output) is how Bitcoin tracks ownership. Your BTC balance is the sum of all unspent outputs you've received. When you send BTC, you spend existing UTXOs and create new ones.
**Example:** You receive 1 BTC from Alice and 0.8 BTC from Bob. Your wallet now has:
* UTXO1: 1 BTC
* UTXO2: 0.8 BTC
To send 0.5 BTC, you could spend either UTXO and receive change. To send 1.2 BTC, you'd spend both UTXOs and receive 0.6 BTC change (minus fees).
### Insufficient UTXOs
If your available UTXOs can't cover the transaction plus fees, you'll see a "UTXO Insufficient" error. Either wait for pending transactions to confirm or add funds from another address.
## Network Congestion
Bitcoin blocks have limited capacity. When transaction volume exceeds this limit, the network becomes congested and confirmations slow down.
### Avoid Congestion
| Strategy | Description |
| - | - |
| Set appropriate fees | Higher fees incentivize miners to prioritize your transaction |
| Use batch payments | Combine multiple transfers into one transaction ([learn more](/guides/9-how-to-send-a-batch-payment/index)) |
| Time your transactions | Avoid peak congestion periods when possible |
# Create an Organization
Source: https://docs.mpcvault.com/guides/2-how-to-create-an-organization/index
Set up your team workspace in MPCVault.
Before creating an organization, you must register and generate a personal key certificate.
## Steps
1. **Name your organization** — This name will be visible to all members.
2. **Complete the questionnaire** — Answer questions about your use case.
3. **Select a plan** — Choose the plan that fits your needs and subscribe to activate.
4. **Generate your MPC root key** — Follow the on-screen instructions on your phone. This key secures your organization's crypto assets.
You can also create an organization from **My Account** in the console after backing up your personal key certificate. You can only set up one organization at a time.
# TRON Wallet
Source: https://docs.mpcvault.com/guides/20-tron-wallet/index
Activate your TRON wallet and understand bandwidth and energy fees.
## Account Activation
New TRON wallets must be activated before use. Send TRX or TRC-10 tokens to the new address to activate it. Activation costs 1 TRX plus bandwidth fees.
TRC-20 tokens (USDT, USDC) do not activate accounts. You must send TRX or TRC-10 tokens first.
## Network Fees
TRON uses bandwidth and energy instead of gas fees.
| Resource | Description | Free Allocation |
| - | - | - |
| Bandwidth | Required for all transactions | 600/day per account |
| Energy | Required for smart contracts (TRC-20) | None |
If you lack bandwidth or energy, TRX is automatically burned to cover fees.
### Typical Costs
A TRC-20 transfer (e.g., USDT) requires \~345 bandwidth and \~64,285 energy:
* Burning TRX directly: \~13.61 TRX
* Purchasing energy on MPCVault: 6 TRX for 65,000 energy
### Buy Energy on MPCVault
1. Go to **Wallets** and select your TRON wallet.
2. Click **Buy Energy**.
3. Sign the transaction in the mobile app.
If the recipient has never held the token you're sending, energy costs may double.
# TON Wallet
Source: https://docs.mpcvault.com/guides/21-ton-wallet/index
Understand TON wallet contracts, fees, and the Comment field for exchange deposits.
## How TON Wallets Work
On TON, every wallet is a smart contract. Your first transaction deploys this contract, requiring a small GRAM (prev. TON) payment. MPCVault displays addresses in "UQ" format.
## Transaction Fees
TON fees consist of multiple components:
| Fee Type | Description |
| - | - |
| Storage | Cost for storing your wallet contract on-chain |
| Forward | Fees for sending messages between contracts |
| Action | Fee for executing the transaction |
| Computation | Cost for running contract code |
TON fees cannot be customized. MPCVault does not charge additional fees.
## Usage Tips
* First transaction costs extra to deploy the wallet contract (one-time)
* Every transaction incurs storage fees
* When sending to exchanges, always include the required **Comment (memo/tag)**
## Comment vs Transaction Notes
| Field | Visibility | Purpose |
| - | - | - |
| Comment | Public (on-chain) | Required by exchanges to identify deposits |
| Transaction Notes | Private (MPCVault only) | Internal tracking for your team |
When depositing to an exchange, enter the memo/tag in the **Comment** field, not Transaction Notes. If you forget, contact the exchange support—your funds are safe as long as the address is correct.
# Aptos Wallet
Source: https://docs.mpcvault.com/guides/23-how-to-receive-assets-into-your-aptos-wallet/index
Register coins and enable NFT receiving on your Aptos wallet.
Aptos requires coins to be registered before you can receive them. This is an on-chain action requiring APT for fees.
## Add Coins
1. Go to [console.mpcvault.com](https://console.mpcvault.com/).
2. Select your Aptos wallet > **...** > **Add coins**.
3. Choose the coin and click **Add coins**.
4. Sign the request in the app.
If a coin isn't listed, contact support to request it.
## Enable NFT Receiving
1. Go to [console.mpcvault.com](https://console.mpcvault.com/).
2. Select your Aptos wallet > **...** > **Enable NFT receive**.
3. Click **Confirm** and sign in the app.
Ensure your account has sufficient APT for network fees.
# Custom EVM Networks
Source: https://docs.mpcvault.com/guides/24-how-to-use-custom-evm-networks/index
Add any EVM-compatible chain not natively supported by MPCVault.
Add custom EVM networks when your chain isn't listed or to recover funds sent to the wrong network.
## Setup Process
1. Add the network in **Custom EVM networks** settings
2. Import tokens via **Token list** (see [Manage Tokens & NFTs](/guides/7-how-to-manage-your-tokens-and-nfts/index))
3. Add the custom chain to your wallet
4. Transact as you would on any EVM chain
## Add a Custom Network
1. Go to [console.mpcvault.com](https://console.mpcvault.com/).
2. Navigate to vault settings > **Custom EVM networks**.
3. Click **+ Add a network** and enter the chain details.
4. Click **Create** to save.
Only add trusted RPC URLs. Reference [Chainlist](https://chainlist.org/) for verified chain and node information.
## Troubleshooting
### Transaction Not Found
The transaction may not have been broadcast yet. Use the **Re-broadcast** button in the signing request details.
### Transaction Failed
Usually caused by incorrect gas settings. Reference recent similar transactions on a block explorer to find appropriate values.
### "Intrinsic gas too low" Error
1. Find your chain's block explorer (search "\[chain name] explorer")
2. Locate a recent successful transaction of the same type
3. Check the **Gas Limit & Usage** and **Gas Price** fields
4. Set your gas slightly higher than the reference values
Match the transaction type (Legacy or EIP-1559) when referencing gas values.
### "Nonce too low" Error
Re-initiate with the correct nonce. The nonce starts at 0 and increments by 1 for each transaction. Check the block explorer for your wallet's latest nonce.
### Empty Gas/Nonce Fields
If fields are frequently empty, your RPC node may be unstable. Update to a more reliable RPC URL from [Chainlist](https://chainlist.org/).
# Solana Wallet
Source: https://docs.mpcvault.com/guides/25-why-did-my-solana-transaction-fail/index
Recommended balance and tips for successful Solana transactions.
## Minimum Balance
Maintain at least **0.05 SOL** in your wallet to cover transaction fees and rent costs.
When sending to a new address, send at least **0.05 SOL** to ensure the recipient can use the account.
Actual requirements vary with network congestion and transaction type. Check current fees and keep an appropriate buffer.
# MetaMask Institutional
Source: https://docs.mpcvault.com/guides/26-how-to-use-metamask-institutional-on-mpcvault/index
Connect MetaMask Institutional to MPCVault for enterprise-grade transaction signing.
Initiate transactions from MetaMask Institutional and sign them in MPCVault. All transactions follow your organization's policies.
## Connect to MMI
1. Go to [console.mpcvault.com](https://console.mpcvault.com/) and log in.
2. Navigate to **Settings** > **General** > **MetaMask Institutional**.
3. Click **Connect MMI** to open the MetaMask extension.
4. Select the wallets to connect and click **Confirm**.
To disconnect: click **...** next to the account and select **Remove account**.
Disable other wallet extensions temporarily to avoid conflicts with MetaMask.
## Sign Transactions
1. Initiate a transaction from MetaMask Institutional.
2. The transaction is forwarded to MPCVault automatically.
3. Review the transaction details in MPCVault.
4. Sign the transaction in the MPCVault mobile app.
# Token Approval Security
Source: https://docs.mpcvault.com/guides/28-how-to-deal-with-token-approvals-risk/index
Manage and revoke token approvals to protect your assets.
Token approvals let dApps interact with your tokens, but they carry risk. If a smart contract you approved gets hacked, your tokens can be stolen. Regularly review and revoke unnecessary approvals.
## Review Approvals in MPCVault
1. Visit [console.mpcvault.com](https://console.mpcvault.com/).
2. Go to **Wallets**.
3. Click the **x approval** button on any token.
4. Review the list of approved contracts.
5. Click **Revoke** to submit a signing request.
6. Approve and sign in the MPCVault app.
## Review Approvals in Revoke.cash
1. Go to **Wallets** in MPCVault.
2. Click **View approval risks** to open [Revoke.cash](https://revoke.cash/).
3. Connect your wallet to view all approvals.
4. Revoke or modify approval amounts as needed.
**Best practices:**
* Review approvals monthly, especially after using new dApps
* Revoke unused or outdated authorizations immediately
* Avoid setting unlimited approval amounts
# MPCVault Card
Source: https://docs.mpcvault.com/guides/29-how-to-use-an-mpcvault-card/index
Spend crypto anywhere with virtual Visa cards for your team.
Create virtual Visa cards funded by crypto. Allocate funds to team members while maintaining individual spending controls.
## Getting Started
Complete KYB verification before issuing cards.
1. Navigate to **Cards** and click **Get started**.
2. Submit required documents (\$10 USD verification fee).
3. Wait for approval—the card feature unlocks once verified.
## Deposit Funds
Top up your card account with USDC on Ethereum, Polygon, or Solana.
### Via Web
1. Go to **Cards** > **Home** and click **+ Top Up**.
2. Select wallet and network.
3. Enter amount and click **Deposit**.
### Via Mobile App
1. Go to **Card** > **Top Up**.
2. Select vault, wallet, and network.
3. Enter amount and sign the transaction.
Fee: 3 USDC + 0.5% per deposit. Funds may take a few minutes to credit.
## Create Cards
1. Go to **Cards** > **Home** and click **+ New Virtual Card**.
2. Enter card nickname and spending limit.
3. Click **Create** (1 USDC fee per card).
No limit on the number of cards you can create.
## Use Your Card
* **In-store**: Add to Apple Pay, Google Pay, or AliPay
* **Online**: Amazon, eBay, subscriptions (Netflix, Spotify), digital services (ChatGPT, Shopify)
* **Travel**: Flights, hotels, rental cars
* **Global**: Accepted at 90M+ merchants worldwide
## Deactivate Cards
1. Find the card in **Cards** > **Home**.
2. Click **...** > **Deactivate**.
3. Confirm deactivation.
## Transactions
View all card activity in **Cards** > **Transactions**. Click any record to see details and add notes.
### Transaction Statuses
| Status | Description |
| - | - |
| Pending | Authorized but not yet settled |
| Completed | Fully settled, funds deducted |
| Failed | Unsuccessful, no funds deducted |
## Fees
| Fee Type | Amount |
| - | - |
| KYB verification | \$10 |
| Card issuance | \$1 per card |
| Crypto deposit | 3 USDC + 0.5% |
| International transactions | Up to 3% (USD with US merchants: 0%) |
| Transaction disputes | \$35 per case |
## Blocked Merchant Categories
Transactions with certain high-risk merchant categories (MCCs) may be declined for compliance and security reasons.
| MCC | Category |
| :- | :- |
| 2892 | Explosives |
| 3484 | Armas de pequeño calibre |
| 4829 | WIRE TRANSFER - MONEY ORDER |
| 5122 | Drugs, Drug proprietaries, druggiest sundries |
| 5542 | Automated fuel dispenders |
| 5681 | FURRIERS AND FUR SHOPS |
| 5816 | Digital Goods - games for transactions involving skilled game wagering (daily fantasy sports) |
| 5932 | ANTIQUE SHOPS |
| 5933 | PAWN SHOPS |
| 5937 | ANTIQUE REPRODUCTIONS |
| 5944 | JEWELRY STORES |
| 5960 | Direct marketing - Insurance |
| 5962 | Direct marketing - travel related arrangement services |
| 5964 | Direct marketing - catalog merchants |
| 5965 | Direct Marketing—Combination Catalog and Retail Merchants |
| 5966 | Direct marketing - Outbound telemarketing merchants |
| 5967 | Direct Marketing - Inbound Telemarketing merchants |
| 5969 | Direct Marketing/Direct Marketers (Not elsewhere classified) |
| 5972 | STAMP & COIN STORES |
| 5993 | Cigar stores and stands |
| 6010 | FINANCIAL INSTITUTIONS - MANUAL CASH DISBURSEMENTS |
| 6011 | FINANCIAL INSTITUTIONS - AUTOMATED CASH DISBURSEMENTS |
| 6012 | FINANCIAL INSTITUTIONS - MERCHANDISE & SERVICES |
| 6050 | QUASI CASH - MEMBER FINANCIAL INSTITUTION |
| 6051 | QUASI CASH |
| 6211 | SECURITY BROKERS/DEALERS |
| 6529 | REMOTE STORED VALUE LOAD-MEMBER FINANCIAL INSTITUTION |
| 6530 | REMOTE STORED VALUE LOAD - MERCHANT |
| 6531 | PAYMENT SERVICE PROVIDER - MONEY TRANSFER |
| 6532 | PAYMENT TRANSACTION - MEMBER FINANCIAL I |
| 6533 | PAYMENT TRANSACTION - MERCHANT |
| 6534 | MONEY TRANSFER - MEMBER FINANCIAL INSTITUTION |
| 6535 | VALUE PURCHASE - MEMBER FINANCIAL INSTITUTION |
| 6536 | MONEYSEND INTRACOUNTRY |
| 6537 | MASTERCARD MONEY SEND INTERCOUNTY |
| 6538 | MASTERCARD MONEYSEND FUNDING TRANSACTION |
| 6540 | POI FUNDING TRANSACTIONS |
| 6555 | MASTERCARD INITIATED REBATE/REWARDS |
| 6611 | OVERPAYMENTS |
| 6760 | SAVINGS BONDS |
| 7272 | ESCORT SERVICES |
| 7273 | DATING OR ESCORT SERVICES |
| 7280 | HOSPITAL PATIENT PERSONAL FUNDS WITHDRAW |
| 7322 | DEBT COLLECTION AGENCIES |
| 7800 | GOVERNMENT - OWNED LOTTERIES |
| 7801 | GOVERNMENT LICENSED CASINOS (ONLINE GAMBLING) |
| 7802 | GOVERNMENT LICENSED HORSE/DOG RACING |
| 7948 | Organización de carreras |
| 7995 | Betting, including lottery tickets, casino gaming chips, off-track betting, wagers at race tracks and games of chance to win prizes of monetary value |
| 8631 | Labor Unions |
| 8651 | Political Organizations |
| 8661 | Religious organizations |
| 9223 | Bail and bond payments |
| 9401 | I-PURCHASING PILOT |
| 9405 | Intra-Government Purchases (Government only) |
| 9411 | GOVERNMENT LOAN PAYMENTS |
| 9700 | International Automated Referral Service (Visa use only) |
| 9701 | Visa Credential Server (Visa use only) |
| 9702 | GCAS Emergency Services (Visa use only) |
| 9721 | Asuntos internacionales (embajadas) |
| 9754 | GAMBLING-HORSE RACING,DOG RACING,STATELOT |
| 9950 | Intra-Company Purchases |
| 6531 | PYMT SVC PROV - MONEY TRANSFER FOR A PURCHASE |
| 6532 | PYMT SVC PROV - MEMBER FIN INSTITUTION - PYMT TRAN |
| 6533 | PYMT SVC PROV - MERCHANT - PYMT TRAN |
| 7297 | MASSAGE PARLORS |
| 7995 | BETTING/TRACK/CASINO/LOTTO |
# Invite Members
Source: https://docs.mpcvault.com/guides/3-how-to-invite-members-to-your-organization/index
Add team members to your organization.
## Inviting Members
Owners and admins can invite new members to the organization.
1. Go to **Settings** in the side menu.
2. On the **General** page, click **+ New member**.
3. Enter the invitee's email and select their role.
4. Click **Send invites**.
Once invitees accept and set up their account, they join your team with the assigned role permissions.
## Accepting an Invitation
1. Open the MPCVault app.
2. Go to **Me** > **Organization**.
3. Select the organization and tap **Join now**.
If you received an invitation but don't see the organization listed, try switching networks or restarting the app.
## Deactivating a Member
Deactivated members cannot log in to your organization. This does not change vault signing policies—ensure the member has transferred any necessary rights first.
1. Visit [console.mpcvault.com](https://console.mpcvault.com/).
2. Go to **Settings**.
3. Find the member and click **...** > **Deactivate member**.
4. Confirm when prompted.
Only admins can deactivate members. The organization owner cannot be deactivated.
# Off-Ramp Crypto
Source: https://docs.mpcvault.com/guides/30-how-to-off-ramp-crypto/index
Convert stablecoins to fiat and send funds to any verified bank account.
Convert USDC or USDT to fiat currency (USD, EUR, GBP, etc.) and transfer directly to verified bank accounts.
**Use cases:**
* Withdraw to your business bank account
* Pay vendors or suppliers
* Settle invoices
## Quick Start
1. **Complete KYB** — Verify your business
2. **Add a recipient** — Verify the recipient's bank account
3. **Create a fiat payment** — Convert and transfer
## Step 1: Complete KYB
KYB is required for fiat payments (business accounts only).
1. Go to **Fiat payment** and click **Get started**.
2. Submit required documents.
3. Wait for approval.
## Step 2: Add a Recipient
Recipients (individuals or businesses) must be verified per AML regulations.
1. Go to **Recipients** > **+ Add a recipient**.
2. Submit required documents.
3. Wait for **Verified** status.
## Step 3: Create a Fiat Payment
1. Go to **New payment** > **+ New fiat payment**.
2. Enter wallet, recipient, and currency details.
3. Click **Continue** to create the signing request.
4. Sign in the MPCVault app.
## Order Statuses
| Status | Description | Action |
| - | - | - |
| Reviewing order | Under review | Wait |
| Action needed | Awaiting signature | Sign within 30 minutes |
| Pending on chain | Broadcasting | None |
| Processing payout | Transferring to bank | None |
| Completed | Success | Check bank account |
| Failed | Payment failed | Check balance and gas, retry |
## Supported Options
| Type | Options |
| - | - |
| Crypto | USDC, USDT |
| Fiat | USD, EUR, GBP, SGD, AUD, AED |
| Chains | Ethereum, Polygon, Solana, Tron |
## Fees
| Currency | Paid Plan | Free Plan |
| - | - | - |
| USD ACH | \$11 + 0.25% | \$11 + 0.40% |
| USD SWIFT | \$40 + 0.25% | \$40 + 0.40% |
| USD WIRE | \$35 + 0.25% | \$35 + 0.40% |
| EUR | \$10 + 0.35% | \$10 + 0.50% |
| GBP | \$10 + 0.35% | \$10 + 0.50% |
| SGD | \$10 + 1.00% | \$10 + 1.00% |
| AUD | \$10 + 1.00% | \$10 + 1.00% |
| AED SWIFT | \$35 + 0.60% | \$35 + 0.75% |
* Ensure sufficient stablecoins and native tokens (for gas) before creating a payment.
* Signing requests expire in 30 minutes.
* Fiat payouts typically arrive within 2–12 hours (delays possible on non-business days).
# Signing Request Errors
Source: https://docs.mpcvault.com/guides/31-why-do-I-encounter-an-unknown-error-when-opening-a-signing-request/index
Fix unknown errors when opening signing requests.
Unknown errors when opening signing requests are typically caused by network issues or outdated app versions.
## Solutions
1. **Check your connection** — Ensure stable internet (try switching between Wi-Fi and mobile data)
2. **Update the app** — Install the latest version from your app store
3. **Restart the app** — Close and reopen MPCVault
If the issue persists, contact support.
# Device Troubleshooting
Source: https://docs.mpcvault.com/guides/32-common-device-troubleshooting-guide/index
Common fixes for MPCVault app, web, and browser extension issues.
## Mobile App
| Issue | Solution |
| - | - |
| General glitches | Restart your device |
| Login errors | Verify device time and time zone are correct |
| Data not loading | Switch networks (Wi-Fi/mobile) or disable VPN |
| Features not working | Update to the latest app version |
| Missing features | Check app permissions (storage, camera, network) |
## Web Console
| Issue | Solution |
| - | - |
| Display issues | Try a different browser (Chrome, Firefox, Safari) |
| Unexpected behavior | Clear browser cache and cookies |
| Data not loading | Switch networks or disable VPN |
## Browser Extension
| Issue | Solution |
| - | - |
| Won't launch on "Connect Wallet" | Disable other wallet extensions |
| Connection issues | Update the extension and browser |
| dApp not connecting | Refresh the dApp page |
| General issues | Restart extension: disable → wait → re-enable |
If issues persist, contact us via **Contact Us**.
# Pending Transactions
Source: https://docs.mpcvault.com/guides/33-how-to-handle-pending-transactions/index
Diagnose and resolve stuck or pending transactions.
## Common Causes
### EVM Chains
| Issue | How to Check |
| - | - |
| Low gas fees | Compare to current fees on a block explorer |
| Incorrect nonce | Verify nonce is sequential (no gaps) |
| Insufficient balance | Confirm balance covers amount + gas |
| Network congestion | Check network status |
### Non-EVM Chains
| Issue | How to Check |
| - | - |
| Low fees | Compare to current network fees |
| Network congestion | Check blockchain status |
## Solutions
### EVM Chains
| Problem | Solution |
| - | - |
| Low gas fees | Resend with higher gas |
| Nonce gap | Send missing nonce transactions first |
| Insufficient funds | Reduce amount or add funds |
| Hash not found | Use **Re-broadcast** in signing request |
| Congestion | Wait or rebroadcast |
To stop a pending transaction, [cancel it](/guides/12-how-to-cancel-a-transaction/index). Transactions with nonce gaps must be resolved in order.
### Non-EVM Chains
Use **Re-broadcast** in the signing request details. For minor congestion, waiting may be sufficient.
## Dropped Transactions
If a transaction shows "dropped" status, click the transaction hash to verify its final status on the block explorer.
# Stellar Wallet
Source: https://docs.mpcvault.com/guides/34-stellar-wallet/index
MPCVault now supports the Stellar network, allowing your organization to manage XLM and other Stellar assets (such as USDC) with institutional-grade security.
## Account Activation
Unlike most networks, a Stellar account must be activated before it can be used to send transactions or create trustlines.
* Minimum Balance: To activate an account, you must send **at least 1 XLM** to your new Stellar address.
* Base Reserve: This 1 XLM is a "Base Reserve" required by the Stellar network and will be locked to maintain the account's existence on-chain.
Ensure your first transfer to a new MPCVault Stellar address is at least 1 XLM to avoid "Account Not Found" errors on block explorers.
## Managing Trustlines
To receive any asset other than XLM (e.g., USDC), you must first establish a Trustline. This is a Stellar-specific mechanism to prevent unauthorized assets from being sent to your wallet.
### How to create a Trustline
1. **Initiate:**
* **Quick Entry**: If your wallet does not yet hold any non-native assets, look for the hint: "Want to receive USDC? Create trustline first." Clicking this will open the setup window automatically.
* **Web**: Click the **three-dot menu** next to your Stellar wallet address and select Create Trustline.
* **App**: Open the wallet details page, tap the **three-dot menu** in the top right corner, and select Create Trustline.
2. **Details:** In the popup, enter the **Asset Code** or the **Issuer Address**.
3. **Sign**: As this is an on-chain operation, a signing request will be sent to your MPCVault App. The trustline will be established once the transaction is signed and confirmed.
Each Trustline increases your account's minimum required balance by **0.5 XLM**. Ensure you have sufficient XLM in your wallet before adding new assets.
## Receiving & Sending Assets
* **Receiving**: Share your "G" address to receive funds. Before receiving assets like USDC, ensure you have first created a Trustline for that specific asset.
* **Sending**: When withdrawing to an exchange, always include the Destination Memo provided by the recipient to ensure the funds are credited correctly.
* **Approval Flow**: All Stellar transactions, including creating trustlines, follow your vault's defined Transaction Policy.
# Apple ID Relay Email
Source: https://docs.mpcvault.com/guides/35-Apple-ID-relay-email/index
If you plan to log in to MPCVault using Sign in with Apple and select Hide My Email, Apple will generate a unique, random **@privaterelay.appleid.com** address for your account.
MPCVault uses email to deliver organization invitations, transaction notifications, and product updates. Your administrator must send your invite to this exact Private Relay address.
## Best practice
To avoid relay delays and ensure seamless team onboarding, we recommend registering via:
* Continue with Google
* Sign up with Email (using the exact email address where you received the invitation)
## How to find your private Apple relay email
Before your administrator sends the invitation, retrieve your relay address and ensure email forwarding is active:
**On iPhone / iPad**:
1. Open **Settings** > tap your **Apple ID** > **Sign in with Apple**.
2. Select **MPCVault** from the list of apps.
3. **Long press** the email address under Hide My Email (ending in @privaterelay.appleid.com) to copy it, then send it to your administrator.
**On Mac**:
1. Open System **Settings** > click your **Apple ID** > **Sign in with Apple**.
2. Click **MPCVault** to view your relay email address.
3. Copy the address and then send it to your administrator.
Note for Admins: If the user uses Apple's "Hide My Email," make sure to invite their @privaterelay.appleid.com address to ensure proper organization access.
Revoking access or turning off Forward To in your Apple ID settings will result in not receiving emails. To restore email delivery, log out of MPCVault and log in again using Sign in with Apple to re-authorize access.
# Deposit & Sweep
Source: https://docs.mpcvault.com/guides/36-deposit-and-sweep/index
Give every user a dedicated deposit address, get notified in real time, and let MPCVault collect the funds for you.
Sweep is a deposit solution for platforms that accept crypto payments from many end users - exchanges, payment processors, gaming platforms, and marketplaces.
Each of your users gets a dedicated on-chain deposit address. When a transfer lands on it, MPCVault notifies your server in real time; USDC/USDT deposits are then swept automatically into a single address you control.
**Why use it:**
* **Dedicated Addresses** - Create one or more addresses per user; deposits are attributed by address, so there are no memos or order IDs for users to forget, and no misattributed funds
* **No Wallet Infrastructure** - You manage no private keys, hot wallets, or address pools
* **Automatic Sweeping** - No manual collection, and you never handle Gas across thousands of small addresses
* **Built-in Risk Controls** - Two-stage confirmation thresholds (credit vs. release) plus reorg notifications
Supported networks: EVM (Ethereum, Arbitrum, Base, Polygon, BSC) and Solana.
## How It Works
1. Your server requests one or more deposit addresses for a user via the API.
2. The user deposits to the address - any time, any amount, as many times as they like.
3. MPCVault sends a signed webhook to your webhook URL in real time for each transfer, and you credit the user's account.
4. USDC/USDT deposits are transferred to your configured sweep address per the sweep policy, net of a small network fee.
Crediting users is driven entirely by webhooks - it does not wait for sweeping.
## Security
The design closes off several common attack paths:
* **Address Poisoning** - Sweeping sends funds to your pre-configured sweep address; no address is ever copied per transfer, so poisoned history has nothing to exploit
* **Fake Deposit Notifications** - Every webhook is Ed25519-signed; forged callbacks fail verification
* **Counterfeit Tokens** - Webhooks identify tokens by contract address (`mint_address`), never by symbol, so fake "USDT" contracts can't be credited
* **Chain Reorgs** - Two-stage confirmations prevent crediting funds that get rolled back; EVM reorgs are delivered as `REVERTED` notifications
## TRON Watch Address
Alongside Sweep, the same API token also lets you register TRON addresses for monitoring - built for wallets you run yourself. MPCVault sends a signed webhook whenever a registered address sends or receives TRX or USDT - notification only, no wallet is created and no assets are moved.
## Getting Started
Sweep is enabled per account: the API token is issued by MPCVault, and your sweep address and webhook URL are configured with your account manager. Contact your MPCVault account manager to begin.
Once enabled, head to the API documentation:
Create deposit wallets, handle webhooks, and review sweep rules and fees.
Register TRON addresses and receive transfer notifications.
# Vaults and Wallets
Source: https://docs.mpcvault.com/guides/4-what-are-vaults-and-wallets/index
Understand how vaults and wallets organize your assets in MPCVault.
## Vaults
A vault is a collection of blockchain addresses with its own members and transaction policies. Use multiple vaults to separate assets with different security requirements.
**Example setup:**
| Vault | Purpose | Policy |
| - | - | - |
| Operating | Day-to-day transactions | Any member can sign |
| Reserve | Large holdings | 2-of-3 approval for amounts over \$1,000 |
## Wallets
A wallet is a blockchain address with its own key pair. Create multiple wallets within a vault for different chains and purposes.
MPCVault maintains the same address across all EVM chains—no risk of sending to the wrong network.
Each wallet address is derived using a unique path based on the vault index, network, and address index. See [Key Derivation](/key-derivation#derivation-paths--networks) for technical details on derivation paths and supported networks.
## Creating a Wallet
1. Go to **Wallets** and click **Create wallet**.
2. Select the blockchain network and click **Continue**.
3. Sign the request in the MPCVault app.
If **Manager has to approve wallet creations** is enabled in settings, a manager must approve the request.
# Vault Members & Multisig
Source: https://docs.mpcvault.com/guides/5-how-to-add-vault-members-and-set-up-multisig/index
Add team members to vaults and configure multi-signature policies.
## Adding Vault Members
Only vault managers can add members. Invitees must already be part of the organization ([invite members first](/guides/3-how-to-invite-members-to-your-organization/index)).
### Via Web Console
1. Select the vault and go to **Team & Tx policies**.
2. Click **Edit member** > **+ Add vault members**.
3. Select members, assign roles, and click **Continue** > **Confirm**.
All vault managers receive a **Vault setting update** signing request.
### Via Mobile App
1. Select the vault from the home page.
2. Tap **...** > **Vault members** > **Manage members**.
3. Select members, assign roles, and tap **Confirm**.
## Configuring Multisig Policies
Set approval requirements based on transaction volume, destination, or type. Each vault can have different policies.
### Setup Steps
1. Go to **Team & Tx policies** and click **+ New policy**.
2. Select the [policy type](/guides/15-vault-transaction-policies/index).
3. Configure the rules and click **Confirm**.
4. Approve the signing request in the app.
The number of required managers cannot exceed the [manager quorum](/guides/16-what-is-a-quorum/index).
### Example
For a reserve vault holding significant funds:
| Daily Volume | Approval Required |
| - | - |
| \< \$10,000 | Any member |
| ≥ \$10,000 | 3 managers |
***
## How Multisig Works
MPCVault's multisig is implemented through **system-enforced approval policies**, not traditional on-chain multisig.
### Policy Enforcement
When a signing request is created:
1. The MPCVault server checks the transaction against configured policies
2. If the required approvals are not met, the server **refuses to participate** in the MPC signing protocol
3. Only when all policy conditions are satisfied does the server allow the signing to proceed
```mermaid theme={null}
flowchart LR
A[Signing Request] --> B{Policy Check}
B -->|Not Met| C[Server Refuses]
B -->|Met| D[MPC Signing Proceeds]
D --> E[Transaction Signed]
```
### Key Security Model
**MPCVault cannot sign transactions alone.** The server holds only one of three key shares required for signing.
Even though the server enforces policies, it cannot unilaterally sign transactions because:
| Component | Key Share | Role |
| - | - | - |
| Your device | Share 1 | You control this share |
| MPCVault (Google Cloud) | Share 2 | Enforces policies, participates in MPC |
| MPCVault (Azure) | Share 3 | Participates in MPC |
All three shares must participate in the MPC computation to produce a valid signature. The server's policy enforcement is an **additional security layer** on top of the cryptographic requirement that you must provide your key share.
### What This Means
* **You remain in control**: No signature is possible without your key share
* **Policies are enforced**: The server won't participate unless your configured rules are met
* **No single point of failure**: Even if the server were compromised, attackers cannot sign without your share
# Deposit Assets
Source: https://docs.mpcvault.com/guides/6-how-do-I-transfer-funds-into-mpcvault/index
Transfer funds into your MPCVault wallets.
MPCVault wallets are standard blockchain addresses. EVM wallets maintain the same address across all EVM chains. Non-EVM chains have separate addresses.
## How to Deposit
1. Go to **Wallets** and select your wallet.
2. Click the **Copy** icon to copy the address.
3. Send funds from your external wallet or exchange.
Verify you're sending to the correct network before transferring.
## Supported Networks
| Network | Assets | For example |
| - | - | - |
| Ethereum | ETH, ERC-20, ERC-721, ERC-1155 | ETH, USDC, USDT, DAI, and more |
| Polygon | POL, ERC-20, ERC-721, ERC-1155 | POL, WETH, USDC, USDT, BUSD, and more |
| BNB Smart Chain | BNB, BEP-20, ERC-721, ERC-1155 | BNB, ETH, BUSD, USDC, USDT, WBNB, and more |
| Arbitrum | ETH, ERC-20, ERC-721, ERC-1155 | ETH, USDT, USDC, LINK, WBTC, DAI, and more |
| Optimism | ETH, ERC-20, ERC-721, ERC-1155 | ETH, USDT, USDC, LINK, WBTC, DAI, and more |
| Avalanche C-Chain | AVAX, ERC-20, ERC-721, ERC-1155 | AVAX, USDt, USDC, LINK, DAI, and more |
| Base | ETH, ERC-20, ERC-721, ERC-1155 | ETH, USDC, DAI, WETH, cbETH, and more |
| Bitcoin | BTC (Only supports BTC) | BTC |
| TRON | TRX, TRC-10, TRC-20, TRC-721 | TRX, WTRX, USDT, USDC, and more |
| Aptos | APT, Coins, Tokens | APT, zUSDC, zUSDT, and more |
| Sui | SUI, Coins, NFTs | SUI, USDC, USDT, and more |
| Solana | SOL, Tokens, NFTs | SOL, USDC, USDT, and more |
| TON | TON, Jettons | TON, GRAM, NOT, and more |
| DATA Network (prev. Story) | DATA, ERC-20, ERC-721, ERC-1155 | DATA, USDC, Sona, and more |
| Movement | MOVE, Coins, NFTs | MOVE, USDC, and more |
| Sonic SVM | SOL, Tokens, NFTs | SOL, SONIC, USDC, and more |
Ensure your account has enough native tokens to cover network fees.
# Manage Tokens & NFTs
Source: https://docs.mpcvault.com/guides/7-how-to-manage-your-tokens-and-nfts/index
Import missing tokens and hide spam assets.
## Whitelist (Import Tokens)
If a token doesn't appear in your wallet, import it manually.
1. Go to **Token list** in the web console.
2. Click **Import tokens**.
3. To remove: click **...** > **Remove from whitelist**.
### Supported networks
* Ethereum
* Polygon
* BNB Smart Chain
* Optimism
* Arbitrum
* Avalanche C-Chain
* Base
* DATA Network (prev. Story)
* Solana
* Sonic SVM
* Tron
* Sui
* TON
* Added EVM network ([how to add](/guides/24-how-to-use-custom-evm-networks/index))
Only import tokens you trust. For NFTs, use a block explorer or dApp to [transfer](/guides/8-how-to-transfer-nfts/index).
## Blocklist (Hide Spam)
Hide unwanted tokens and NFTs from your dashboard and transaction history.
### Via Web Console
1. Go to [console.mpcvault.com](https://console.mpcvault.com/).
2. Find the asset and click **...** > **Mark as spam**.
### Via Mobile App
* **From wallet:** Open asset details > **...** > **Mark as spam**
* **From transactions:** Tap transaction > **...** > **Mark as Spam**
To restore: go to **Blocklist** and select **Remove from blocklist**.
Blocklisted assets are hidden from your dashboard and history.
# How to Transfer Nfts
Source: https://docs.mpcvault.com/guides/8-how-to-transfer-nfts/index
MPCVault currently does not directly provide NFT transfers. You can complete the transfer of NFTs in the following ways.
MPCVault currently does not directly provide NFT transfers. You can complete the transfer of NFTs in the following ways.
1. Use WalletConnect or the MPCVault Plugin to complete the transfer on a dApp that supports NFT transfers. Here's how to do it:
* Visit dApp that supports NFT transfers, e.g. [OpenSea](https://opensea.io/), [Element](https://element.market/).
* After the wallet is successfully connected, navigate to the "**Profile**" page.
* Locate the NFT you wish to transfer on the NFT asset list and initiate the transfer request.
* Go back to the MPCVault app to sign the request.
2. Interact directly with the NFT contract on a block explorer to complete the transfer. Here's how to do it:
* Locate the NFT contract you want to transfer on a block explorer, e.g. [etherscan](https://etherscan.io/), [polygonscan](https://polygonscan.com/)、[bscscan](https://bscscan.com/).
* View the contract and enter the "**Write Contract**" page, click on "**Connect to Web3**" to connect the wallet you want to operate.
* Find the transfer method, input relevant parameters, and click the "**Write**" button.
* Go back to the MPCVault app to sign the request.
Note: This method is only applicable for verified NFT contracts.
3. Transfer NFTs programmatically, that is, sending [custom transaction](/guides/11-how-to-set-custom-payload-for-your-transaction/index) on the MPCVault platform.
For more information on how to manage NFTs, [see here](/guides/7-how-to-manage-your-tokens-and-nfts/index).
# Batch Payments
Source: https://docs.mpcvault.com/guides/9-how-to-send-a-batch-payment/index
Send crypto to multiple recipients in a single transaction.
Send to up to **254 recipients** in one transaction. Upload a CSV file or clone previous payments. All entries appear in your transaction history.
## Supported assets
| **Network** | **Assets** |
| :- | :- |
| Ethereum | ETH, ERC-20 |
| Polygon | POL, ERC-20 |
| BNB Smart Chain | BNB, BEP-20 |
| Arbitrum | ETH, ERC-20 |
| Optimism | ETH, ERC-20 |
| Avalanche C-Chain | AVAX, ERC-20 |
| Base | ETH, ERC-20 |
| Bitcoin | BTC (Only supports BTC) |
| Sui | SUI, Coin |
| DATA Network (prev. Story) | DATA, ERC-20 |
## Creating a Batch Payment
1. Go to your vault and click **Batch payment** > **New batch payment**.
2. Select wallet and asset. Enter recipients manually or click **Upload CSV/Excel**.
3. Review details and click **Confirm**.
4. Initiate the transaction:
* **Native tokens:** Click **Create batch transaction**.
* **ERC-20 tokens:** First click **Create approval transaction**, then **Create batch transaction**.
**ERC-20 batch payments require approval + send in sequence.** Complete both steps for one payment before starting the next.
**Correct:** Approval (300) → Send (300) → Approval (200) → Send (200)
**Incorrect:** Approval (300) → Approval (200) → Send (300) → Send (200) — the 300 send will fail.
## USDT/CRV Authorization Issues
Some tokens (USDT, CRV) require revoking existing approvals before setting a new amount. This is an on-chain action that incurs gas fees.
### Revoking USDT Approval (Ethereum)
1. Go to the [USDT contract on Etherscan](https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7#writeContract).
2. Click **Connect to Web3**.
3. Find the **approve** function and set:
```
_spender: 0xa4994144a9217e3779bDa588798EfF546b69DEfB
_value: 0
```
4. Click **Write** and sign in the MPCVault app.
Retry the batch payment after the revocation confirms.
### MPCVault batch contract
| **Network** | **Chain ID** | **Block explorer** | **Batch contract address** |
| :- | :-: | :- | :- |
| Ethereum | 1 | [etherscan](https://etherscan.io/) | 0xa4994144a9217e3779bda588798eff546b69defb |
| Polygon | 137 | [polygonscan](https://polygonscan.com/) | 0x6569189b6f3c9107abf61383a8f7bbe30263ecde |
| BNB Smart Chain | 56 | [bscscan](https://bscscan.com/) | 0xa4994144a9217e3779bda588798eff546b69defb |
| Arbitrum | 42161 | [arbiscan](https://arbiscan.io/) | 0x09ef519886ff608c7965d7d8dc4fbed62c083b6e |
| Optimism | 10 | [optimistic](https://optimistic.etherscan.io/) | 0xa4994144a9217e3779bda588798eff546b69defb |
| Avalanche C-Chain | 43114 | [snowtrace](https://snowtrace.io/) | 0x09ef519886ff608c7965d7d8dc4fbed62c083b6e |
| Base | 8453 | [basescan](https://basescan.org) | 0x09ef519886ff608c7965d7d8dc4fbed62c083b6e |
| DATA Network (prev. Story) | 1514 | [datanetscan](https://www.datanetscan.io/) | 0xD96D782Bc3B3257d7DF78c9e29DA6ef6AC5EdE0B |
# Overview
Source: https://docs.mpcvault.com/index
Non-custodial Web3 wallet for teams with multi-chain, multi-asset, and multi-sig features.
MPCVault is a **non-custodial wallet for teams** built on multi-party computation (MPC) technology. Unlike traditional wallets where a single private key controls your assets, MPCVault splits your key into three shares distributed across your device and two separate cloud environments. All three shares are required to sign transactions—no single party ever has complete control.
Over **1,000 active organizations** trust MPCVault to secure their assets, processing more than **\$2 billion in daily transaction volume**. Our customers include leading exchanges, crypto VCs, Web3 firms, hedge funds, and trading desks worldwide.
## How It Works
| Component | Description |
| - | - |
| **Your Device** | Holds one key share |
| **Google Cloud (AMD SEV)** | Holds second key share in a secure enclave |
| **Microsoft Azure (Intel SGX)** | Holds third key share in a separate secure enclave |
When you sign a transaction, all three parties compute their part without ever reconstructing the full private key. This eliminates single points of failure and removes counterparty risk.
## Key Features
| Feature | What It Means |
| - | - |
| **Multi-chain** | One wallet for Ethereum, Bitcoin, Solana, TRON, TON, Aptos, and all EVM chains |
| **Multi-sig** | Require multiple approvals based on transaction type, amount, or destination |
| **Hardened Derivation** | Patented key derivation prevents former team members from tracking new addresses |
| **Key Rotation** | Key shares automatically refresh to new values, invalidating any stolen shares |
| **End-to-End Encryption** | Zero-trust architecture with Noise protocol—even MPCVault's servers can't see your data |
## Who Uses MPCVault
* **DeFi Funds** — Secure fund operations with institutional-grade custody and flexible approval policies
* **Exchanges** — Manage hot and cold wallets with automated signing workflows
* **Web3 Companies** — Treasury management, payroll, and operational payments
* **Trading Desks** — Fast execution with programmable transaction policies
## What You Can Do
* **Multi-chain wallets** — Manage assets on Ethereum, Bitcoin, Solana, TRON, TON, Aptos, Sui, and all EVM networks from a single platform
* **Batch send** — Pay hundreds of recipients in one transaction for payroll, airdrops, and distributions
* **DeFi access** — Connect to any protocol via WalletConnect, MetaMask Institutional, [MPCVault Chrome extension](https://chromewebstore.google.com/detail/mpcvault/jgfmfplofjigjfokigdiaiibhonfnedj), or MPCVault in-app
* **Programmable policies** — Set approval rules based on transaction type, amount, destination, or time
* **API automation** — Build workflows with REST/gRPC APIs and Client Signer SDK for programmatic signing
* **Spend & off-ramp** — Use Visa debit cards for direct spending or convert to fiat via bank transfer
## Get Started
1. [Create an Organization](/guides/2-how-to-create-an-organization/index) — Set up your team workspace
2. [Back Up Your Key](/guides/1-how-to-back-up-your-personal-key-certificate/index) — Secure your personal key certificate
3. [Create Your First Vault](/guides/4-what-are-vaults-and-wallets/index) — Understand vaults and start managing assets
# Key Derivation
Source: https://docs.mpcvault.com/key-derivation
MPCVault's patented hardened key derivation for MPC wallets.
## Hardened Derivation
MPCVault is the only MPC provider with patented hardened hierarchical derivation. In the non-MPC world, all wallets use hardened derivation - MPCVault brings this security standard to MPC.
## Why Hardened Derivation Matters
Without hardened keys:
| Risk | Impact |
| - | - |
| Former team members | Can track your newly added assets |
| Compromised child key | Exposes master keys and assets on other blockchains |
| Cross-chain attacks | Signature reuse across different chains |
With MPCVault's hardened derivation, each address has an isolated derived key. Compromise of one key does not affect others.
## How It Works
For each new address you create:
1. A new derived key is generated from your master key
2. The derivation uses hardened paths that prevent key leakage
3. Each blockchain and address is cryptographically isolated
## Granular Permissions
The hierarchical derivation tree enables precise permission control:
* Grant access to specific vaults only
* Limit users to certain blockchains
* Follow the principle of least privilege
Allocate minimum necessary permissions to users for managing vaults.
***
## Derivation Paths & Networks
MPCVault uses a structured derivation path format to generate unique keys for each vault, network, and address.
### Path Format
```
[prefix, vault_index, coin_type, account, change, address_index]
```
| Position | Name | Description |
| - | - | - |
| 0 | `prefix` | Always `9` (MPCVault identifier) |
| 1 | `vault_index` | Vault number starting from 0 |
| 2 | `coin_type` | Blockchain identifier (see table below) |
| 3 | `account` | Account index (typically 0) |
| 4 | `change` | Change index (typically 0) |
| 5 | `address_index` | Address index (0, 1, 2, ...) |
### Hardening Rules
Different networks use different hardening for the last two path positions:
| Network | Last Two Positions | Example |
| - | - | - |
| **Bitcoin** | Non-hardened (`N0`, `N1`) | `[9,0,2147483648,0,N0,N0]` |
| **All others** | Hardened (0, 1, 2...) | `[9,0,2147483708,0,0,0]` |
Non-hardened derivation (marked with `N`) allows public key derivation without the private key, which is required for Bitcoin's address discovery mechanism.
### Supported Networks
| Network | Coin Type | Key Type | Curve | Example Path |
| - | - | - | - | - |
| EVM (Ethereum, etc.) | 2147483708 | ECDSA | secp256k1 | `[9,0,2147483708,0,0,0]` |
| Bitcoin | 2147483648 | ECDSA | secp256k1 | `[9,0,2147483648,0,N0,N0]` |
| Tron | 2147483843 | ECDSA | secp256k1 | `[9,0,2147483843,0,0,0]` |
| Aptos | 2147484285 | EdDSA | Ed25519 | `[9,0,2147484285,0,0,0]` |
| Solana | 2147484149 | EdDSA | Ed25519 | `[9,0,2147484149,0,0,0]` |
| Sui | 2147484432 | EdDSA | Ed25519 | `[9,0,2147484432,0,0,0]` |
| TON | 2147484355 | EdDSA | Ed25519 | `[9,0,2147484355,0,0,0]` |
Coin types follow the [SLIP-0044](https://github.com/satoshilabs/slips/blob/master/slip-0044.md) standard with the hardened bit (0x80000000) applied.
### Key Types
MPCVault supports two cryptographic signature schemes:
| Key Type | Curve | Used By |
| - | - | - |
| **ECDSA** | secp256k1 | EVM chains, Bitcoin, Tron, Litecoin |
| **EdDSA** | Ed25519 | Aptos, Solana, Sui, TON |
### Address Generation
Each network derives addresses from public keys using different algorithms:
| Network | Hash Algorithm | Address Format | Example |
| - | - | - | - |
| EVM | Keccak-256 (last 20 bytes) | `0x` + 40 hex chars | `0x1234...abcd` |
| Bitcoin | SHA-256 + RIPEMD-160 | SegWit P2SH (Base58Check) | `3J98t1...` |
| Tron | Keccak-256 + Base58Check | `T` prefix | `TJRyWw...` |
| Aptos | SHA3-256 | `0x` + 64 hex chars | `0x1234...` |
| Solana | Direct public key | Base58 | `7EcDhS...` |
| Sui | BLAKE2b | `0x` + 64 hex chars | `0x1234...` |
| TON | SHA-256 | Base64 or raw | `EQDk2V...` |
### Deriving Multiple Addresses
To create multiple addresses within the same vault and network, increment the `address_index`:
```
Vault 0, EVM, Address 0: [9,0,2147483708,0,0,0]
Vault 0, EVM, Address 1: [9,0,2147483708,0,0,1]
Vault 0, EVM, Address 2: [9,0,2147483708,0,0,2]
```
Each address has a completely independent derived key due to hardened derivation.
# Key Export
Source: https://docs.mpcvault.com/key-export
Export root keys for wallet recovery outside of MPCVault.
Key export lets you obtain a backup of your organization's root keys, giving you complete control over your funds outside of MPCVault. Once exported, you can derive private keys for all wallets—including those created after the export.
Available for **business and enterprise customers on annual plans**. Contact your account manager to begin.
## When to Export
**Set up key export when you create your organization.** Exporting later is possible but incurs an additional charge.
Key export is initiated manually by your account manager—it's not a self-service feature. If you anticipate needing key export, discuss it with your account manager before your organization goes live.
## How It Works
MPCVault uses key derivation to generate wallet addresses from root keys. Once root keys are exported, you can calculate private keys for **all addresses**—including wallets created after the export.
### Encryption-Based Security
MPCVault uses 3-of-3 MPC, meaning your root key is split into three shares. Rather than providing raw key shares directly, we ask you to generate three Ed25519 encryption keys locally. Each root share is then encrypted using one of your public keys, along with other necessary information like the chaincode.
This design ensures:
* **No one in the backup process** (including MPCVault) can access your actual key values
* **Intercepted backups are useless** without your corresponding private keys
* **Full cryptographic control** remains with whoever holds the encryption keys
### Root Key Types
To derive all wallet addresses, you need both root key types exported:
| Key Type | Used For |
| - | - |
| `ECC_ED25519` | Ed25519-based chains (Solana, TON, Aptos, Sui) |
| `ECC_SECP256K1` | Bitcoin, Ethereum, and all EVM chains |
## Export Steps
### 1. Generate three encryption keys
Run these commands in your terminal to create three Ed25519 key pairs:
```bash theme={null}
ssh-keygen -t ed25519 -C "backup-key-1"
ssh-keygen -t ed25519 -C "backup-key-2"
ssh-keygen -t ed25519 -C "backup-key-3"
```
For each key:
1. Choose a save location
2. Set a strong password (recommended)
3. Store the private key file securely
**Multi-party key generation:** For enhanced security, have three different trusted individuals each generate one key. This ensures no single person holds all encryption keys.
### 2. Send public keys to your account manager
Your public keys look like this:
```
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0wmN/Cr3JXqmLW7u+g9pTh+wyqDHpSQEIQczXkVx9q backup-key-1
```
Send all three public keys to your account manager, who will create the backup request.
### 3. Approve the backup request
An **Org root key backup** signing request will appear in your signing request list. All active organization members must approve and sign.
### 4. Download the backup package
Once approved, download the encrypted backup from the signing request details page in the web console.
Download within 15 days—the backup expires after that.
### 5. Store securely
Store the backup package and encryption keys in separate, secure locations:
| Item | Storage Recommendations |
| - | - |
| Backup package | Store multiple copies in different secure locations (safe deposit box, encrypted cloud storage, etc.) |
| Encryption private keys | Each key in a separate secure location, ideally held by different trusted parties |
| Key passwords | Store separately from the private keys they protect |
## Recovery Requirements
To recover your wallets later, you'll need:
| Item | Description |
| - | - |
| Backup package | The encrypted JSON file |
| Private keys | Your three Ed25519 private keys |
| Passwords | Passwords for the private keys (if set) |
| Recovery tool | Provided by your account manager |
**Your personal key certificate is not needed for recovery.** The backup package and encryption keys are completely independent from your MPCVault app credentials.
### Security Best Practices
**Do not split the backup file among multiple people.** The encrypted file alone cannot recover your keys—it's useless without the corresponding private keys. Instead:
* Store redundant copies of the backup package in secure locations
* Focus access control on the **encryption keys**, not the encrypted file
* Consider using [Shamir's Secret Sharing](https://en.wikipedia.org/wiki/Shamir%27s_secret_sharing) to split each encryption key if you need multi-party control
## Backup Package Format
The backup package is a JSON file containing encrypted key shares and metadata needed for key derivation.
```json theme={null}
{
"version": "1.0",
"exported_key_shares": [
{
"key_id": "1a6bd986-aea3-47dd-9486-db4f42835599",
"org_id": "617c0325-1223-4c59-97d7-f44fd1188b4f",
"key_type": "KEY_TYPE_ECC_ED25519",
"chaincode": "diLn5mFhQmNuC3mLXHSnk3mhkiv4c102OfyJilPBSOY=",
"encryption_pubkeys": [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0wmN/Cr3JXqmLW7u+g9pTh+wyqDHpSQEIQczXkVx9q backup-key-1",
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJKylTU8A4orMxP1NHD9Lqo5K9w/yvqMhl6v5mPGBBEr backup-key-2",
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDhSbRi6ky7VqVRP9SLKLzGj0X8zN2Nmf4xF5QH8K6Qj backup-key-3"
],
"encrypted_shares": [
"LS0tLS1CRUdJTiBTU0ggRU5DUllQVEVEIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUF...",
"LS0tLS1CRUdJTiBTU0ggRU5DUllQVEVEIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUF...",
"LS0tLS1CRUdJTiBTU0ggRU5DUllQVEVEIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUF..."
]
},
{
"key_id": "2b7ce097-bfb4-58ee-a597-ec5g53946610",
"org_id": "617c0325-1223-4c59-97d7-f44fd1188b4f",
"key_type": "KEY_TYPE_ECC_SECP256K1",
"chaincode": "xKMp6nGiRnOvD4nMYITol4nikjw5d213PgzKjmQCTPZ=",
"encryption_pubkeys": [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0wmN/Cr3JXqmLW7u+g9pTh+wyqDHpSQEIQczXkVx9q backup-key-1",
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJKylTU8A4orMxP1NHD9Lqo5K9w/yvqMhl6v5mPGBBEr backup-key-2",
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDhSbRi6ky7VqVRP9SLKLzGj0X8zN2Nmf4xF5QH8K6Qj backup-key-3"
],
"encrypted_shares": [
"LS0tLS1CRUdJTiBTU0ggRU5DUllQVEVEIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUF...",
"LS0tLS1CRUdJTiBTU0ggRU5DUllQVEVEIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUF...",
"LS0tLS1CRUdJTiBTU0ggRU5DUllQVEVEIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUF..."
]
}
],
"timestamp": 1707118991467
}
```
| Field | Description |
| - | - |
| `key_id` | Unique identifier for the root key |
| `org_id` | Your organization's identifier |
| `key_type` | Either `ECC_ED25519` or `ECC_SECP256K1` |
| `chaincode` | Required for hierarchical key derivation (base64 encoded) |
| `encryption_pubkeys` | The three public keys you provided |
| `encrypted_shares` | Your three encrypted key shares (ciphertext) |
| `timestamp` | Export time in Unix milliseconds |
The backup file alone cannot recover private keys. You must have the corresponding Ed25519 private keys and their passwords to decrypt the shares.
# Key Refresh
Source: https://docs.mpcvault.com/key-refresh
Periodic key share rotation to prevent adaptive attacks.
## Periodic Refresh
MPCVault periodically refreshes all key shares to new values while keeping the public key unchanged. This prevents adaptive compromise of key shares over time.
## How It Works
| Property | Before Refresh | After Refresh |
| - | - | - |
| Public Key | `0x1234...` | `0x1234...` (unchanged) |
| Share 1 | Value A | Value X (new) |
| Share 2 | Value B | Value Y (new) |
| Share 3 | Value C | Value Z (new) |
The refresh process:
1. All parties participate in the refresh protocol
2. Key shares are updated to new random values
3. No single party sees the complete key during refresh
4. The underlying private key remains mathematically equivalent
## Security Benefits
Once refreshed, any previously stolen shares become useless:
* Old shares contain no useful information
* Attackers cannot combine old and new shares
* The quorum requirement resets with each refresh
This protects against attackers who slowly accumulate key shares over time.
# MPCVault vs Gnosis Safe
Source: https://docs.mpcvault.com/vs-gnosis-safe
Key differences between MPCVault and smart contract wallets.
## Feature Comparison
| Feature | Gnosis Safe | MPCVault |
| - | - | - |
| **Multi-address** | No. Requires new safes and on-chain transactions for each. | Yes. Multiple addresses within one organization, no on-chain setup. |
| **Multi-chain** | EVM only. Need different solutions for other chains. | All chains including Bitcoin, Solana, Aptos, TON. |
| **eth\_sign support** | No. Cannot use zk-based apps like dYdX. | Yes. Full support for zk-based applications. |
| **EVM compatibility** | Wrong network = lost funds. Cannot use bridges like Arbitrum Bridge. | Same address across all EVM chains. Works with any bridge. |
| **Transaction tracking** | Manual spreadsheet tracking. | Bank-like history with memos, CSV export. |
## Visual Comparison