# Deeplinks

Backpack allows for iOS and Android apps to natively interact with it using either universal links **(recommended)** or deeplinks.

{% hint style="info" %}
These workflows are collectively known as "deeplinks."
{% endhint %}

All [Provider Methods](/deeplinks/provider-methods) follow a protocol format of:

```
https://backpack.app/ul/<version>/<method> 
```


# Provider Methods

All provider methods follow a protocol format of:


# Connect

Before an app can interact with Backpack, it must first establish a connection. This connection request prompts the user to share their public key, signaling their consent to proceed.&#x20;

Once the user connects, Backpack provides a session parameter that should be used for all subsequent methods.

{% hint style="info" %}
Please see [Handling Sessions](/deeplinks/handling-sessions) for more information on sessions.
{% endhint %}

## Base URL

```
https://backpack.app/ul/v1/connect
```

## Query String Parameters

* `app_url` (required): A URL that provides app metadata (e.g., title, icon). It must be URL-encoded.
* `dapp_encryption_public_key` (required): A public key for end-to-end encryption, used to generate a shared secret. Refer to the [Encryption](/deeplinks/encryption) section for details on how Backpack manages shared secrets.
* `redirect_link` (required): The URI where Backpack should redirect the user upon connection. See [Specifying Redirects](/deeplinks/specifying-redirects) for more details. Must be URL-encoded.
* `cluster` (optional): Specifies the network for subsequent interactions. To connect to Solana mainnet, leave the parameter unset or set it to `mainnet-beta`. To connect to Eclipse, set the parameter to `solana:EAQLJCV2mh23BsK2P9oYpV5CHVLDNHTxY`.

## Returns

### Approve

* `wallet_xxx`: A base58-encoded encryption public key used by Backpack to build a shared secret between the connecting app and Backpack.
* `nonce`: A nonce encoded in base58 that is used to encrypt the response.
* `data`: JSON string that has been encrypted. Learn how apps can decrypt data using a shared secret in [Encryption](/deeplinks/encryption). Base58 is used to encode encrypted bytes.

  ```
  // content of decrypted `data`-parameter
  {
    // base58 encoding of user public key
    "public_key": "3huUrtWW5s5ew98eUFRYz9LPsDUQTujNzzYaB9DBkppQ",

    // session token for subsequent signatures and messages
    // apps should send this with any other deeplinks after connect
    "session": "..."
  }
  ```

  * `public_key`: The user's public key, represented as a base58-encoded string.
  * `session`: A string encoded in base58. This should be treated as opaque by the connecting app, as it only needs to be passed alongside other parameters. Sessions do not expire. For more information on sessions, please review [Handling Sessions](/deeplinks/handling-sessions).

### Reject

An `errorCode` and `errorMessage` as query parameters.

