---
updatedAt: 2025-07-26T14:14:29.000Z
agentTools:
  projectIndex: https://docs.metakeep.xyz/llms.txt
---

# Sign Transaction (Batch)

This API allows developers to `sign a batch` of transactions in a single call. This is useful if you want to `sign multiple` transactions in a single call e.g. approve a token, mint an NFT, and transfer the NFT on blockchains like`Solana` where the `transaction size is limited`. This `improves the user experience` by reducing the number of popups shown to the user to get their consent.

> 📘 This API is only supported for the `Solana` apps at the moment.

> 📘 The API requires SDK version 2.2.3 or higher.

## Sign Solana Transaction

Once you have built multiple Solana transaction objects using `@solana/web3.js`, you can ask the user to sign them by using the`signTransactionMultiple` function in the MetaKeep SDK. The function expects a non-empty `reason` for the request and for each transaction in the batch which will be shown to the user at the time of requesting consent.

If you are not using `@solana/web3.js`, you need to serialize the transaction message that needs to be signed before sending it to the MetaKeep SDK.

> 👍 Solana versioned transactions are supported

```javascript Sign Solana Transaction Batch
// Legacy transaction
const legacyTx = new Transaction().add(
  SystemProgram.transfer({
    fromPubkey: fromPublicKey,
    toPubkey: toPublicKey,
    lamports: 1 * LAMPORTS_PER_SOL,
  })
);

// Versioned transaction
const messageV0WithLookupTable = new TransactionMessage({
  payerKey: payerPublicKey,
  recentBlockhash: recentBlockhash,
  instructions: [
    SystemProgram.transfer({
      fromPubkey: fromPublicKey,
      toPubkey: toPublicKey,
      lamports: amountToTransfer * LAMPORTS_PER_SOL,
    }),
  ],
}).compileToV0Message([lookupTableAccount]);

const versionedTx = new VersionedTransaction(messageV0WithLookupTable);

await sdk.signTransactionMultiple(
  // Transaction batch with reason for each transaction
  [
    {
      transactionObject: legacyTx,
      reason: "Sign reason 1",
    },
    {
      transactionObject: versionedTx,
      reason: "Sign reason 2",
    },
    // You can also send a serialized Solana transaction message if You
    // only have access to the serialized message.
    {
      transactionObject: {
        serializedTransactionMessage:
          "0x" +
          Buffer.from(messageV0WithLookupTable.serialize()).toString("hex"),
      },
      reason: "Sign reason 3",
    },
  ],
  // Signing reason
  "test sign transaction batch"
);
```

Here's a reference implementation of this code: <https://codesandbox.io/p/sandbox/metakeep-sign-solana-transaction-batch-tw38y5?file=%2Fsrc%2FApp.js%3A50%2C35>

> 📘 The latest `@solana/web3.js` supported version is 1.75.0
>
> Let us know if you would like us to support a more recent version :)

<br />

## Response

`signTransactionMultiple` returns a promise which succeeds when the sign operation is successful. The response looks like this-

```json Sign Solana Transaction Response
{
  "status": "SUCCESS",
  // Signatures array with each signature in the hex format.
  "signatures": [
    {
      "signature": "0x023d9a5700b77971b8de539936143e0d82808809b856cc9ab9bcc41a02a3794ec516a44db6ed666f3e4f7549ae91939062ce076a9ef419febc21c41eebb98f0a"
    },
    {
      "signature": "0xee1af2c9bd70596a2bd41727126de50de3e834f29a5ef4afae1b9c4b7522779a071408faa667529260fb3d26ec312f81647cc5996f0562d98ec3757ea431c50a"
    }
  ]
}
```

## Error status

`signTransactionMultiple` returns a promise which throws an error when the sign operation is unsuccessful. The error object looks like this-

```json Error object
{
  status: "USER_CONSENT_DENIED"
}
```

Here's a table of all possible error status returned by the SDK

<Table align={["left","left"]}>
  <thead>
    <tr>
      <th>
        Status
      </th>

      <th>
        Description
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        USER\_REQUEST\_DENIED
      </td>

      <td>
        The user has denied the sign operation.\
        In this case, you should ask the user if they want to try again.
      </td>
    </tr>

    <tr>
      <td>
        INVALID\_REQUEST
      </td>

      <td>
        Invalid data passed to sign operation.\
        Please get in touch with us if you are unable to fix this.
      </td>
    </tr>

    <tr>
      <td>
        MISSING\_NONCE
      </td>

      <td>
        The nonce is missing. Please specify `nonce` for the transaction.
      </td>
    </tr>

    <tr>
      <td>
        MISSING\_GAS
      </td>

      <td>
        Gas is missing. Please specify `gas` for the transaction.
      </td>
    </tr>

    <tr>
      <td>
        INVALID\_GAS\_FEE\_PARAMS
      </td>

      <td>
        The transaction contains `gasPrice` `maxFeePerGas` and `maxPriorityFeePerGas`. Please specify either `gasPrice` or `maxFeePerGas` and `maxPriorityFeePerGas`
      </td>
    </tr>

    <tr>
      <td>
        MISSING\_GAS\_PRICE
      </td>

      <td>
        Gas price is missing for type 1 transactions. Please specify `gasPrice`.
      </td>
    </tr>

    <tr>
      <td>
        MISSING\_MAX\_FEE\_PER\_GAS
      </td>

      <td>
        The max fee per gas is missing for type 2 transactions. Please specify both `maxFeePerGas` and `maxPriorityFeePerGas`
      </td>
    </tr>

    <tr>
      <td>
        MISSING\_MAX\_PRIORITY\_FEE\_PER\_GAS
      </td>

      <td>
        The max priority fee per gas is missing for type 2 transactions. Please specify both `maxFeePerGas` and `maxPriorityFeePerGas`
      </td>
    </tr>

    <tr>
      <td>
        APP\_ID\_REQUIRED
      </td>

      <td>
        No app-id was provided when initializing the SDK.\
        You can find the app id in the MetaKeep Developer Console.
      </td>
    </tr>

    <tr>
      <td>
        APP\_NOT\_FOUND
      </td>

      <td>
        The provided app-id is invalid.\
        You can find the correct app-id in the MetaKeep Developer Console.
      </td>
    </tr>

    <tr>
      <td>
        FROM\_ADDRESS\_DOES\_NOT\_MATCH\_SIGNER
      </td>

      <td>
        The `from` address in the transaction message does not match the signer's address.
      </td>
    </tr>

    <tr>
      <td>
        TOO\_MANY\_TRANSACTIONS
      </td>

      <td>
        There are too many transactions in the batch. Currently, only up to 5 transactions are supported in a single batch.
      </td>
    </tr>

    <tr>
      <td>
        SOMETHING\_WENT\_WRONG
      </td>

      <td>
        An unknown error happened.\
        Please get in touch with us if you continue seeing this error.
      </td>
    </tr>
  </tbody>
</Table>

© Copyright 2024, Passbird Research Inc.