> For the complete documentation index, see [llms.txt](https://blocknote-js.gitbook.io/doc/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://blocknote-js.gitbook.io/doc/upload-content/blocknotemanager.md).

# BlocknoteManager

When using Blocknote behind an API, it's important to address a few complexities:

* Users should never share their mnemonic. Instead, they should sign using their wallet.
* Asking users to manually sign numerous transactions before uploading is impractical.
* Uploading, compressing, and sending large files can exceed standard web request time limits (typically 30 seconds).

The `BlocknoteManager` will help streamline these processes efficiently.\
The following documentation explains how your frontend and your backend must work together.

***

### The 'funder-sender-receiver' pattern

The `BlocknoteManager` uses a simple pattern so the user never has to share their mnemonic.\
They only need to sign one transaction to fund the entire process:

1. The cost of the operation is calculated, 2 accounts are created, **the sender** and **the receiver**.
2. A transaction is built with the amount to fund, this is **the bootstrap transaction**.
3. The user, acting as **the funder**, sign and send the boostrap transaction to the sender.
4. **The sender** sends the payload & the upload to **the receiver**.
5. When the process is over, both **receiver** and **sender** are closed and the left funds are sent back to the **funder**.

<figure><img src="/files/uNehu0BpNZCsDzR79mqh" alt=""><figcaption></figcaption></figure>

### Good to know

* The bootstrap transaction has an encrypted note. It contains the mnemonic of the sender. The receiver is a child address of the sender (HD address) .&#x20;
* The bootstrap transaction amount is always slightly higher than the exact calculated upload cost, the fees of each transaction is multiplied by 3 (this setting can be changed).\
  This is because Algorand fees are dynamic and may change after the calculation. This doesn’t make the upload more expensive, because any leftover funds are sent back to the user at the end.

### Handling API web request time limits

To avoid web request time limitation on the API side, the methods of the BlocknoteManager are queued and processed in the background. For every call, a UUID will be returned immediately.

You can use this UUID to check the status of the queued process and later retrieve the final response.

To support this workflow flawlessly, you will need:

**1.** An API endpoint that receives a UUID and returns the current status of the process from the queue. \
For this purpose, the method `getFromQueue(uuid)` must be used

```javascript
app.get('/queued/:uuid', (req, res) => {
    
    const uuid   = req.params.uuid; 
    const status = BlocknoteManager.getFromQueue(uuid) ?? null;
   
    res.send(status);
});
```

**2.** A simple **frontend** function that polls this endpoint to check progress, errors, and completion.

```javascript
/*
* Poll the API every 500ms to get the status of a queued process using its UUID
*
* @params uuid - The UUID of the process
* @params onProgress - Callback to track progress updates
* @params onError - Callback to receive error messages
*/
const getQueued = async (uuid, onProgress, onError) => {

  try {
  
    const response = await fetch("https://api.yourdomain.com/queued/" + uuid);

    if (!response.ok) {        
      onError("Request failed with HTTP status " + response.status);      
      return;
    }

    const queued_process = await response.json();

    if (queued_process?.error) {        
      onError(queued_process.error);      
      return;
    }

    if (queued_process?.status !== "done") {        
      onProgress(data);
      // Wait 500ms before polling again
      await new Promise(resolve => setTimeout(resolve, 500));      
      return getQueued(uuid, onProgress, onError);
    }

    return queued_process;
  } 
  catch (e) { onError(e.toString()); }
};

```

***

### Step 1 - Prepare the Bootstrap transaction

The first method from the `BlocknoteManager` you want to use is `prepareBoostrapTransaction()` \
It will calculate the required funds for the given content and prepare a transaction for the user to sign.

{% code fullWidth="false" %}

```javascript
app.post('/get-bootstrap-transaction', (req, res) => {
    
    const buffer    = req.body.file;   
    const address   = req.body.user_address;
    const title     = req.body.title;  
    const mime      = req.body.mime    
    const options   = {title:title, mime:mime}; 
    const uuid      = BlocknoteManager.prepareBootstrapTransaction(
        address, 
        buffer,         
        options
    );

    res.send(uuid);       
});
```

{% endcode %}

You will be returned a UUID. \
Use the frontend `getQueued()` method seen previously to poll your api until the process is done.

* If the process is running, you will receive the [onProgress status](/doc/upload-content/onprogress-statuses.md) from the underlying Blocknote instance.&#x20;
* When completed, the response will include all relevant upload's details.

<details>

<summary>View a response example</summary>

```json5
{
    output: {
        fees: 12000,
        start: 1754273414659,
        simulation: true,        
        compression: {
            compression: "zstd",
            original_size: 12292,
            compressed_size: 10583
        },
        end: 1754273414926,
        duration: 267,
        payload: {
            version: 0.1,
            title: "JpeVFg-G_400x400.jpg",
            type: "text",
            compression: "zstd",
            txns: 11
        },        
        funding: {
            amount: 239000,
            expected_refund: 224000
        }
    },
    transaction: "iqNhbXTOAANACKNmZWXNA+iiZnbOAzsUWaNnZW6sdGVzdG5ldC12MS4womdoxCBIY7UYpLPITsgQ8i1PEIHLD3HwWaesIN7GL39w5Qk6IqJsds4DOxhBpG5vdGXFApB7ImJsb2Nrbm90ZSI6ImV5SnBkaUk2SW1Sak5HWmpZVE00TVdRd00yTXlNek0wWm1RMk5tRXdNaUlzSW1SaGRHRWlPaUpqTTJNMU0ySXlZMk13WVRFNU56TTNZMlptTnpabVpXUTVZakl5TXpRM01EbGpOREUzWVRabU5tUTVPV1U1WmpnM09EVTVZMlEwT1dZek1XTm1ZVEE1WldKaE16UTFNRGsyWlRoa1pHTTFOVFJpT0dVMVl6VTBOV1E1TkRJeFltTTVaRFV6T0dZM1lUSTNOVGcwWkRWbE9HRTRNakkwWlRCbVpUTXhPVEV3TWpFeE5EVTFOalEwTldWa05UWmtNak16TnpNMFpqSTNOR0prT1daak5XRmxZMk0zWW1Kak5tSmlaREEzTnpBeU9EZzNZekZoTmpJeFlUTXdZV1E1Wm1Rd1kyWXhOemsxTURCbU9HVTJZMlU1WldFd09XWmpNak15WVdOallqSmlZV1E1TW1KaU1qWTRNMkV6TURaaE1XVTFOMk00TlRBellqaGhNRGhsTTJNM05USm1PVGN6TVRSaFkyUmlNemRpTW1Zd09UWm1aVEU1WVRoaFpqQmpNVFJrWXpJMU56STNOamhpT1RCbFptUTROelkwWVdKallXSTJPVFZrWkRNNVpqVTRaV05rWlRnNE1XWmxPV1EwWVdGa09ESTFZakZrTUdVMU56SXlPRGxoTnpkaFptVmxZV0UxTWpBNE5EazROalF5WkRRMlpETmpNRGM0TkRBNVlqaGlNemN4TldVNU16azVJaXdpZEdGbklqb2lNVFZqT1RVeVltRm1OemczT1RrNU9XTXpOelJoTmpBMU5tSXdZbVU1T1RVaWZRPT0ifaNyY3bEILTQqIuply9ptA0ZSLlsbrUSqOZn/n/8OfkwwWiqF5Syo3NuZMQg22E7DxSrOhFtsC+9Lnsz3+wHNXa7eoNKB14sWZ+/XnSkdHlwZaNwYXk=",
    key:"L7VzamkL0n/40A7nPao3wi/CkqLKlLv83km3Jq236AY=",
    status: "done"
}
```

</details>

The response includes a `transaction` property containing the bootstrap transaction and a `key` property. As the transaction is base64 encoded, the frontend would need to decode it:\
\
`algosdk.decodeUnsignedTransaction(algosdk.base64ToBytes(transaction));`\
\
On the frontend, the user **must sign and send** the transaction using their wallet.\
Once the transaction is sent, retrieve its transaction id. \
Both the transaction id and the key are required for the next step in the process.

### Step 2 - Start upload

Call the `runFromBootstrapTransaction()` method giving it the bootstrap transaction id and the key. This will start the on-chain writing process. Note that if you want to encrypt your upload, the encryption details have to be inserted here.

{% code fullWidth="false" %}

```javascript
// Encryption details have to be inserted here if required.
// In this example, the upload is encrypted with a password but it 
// is asked to don't encrypt the title.
app.post('/run-bootstrap-transaction/:boostrap_transaction_id', async (req, res) => {

    const encryption = {password:"Pd39mp=DMO-78pF_sD$", encrypt_title: false}
    const key        = req.body.key;
    const uuid       = BlocknoteManager.runFromBoostrapTransaction(
        req.params.boostrap_transaction_id, 
        key,
        encryption
    );
    
    res.send(uuid);
});
```

{% endcode %}

From now, the process of writing data on-chain will be initiate. \
A UUID is returned.\
Again, use the `getQueued()` method to check the status of that task.
