Dbrij Storage docs

The complete Dbrij Storage reference: buckets, objects, presigned uploads, the S3 endpoint, access keys, versioning, lifecycle, public links and plans.

Dbrij Storage

Dbrij Storage keeps files. Two faces, one allowance: Buckets, which your code reaches through the REST API below or through the S3 protocol with any tool that speaks it, and Files, the drive people use from the app with folders, sharing and editors. A person's storage is theirs; a company's is the company's, and every meter and cap is by that principal.

Bytes live on an S3 compatible object store with traffic included, which is why no plan carries an egress fee. Uploads go straight to the store through presigned URLs, so a large file never streams through the API.

REST basehttps://api.dbrij.com/api/storage
S3 endpointhttps://s3.dbrij.com
Delivery hosthttps://files.dbrij.com

REST calls carry Authorization: Bearer <accessKeyId>:<secret>. S3 calls sign with the same id and secret as AWS credentials. Keys are minted on the Access keys page; the secret is shown once.

Quickstart

Three calls put a file in a bucket and read it back. Every step also works with the AWS CLI, shown afterwards.

1. Create a bucket
curl https://api.dbrij.com/api/storage/buckets \
  -H "Authorization: Bearer dbsk_…:dbss_…" \
  -H "Content-Type: application/json" \
  -d '{ "name": "my-assets" }'
2. Get an upload URL, then PUT the bytes to it
curl https://api.dbrij.com/api/storage/buckets/<bucketId>/upload-url \
  -H "Authorization: Bearer dbsk_…:dbss_…" \
  -H "Content-Type: application/json" \
  -d '{ "key": "images/logo.png", "contentType": "image/png" }'
# → { "url": "https://…", "headers": { "Content-Type": "image/png" } }

curl -X PUT "<url from the response>" -H "Content-Type: image/png" --data-binary @logo.png
3. Confirm, so the object exists
curl https://api.dbrij.com/api/storage/buckets/<bucketId>/confirm \
  -H "Authorization: Bearer dbsk_…:dbss_…" \
  -H "Content-Type: application/json" \
  -d '{ "key": "images/logo.png" }'
The same thing with the AWS CLI
export AWS_ACCESS_KEY_ID=dbsk_…
export AWS_SECRET_ACCESS_KEY=dbss_…
aws --endpoint-url https://s3.dbrij.com s3 mb s3://my-assets
aws --endpoint-url https://s3.dbrij.com s3 cp logo.png s3://my-assets/images/logo.png
aws --endpoint-url https://s3.dbrij.com s3 ls s3://my-assets/images/

Over S3 there is no confirm step: the store tells Dbrij when the bytes land. Use whichever surface your stack already speaks. Most frameworks have an S3 storage driver, and pointing it here is a two line change.

Keys and the S3 endpoint

An access key is an id (dbsk_…) and a secret (dbss_…) with a scope of read, write or both. A key made in your personal space reaches your buckets. A key made while working in a company reaches the company's buckets and bills to the company. The secret is shown once, at creation.

WHAT EACH SCOPE ALLOWS

readscopeList buckets and objects, download, and every S3 GET, HEAD and LIST.
writescopeCreate buckets, upload, delete, copy, multipart, and bucket configuration over S3.
rclone
rclone config create dbrij s3 provider=Other access_key_id=dbsk_… secret_access_key=dbss_… endpoint=https://s3.dbrij.com
rclone sync ./public dbrij:my-assets/public
Node, with the AWS SDK
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

const s3 = new S3Client({
  endpoint: 'https://s3.dbrij.com',
  region: 'auto',
  forcePathStyle: true,
  credentials: { accessKeyId: process.env.DBRIJ_KEY_ID!, secretAccessKey: process.env.DBRIJ_KEY_SECRET! },
});
await s3.send(new PutObjectCommand({ Bucket: 'my-assets', Key: 'images/logo.png', Body: bytes, ContentType: 'image/png' }));

