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.
| Method | Path | What | Scope |
|---|---|---|---|
| GET | /workspaces/{ws}/files?path=/Deliveries | List a folder. | read |
| POST | /workspaces/{ws}/files/folder | Create a folder ({ path }). | write |
| PATCH · DELETE | /workspaces/{ws}/files | Rename ({ path, newName }) or move to trash ({ paths }). /files/search?q= and /files/trash are read routes. | write |
| GET | /workspaces/{ws}/shares | List share links; /{id} for one, /{id}/receipt for the delivery receipt (JSON or .pdf). | read |
| POST | /workspaces/{ws}/shares | Create 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}/portals | List or create upload portals. | write |
| GET | /workspaces/{ws}/transfers | Transfer history with status, bytes, speed. | read |
| POST | /workspaces/{ws}/transfers | Mint a transfer for the Boita desktop app or transfer engine to run (returns a transfer specification). | write |
| GET | /workspaces/{ws}/usage | Storage 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
POSTwithContent-Type: application/json, a 10-second timeout, no redirects followed.- Body:
{ id, type, createdAt, workspaceId, data, delivery: { id, attempt } }. Treatidas 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.completed | An upload or download finished cleanly (files, bytes, rate, client, paths). |
| transfer.failed | A transfer ended with an error. |
| share.created | A share link was created (items, expiry, recipients). |
| share.downloaded | A recipient completed a download of a share link. |
| share.extended | A share link’s expiry was extended. |
| share.revoked | A share link was revoked. |
| share.expired | A share link reached its expiry. |
| portal.created | An upload portal was created. |
| portal.upload.completed | A client’s upload through a portal landed (folder, files, bytes, sender). |
| watch_folder.created | A watch folder was set up. |
| member.joined | Someone joined the workspace. |
| member.removed | A 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.