Calling the API

Addresses, request and response format, errors, and examples for calling Bramble from outside the platform.

Everything the Bramble apps do, they do through HTTP APIs, and you can call the same APIs from your own scripts, servers and products.

#Addresses

Use your organisation's address. Every API lives under it:

https://<your-org>.brambleit.cloud/api/v1/...      BRM-API (platform API)
https://<your-org>.brambleit.cloud/api/v2/...      BRM-API (newer RMM endpoints)
https://<your-org>.brambleit.cloud/<app>/api/...   an app's own API, e.g. /warden/api/overview

Each page in the API reference gives the full address of every route. Paths with :name in them take a value there, e.g. /api/v1/app/psa/tickets/:id → /api/v1/app/psa/tickets/1234.

#Which API to use from a script

You want to… Use Sign in with
Work with people, groups, licences, admin settings BRM-API /api/v1/... API key
RMM, PSA, Projects, WiKi, Forms, To Do BRM-API /api/v1/app/..., /api/v2/app/... API key
Files (Drive) or Sites /drive/api/v2/..., /sites/api/v2/... API key
Warden, Atlas, HR, Flows, Paper, Mail, SimpleBooks that app's /<app>/api/... browser session (see below)

The apps in the last row currently accept a signed-in browser session only. From outside the platform, the supported routes are:

  • Flows: build the automation in Flows itself and trigger it from outside with a webhook. Flows' Bramble steps can call those apps for you.
  • Calendar and contacts: CalDAV, CardDAV and .ics links (see Webhooks & integrations).
  • Events out of Bramble: Flows triggers on app events (new ticket, device enrolled, alert raised…) and can call your system.

#Requests

  • Send and receive JSON (Content-Type: application/json), unless the route says it takes a file upload (multipart/form-data) or returns a file.
  • Times are ISO 8601 (2026-11-12T09:30:00Z) unless the route says otherwise; dates are YYYY-MM-DD.
  • IDs are numbers for most records; devices in RMM use a 32-character device_id string.
  • Lists usually take limit and offset (or page) in the query; the reference lists the query parameters each route reads.

#Responses and errors

Successful calls return 200 (or 201 for some creates) with a JSON body. The reference shows the fields each route returns, e.g. 200 { ticket, messages, activity }.

Errors return a JSON body with a human-readable message:

JSON
{ "message": "Ticket not found" }
Status Meaning
400 The request is missing something or a value isn't valid. message says what.
401 Not signed in, or the session expired.
403 Signed in, but not allowed: no licence for that app, a missing role or permission, an expired or revoked API key, or a turned-off account.
404 Not found, or not in your organisation (Bramble never reveals other organisations' records).
409 Conflicts with the current state (e.g. someone else changed it first).
413 Upload too large.
429 Too many requests. Wait and try again; Retry-After says how long when sent.
5xx Something went wrong on Bramble's side. Safe to retry reads; check before retrying writes.

#Examples

#curl

Bash
export BRAMBLE=https://<your-org>.brambleit.cloud
export BRAMBLE_KEY=...   # Hub → Account → API keys

# Who am I, and which organisation?
curl -s -H "X-API-Key: $BRAMBLE_KEY" $BRAMBLE/api/v1/user
curl -s -H "X-API-Key: $BRAMBLE_KEY" $BRAMBLE/api/v1/tenant/info

# PSA: list tickets, then open one
curl -s -H "X-API-Key: $BRAMBLE_KEY" "$BRAMBLE/api/v1/app/psa/tickets"
curl -s -H "X-API-Key: $BRAMBLE_KEY" "$BRAMBLE/api/v1/app/psa/tickets/1234"

# PSA: raise a ticket
curl -s -X POST -H "X-API-Key: $BRAMBLE_KEY" -H "Content-Type: application/json" \
  -d '{"subject":"Printer offline","body":"The 2nd floor printer is offline.","priority":"high"}' \
  "$BRAMBLE/api/v1/app/psa/tickets"

# To Do: your lists
curl -s -H "X-API-Key: $BRAMBLE_KEY" "$BRAMBLE/api/v1/app/todo/lists"

#Node.js

JavaScript
const BASE = 'https://<your-org>.brambleit.cloud';
const KEY = process.env.BRAMBLE_KEY;

async function bramble(method, path, body) {
  const res = await fetch(BASE + path, {
    method,
    headers: { 'X-API-Key': KEY, ...(body ? { 'Content-Type': 'application/json' } : {}) },
    body: body ? JSON.stringify(body) : undefined,
  });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) throw new Error(`${res.status}: ${data.message || res.statusText}`);
  return data;
}

const { tickets } = await bramble('GET', '/api/v1/app/psa/tickets');
console.log(tickets.length, 'tickets');

#Python

Python
import os, requests

BASE = "https://<your-org>.brambleit.cloud"
s = requests.Session()
s.headers["X-API-Key"] = os.environ["BRAMBLE_KEY"]

r = s.get(f"{BASE}/api/v1/tenant/users")
r.raise_for_status()
for u in r.json().get("users", []):
    print(u["email"])

#Good practice

  • Keep keys out of source code: environment variables or a secret store.
  • Use a dedicated Bramble user for each integration, with only the licences and roles it needs, so you can see its changes in the audit log and turn it off on its own.
  • Every change made with your key is recorded in the organisation's audit log under your name.
  • Don't poll faster than you need. Use Flows triggers for "tell me when X happens" instead of polling.

#The full list of routes

The API reference is generated from the source code of every service, so it lists every route that exists, including the ones without hand-written descriptions. A machine-readable copy is at routes.json.