Skip to main content
RapidDev - Software Development Agency
retool-integrationsREST API Resource

How to Integrate Retool with Backblaze B2 Cloud Storage

Connect Retool to Backblaze B2 Cloud Storage using the native B2 API — not the S3-compatible API. Authenticate by calling b2_authorize_account with your key ID and application key to get an authorization token and API URL, then use that token for all subsequent B2 API calls including bucket listing, object management, and download authorization. This approach unlocks B2-specific features unavailable through the S3-compatible layer.

What you'll learn

  • How to implement B2's two-step native API authentication flow (authorize_account → session token) in Retool
  • How to configure Retool resources and queries to chain B2 authorization with bucket and file operations
  • How to list buckets, browse files, and retrieve object metadata using B2's native API endpoints
  • How to generate authorized download URLs for private B2 bucket objects from Retool
  • How to build a storage monitoring dashboard with bucket size tracking and bandwidth usage metrics
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate16 min read25 minutesStorageLast updated April 2026RapidDev Engineering Team
TL;DR

Connect Retool to Backblaze B2 Cloud Storage using the native B2 API — not the S3-compatible API. Authenticate by calling b2_authorize_account with your key ID and application key to get an authorization token and API URL, then use that token for all subsequent B2 API calls including bucket listing, object management, and download authorization. This approach unlocks B2-specific features unavailable through the S3-compatible layer.

Quick facts about this guide
FactValue
ToolBackblaze B2 Cloud Storage
CategoryStorage
MethodREST API Resource
DifficultyIntermediate
Time required25 minutes
Last updatedApril 2026

Why Use B2's Native API Instead of the S3-Compatible Endpoint?

Backblaze B2 supports two API interfaces: an S3-compatible layer that mirrors AWS S3 conventions, and the native B2 API that was B2's original interface. The native API unlocks capabilities that the S3-compatible layer does not expose: granular download authorization tokens with time-limited access and prefix restrictions, server-side encryption configuration, lifecycle rule management, detailed bandwidth and transaction accounting, and bucket-level event notifications. For teams that need more than basic file browsing — particularly those managing private content delivery, compliance-driven lifecycle policies, or cost tracking — the native B2 API is the better choice.

The key difference in the native API is its dynamic authentication model. Unlike the S3-compatible API's static credential signing, the native B2 API requires you to first call b2_authorize_account to receive a session-scoped authorization token and an API URL that may change between sessions. This two-step flow adds a small amount of complexity to the Retool setup — you chain an authorization query before every bucket operation session — but the approach works reliably within Retool's query chaining and event handler system.

Retool's server-side proxying handles both the authorization call and subsequent API calls securely. Your B2 application key ID and key are stored as configuration variables in Retool's settings, never exposed in the browser. The authorization token received from B2 is used only within Retool's server-side query execution layer, making this integration appropriate even for buckets containing sensitive or regulated content.

Integration method

REST API Resource

Backblaze B2's native API uses a two-step authentication flow: first call b2_authorize_account to receive an authorization token and dynamic API URL, then use that token and URL for all subsequent API operations. In Retool, you configure a REST API Resource targeting B2's fixed authorization endpoint, then use a query chain to obtain and cache the session token for bucket and file operations. Retool proxies all requests server-side, keeping your B2 credentials secure.

Prerequisites

  • A Retool account (Cloud or self-hosted) with permission to add Resources
  • A Backblaze account with at least one B2 bucket
  • A B2 application key with appropriate capabilities — create in Backblaze Dashboard → App Keys → Add a New Application Key
  • Your B2 application key ID (keyId) and application key value — save the key value immediately at creation as it is shown only once
  • Basic familiarity with Retool's query chaining (event handlers triggering subsequent queries) since the B2 native API requires an authorization step before data queries

Step-by-step guide

1

Create a B2 application key with the required capabilities