Path style (https://s3.dbrij.com/my-assets/key) is always accepted. Virtual host style (my-assets.s3.dbrij.com) works too. Presigned S3 URLs from any SDK verify the same way.

Rotation. Mint the new key, move your deployments to it, then revoke the old one. A revoked key fails every call immediately with 401. Keys made before the S3 endpoint existed show as REST only on the keys page and cannot sign S3 requests; mint a new one.

Scoped keys (Pro plan and up) are narrowed at creation: one bucket, a prefix under it, an end date, an IP allowlist. Out of scope calls fail with 403 on REST and AccessDenied over S3; an expired key fails with 401. A key for one service that can only write uploads/ in one bucket and stops working next quarter is the key to put in that service's environment.

The SDK

@dbrij/storage is a zero dependency client for Node 18+ and browsers. It covers what S3 does not: delivery links, transformations, presets, and the confirm step REST uploads need. Keep using an AWS SDK for everything else if you already do.

Install
npm install @dbrij/storage
Server side, with a key
import { DbrijStorage, transform } from '@dbrij/storage';

const storage = new DbrijStorage({ keyId: process.env.DBRIJ_KEY_ID, secret: process.env.DBRIJ_KEY_SECRET });

const bucket = await storage.buckets.create('my-assets');
await storage.objects.upload(bucket.id, 'images/logo.png', bytes, { contentType: 'image/png' });
const link = await storage.delivery.url(bucket.id, 'images/logo.png', { transform: transform({ width: 800, format: 'auto' }) });
// link.url → https://files.dbrij.com/t/w_800,f_auto/<bucketId>/images/logo.png
Browser, with a preset and no key
import { DbrijStorage } from '@dbrij/storage';

const file = await DbrijStorage.presetUpload('dbup_…', input.files[0], { onProgress: (f) => bar.style.width = f * 100 + '%' });
img.src = file.deliveryUrl;

METHODS

buckets.list / createkeyThe buckets the key can reach; create a private or public one.
objects.list / upload / delete / downloadUrlkeyupload presigns, PUTs the bytes and confirms in one call, with progress in browsers.
delivery.urlkeyA delivery link, signed for private objects, transformed for images.
DbrijStorage.presetUploadno keyA keyless upload through a preset, for browsers and mobile.
transform(...)helperNamed options → the token string, so code reads width: 800 rather than w_800.

Python, Go and PHP: point the AWS SDK for that language at https://s3.dbrij.com with the key id and secret, and call the REST endpoints in this reference for delivery links and presets. Dedicated packages follow.

Buckets

A bucket is a named space for objects. It is private by default: nothing in it can be read without a signed URL or a key. Switching it public makes every object's stable link readable by anyone. A public bucket can also be put on signed, expiring links instead of permanent ones, for downloads you want to be able to withdraw.

GET/storage/bucketsread

List buckets

Every bucket the key can reach: a personal key sees the person's buckets, a company key the company's. Counts and bytes ride along.

Request
curl -X GET https://api.dbrij.com/api/storage/buckets \
  -H "Authorization: Bearer $DBRIJ_API_KEY"
Response 200
{
  "success": true,
  "data": [{ "id": "b1…", "name": "my-assets", "visibility": "private", "versioning": null, "objectCount": 128, "totalBytes": 91827364, "createdAt": "…" }]
}
POST/storage/bucketswrite

Create a bucket

Names are 3 to 63 lowercase letters, numbers and hyphens, unique per owner. A public bucket serves permanent links from the moment it exists.

PATH / BODY PARAMETERS

name*stringThe bucket name, used in every S3 path.
visibility"private" | "public"Private by default: objects are reachable only through signed URLs.
Request
curl -X POST https://api.dbrij.com/api/storage/buckets \
  -H "Authorization: Bearer $DBRIJ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "my-assets", "visibility": "private" }'
Request body
{ "name": "my-assets", "visibility": "private" }
Response 200
{
  "success": true,
  "data": { "id": "b1…", "name": "my-assets", "visibility": "private", "objectCount": 0, "totalBytes": 0 }
}

Over S3, CreateBucket, ListBuckets, DeleteBucket, PutBucketVersioning, PutBucketLifecycleConfiguration and PutBucketPolicy are all served. Deleting a bucket needs it empty, as everywhere.

Objects and uploads

Keys are paths: slashes make folders, and a key ending in a slash is a folder marker with no bytes. Objects can be up to five gigabytes each, subject to the plan's allowance. Uploads never stream through the API: REST hands you a presigned PUT, S3 uploads go to the endpoint directly, multipart included.

GET/storage/buckets/:bucketId/objectsread

List objects

Objects in a bucket, optionally under a key prefix. Folder markers (keys ending in a slash) come back with isFolder true and no bytes.

PATH / BODY PARAMETERS

prefixstringQuery parameter. Only keys starting with this, e.g. images/.
Request
curl -X GET https://api.dbrij.com/api/storage/buckets/:bucketId/objects \
  -H "Authorization: Bearer $DBRIJ_API_KEY"
Response 200
{
  "success": true,
  "data": [{ "key": "images/logo.png", "size": 18233, "contentType": "image/png", "isFolder": false, "url": null, "updatedAt": "…" }]
}
POST/storage/buckets/:bucketId/upload-urlwrite

Get a presigned upload URL

Step one of an upload. The URL points at the object store, not the API: PUT the raw bytes there with the headers returned, with no Authorization header and no JSON envelope. It expires after fifteen minutes.

PATH / BODY PARAMETERS

key*stringThe object key, up to 1,024 characters. Slashes make folders.
contentTypestringSent as the object's Content-Type. Defaults to application/octet-stream.
Request
curl -X POST https://api.dbrij.com/api/storage/buckets/:bucketId/upload-url \
  -H "Authorization: Bearer $DBRIJ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "key": "images/logo.png", "contentType": "image/png" }'
Request body
{ "key": "images/logo.png", "contentType": "image/png" }
Response 200
{
  "success": true,
  "data": { "url": "https://…", "method": "PUT", "headers": { "Content-Type": "image/png" }, "key": "images/logo.png", "expiresIn": 900 }
}
POST/storage/buckets/:bucketId/confirmwrite

Confirm an upload

Step two. Dbrij reads the object's real size from the store and records it. An upload that is never confirmed is swept away after a day, so the confirm is what makes an object exist.

PATH / BODY PARAMETERS

key*stringThe key you uploaded to.
Request
curl -X POST https://api.dbrij.com/api/storage/buckets/:bucketId/confirm \
  -H "Authorization: Bearer $DBRIJ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "key": "images/logo.png" }'
Request body
{ "key": "images/logo.png" }
Response 200
{
  "success": true,
  "data": { "key": "images/logo.png", "size": 18233, "contentType": "image/png", "url": null }
}
GET/storage/buckets/:bucketId/object?key=…read

Download an object

Redirects (302) to a signed URL for the bytes, good for one hour. Follow the redirect, or read the Location header to hand the URL to a browser.

Request
curl -X GET https://api.dbrij.com/api/storage/buckets/:bucketId/object?key=… \
  -H "Authorization: Bearer $DBRIJ_API_KEY"
DELETE/storage/buckets/:bucketId/object?key=…write

Delete an object

On a versioned bucket this writes a delete marker and keeps the previous version; on an unversioned bucket the bytes are gone.

Request
curl -X DELETE https://api.dbrij.com/api/storage/buckets/:bucketId/object?key=… \
  -H "Authorization: Bearer $DBRIJ_API_KEY"
Response 200
{
  "success": true,
  "data": { "deleted": true }
}

Big files. Use S3 multipart for anything over a hundred megabytes: CreateMultipartUpload, UploadPart, ListParts, CompleteMultipartUpload and UploadPartCopy are served, and every SDK's high level upload helper uses them for you.

Copy. CopyObject copies within and between your buckets on the server, no download.

Browser uploads. The presigned URL from the REST call is safe to hand to a browser: it carries no key and expires in fifteen minutes. Bucket CORS is configured for direct browser PUTs.

Image transformations

Put tokens in the path and the delivery host resizes, crops and re-encodes the image on first request, caches the result, and serves it from the cache after that. Only images transform; anything else is served as is. A transformation counts against the plan's allowance the first time it runs, never on a cache hit.

Shape
https://files.dbrij.com/t/<tokens>/<bucketId>/<key>
https://cdn.example.com/t/<tokens>/<key>            # on a custom domain

TOKENS

w_800, h_600sizeWidth and height in pixels, up to 4096. One alone keeps the aspect ratio.
c_fill | fit | scale | pad | cropcropfill covers the box and crops; fit sits inside it without enlarging; scale stretches; pad letterboxes with the background; crop cuts to the box.
g_auto | center | north | south | east | west | northeast …gravityWhere fill and crop keep. auto picks the busiest region.
f_auto | webp | avif | jpg | png | gifformatauto serves AVIF or WebP when the browser accepts it, else the source format, and never drops transparency into JPEG.
q_80quality1 to 100. Defaults suit each format.
dpr_2densityMultiplies w and h for high density screens, up to 3.
r_20 | r_maxcornersRounded corners in pixels, or max for a circle.
b_ffffffbackgroundHex colour behind pad and under transparency flattened into JPEG.
a_90rotateQuarter turns clockwise. EXIF orientation is honoured on its own.
e_blur:200, e_grayscale, e_sharpeneffectsBlur strength up to 2000, greyscale, and a sharpen pass.
flip, flopmirrorVertical and horizontal mirror.

Unknown tokens are refused with the token named, never ignored. Sources up to 40 MB transform; SVG and icons are served untouched. Cloudinary style paths (/image/upload/w_300,c_fill/v1712/folder/file.jpg) are read too, on the delivery host after the bucket id and on custom domains directly, so URLs copied from an existing site keep working after a switch.

Upload presets and the widget

An upload preset opens one bucket prefix to keyless uploads from a browser or a mobile app, inside limits you set: accepted types, a size cap, and the origins allowed. The preset token (dbup_…) is safe in page source. Create presets on the bucket page.

The widget
<script src="https://app.dbrij.com/storage-widget.js"></script>
<button id="upload">Upload files</button>
<script>
  DbrijStorage.attach(document.querySelector('#upload'), {
    preset: 'dbup_…',
    onUploaded: (file) => console.log(file.key, file.deliveryUrl),
  });
  // or without UI: DbrijStorage.upload('dbup_…', fileInput.files[0]).then(console.log)
</script>
POST/storage/uploads/:presetTokennone

Start a preset upload

No key. Returns a presigned PUT for a key under the preset prefix; PUT the bytes there with the headers given, then confirm.

PATH / BODY PARAMETERS

filename*stringUsed for the key's last segment, sanitised.
contentTypestringChecked against the preset's allowed types.
sizenumberChecked against the cap up front; the real size is checked again at confirm.
Request
curl -X POST https://api.dbrij.com/api/storage/uploads/:presetToken \
  -H "Authorization: Bearer $DBRIJ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "filename": "avatar.png", "contentType": "image/png", "size": 18233 }'
Request body
{ "filename": "avatar.png", "contentType": "image/png", "size": 18233 }
Response 200
{
  "success": true,
  "data": { "uploadUrl": "https://…", "method": "PUT", "headers": { "Content-Type": "image/png" }, "key": "uploads/2026/09/1a2b3c4d-avatar.png", "expiresIn": 900, "confirmUrl": "…" }
}
POST/storage/uploads/:presetToken/confirmnone

Confirm a preset upload

Reads what actually landed. Past the size cap or outside the allowed types, the bytes are deleted and the call fails; otherwise the object exists and a delivery link good for a day comes back.

Request
curl -X POST https://api.dbrij.com/api/storage/uploads/:presetToken/confirm \
  -H "Authorization: Bearer $DBRIJ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "key": "uploads/2026/09/1a2b3c4d-avatar.png" }'
Request body
{ "key": "uploads/2026/09/1a2b3c4d-avatar.png" }
Response 200
{
  "success": true,
  "data": { "key": "…", "size": 18233, "contentType": "image/png", "url": null, "deliveryUrl": "https://…?exp=…&sig=…" }
}

Custom domains

Put your own hostname in front of a bucket. cdn.example.com/images/hero.jpg serves the object, cdn.example.com/t/w_800/images/hero.jpg the transformation, and Cloudinary style paths are read as well. The plan sets how many domains a space may attach.

DNS

CNAMErecommendedPoint the hostname at files.dbrij.com. Verification passes on the CNAME alone and a certificate is issued on first request.
TXTownership onlyPut the token from the bucket page at _dbrij.<hostname>. Use it when the hostname must stay pointed elsewhere while you prove ownership.

Add the domain on the bucket page, add the record, press Check. Signed links work on custom domains too; the signature does not depend on the host.

Versioning and lifecycle

Turn versioning on for a bucket and every overwrite keeps the previous bytes as a version, every delete writes a delete marker instead of removing anything, and deleting the marker brings the object back. Versions count against the allowance until a lifecycle rule or an explicit delete removes them.

Enable versioning with the AWS CLI
aws --endpoint-url https://s3.dbrij.com s3api put-bucket-versioning \
  --bucket my-assets --versioning-configuration Status=Enabled
Restore a deleted object: delete its delete marker
aws --endpoint-url https://s3.dbrij.com s3api list-object-versions --bucket my-assets --prefix images/logo.png
aws --endpoint-url https://s3.dbrij.com s3api delete-object --bucket my-assets --key images/logo.png --version-id <marker id>

Lifecycle rules run every hour. The applied subset is Expiration.Days (current objects older than this are deleted, a delete marker on a versioned bucket), NoncurrentVersionExpiration.NoncurrentDays (previous versions removed for good) and ExpiredObjectDeleteMarker. Transitions, tag filters and date based rules are refused with a reason rather than silently ignored.

Expire previous versions after thirty days
aws --endpoint-url https://s3.dbrij.com s3api put-bucket-lifecycle-configuration --bucket my-assets --lifecycle-configuration '{
  "Rules": [{ "ID": "prune-versions", "Status": "Enabled", "Filter": { "Prefix": "" },
              "NoncurrentVersionExpiration": { "NoncurrentDays": 30 } }]
}'

