Skip to content

Developers

Your pipeline hears about every delivery.

A workspace API key gives scripts, render farms and integration platforms the same REST surface the Boita apps use. Webhooks post a signed event the moment a client downloads, a portal upload lands or a transfer completes. Included from the Pro plan.

Authentication

API keys

Create a key under Developers in your workspace (admin role). Send it as a bearer token.

  • Scope. A key acts as the member who created it, in that workspace only, on the resource endpoints below. It cannot sign in, change members or billing, or reach other workspaces. Read keys can only GET; read + write keys can create shares, portals, transfers and manage files.
  • Lifetime. Optional expiry; revoke any time. A key stops working the moment its creator leaves the workspace.
  • Limits. 600 requests per minute per key. Errors come back as { "error": { "code", "message", "details" } }.
  • Base URL. https://api.boita.io/v1. All timestamps are ISO 8601 UTC; sizes are bytes.
# List a folder
curl https://api.boita.io/v1/workspaces/$WS/files?path=/Deliveries \
  -H "Authorization: Bearer boita_sk_…"

# Create a share link for two files, valid 7 days, sent to a client
curl -X POST https://api.boita.io/v1/workspaces/$WS/shares \
  -H "Authorization: Bearer boita_sk_…" -H "Content-Type: application/json" \
  -d '{"paths":["Deliveries/EP03_v04.mov","Deliveries/EP03_mix.wav"],"title":"EP03 v04","expiresInDays":7,"recipients":["ravi@client.tv"]}'

# Poll the event stream from the last id you saw
curl "https://api.boita.io/v1/workspaces/$WS/events?after=$LAST_ID" -H "Authorization: Bearer boita_sk_…"

REST

Endpoints

The same API the web, desktop and mobile apps are built on. {ws} is your workspace id, shown on the Developers page.

MethodPathWhatScope
GET/workspaces/{ws}/files?path=/DeliveriesList a folder.read
POST/workspaces/{ws}/files/folderCreate a folder ({ path }).write
PATCH · DELETE/workspaces/{ws}/filesRename ({ path, newName }) or move to trash ({ paths }). /files/search?q= and /files/trash are read routes.write
GET/workspaces/{ws}/sharesList share links; /{id} for one, /{id}/receipt for the delivery receipt (JSON or .pdf).read
POST/workspaces/{ws}/sharesCreate a share link: paths, title, message, expiresInDays, maxDownloads, password, recipients.write
PATCH · DELETE/workspaces/{ws}/shares/{id}Extend or revoke.write
GET · POST/workspaces/{ws}/portalsList or create upload portals.write
GET/workspaces/{ws}/transfersTransfer history with status, bytes, speed.read
POST/workspaces/{ws}/transfersMint a transfer for the Boita desktop app or transfer engine to run (returns a transfer specification).write
GET/workspaces/{ws}/usageStorage used, data moved, plan limits.read
GET/workspaces/{ws}/events?after={id}The workspace event stream, for polling instead of webhooks.read

Transfers minted through the API are run by the Boita desktop app (including “Send from my computer” from the phone) or your own transfer client; the API returns the transfer specification and tracks progress and completion.

Webhooks

Signed events, retried until they land

Add an HTTPS endpoint under Developers, pick the events, and keep the signing secret shown once.

Delivery

  • POST with Content-Type: application/json, a 10-second timeout, no redirects followed.
  • Body: { id, type, createdAt, workspaceId, data, delivery: { id, attempt } }. Treat id as the idempotency key.
  • Headers: Boita-Signature, Boita-Event, Boita-Delivery.
  • Any 2xx counts as delivered. Otherwise we retry after 1 min, 5 min, 30 min, 2 h and 12 h, then mark the delivery failed. Twenty consecutive failures disable the endpoint; re-enable it from Developers, where every delivery can also be resent.

Signature

Boita-Signature: t=<unix seconds>,v1=<hex> where v1 is HMAC-SHA256 of `${t}.${rawBody}` with your endpoint secret. Verify on the raw bytes before parsing JSON, reject if t is more than 5 minutes off, and compare in constant time.

import { createHmac, timingSafeEqual } from 'node:crypto';

export function verifyBoitaSignature(secret, header, rawBody) {
  const { t, v1 } = Object.fromEntries(header.split(',').map((p) => p.trim().split('=')));
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // 5-minute tolerance
  const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
  return expected.length === v1.length && timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(v1, 'hex'));
}

// Express: app.post('/boita', express.raw({ type: 'application/json' }), (req, res) => {
//   if (!verifyBoitaSignature(process.env.BOITA_WEBHOOK_SECRET, req.get('Boita-Signature'), req.body.toString())) return res.sendStatus(401);
//   const event = JSON.parse(req.body); // { id, type, createdAt, workspaceId, data, delivery: { id, attempt } }
//   res.sendStatus(204);
// });
import hmac, hashlib, time

def verify_boita_signature(secret: str, header: str, raw_body: bytes) -> bool:
    parts = dict(p.strip().split("=", 1) for p in header.split(","))
    if abs(time.time() - int(parts["t"])) > 300:
        return False
    expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts["v1"])

Catalogue

Events

Subscribe to specific types or to everything (“*”), which includes types added later.

transfer.completedAn upload or download finished cleanly (files, bytes, rate, client, paths).
transfer.failedA transfer ended with an error.
share.createdA share link was created (items, expiry, recipients).
share.downloadedA recipient completed a download of a share link.
share.extendedA share link’s expiry was extended.
share.revokedA share link was revoked.
share.expiredA share link reached its expiry.
portal.createdAn upload portal was created.
portal.upload.completedA client’s upload through a portal landed (folder, files, bytes, sender).
watch_folder.createdA watch folder was set up.
member.joinedSomeone joined the workspace.
member.removedA member was removed.

The same events are readable at GET /workspaces/{ws}/events for integrations that prefer to poll.

Build on Boita.

API keys and webhooks are included from Pro. If you need something the API does not expose yet, tell us — the roadmap is short and public.

Chat on WhatsApp