B2's native API access is controlled by application keys with explicit capability grants. Navigate to the Backblaze web console (secure.backblaze.com) and go to App Keys → Add a New Application Key. Set the application key configuration: - Name of Key: 'retool-native-api' (descriptive name for tracking purposes) - Allow access to Bucket(s): All (or select specific buckets for tighter access control) - Type of Access: Read and Write — for a monitoring dashboard, Read Only is sufficient - File name prefix: leave blank for full bucket access - Duration: leave blank for a non-expiring key For the native B2 API, the relevant capabilities are: - listBuckets — allows b2_list_buckets - listFiles — allows b2_list_file_names and b2_list_file_versions - readFiles — allows b2_download_file_by_name and b2_download_file_by_id - writeFiles — allows b2_upload_file (only needed for upload features) - deleteFiles — allows b2_delete_file_version (only needed for delete features) - readBucketEncryption — allows reading SSE configuration - writeBucketLifecycle — allows b2_update_bucket lifecycle settings Click Create New Key. Immediately copy both the applicationKeyId (the long numeric/alphanumeric ID) and the applicationKey (the secret value). The applicationKey is shown only once — if you navigate away without copying it, you must create a new key. Next, add these two values as Retool configuration variables: go to Retool Settings → Configuration Variables. Create B2_KEY_ID with the applicationKeyId value (mark as secret), and B2_APPLICATION_KEY with the applicationKey value (mark as secret).

Pro tip: Application keys scoped to specific buckets cannot call b2_list_buckets — that call requires an account-level key. If you need bucket listing in your dashboard, create an account-level key with listBuckets capability alongside bucket-specific keys for file operations.

Expected result: A B2 application key exists with appropriate capabilities. The applicationKeyId and applicationKey are saved as secret configuration variables in Retool Settings → Configuration Variables.

2

Configure the REST API Resource and authorization query

Create a Retool REST API Resource for the B2 authorization endpoint. Go to Resources tab → Add Resource → REST API: - Name: 'Backblaze B2 Native API' - Base URL: https://api.backblazeb2.com - Authentication: Basic Auth - Username: {{ retoolContext.configVars.B2_KEY_ID }} - Password: {{ retoolContext.configVars.B2_APPLICATION_KEY }} Note: Basic Auth here is only used for the b2_authorize_account call. The base URL is B2's fixed authorization endpoint — subsequent API calls will use a dynamic URL returned by the authorization response. Save the resource. Now create an authorization query in your Retool app. Go to the Code panel, create a new query, select the Backblaze B2 Native API resource: - Method: GET - Path: /b2api/v3/b2_authorize_account This call returns a JSON response containing: - authorizationToken — used as the bearer token for all subsequent B2 API calls - apiInfo.storageApi.apiUrl — the dynamic API URL for your account's storage operations - downloadUrl — base URL for direct file downloads - accountId — your B2 account ID Run this query manually and confirm the response. Store the auth token query as 'b2AuthQuery'. Other queries will reference {{ b2AuthQuery.data.authorizationToken }} and {{ b2AuthQuery.data.apiInfo.storageApi.apiUrl }}. Create a second REST API Resource for authenticated B2 API calls: - Name: 'B2 Storage API' - Base URL: {{ b2AuthQuery.data.apiInfo.storageApi.apiUrl }} (note: this is dynamic) - Authentication: Bearer Token - Token: {{ b2AuthQuery.data.authorizationToken }}

Pro tip: B2 authorization tokens expire after 24 hours by default. Add a 'Refresh Auth' button to your dashboard that re-triggers the b2AuthQuery, and set the authorization query to run automatically on page load by enabling 'Run this query on page load' in the query's settings.

Expected result: The b2_authorize_account query returns a JSON response containing the authorizationToken, apiUrl, and downloadUrl. The 'B2 Storage API' resource is configured with these dynamic values from the auth query response.

3

Query bucket listings and file inventories