Public prefixes and policies

A whole bucket can be public, or just a prefix of it: public/ readable by anyone while everything else stays private. Set it from the bucket page, or with a bucket policy over S3. Dbrij reads the policy and maps it to what it enforces; anything finer than "public read on this prefix" is refused with a reason, never accepted and silently unenforced.

Public read on one prefix
aws --endpoint-url https://s3.dbrij.com s3api put-bucket-policy --bucket my-assets --policy '{
  "Version": "2012-10-17",
  "Statement": [{ "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::my-assets/public/*" }]
}'

Object level ACLs (x-amz-acl: public-read) on a private bucket are refused with guidance, because an ACL that quietly did nothing is the kind of thing that leaks a file a year later.

Webhooks

Object events delivered to your own https endpoints (Starter plan and up), signed the way every Dbrij webhook is signed. Add endpoints on the Webhooks page; each one gets a secret shown once and a delivery log you can replay from.

EVENTS

object.createdeventAn object was uploaded, overwritten, copied or imported. data: bucketId, key, size, contentType, versionId.
object.deletedeventAn object was deleted through the console, the REST API or S3. data: bucketId, key.
import.finishedeventAn import completed. data: bucketId, importId, source, copied, skipped, failed, bytes.
bucket.created / bucket.deletedeventdata: bucketId, name.
A delivery
POST https://example.com/hooks/dbrij
Content-Type: application/json
X-Dbrij-Event: object.created
X-Dbrij-Signature: sha256=<hmac(secret, body)>
X-Dbrij-Signature-V2: t=1760000000,sha256=<hmac(secret, "1760000000." + body)>