Please refer to [Errors](/deeplinks/limitations#errors) for a full list of possible error codes.


# Disconnect

After the initial [Connect](/deeplinks/provider-methods/connect) event, an app may disconnect from Backpack at any time. When Backpack is disconnected, it will reject all signature requests until a new connection is established.

## Base URL

```
https://backpack.app/ul/v1/disconnect
```

## Query String Parameters

* `dapp_encryption_public_key` **(required)**: The app's original encryption public key for an existing Connect session.
* `nonce` **(required)**: A base58-encoded nonce is used to encrypt the request.
* `redirect_link` **(required)**: Backpack should redirect the user to this URI after completion. For more information, please see [Specifying Redirects](/deeplinks/specifying-redirects). URL-encoded.
* `payload` **(required)**: An encrypted JSON string with the following fields:

  Copy

  ```
  {
      "session": "...", // token received from the connect method
  }
  ```

  * `session` **(required)**: The session token received from the Connect method. Please see [Handling Sessions](/deeplinks/handling-sessions) for more details.

## Returns

### Approve

No query params are returned.

### Reject

An `errorCode` and `errorMessage` as query parameters.

Please see [Errors](/deeplinks/limitations#errors) for a complete list of possible error codes.

```
{
  "errorCode": "...",
  "errorMessage": "..."
}
```


# SignAndSendTransaction

Once connected to Backpack, an application can ask the user for permission to send transactions on their behalf.

In order to send a transaction, an application must:

1\. Create an unsigned transaction.

2\. Have the transaction be signed and submitted to the network by the user's Backpack wallet.

3\. Optionally await network confirmation using a Solana JSON RPC connection.

{% hint style="info" %}
For more information about the nature of Solana transactions, please review the [`solana-web3.js` docs](https://solana-labs.github.io/solana-web3.js/), as well as the [Solana Cookbook](https://solanacookbook.com/core-concepts/transactions.html#transactions).
{% endhint %}

## Base URL

```
https://backpack.app/ul/v1/signAndSendTransaction  
```

## Query String Parameters

* `dapp_encryption_public_key` **(required)**: The original encryption public key used from the app for an existing [Connect](/deeplinks/provider-methods/connect) session.
* `nonce` **(required)**: A nonce used for encrypting the request, encoded in base58.
* `redirect_link` **(required)**: The URI where Backpack should redirect the user upon completion. Please review [Specifying Redirects](/deeplinks/specifying-redirects) for more details. URL-encoded.
* `payload` **(required)**: An encrypted JSON string with the following fields:

```
{
  "transaction": "...", // serialized transaction, base58-encoded
  "sendOptions": "..." // an optional Solana web3.js sendOptions object
  "session": "...", // token received from the connect method
}
```

* `transaction` **(required)**: The [transaction](https://solana-labs.github.io/solana-web3.js/classes/Transaction.html) Backpack will sign and submit is serialized and encoded in base58.
* `sendOptions` (optional): An optional object that specifies options for how Backpack should submit the transaction. This object is [defined in Solana web3.js](https://solana-labs.github.io/solana-web3.js/modules.html#SendOptions).
* `session` **(required)**: The session token received from the [Connect](/deeplinks/provider-methods/connect) method. Please see [Handling Sessions](/deeplinks/handling-sessions) for more details.

## Returns

### Approve

* `nonce`: A nonce used for encrypting the response, encoded in base58.
* `data`: An encrypted JSON string. Refer to [Encryption](/deeplinks/encryption) to learn how apps can decrypt `data` using a shared secret. Encrypted bytes are encoded in base58.

```
// content of decrypted `data`-parameter
{  
    "signature": "..." // transaction-signature
}
```

* `signature`: The first signature in the transaction can be used as its [transaction id](https://docs.solana.com/terminology#transaction-id).

### Reject

An `errorCode` and `errorMessage` as query parameters. Please refer to [Errors](/deeplinks/limitations#errors) for a full list of possible error codes.

```
{          
    "errorCode": "...",          
    "errorMessage": "..."          
}  
```


# SignAllTransactions

Once an app is connected, it is also possible to sign multiple transactions at once. Unlike [SignAndSendTransaction](/deeplinks/provider-methods/signandsendtransaction), Backpack will not submit these transactions to the network.

Applications can submit signed transactions using the [web3.js](https://solana-labs.github.io/solana-web3.js/classes/Connection.html#sendRawTransaction) `sendRawTransaction`.

## Base URL

```
https://backpack.app/ul/v1/signAllTransactions
```

## Query String Parameters

* `dapp_encryption_public_key` **(required)**: The original encryption public key used from the app side for an existing [Connect](/deeplinks/provider-methods/connect) session.
* `nonce` **(required)**: A nonce used for encrypting the request, encoded in base58.
* `redirect_link` **(required)**: The URI where Backpack should redirect the user upon completion. Please review [Specifying Redirects](/deeplinks/specifying-redirects) for more details. URL-encoded.
* `payload` **(required)**: An encrypted JSON string with the following fields:

  ```
  {
    "transactions": [
      "...", // serialized transaction, bs58-encoded
      "...", // serialized transaction, bs58-encoded
    ],
    "session": "...", // token received from connect-method
  }
  ```

  * `transactions` **(required)**: A serialized array of [transactions](https://solana-labs.github.io/solana-web3.js/classes/Transaction.html), encoded in base58, that Backpack will sign.
  * `session` **(required)**: The session token received from the [Connect](/deeplinks/provider-methods/connect) method. Please see [Handling Sessions](/deeplinks/handling-sessions) for more details.

## Returns

### Approve

* `nonce`: A nonce used for encrypting the response, encoded in base58.
* `data`: An encrypted JSON string. Refer to [Encryption](/deeplinks/encryption) to learn how apps can decrypt `data` using a shared secret. Encrypted bytes are encoded in base58.

  ```
  // content of decrypted `data`-parameter
  {
      transactions: [
          "...", // signed serialized transaction, bs58-encoded
          "...", // signed serialized transaction, bs58-encoded
      ] 
  }
  ```

  * `transactions`: An array of signed, serialized transactions that are base58 encoded. Backpack will not submit these transactions. Applications can submit these transactions themselves via the [web3.js](https://solana-labs.github.io/solana-web3.js/classes/Connection.html#sendRawTransaction) `sendRawTransaction`.

### Reject

An `errorCode` and `errorMessage` as query parameters.

Please refer to [Errors](/deeplinks/limitations#errors) for a full list of possible error codes.

```
{
  "errorCode": "...",
  "errorMessage": "..."
}
```


# SignTransaction

[SignAndSendTransaction](/deeplinks/provider-methods/signandsendtransaction) is the simplest and most recommended method for sending a transaction. Backpack submits the transaction immediately after signing so it is safer for users and a simpler API for developers, rather than relying on the application to do so.

However, it is also possible for an app to request just the signature from Backpack. Once signed, an app can submit the transaction itself using the [web3.js](https://solana-labs.github.io/solana-web3.js/classes/Connection.html#sendRawTransaction) `sendRawTransaction`.

## Base URL

```
https://backpack.app/ul/v1/signTransaction
```

## Query String Parameters

* `dapp_encryption_public_key` **(required)**: The original encryption public key used from the app side for an existing [Connect](/deeplinks/provider-methods/connect) session.
* `nonce` **(required)**: A nonce used for encrypting the request, encoded in base58.
* `redirect_link` **(required)**: The URI where Backpack should redirect the user upon completion. Please review [Specifying Redirects](/deeplinks/specifying-redirects) for more details. URL-encoded.
* `payload` **(required)**: An encrypted JSON string with the following fields:

  ```
  {
    "transaction": "...", // serialized transaction, base58 encoded
    "session": "...", // token received from connect-method
  }
  ```

  * `transaction` **(required)**: The [transaction](https://solana-labs.github.io/solana-web3.js/classes/Transaction.html) that Backpack will sign is serialized and encoded in base58.
  * `session` **(required)**: The session token received from the [Connect](/deeplinks/provider-methods/connect) method. Please see [Handling Sessions](/deeplinks/handling-sessions) for more details.

## Returns

### Approve

* `nonce`: A nonce used for encrypting the response, encoded in base58.
* `data`: An encrypted JSON string. Refer to [Encryption](/deeplinks/encryption) to learn how apps can decrypt `data` using a shared secret. Encrypted bytes are encoded in base58.

  ```
  // content of decrypted `data`-parameter
  {
      transaction: "...", // signed serialized transaction, base58 encoded
  }
  ```

  * `transaction`: The signed and serialized transaction that is encoded in base58. Backpack will not submit this transaction. An application can submit this transaction via the [web3.js](https://solana-labs.github.io/solana-web3.js/classes/Connection.html#sendRawTransaction) `sendRawTransaction`.

### Reject

An `errorCode` and `errorMessage` as query parameters.

Please refer to [Errors](/deeplinks/limitations#errors) for a full list of possible error codes.

```
{
  "errorCode": "...",
  "errorMessage": "..."
}
```


# SignMessage

After connecting to Backpack, an app can request that the user sign a message. Applications can create their own messages, which will be displayed to users from Backpack's signature prompt. Message signatures do not incur network fees and are a convenient way for apps to verify address ownership.

In order to send a message for the user to sign, an application must:

1. Provide a **hex** or **UTF-8** encoded string as a Uint8Array and then **base58-encoded it**.
2. Request that the encoded message is signed via the user's Backpack wallet.

For more information on how to verify the signature of a message, please refer to [Encryption Resources](/deeplinks/encryption#encryption-resources).

## Base URL

```
https://backpack.app/ul/v1/signMessage
```

## Query String Parameters

* `dapp_encryption_public_key` **(required)**: The original encryption public key used from the app side for an existing [Connect](/deeplinks/provider-methods/connect) session.
* `nonce` **(required)**: A nonce used for encrypting the request, encoded in base58.
* `redirect_link` **(required)**: The URI where Backpack should redirect the user upon completion. Please review [Specifying Redirects](/deeplinks/specifying-redirects) for more details. URL-encoded.
* `payload` **(required)**: An encrypted JSON string with the following fields:

  ```
  {
    "message": "...", // the message, base58 encoded
    "session": "...", // token received from connect-method
    "display": "utf8" | "hex", // the encoding to use when displaying the message 
  }
  ```

  * `message` **(required)**: The message that should be signed by the user, encoded in base58. Backpack will display this message to the user when they are prompted to sign.
  * `session` **(required)**: The session token received from the [Connect](/deeplinks/provider-methods/connect) method. Please see Handling Sessions for more details.
  * `display` **(optional)**: How you want us to display the string to the user. Defaults to `utf8`

## Returns

### Approve

* `nonce`: A nonce used for encrypting the response, encoded in base58.
* `data`: An encrypted JSON string. Refer to [Encryption](/deeplinks/encryption) to learn how apps can decrypt `data` using a shared secret. Encrypted bytes are encoded in base58.

  ```
  // content of decrypted `data`-parameter
  {
      signature: "...", // message-signature
  }
  ```

  * `signature`: The message signature, encoded in base58. For more information on how to verify the signature of a message, please refer to [Encryption Resources](/deeplinks/encryption#encryption-resources).

### Reject

An `errorCode` and `errorMessage` as query parameters.

Please refer to [Errors](/deeplinks/limitations#errors) for a full list of possible error codes.

```
{
  "errorCode": "...",
  "errorMessage": "..."
}
```


# Other Methods

Backpack supports additional methods accessible via deeplinks in addition to its [Provider Methods](/deeplinks/provider-methods).

Users can use the [Browse](/deeplinks/other-methods/browse) deeplink to open web apps within Backpack's in-app browser.

***

Deeplinks make it easy for users to open web apps within Backpack. Users can scan a QR code with their phone's camera to open a page directly within Backpack's in-app browser. If a web app detects that a user is using a mobile device, it can prompt the user to open a specific page in Bacpack's in-app browser.

The `browse` deeplink can be used before a Connect event takes place, as it does not require a `session` param.&#x20;

`browse` deeplinks are not intended to be pasted into mobile web browsers.

These deeplinks must either be handled by an app or clicked on by an end user.

## URL Structure

```
https://backpack.app/ul/browse/?ref=
```

## Parameters

* `url` **(required)**: The URL that should open within Backpack's in-app browser, URL-encoded.
* `ref` **(required)**: The URL of the requesting app, URL-encoded

<br>


# Browse

Deeplinks make it easy for users to open web apps within Backpack. Users can scan a QR code with their phone's camera to open a page directly within Backpack's in-app browser. If a web app detects that a user is using a mobile device, it can prompt the user to open a specific page in Backpack's in-app browser.

The `browse` deeplink can be used before a Connect event takes place, as it does not require a `session` parameter.

`browse` deeplinks are not intended to be pasted into mobile web browsers. These deeplinks must either be handled by an app or clicked on by an end user.

## URL Structure

```
https://backpack.app/ul/v1/browse/<url>?ref=<ref>
```

#### **Parameters** <a href="#parameters" id="parameters"></a>

* `url` **(required)**: The URL that should open within Backpack's in-app browser, URL-encoded.
* `ref` **(required)**: The URL of the requesting app, URL-encoded


# Handling Sessions

When a user first connects to Backpack, Backpack returns a session param that represents the user's connection. On all subsequent [Provider Methods](/deeplinks/provider-methods), the app should pass this `session` parameter back to Backpack. The app is responsible for storing this session.

Sessions do not expire. Once a user has connected with Backpack, the corresponding app can make requests like SignAndSendTransaction and SignMessage indefinitely without prompting the user to reconnect with Backpack. Apps will still need to reconnect to Backpack after a Disconnect event or an Invalid Session.

## Session Structure

The entire `session` parameter is encoded in base58. A `session` should contain the following data:

* **JSON Data Signature**: A base58 signature of the JSON data that is 64 bytes. Backpack will check the signature against the actual message that was signed.
* **JSON Data**: A JSON object with the following fields:
  * `app_url` (string): A URL used to fetch app metadata (i.e. title, icon).
  * `timestamp` (number): The timestamp at which the user approved the connection. At the time of this writing, sessions do not expire.
  * `chain` (string): The chain that the user connected to at the start of the session. Sessions cannot be used across two different chains with the same keypair (e.g. the user cannot connect to Backpack and then sign on Ethereum).
  * `cluster` (string) (optional): The approved cluster that the app and user initially connected to.&#x20;

## Decoding Sessions

Backpack will decode and validate the `session` param on every request. To decode the session, we decode it with `bs58`, slice off the first 64 bytes of the signature, and treat the rest as JSON data.

We then sign the JSON data again with the same key pair and compare that signature against the signature in the session. If the signatures are the same, the session is valid. Otherwise, we conclude that the session has been faked, as the signature does not belong to the keypair it claims it does.

Calling `nacl.sign.open` conveniently verifies and returns the original object. For more information, please review [Encryption Resources](/deeplinks/encryption#encryption-resources).

After we determine that the session is valid, we still need to ensure that the JSON fields line up with what we expect. An app could give a session for `pubkey A` when the user is currently using `pubkey B` in Backpack.

In such a scenario, that session should not allow an app to request signatures. Instead, the app must issue a new connect request or use the correct session.

```
// Encoding a session
const privateKey = ...;
const sessionData = JSON.stringify({
  "app_id": "APP_ID",
  "chain": "CHAIN",
  "cluster": "CLUSTER",
  "timestamp": 1644954984,
});
const bytes = Buffer.from(sessionData, "utf-8");

// tweetnacl-js formats signature in format <signature><sessionData>
const signature = bs58.encode(nacl.sign(bytes, privateKey));

// Decoding ja session
const publicKey = ...;
const verifiedSessionData = nacl.sign.open(bs58.decode(signature), publicKey.toBytes());
if (!verifiedSessionData) throw new Error(`This session was not signed by ${publicKey}`);
```

## Invalid Sessions

While sessions do not expire, there are a number of reasons why sessions could still be deemed invalid:

1. It was not signed by the current wallet key pair. This could mean that the session is entirely fake, or that it was signed by another keypair in the user’s wallet.
2. It was signed by the current wallet key pair, but the session's JSON `data` does not pass muster. There are a few reasons why this might occur:
   1. The user switched chains (or possibly networks).
   2. The `app_url` could be blocked if malicious.


# Specifying Redirects

All Methods support a `redirect_link=` param that lets Backpack know how to get back to the original app. The URI specified by this param should be URL encoded.

The following is an example of a `mydapp://onWalletConnected` redirect URI:

```
redirect_link%3Dmydapp%3A%2F%2FonWalletConnected
```

If the deeplink request to Backpack comes with a response, Backpack will append the results as query parameters in the `redirect_link=` upon redirecting.

```
redirect_link=mydapp://onWalletConnected?data=...
```


# Encryption

Deeplinks are encrypted using symmetric key encryption generated from a [Diffie-Hellman key exchange](https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange). While deeplink sessions will be created in plaintext, an encrypted channel will be created to prevent session tokens from getting hijacked.

## Encryption & Decryption Workflow

Backpack deeplinks are encrypted with the following workflows:

### Connect

1. \[dapp]: On the initial `connect` deeplink, apps should include a `dapp_encryption_public_key` query parameter. It's recommended to create a new x25519 keypair for every session started with `connect`. In all methods, the public key for this keypair is referred to as `dapp_encryption_public_key`.
2. \[backpack]: Upon handling a `connect` deeplink, Backpack will also generate a new x25519 keypair.
   * Backpack will return this public key as `wallet_encryption_public_key` in the `connect` response.
   * Backpack will create a secret key using Diffie-Hellman with `dapp_encryption_public_key` and the ***private key*** associated with `wallet_encryption_public_key`.
   * Backpack will locally store a mapping of `dapp_encryption_public_key` to shared secrets for use with decryption in subsequent deeplinks.
3. \[dapp]: Upon receiving the `connect` response, the dapp should create a shared secret by using Diffie-Hellman with `wallet_encryption_public_key` and the ***private key*** associated with `dapp_encryption_public_key`. This shared secret should then be used to decrypt the `data` field in the response. If done correctly, the user's public key will be available to share with the dapp inside the `data` JSON object.

### **Subsequent Deeplinks**

1. \[dapp]: For any subsequent methods (such as [SignAndSendTransaction](/deeplinks/provider-methods/signandsendtransaction) and [SignMessage](/deeplinks/provider-methods/signmessage)), apps should send a `dapp_encryption_public_key` (the public key side of the shared secret) used with Backpack along with an encrypted `payload` object.
2. \[backpack]: Upon approval, Backpack will encrypt the signed response as a JSON object with the encryption sent as a `data=` query param.
3. \[dapp]: Upon receiving the deeplink response, apps should decrypt the object in the `data=` query parameter to view the signature.

## Encryption Resources

To learn more about encryption and decryption, please refer to the following libraries:

**JavaScript**

* [TweetNaCl.js](https://github.com/dchest/tweetnacl-js)

**iOS**

* [TweetNaCl SwiftWrap](https://github.com/bitmark-inc/tweetnacl-swiftwrap)

**Android**

* [Tink](https://github.com/google/tink)
* [TweetNaCl Java](https://github.com/InstantWebP2P/tweetnacl-java)


# Limitations

When making requests to Backpack in Establishing a Connection, Sending a Transaction, or Signing a Message, Backpack may respond with an error.

## Errors

The following is a list of all possible error codes and their meanings. These error messages are inspired by Ethereum's [EIP-1474](https://eips.ethereum.org/EIPS/eip-1474#error-codes) and [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193#provider-errors).

| Code   | Title                            | Description                                                                                                                                                                                                                                                                                        |
| ------ | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 4900   | Disconnected                     | Backpack could not connect to the network.                                                                                                                                                                                                                                                         |
| 4100   | Unauthorized                     | The requested method and/or account have not been authorized by the user.                                                                                                                                                                                                                          |
| 4001   | User Rejected Request            | The user rejected the request through Backpack.                                                                                                                                                                                                                                                    |
| -32000 | Invalid Input                    | Missing or invalid parameters.                                                                                                                                                                                                                                                                     |
| -32002 | Requested resource not available | <p>This error occurs when an app attempts to submit a new transaction while Backpack's approval dialog is already open for a previous transaction.</p><p>Only one approve window can be open at a time. Users should approve or reject their transactions before initiating a new transaction.</p> |
| -32003 | Transaction Rejected             | Backpack does not recognize a valid transaction.                                                                                                                                                                                                                                                   |
| -32601 | Method Not Found                 | Backpack does not recognize the method.                                                                                                                                                                                                                                                            |
| -32603 | Internal Error                   | Something went wrong within Backpack.                                                                                                                                                                                                                                                              |

Typically, these errors will be easily parseable and have both a code and an explanation. For example:

```
try {
  await window.solana.signMessage();
} catch (err) {
  //  {code: 4100, message: 'The requested method and/or account has not been authorized by the user.'}
}
```