Create a query to list all accessible B2 buckets. In the Code panel, create a new query and select the 'B2 Storage API' resource: - Method: GET - Path: /b2api/v3/b2_list_buckets - URL parameter: accountId → {{ b2AuthQuery.data.accountId }} The response returns a buckets array where each bucket includes bucketId, bucketName, bucketType (allPublic, allPrivate, snapshot), and bucketInfo (custom metadata). Bind a Select component to this data with displayField set to bucketName and valueField set to bucketId. Create a file listing query using b2_list_file_names: - Method: GET - Path: /b2api/v3/b2_list_file_names - URL parameter: bucketId → {{ bucketSelect.value }} - URL parameter: maxFileCount → 500 - URL parameter: prefix → {{ prefixInput.value || '' }} - URL parameter: delimiter → / (for folder-like navigation) The response includes a files array where each file has: fileId, fileName, size, contentType, uploadTimestamp, and fileInfo (custom metadata dictionary). Add a JavaScript transformer to format sizes and timestamps, then bind a Table component to {{ fileListQuery.data }}. Enable 'Run automatically when inputs change' on the file list query so it refreshes when the bucket selection changes. Add a Text Input component for prefix filtering to enable folder-like navigation within the bucket.

fileListTransformer.js
1// Transformer for b2_list_file_names response
2const files = data.files || [];
3return files.map(file => {
4 const sizeBytes = file.contentLength || 0;
5 let sizeDisplay;
6 if (sizeBytes >= 1073741824) {
7 sizeDisplay = (sizeBytes / 1073741824).toFixed(2) + ' GB';
8 } else if (sizeBytes >= 1048576) {
9 sizeDisplay = (sizeBytes / 1048576).toFixed(2) + ' MB';
10 } else {
11 sizeDisplay = (sizeBytes / 1024).toFixed(1) + ' KB';
12 }
13 return {
14 file_id: file.fileId,
15 file_name: file.fileName,
16 short_name: file.fileName.split('/').pop(),
17 content_type: file.contentType || '',
18 size_bytes: sizeBytes,
19 size_display: sizeDisplay,
20 upload_time: file.uploadTimestamp
21 ? new Date(file.uploadTimestamp).toLocaleString()
22 : '',
23 action: file.action, // 'upload', 'hide', or 'folder'
24 sha1: file.contentSha1 || ''
25 };
26});

Pro tip: The delimiter: '/' parameter makes B2 return folders as virtual entries with action: 'folder'. These appear as folder entries in the file list that you can use as prefixes for drill-down navigation. Build a breadcrumb component using a Retool text variable that tracks the current prefix path.

Expected result: The bucket selector populates with all accessible B2 buckets. Selecting a bucket populates the file table with filenames, sizes, upload timestamps, and content types. The prefix filter allows navigating into sub-'folders'.

4

Add download authorization token generation for private buckets

B2's native API provides b2_get_download_authorization for generating time-limited, prefix-scoped download tokens — a B2-specific feature not available through the S3-compatible API. This is essential for sharing private content without making entire buckets public. Create a query to generate download authorization: - Method: POST - Path: /b2api/v3/b2_get_download_authorization - Body type: JSON - Body: ```json { "bucketId": "{{ bucketSelect.value }}", "fileNamePrefix": "{{ fileListTable.selectedRow?.file_name || '' }}", "validDurationInSeconds": "{{ tokenDurationSelect.value }}" } ``` Add a Select component for token duration with options: 3600 (1 hour), 86400 (24 hours), 604800 (7 days). Wire it to the validDurationInSeconds parameter. The response returns an authorizationToken specifically for download operations. Construct the authorized download URL in a JavaScript query: ``` const baseUrl = b2AuthQuery.data.downloadUrl; const bucket = bucketsQuery.data.buckets.find(b => b.bucketId === bucketSelect.value)?.bucketName; const fileName = encodeURIComponent(fileListTable.selectedRow.file_name); const token = downloadAuthQuery.data.authorizationToken; return `${baseUrl}/file/${bucket}/${fileName}?Authorization=${token}`; ``` Display the generated URL in a Text Input component (set to read-only) with a Copy to Clipboard button. Add a Container component that shows the token expiration time: new Date(Date.now() + tokenDurationSelect.value * 1000).toLocaleString().