{ "id": "evt_…", "type": "object.created", "createdAt": "…", "data": { "bucketId": "…", "key": "images/logo.png", "size": 18233, "contentType": "image/png" } }
Verify in Node
import { createHmac, timingSafeEqual } from 'node:crypto';

function verify(secret, body, header) {
  const [t, sig] = header.split(',').map((p) => p.split('=')[1]);
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = createHmac('sha256', secret).update(t + '.' + body).digest('hex');
  return timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
}

Reply with any 2xx within ten seconds. Anything else is retried four more times over a few hours; twenty consecutive failures switch the endpoint off until you turn it back on. Deliveries are kept for thirty days.

Files for people

Files is the drive: what a person or a company keeps without writing code. Folders, sharing with members or by email, links anyone can open, trash, versions of edited files, and editors for documents, spreadsheets and presentations. It sits on the same allowance as the buckets, so a company buys storage once.

WHAT LIVES WHERE

FilespeopleDrive and Documents in the app and on mobile. Sharing, links, editors, trash. Counted as driveBytes.
BucketscodeObjects reached by key or by S3. Public links, presigned uploads, versioning, lifecycle. Counted as bucketBytes.
Database backupshostingNightly dumps from hosted databases, kept in the same store and counted against the same allowance.

Import from Google Drive, Dropbox and OneDrive, and mounting Files as a disk over WebDAV, are on the roadmap and land with the switching tools below.

