> For the complete documentation index, see [llms.txt](https://shinkalabs.gitbook.io/hub/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://shinkalabs.gitbook.io/hub/andromeda/getting-started/sign.md).

# Sign a message

Signing takes a dWallet, a raw message, and an on-chain approval, and returns a raw signature. You then assemble and broadcast the transaction on the destination chain. Andromeda never touches the destination chain.

Two ways, matching the two ways to [create a dWallet](/hub/andromeda/getting-started/create-dwallet.md):

* **High-level** (also an MCP tool): `POST /v1/dwallet/sign` with the dWallet, the message, the scheme, the approval proof, and your passphrase. Andromeda does the MPC client side. Use this for MCP-created dWallets.
* **Low-level**: `POST /v1/dwallet/sign/submit` — you did the client-side MPC yourself (paired with the low-level DKG).

{% hint style="info" %}
Exact bodies are in the [OpenAPI spec](https://api.andromedainfra.pro/openapi.json). `message` is the **raw, un-hashed** bytes — the network applies the hash from the chosen `scheme`.
{% endhint %}

## The MCP flow: `create` → `approve` → `sign`

For a dWallet created with `attachRecoveryPolicy: true` ([create a dWallet](/hub/andromeda/getting-started/create-dwallet.md)), the three steps are:

1. **`POST /v1/dwallet/approve`** — you, as the policy's primary owner, authorise the message. Andromeda unwraps the keystore key with your passphrase, signs the canonical challenge, drives `recover_as_primary` on-chain (gas-sponsored), which mints the `MessageApproval`. It returns the approval proof:

   ```bash
   curl -X POST https://api.andromedainfra.pro/v1/dwallet/approve \
     -H "X-Api-Key: $ANDROMEDA_KEY" -H "Content-Type: application/json" \
     -d '{ "dwalletAddress": "<DWALLET>", "passphrase": "…", "messageHex": "<raw message, hex>", "signatureScheme": 5 }'
   # returns: { "success": true, "data": {
   #     "approvalTxSignatureBase58": "…", "approvalSlot": "123456789", "messageApprovalAddress": "…" }}
   ```

   `signatureScheme` is the on-chain scheme id (same table as `scheme` below). No per-message rate limit — the primary path is a full bypass of the policy's cooldown / daily limit. (MCP tool: `approve`.) If the dWallet has no policy attached, `409`; if the policy's primary owner is an external wallet rather than this keystore key, also `409` (then use the [recovery-primary endpoints](/hub/andromeda/guides/configure-recovery.md) with that wallet instead).
2. **`POST /v1/dwallet/sign`** — pass the `approvalTxSignatureBase58` + `approvalSlot` from step 1 (see below).
3. Broadcast the returned signature on the destination chain.

## Prerequisites (low-level / external-policy dWallets)

If the dWallet's authority is some other [policy program](/hub/andromeda/concepts/policies.md), or you're driving the MPC client side yourself, you supply the approval proof directly:

1. **A dWallet whose authority is a policy program** — only a program can mint the `MessageApproval` the network requires. A bare dWallet (right after [create](/hub/andromeda/getting-started/create-dwallet.md) without `attachRecoveryPolicy`) is not signable until delegated; see [transfer-ownership](/hub/andromeda/getting-started/create-dwallet.md).
2. **An on-chain `MessageApproval`** for `(dwallet, keccak256(message), keccak256(metadata) or 32×0)`, status `Pending`, produced by that policy. Pass the tx signature + slot that created it.
3. **A presignature** (`presignSessionIdHex`). Allocate one with `POST /v1/dwallet/presign` (no passphrase needed) or let the sign call allocate one.

## High-level: `POST /v1/dwallet/sign`

```bash
curl -X POST https://api.andromedainfra.pro/v1/dwallet/sign \
  -H "X-Api-Key: $ANDROMEDA_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "dwalletAddress": "<DWALLET>",
    "passphrase": "the passphrase you set at create time",
    "messageHex": "<raw message bytes, hex>",
    "scheme": 5,
    "approvalTxSignatureBase58": "<sig of the tx that created the MessageApproval>",
    "approvalSlot": 123456789,
    "presignSessionIdHex": "<optional; auto-allocated if omitted>",
    "messageMetadataHex": "<optional; some schemes need it>"
  }'
# returns: { "success": true, "data": { "signatureBase64": "…", "scheme": 5, "presignSessionIdHex": "…" } }
```

`scheme` ids: `0` EcdsaKeccak256 (EVM), `1` EcdsaSha256 (Bitcoin legacy / WebAuthn), `2` EcdsaDoubleSha256 (Bitcoin BIP143), `3` TaprootSha256, `4` EcdsaBlake2b256 (Zcash), `5` EddsaSha512 (Solana, Sui), `6` SchnorrkelMerlin (Substrate). Pick the one matching the dWallet's curve and the destination chain. The passphrase unwraps the signer key in memory for this one operation, then it's discarded — wrong passphrase → `401`. (MCP tool: `sign_message`.)

## What you get back

A raw signature in the dWallet's curve. Build the destination chain's transaction, attach the signature, and broadcast it with your own RPC client (Andromeda does not). For EVM a secp256k1 signature, for Solana an ed25519 signature, etc. See [Chains & curves](/hub/andromeda/reference/chains-curves.md).

## Low-level: `POST /v1/dwallet/sign/submit`

For clients that ran the MPC client side themselves: submit the signed `SignedRequestData` (carrying your `message_centralized_signature` and the approval proof). Use an [`Idempotency-Key`](/hub/andromeda/guides/idempotency.md) so a retry does not consume a second presignature.

## Related

* **Policies**: the policy program is what authorises the sign on-chain — allowlists, velocity guards, quorums, confidential checks, session keys. See [On-chain policies](/hub/andromeda/concepts/policies.md).
* **Future-Sign**: pre-authorise a signature that fires later on a condition. See [Future-Sign triggers](/hub/andromeda/guides/future-sign.md).
* **Dry-run**: simulate before committing. See [Dry-run / Simulate](/hub/andromeda/guides/simulate.md).
* **Batching**: pack many signature requests into the fewest Solana transactions. See [Auto-batching](/hub/andromeda/guides/batching.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://shinkalabs.gitbook.io/hub/andromeda/getting-started/sign.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