buildDownloadUrl.js
1// JavaScript query to construct authorized download URL
2// Runs after downloadAuthQuery succeeds
3const baseUrl = b2AuthQuery.data.downloadUrl;
4const selectedBucketId = bucketSelect.value;
5const buckets = bucketsQuery.data.buckets || [];
6const bucket = buckets.find(b => b.bucketId === selectedBucketId);
7if (!bucket) return { url: '', error: 'Bucket not found' };
8const selectedFile = fileListTable.selectedRow;
9if (!selectedFile) return { url: '', error: 'No file selected' };
10const encodedName = selectedFile.file_name.split('/').map(encodeURIComponent).join('/');
11const token = downloadAuthQuery.data.authorizationToken;
12const expiresAt = new Date(Date.now() + (tokenDurationSelect.value * 1000)).toLocaleString();
13return {
14 url: `${baseUrl}/file/${bucket.bucketName}/${encodedName}?Authorization=${token}`,
15 expires_at: expiresAt,
16 file_name: selectedFile.file_name,
17 duration_label: tokenDurationSelect.label
18};

Pro tip: Download authorization tokens can be scoped to a file prefix, not just a single file. Setting fileNamePrefix to 'reports/2024/' allows the token to authorize downloads of any file under that prefix — useful for generating batch download sessions for entire folders.

Expected result: Selecting a file and clicking 'Generate Download Link' triggers the download authorization query and constructs a time-limited URL displayed in the panel. The URL opens the private B2 file without requiring the user to have B2 credentials.

5

Add bucket metadata, lifecycle display, and a storage summary

Add a bucket detail panel that shows the selected bucket's configuration, including lifecycle rules, server-side encryption settings, and bucket type. Create a query for bucket details: - Method: GET - Path: /b2api/v3/b2_list_buckets - URL parameter: accountId → {{ b2AuthQuery.data.accountId }} - URL parameter: bucketId → {{ bucketSelect.value }} - URL parameter: bucketTypes → allPrivate,allPublic,snapshot The response includes the full bucket object with lifecycleRules array, defaultServerSideEncryption, and bucketInfo. Display lifecycle rules in an editable table showing daysFromHidingToDeleting and daysFromUploadingToHiding for each rule. For storage usage, B2's b2_list_buckets response includes a filesAndVersionsCount and storageBytesUsed per bucket — use this for a storage summary without needing to enumerate all files. Create a summary transformer that reads from the buckets list to display total storage across all buckets. Drag a Stats Summary section at the top of the dashboard with Statistic components showing: - Total buckets - Total storage (sum of storageBytesUsed in GB) - Estimated monthly cost ($0.006 × total GB) - Total files (sum of filesAndVersionsCount) For complex integrations involving multiple B2 buckets, custom download authorization workflows, and automated lifecycle management via Retool Workflows, RapidDev's team can help architect and build your Retool solution.

storageSummaryTransformer.js
1// Storage summary transformer — reads from b2_list_buckets response
2// data.buckets is the array of all bucket objects
3const buckets = data.buckets || [];
4const totalBytes = buckets.reduce((sum, b) => sum + (b.storageBytesUsed || 0), 0);
5const totalFiles = buckets.reduce((sum, b) => sum + (b.filesAndVersionsCount || 0), 0);
6const totalGB = totalBytes / (1024 * 1024 * 1024);
7const monthlyCost = totalGB * 0.006;
8return {
9 bucket_count: buckets.length,
10 total_files: totalFiles.toLocaleString(),
11 total_storage_gb: totalGB.toFixed(3),
12 total_storage_display: totalGB >= 1 ? totalGB.toFixed(2) + ' GB' : (totalBytes / 1048576).toFixed(1) + ' MB',
13 monthly_cost_estimate: '$' + monthlyCost.toFixed(4),
14 buckets_summary: buckets.map(b => ({
15 name: b.bucketName,
16 type: b.bucketType,
17 files: b.filesAndVersionsCount || 0,
18 size_gb: ((b.storageBytesUsed || 0) / 1073741824).toFixed(4)
19 }))
20};

Pro tip: B2's b2_list_buckets includes storageBytesUsed and filesAndVersionsCount only when the account-level key is used. Bucket-scoped keys may not return these aggregate fields — use an account-level key for the monitoring dashboard queries while using a bucket-scoped key for file operations.