Switching to Dbrij

Because the endpoint speaks S3, most moves are a change of endpoint and key. This is what changes in the common stacks, and what does not.

FROM AN S3 COMPATIBLE STORE (AWS S3, CLOUDFLARE R2, BACKBLAZE B2, WASABI, DIGITALOCEAN SPACES, MINIO, SUPABASE STORAGE)

Endpointchangehttps://s3.dbrij.com, path style on. Region can stay whatever it was.
CredentialschangeA Dbrij access key id and secret in place of the old pair.
Bucket nameskeepCreate buckets with the same names and your keys and paths stay identical.
Your codekeepSDK calls, presigned URLs and multipart uploads are unchanged.
Copying the databuilt inOpen the bucket, Delivery → Import, paste the source endpoint, bucket and keys, and Dbrij copies everything in the background (dry run first if you like). Sync mode skips what is already here, so run it again right before cutover. rclone works too.
Moving the hostname firstlazy fetchSet the old bucket URL as the origin on the bucket page and point your delivery domain here now: any key not yet copied is pulled across on first request and kept.
Copy a bucket across with rclone
rclone config create old s3 provider=AWS access_key_id=… secret_access_key=… region=eu-west-1
rclone config create dbrij s3 provider=Other access_key_id=dbsk_… secret_access_key=dbss_… endpoint=https://s3.dbrij.com
rclone sync old:my-assets dbrij:my-assets --transfers 16 --checksum
# run it again just before cutover: only what changed is copied

