> ## Documentation Index
> Fetch the complete documentation index at: https://developers.fireblocks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Raw signing

> Create a RAW transaction to sign an arbitrary message with a vault account or Embedded Wallet key, for supported and unsupported assets.

The examples on this page assume you have an initialised client, as described in [Choose an interface](/transactions/create-transactions#choose-an-interface). Raw signing is performed through the [Create transaction](/reference/createtransaction) endpoint by setting `operation` to `RAW`, and it signs a message you supply rather than building a blockchain transaction for you. For the concepts, use cases and enablement steps, see [Raw signing](/docs/raw-signing), and for complete worked examples see [Raw signing code examples](/reference/code-examples-2).

<Warning>
  Raw signing is an insecure signing method because bad actors can trick someone into signing a valid transaction message and use it to steal funds. It is a premium feature that is not available in production workspaces by default, so you must contact your Customer Success Manager to enable it, although Sandbox workspaces have it enabled for testing. Policies reject all raw transactions by default, so after it is enabled you must add Policy rules that allow users to initiate, approve and sign raw transactions from specific vault accounts. See [Raw signing](/docs/raw-signing) for details.
</Warning>

## Raw signing in vault accounts

In your vault accounts you can sign raw messages for either a natively supported asset or an unsupported asset. The signing key is derived from a BIP44-like derivation path, which you pass either implicitly by giving the vault account and asset or explicitly by giving the derivation path and algorithm. To avoid creating duplicate requests when you retry, set a unique `externalTxId` on every request, as described in [Transaction idempotency](/reference/api-idempotency#transaction-idempotency).

### Natively supported asset

For a natively supported asset you provide the `assetId` and the source vault account, and Fireblocks derives the signing key from them. The `content` is the message to sign in hexadecimal format, and you omit the message `type` because it applies only to typed messages. You can optionally add `bip44AddressIndex` and `bip44change` to a message to set the address index and change levels of the derivation path.

<Tabs>
  <Tab title="SDK">
    <CodeGroup>
      ```typescript TypeScript theme={"system"}
      import { TransactionOperation, TransferPeerPathType } from "@fireblocks/ts-sdk";

      const response = await fireblocks.transactions.createTransaction({
        transactionRequest: {
          operation: TransactionOperation.Raw,
          assetId: "BTC_TEST",
          source: {
            type: TransferPeerPathType.VaultAccount,
            id: "<SOURCE_VAULT_ACCOUNT_ID>",
          },
          note: "Raw signing test", // Optional - Free-text note shown in your workspace, not sent to the blockchain
          extraParameters: {
            rawMessageData: {
              messages: [
                {
                  content: "<HEX_ENCODED_MESSAGE>",
                  // bip44AddressIndex: 0, // Optional - BIP44 address_index path level
                  // bip44change: 0, // Optional - BIP44 change path level
                },
              ],
            },
          },
          externalTxId: "<YOUR_UNIQUE_ID>", // Optional - Your unique ID; Fireblocks rejects later requests with the same value
        },
      });
      console.log(response.data);
      ```

      ```python Python theme={"system"}
      from fireblocks.models.transaction_request import TransactionRequest
      from fireblocks.models.transaction_operation import TransactionOperation
      from fireblocks.models.source_transfer_peer_path import SourceTransferPeerPath
      from fireblocks.models.transfer_peer_path_type import TransferPeerPathType
      from fireblocks.models.extra_parameters import ExtraParameters

      transaction_request = TransactionRequest(
          operation=TransactionOperation.RAW,
          asset_id="BTC_TEST",
          source=SourceTransferPeerPath(
              type=TransferPeerPathType.VAULT_ACCOUNT,
              id="<SOURCE_VAULT_ACCOUNT_ID>",
          ),
          note="Raw signing test",  # Optional - Free-text note shown in your workspace, not sent to the blockchain
          extra_parameters=ExtraParameters(
              raw_message_data={
                  "messages": [
                      {
                          "content": "<HEX_ENCODED_MESSAGE>",
                          # "bip44AddressIndex": 0,  # Optional - BIP44 address_index path level
                          # "bip44change": 0,  # Optional - BIP44 change path level
                      }
                  ]
              }
          ),
          external_tx_id="<YOUR_UNIQUE_ID>",  # Optional - Your unique ID; Fireblocks rejects later requests with the same value
      )

      future = fireblocks.transactions.create_transaction(
          transaction_request=transaction_request,
      )
      print(future.result().data)
      ```

      ```java Java theme={"system"}
      import com.fireblocks.sdk.model.*;
      import java.util.List;
      import java.util.Map;

      TransactionRequest transactionRequest = new TransactionRequest()
          .operation(TransactionOperation.RAW)
          .assetId("BTC_TEST")
          .source(new SourceTransferPeerPath()
              .type(TransferPeerPathType.VAULT_ACCOUNT)
              .id("<SOURCE_VAULT_ACCOUNT_ID>"))
          .note("Raw signing test") // Optional - Free-text note shown in your workspace, not sent to the blockchain
          .extraParameters(new ExtraParameters().rawMessageData(Map.of(
              "messages", List.of(Map.of("content", "<HEX_ENCODED_MESSAGE>")))))
          .externalTxId("<YOUR_UNIQUE_ID>"); // Optional - Your unique ID; Fireblocks rejects later requests with the same value

      CreateTransactionResponse transaction = fireblocks.transactions()
          .createTransaction(
              transactionRequest,
              null, // Optional - xEndUserWalletId (UUID), only for end-user wallet operations
              null) // Optional - Not used for transactions; use externalTxId in the request body
          .get()
          .getData();
      System.out.println(transaction);
      ```
    </CodeGroup>
  </Tab>

  <Tab title="API">
    ```http theme={"system"}
    POST /v1/transactions
    ```

    ```json theme={"system"}
    {
      "operation": "RAW",
      "assetId": "BTC_TEST",
      "source": { "type": "VAULT_ACCOUNT", "id": "<SOURCE_VAULT_ACCOUNT_ID>" },
      "note": "Raw signing test",
      "extraParameters": {
        "rawMessageData": {
          "messages": [{ "content": "<HEX_ENCODED_MESSAGE>" }]
        }
      },
      "externalTxId": "<YOUR_UNIQUE_ID>"
    }
    ```

    Sign the request with a JWT; see [Signing a request](/reference/signing-a-request-jwt-structure).
  </Tab>

  <Tab title="CLI">
    ```bash theme={"system"}
    # Preview the request without sending it
    fireblocks transactions create-transaction \
      --data '{"operation":"RAW","assetId":"BTC_TEST","source":{"type":"VAULT_ACCOUNT","id":"<SOURCE_VAULT_ACCOUNT_ID>"},"extraParameters":{"rawMessageData":{"messages":[{"content":"<HEX_ENCODED_MESSAGE>"}]}},"externalTxId":"<YOUR_UNIQUE_ID>"}' \
      --dry-run

    # Execute
    fireblocks transactions create-transaction \
      --data '{"operation":"RAW","assetId":"BTC_TEST","source":{"type":"VAULT_ACCOUNT","id":"<SOURCE_VAULT_ACCOUNT_ID>"},"extraParameters":{"rawMessageData":{"messages":[{"content":"<HEX_ENCODED_MESSAGE>"}]}},"externalTxId":"<YOUR_UNIQUE_ID>"}' \
      --no-confirm
    ```
  </Tab>
</Tabs>

### Unsupported asset

For an asset that Fireblocks does not natively support, you pass the `derivationPath` on each message and the signing `algorithm` on `rawMessageData` instead of an `assetId`. The `algorithm` is `MPC_ECDSA_SECP256K1` or `MPC_EDDSA_ED25519`, and for testnet assets the `coin_type` in the derivation path is always `1`.

<Tabs>
  <Tab title="SDK">
    <CodeGroup>
      ```typescript TypeScript theme={"system"}
      import { TransactionOperation, TransferPeerPathType } from "@fireblocks/ts-sdk";

      const response = await fireblocks.transactions.createTransaction({
        transactionRequest: {
          operation: TransactionOperation.Raw,
          source: {
            type: TransferPeerPathType.VaultAccount,
          },
          note: "Raw signing test", // Optional - Free-text note shown in your workspace, not sent to the blockchain
          extraParameters: {
            rawMessageData: {
              messages: [
                {
                  content: "<HEX_ENCODED_MESSAGE>",
                  derivationPath: [44, 0, 0, 0, 0], // Conditional - Required when no assetId is given
                },
              ],
              algorithm: "MPC_ECDSA_SECP256K1", // Conditional - Required with derivationPath. Also MPC_EDDSA_ED25519
            },
          },
          externalTxId: "<YOUR_UNIQUE_ID>", // Optional - Your unique ID; Fireblocks rejects later requests with the same value
        },
      });
      console.log(response.data);
      ```

      ```python Python theme={"system"}
      from fireblocks.models.transaction_request import TransactionRequest
      from fireblocks.models.transaction_operation import TransactionOperation
      from fireblocks.models.source_transfer_peer_path import SourceTransferPeerPath
      from fireblocks.models.transfer_peer_path_type import TransferPeerPathType
      from fireblocks.models.extra_parameters import ExtraParameters

      transaction_request = TransactionRequest(
          operation=TransactionOperation.RAW,
          source=SourceTransferPeerPath(
              type=TransferPeerPathType.VAULT_ACCOUNT,
          ),
          note="Raw signing test",  # Optional - Free-text note shown in your workspace, not sent to the blockchain
          extra_parameters=ExtraParameters(
              raw_message_data={
                  "messages": [
                      {
                          "content": "<HEX_ENCODED_MESSAGE>",
                          "derivationPath": [44, 0, 0, 0, 0],  # Conditional - Required when no assetId is given
                      }
                  ],
                  "algorithm": "MPC_ECDSA_SECP256K1",  # Conditional - Required with derivationPath. Also MPC_EDDSA_ED25519
              }
          ),
          external_tx_id="<YOUR_UNIQUE_ID>",  # Optional - Your unique ID; Fireblocks rejects later requests with the same value
      )

      future = fireblocks.transactions.create_transaction(
          transaction_request=transaction_request,
      )
      print(future.result().data)
      ```

      ```java Java theme={"system"}
      import com.fireblocks.sdk.model.*;
      import java.util.List;
      import java.util.Map;

      TransactionRequest transactionRequest = new TransactionRequest()
          .operation(TransactionOperation.RAW)
          .source(new SourceTransferPeerPath()
              .type(TransferPeerPathType.VAULT_ACCOUNT))
          .note("Raw signing test") // Optional - Free-text note shown in your workspace, not sent to the blockchain
          .extraParameters(new ExtraParameters().rawMessageData(Map.of(
              "messages", List.of(Map.of(
                  "content", "<HEX_ENCODED_MESSAGE>",
                  "derivationPath", List.of(44, 0, 0, 0, 0))), // Conditional - Required when no assetId is given
              "algorithm", "MPC_ECDSA_SECP256K1"))) // Conditional - Required with derivationPath. Also MPC_EDDSA_ED25519
          .externalTxId("<YOUR_UNIQUE_ID>"); // Optional - Your unique ID; Fireblocks rejects later requests with the same value

      CreateTransactionResponse transaction = fireblocks.transactions()
          .createTransaction(
              transactionRequest,
              null, // Optional - xEndUserWalletId (UUID), only for end-user wallet operations
              null) // Optional - Not used for transactions; use externalTxId in the request body
          .get()
          .getData();
      System.out.println(transaction);
      ```
    </CodeGroup>
  </Tab>

  <Tab title="API">
    ```http theme={"system"}
    POST /v1/transactions
    ```

    ```json theme={"system"}
    {
      "operation": "RAW",
      "source": { "type": "VAULT_ACCOUNT" },
      "note": "Raw signing test",
      "extraParameters": {
        "rawMessageData": {
          "messages": [
            { "content": "<HEX_ENCODED_MESSAGE>", "derivationPath": [44, 0, 0, 0, 0] }
          ],
          "algorithm": "MPC_ECDSA_SECP256K1"
        }
      },
      "externalTxId": "<YOUR_UNIQUE_ID>"
    }
    ```

    Sign the request with a JWT; see [Signing a request](/reference/signing-a-request-jwt-structure).
  </Tab>

  <Tab title="CLI">
    ```bash theme={"system"}
    # Preview the request without sending it
    fireblocks transactions create-transaction \
      --data '{"operation":"RAW","source":{"type":"VAULT_ACCOUNT"},"extraParameters":{"rawMessageData":{"messages":[{"content":"<HEX_ENCODED_MESSAGE>","derivationPath":[44,0,0,0,0]}],"algorithm":"MPC_ECDSA_SECP256K1"}},"externalTxId":"<YOUR_UNIQUE_ID>"}' \
      --dry-run

    # Execute
    fireblocks transactions create-transaction \
      --data '{"operation":"RAW","source":{"type":"VAULT_ACCOUNT"},"extraParameters":{"rawMessageData":{"messages":[{"content":"<HEX_ENCODED_MESSAGE>","derivationPath":[44,0,0,0,0]}],"algorithm":"MPC_ECDSA_SECP256K1"}},"externalTxId":"<YOUR_UNIQUE_ID>"}' \
      --no-confirm
    ```
  </Tab>
</Tabs>

## Raw signing in Embedded Wallets

In Embedded Wallets you can also sign raw messages for a natively supported or unsupported asset. These requests use the NCW SDK rather than the SDK, API and CLI interfaces above, so the examples are plain code blocks and each call passes the `walletId` in its options.

For a natively supported asset, provide the `assetId` and the wallet account as the source.

```javascript theme={"system"}
const res = await signer.createTransaction(
  {
    assetId: "BTC_TEST",
    note: "raw signing test",
    source: {
      type: PeerType.END_USER_WALLET,
      walletId,
      id: "<WALLET_ACCOUNT_ID>",
    },
    operation: TransactionOperation.RAW,
    extraParameters: {
      rawMessageData: {
        messages: [
          {
            content, // Hex-encoded message to sign
          },
        ],
      },
    },
  },
  { ncw: { walletId } },
);
```

For an unsupported asset, provide the `derivationPath` and `algorithm` instead of an `assetId`.

```javascript theme={"system"}
const res = await signer.createTransaction(
  {
    note: "raw signing test",
    source: {
      type: PeerType.END_USER_WALLET,
      walletId,
    },
    operation: TransactionOperation.RAW,
    extraParameters: {
      rawMessageData: {
        messages: [
          {
            content: "<HEX_ENCODED_MESSAGE>",
            derivationPath: [44, 0, 0, 0, 0],
          },
        ],
        algorithm: "MPC_ECDSA_SECP256K1", // Or "MPC_EDDSA_ED25519"
      },
    },
  },
  { ncw: { walletId } },
);
```

## About the rawMessageData object

<Note>
  For the fields you can set on each message, such as `preHash`, which is required only in Cold Wallet workspaces, see [Raw signing objects](/reference/raw-signing-objects#rawmessagedata). A single raw signing request can aggregate a maximum of 127 messages.
</Note>

For all request and response schemas, see the [Create transaction](/reference/createtransaction) API reference.