Expected result: A storage summary panel shows total buckets, files, storage, and estimated cost. The bucket detail panel shows lifecycle rules and encryption settings for the selected bucket. Download authorization URLs are generated with configurable expiration times.

Common use cases

Build a private content delivery management panel

Create a Retool panel for managing private B2 buckets used for content delivery. Display bucket contents, generate time-limited download authorization tokens for selected files, and track download counts per file. Add a bulk token generation tool that creates download URLs with configurable expiration times for a set of selected objects.

Retool Prompt

Build a content delivery panel that lists files in a private B2 bucket. When a file is selected, show a 'Generate Download Link' panel with an expiration time picker (1 hour, 24 hours, 7 days) and a Generate button. The generated URL should be displayed and copyable. Add a second panel showing a log of recently generated download tokens stored in the internal content_tokens database table.

Copy this prompt to try it in Retool

Build a lifecycle policy management dashboard

Create a Retool panel that displays current B2 lifecycle rules for each bucket, allows editing rule parameters like daysFromHidingToDeleting and daysFromUploadingToHiding, and shows the impact of proposed rule changes on estimated storage costs. Add a Workflow that periodically audits bucket lifecycle configurations against company retention policies.

Retool Prompt

Build a lifecycle management panel showing all B2 buckets in a table with their current lifecycle rule settings. When a bucket is selected, display the lifecycle rules in an editable form showing daysFromHidingToDeleting and daysFromUploadingToHiding values. Add an estimated impact calculator that projects how many bytes and files would be affected by the rule change based on current bucket contents. Include a Save Changes button that calls b2_update_bucket.

Copy this prompt to try it in Retool

Build a storage cost and bandwidth monitoring dashboard

Create a Retool dashboard that uses B2's b2_list_buckets endpoint (which returns storageBytesUsed per bucket) to display storage usage across all buckets, estimated monthly costs, and download bandwidth consumed. Add Chart components for storage growth over time and a comparison view between buckets to identify cost optimization opportunities.

Retool Prompt

Build a storage cost dashboard that queries all B2 buckets and displays storageBytesUsed for each. Show a summary card with total storage in GB and estimated monthly cost ($0.006/GB). Add a pie chart showing storage distribution by bucket. Include a trend section that compares current usage against last week's snapshot stored in the internal storage_snapshots table.

Copy this prompt to try it in Retool

Troubleshooting

b2_authorize_account returns 401 Unauthorized

Cause: The applicationKeyId or applicationKey is incorrect, or Basic Auth credentials are being passed in the wrong order. In B2's native API, the Basic Auth username is the applicationKeyId and the password is the applicationKey — these are swapped from what some developers expect.

Solution: Verify the applicationKeyId is in the Retool resource's Basic Auth Username field and the applicationKey (the long secret value) is in the Password field. Double-check both values in Retool's configuration variables by editing them — character truncation can occur if the values were pasted with surrounding whitespace. If in doubt, generate a new application key in Backblaze Dashboard and update the configuration variables.

File listing query returns 401 even after successful authorization

Cause: The dynamic API URL from b2_authorize_account's response (apiInfo.storageApi.apiUrl) is not being used correctly as the base URL for the 'B2 Storage API' resource, or the authorization token has expired.

Solution: Confirm the 'B2 Storage API' resource base URL references {{ b2AuthQuery.data.apiInfo.storageApi.apiUrl }} and that b2AuthQuery has run successfully before the file listing query. Since the base URL is dynamic, it resolves at query execution time — trigger b2AuthQuery first using a page load trigger or a manual 'Connect' button. If the token expired (after 24 hours), re-run b2AuthQuery to get a fresh token.

b2_list_buckets returns an empty buckets array even though buckets exist

Cause: The application key was scoped to specific buckets rather than all buckets, or the accountId parameter in the query doesn't match the account the key belongs to.

Solution: Verify the accountId URL parameter matches {{ b2AuthQuery.data.accountId }} — do not hardcode it. If using a bucket-scoped key, b2_list_buckets will only return the bucket(s) the key has access to, not all account buckets. For a full multi-bucket dashboard, create an account-level master key with listBuckets capability for the listing query, and separate bucket-scoped keys for file operations.