FROM CLOUDINARY

UploadschangeAn unsigned upload preset replaces the upload preset; the widget replaces the upload widget; signed uploads become a presigned PUT or an S3 PutObject.
Delivery URLsmostly keepThe delivery host reads Cloudinary path syntax (/image/upload/w_300,c_fill/v123/folder/file.jpg) on a custom domain, so a CNAME from your media hostname keeps existing URLs serving. The common transformation tokens are the same.
Copying the databuilt inOpen the bucket, Delivery → Import, choose Cloudinary and paste the cloud name, API key and secret. Every image, video and raw file is copied with its public id as the key, so /image/upload paths keep resolving.
Lazy fetchzero downtimeSet https://res.cloudinary.com/<cloud>/image/upload as the origin and CNAME your media hostname here: anything not yet imported is pulled on first request.

FROM FIREBASE STORAGE

UploadschangeFirebase's SDK uploads become presigned PUTs or S3 PutObject calls.
Copying the databuilt inGoogle Cloud Storage offers S3 interoperability keys: make a pair in the Cloud console, then run an S3 import with endpoint https://storage.googleapis.com and your bucket name.

FROM GOOGLE DRIVE, DROPBOX OR ONEDRIVE (FOR PEOPLE)

Google Drivebuilt inIn Files, New → Import from Google Drive. Sign in once and the whole drive is copied in the background with its folders intact; Google Docs, Sheets and Slides arrive as Word, Excel and PowerPoint files you can keep editing.
Dropbox, OneDrivetodayDownload folders and drop them into Files; the drop zone takes whole folders. A one click import for these is next.

Plans, errors and limits

The allowance is one number for the drive and the buckets together. A paid Hosting plan's included storage still counts: the allowance is the sum. Free stops uploads at the allowance. Paid plans keep accepting uploads and bill the gigabytes held above it by the day, at renewal, from the closed period, never the live month. There is no egress fee on any plan.

PlanStorageTransfer a monthBucketsKeysOver the allowanceVersioning
Free5 GB25 GB22Uploads stopNo
Starter100 GB500 GB2510₦25 per GB monthYes
Pro500 GB2 TB1,00050₦25 per GB monthYes
Business2.5 TB10 TB1,000200₦25 per GB monthYes

PLATFORM LIMITS

Object size5 GBPer object, on every plan. Use multipart above a hundred megabytes.
Key length1024 charactersUTF-8, no NUL. Slashes make folders.
Presigned upload15 minutesThen mint another. Unconfirmed uploads are swept after a day.
Signed download60 minutesFrom the REST download endpoint. Sign your own lifetime over S3.

ERRORS WORTH HANDLING

400bad requestA bad bucket name, a key past the limit, a plan cap reached (buckets, keys, or storage on Free). The message says which, and where to change it.
401unauthorizedMissing, revoked or wrong key. Over S3: InvalidAccessKeyId or SignatureDoesNotMatch.
403forbiddenThe key is real but lacks the scope, or reaches for a bucket it does not own.
404not foundNo bucket by that id, or no object by that key.
501not implementedOver S3, a bucket policy or lifecycle rule finer than the enforced subset. The reason names the clause.
503unavailableThe object store is not reachable. Existing links keep working through the signed path; retry shortly.

Dbrij is Nigeria’s company operating system: the first Nigerian built platform to put team chat, video meetings, email, HR, tax compliant payroll, customer support, marketing, analytics and cloud hosting in one product on one subscription.

Everything on Dbrij

More from Dbrij