Download authorization URL returns 403 when accessed in a browser

Cause: The token included in the URL has expired, or the file path doesn't match the fileNamePrefix scope the token was authorized for.

Solution: Check that the token expiration time has not passed. The validDurationInSeconds you specified starts from when b2_get_download_authorization was called, not when the URL is accessed. Verify the fileName in the URL exactly matches or is within the fileNamePrefix scope used when generating the token. File names are case-sensitive in B2. Regenerate the download authorization with a longer duration if needed.

Best practices

  • Trigger b2_authorize_account on page load so all subsequent queries have a valid token; add a manual 'Refresh Connection' button as a fallback for sessions that span more than 24 hours
  • Store your B2 applicationKeyId and applicationKey as secret configuration variables in Retool Settings → Configuration Variables — never inline them in query parameters or body fields
  • Use bucket-scoped application keys for file operation queries and reserve account-level keys for bucket listing and aggregate monitoring queries, following least-privilege principles
  • Scope download authorization tokens to the minimum required prefix and shortest practical duration — 1-hour tokens for one-time sharing, 24-hour tokens for workflow-based access
  • Add pagination handling for b2_list_file_names by checking the nextFileName field in the response — for large buckets with thousands of files, implement a 'Load next page' button rather than trying to load all files at once
  • Cache the bucket list query (30-60 seconds) since bucket configurations rarely change, but do not cache the authorization query — always fetch a fresh token to ensure validity
  • Test your integration against a non-production bucket first to verify lifecycle rule queries before running them against buckets with critical production data

Alternatives

Frequently asked questions

When should I use B2's native API versus the S3-compatible API in Retool?

Use the native B2 API when you need B2-specific features: download authorization tokens for private content, lifecycle rule management (daysFromHidingToDeleting), server-side encryption configuration, or access to B2's detailed account and bucket metadata. Use the S3-compatible API when you want simpler setup, already use S3 patterns in other Retool resources, or only need basic bucket browsing and file management without B2-specific features.

How long do B2 authorization tokens last, and how do I handle expiration in Retool?

B2 authorization tokens from b2_authorize_account are valid for 24 hours by default. In Retool, set the b2_authorize_account query to run on page load so each new session starts with a fresh token. For long-running sessions, add a timer component or a manual 'Reconnect' button that re-triggers the authorization query. When the token expires, all file listing and download queries will return 401 errors — refreshing the auth query resolves this immediately.

Can I upload files to B2 from Retool using the native API?

Yes, but file uploads with B2's native API require a two-step process: first call b2_get_upload_url to get an upload URL and upload authorization token, then POST the file content to that URL with the token as a header. This is more complex than the S3-compatible PUT operation. For upload functionality, you'll need a File Input component in Retool and a query chain: get upload URL → upload file. Large files (over 100MB) should use B2's large file API (b2_start_large_file, b2_get_upload_part_url, b2_upload_part, b2_finish_large_file).

Is there a way to connect Retool to both the B2 native API and S3-compatible API simultaneously?

Yes. Create two separate REST API Resources: one for the native B2 API (api.backblazeb2.com with Basic Auth for authorization calls) and one for the S3-compatible API (s3.REGION.backblazeb2.com with AWS v4 auth). Different queries in the same Retool app can target different resources — use the native API resource for authorization, lifecycle management, and download token generation, and the S3-compatible resource for standard file listing and download operations if preferred.

Does the B2 native API support server-side encryption and lifecycle rules that I can manage from Retool?

Yes. B2's b2_update_bucket endpoint accepts serverSideEncryption settings (SSE-B2 or SSE-C modes) and lifecycleRules arrays. From Retool, you can build a form that reads current bucket settings via b2_list_buckets, allows editing lifecycle rules (daysFromHidingToDeleting, daysFromUploadingToHiding, fileNamePrefix per rule), and submits updates via b2_update_bucket. Add confirmation dialogs before applying lifecycle changes since incorrectly configured rules can cause unintended file deletion.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire Retool integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.