‹/› Developers · Public API

Build on the whole business — not just the books.

The BrioSync Public API is a tenant-scoped REST API across the ERP: tickets, projects, timesheets, people, quotes, orders, invoices, suppliers, purchase orders, bills, journals, deals and more. JSON and XML, Bearer API keys, signed webhooks, a live OpenAPI spec — and Ask Brio, the AI assistant that answers and writes code, right on this page.

REST · JSON + XML16 objects across the suitesSigned webhooksOpenAPI 3.0AI docs assistant

Quick start

Up and running in three steps:

  • Get your API key — a company admin generates keys in Settings → Integrations inside BrioSync. The key is shown once; store it in a secret manager.
  • Make your first request — send the key in the Authorization: Bearer header.
  • Start building — every object below works the same way.
# List your 50 most recent tickets
curl "https://us-central1-deliveryapp-a06ac.cloudfunctions.net/apiGateway/v1/tickets" \
  -H "Authorization: Bearer bsk_live_your_key_here" \
  -H "Content-Type: application/json"
import requests

BASE = "https://us-central1-deliveryapp-a06ac.cloudfunctions.net/apiGateway/v1"
HEADERS = {"Authorization": "Bearer bsk_live_your_key_here"}

r = requests.get(f"{BASE}/tickets", headers=HEADERS, params={"limit": 50})
r.raise_for_status()
for t in r.json()["data"]:
    print(t["id"], t.get("title"))
const BASE = "https://us-central1-deliveryapp-a06ac.cloudfunctions.net/apiGateway/v1";

const res = await fetch(`${BASE}/tickets?limit=50`, {
  headers: { Authorization: "Bearer bsk_live_your_key_here" }
});
const { data } = await res.json();
data.forEach(t => console.log(t.id, t.title));

🔐 Authentication

Bearer API keys, hashed at rest, shown once, revocable — with per-key object and read/write scoping.

Learn more →

📄 Pagination

Offset pagination with limit/offset, plus updatedSince and field-equality filters on any object.

Learn more →

🪝 Webhooks

HMAC-SHA256-signed deliveries on ticket, invoice and deal creation, with automatic retries.

Learn more →

✦ Ask Brio

Stuck? The AI docs assistant answers questions and writes snippets against this exact API — bottom-right of this page.

Ask a question →

Authentication

Every request is authenticated with an API key in the Authorization header:

Authorization: Bearer bsk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

How keys work:

  • Keys are generated by a company admin in Settings → Integrations and belong to your tenant — the API only ever returns data carrying your company's ID. Cross-tenant reads are impossible by construction.
  • The plaintext key is returned once at creation. BrioSync stores only a SHA-256 hash plus a display prefix — we cannot recover a lost key; revoke and re-issue instead.
  • Every key records lastUsedAt, and creation/revocation is written to your tenant's audit log.
Keep keys server-side. Never embed an API key in a browser, mobile app or public repo. If a key leaks, revoke it in Settings → Integrations — revocation is immediate.

Key scopes

Scoping happens at key level, twice over:

Scope typeOptionsBehaviour
Access scoperead or read + writeRead-only keys get 403 on any POST/PATCH. Grant write only to keys that need it.
Object scopeAll objects (*) or an explicit subsetA key scoped to tickets, invoices gets 403 when it touches anything else — least-privilege per integration.

Recommended pattern: one key per integration, named after it, scoped to exactly the objects it touches.

Requests & formats

The API is plain REST over HTTPS. Three verbs:

PatternMeaning
GET/v1/<object>List records (paginated, filterable)
GET/v1/<object>/<id>Fetch one record
POST/v1/<object>Create (writable objects, write-scoped key)
PATCH/v1/<object>/<id>Update allow-listed fields (writable objects)

JSON by default, XML on request

Responses are JSON unless you ask for XML — built for enterprise stacks that still speak XML (Oracle SOA/OIC, SAP PI/PO, BI Publisher, PL/SQL UTL_HTTP):

  • Send Accept: application/xml to receive XML responses.
  • Send Content-Type: application/xml to submit an XML request body on POST/PATCH.
# Same endpoint, XML in and out — no separate SOAP stack needed
curl "https://us-central1-deliveryapp-a06ac.cloudfunctions.net/apiGateway/v1/tickets" \
  -H "Authorization: Bearer bsk_live_your_key_here" \
  -H "Accept: application/xml"

Pagination & filtering

List endpoints use offset pagination and return a consistent envelope:

{
  "object": "tickets",
  "count": 50,        // records in this page
  "total": 1240,      // records matching the query
  "limit": 50,
  "offset": 0,
  "hasMore": true,
  "data": [ { "id": "…" } ]
}
ParameterTypeBehaviour
limitintegerPage size. Default 50, maximum 100.
offsetintegerRecords to skip. Walk pages until hasMore is false.
updatedSinceISO 8601 date-timeOnly records created/updated at or after this instant — the building block for incremental syncs.
any field namestringAny other query parameter becomes a case-insensitive equality filter on that field, e.g. ?status=Delayed or ?stage=Backlog&priority=high.
# Incremental sync: everything that changed since last night, high priority only
curl "https://…/apiGateway/v1/tickets?updatedSince=2026-07-01T00:00:00Z&priority=high&limit=100" \
  -H "Authorization: Bearer bsk_live_your_key_here"

Errors

Standard HTTP status codes with a JSON body: { "error": "human-readable message" }. Error messages tell you exactly what to fix — including which fields or objects are allowed.

StatusWhen
400Bad request — e.g. no valid fields in a create/update body, or PATCH without an id. The message lists the allowed fields.
401Missing, invalid or revoked API key.
403Key lacks write scope, or the object is outside the key's object scope.
404Unknown object, record not found, or record belongs to another tenant (indistinguishable by design).
405Verb other than GET / POST / PATCH.
500Something went wrong on our side — safe to retry with backoff.

Fair use & limits

List responses are capped at 100 records per page. Beyond that, the API runs under fair-use limits sized for typical sync and automation workloads; sustained high-volume patterns (and dedicated allowances) are scoped with your quote. Design integrations to be incremental — updatedSince beats re-pulling full datasets, for you and for us.

Objects

16 objects are readable today, spanning the suites — with create/update (WRITE) enabled on the intake objects integrations most commonly push into. The writable surface expands release by release; the live OpenAPI spec is always the source of truth.

ObjectSuiteEndpoints
ticketsWRITEITSM / Service deskList, get, create, update
leadsWRITECRM & CXCreate, update (intake object)
contactsWRITECRM & CXList, get, create, update
dealsWRITECRM & CXList, get, create, update
customersREADCRM & CXList, get
projectsREADPSA / DeliveryList, get
tasksREADPSA / DeliveryList, get
timesheetsREADPSA / DeliveryList, get
peopleREADHRList, get
quotesREADQuote-to-CashList, get
ordersREADQuote-to-CashList, get
productsREADQuote-to-CashList, get
invoicesREADFinance — ARList, get
billsREADFinance — APList, get
journalsREADFinance — GLList, get
suppliersREADProcurementList, get
purchaseordersREADProcurementList, get
Why aren't journals writable? Deliberate design: financial records must post through BrioSync's double-entry ledger engine — which enforces balanced debits/credits, period control and an append-only audit trail — never through raw API creates. Read the GL freely; post to it through the product (or talk to us about a ledger-safe posting endpoint for your use case).

Reading data

Single records return a data envelope:

# GET /v1/invoices/inv_8f2k…
{
  "data": {
    "id": "inv_8f2k…",
    "companyId": "…",   // always your tenant
    /* full record fields */
  }
}

A 404 means the record doesn't exist or isn't yours — the API never confirms the existence of another tenant's data.

Writing data

Writable objects accept POST (create) and PATCH (update) with an allow-listed field set — unknown fields are ignored, so a misconfigured client can't corrupt records. Requires a write-scoped key.

ObjectAccepted fieldsDefaults applied
ticketstitle, description, type, priority, client, externalTicketIdstatus: On-track, stage: Backlog, type: Incident, priority: normal
leadsname, email, phone, company, source, notes, valuestatus: new
contactsname, email, phone, title, customerId
dealstitle, value, stage, accountId, sourcestage: new
# Create a ticket from your monitoring tool
curl -X POST "https://…/apiGateway/v1/tickets" \
  -H "Authorization: Bearer bsk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Checkout latency above SLO",
    "description": "p95 > 1200ms for 15 min (alert #4812)",
    "type": "Incident",
    "priority": "high",
    "externalTicketId": "PD-4812"
  }'

# → 201 { "id": "…", "object": "tickets", "data": { … } }
# Push website leads into the CRM
requests.post(f"{BASE}/leads", headers=HEADERS, json={
    "name": "Fatima Al Mansouri",
    "email": "fatima@example.ae",
    "company": "Example Contracting LLC",
    "source": "website-form",
})

# Move a deal stage
requests.patch(f"{BASE}/deals/deal_123", headers=HEADERS,
               json={"stage": "negotiation"})
# Same create, from an XML-speaking stack (Oracle OIC, SAP PI/PO…)
curl -X POST "https://…/apiGateway/v1/tickets" \
  -H "Authorization: Bearer bsk_live_your_key_here" \
  -H "Content-Type: application/xml" \
  -H "Accept: application/xml" \
  -d '<ticket>
        <title>Checkout latency above SLO</title>
        <priority>high</priority>
      </ticket>'

Every API-created record is stamped source: "api", so you can always tell integration-created data apart inside BrioSync.

Webhooks

Push, not poll: register HTTPS endpoints in Settings → Integrations and BrioSync delivers events as they happen.

EventFires when
ticket.createdA ticket is created — by a user, the customer portal, or the API
invoice.createdAn invoice is raised
deal.createdA deal enters the pipeline

Verify every delivery

Each delivery is signed with HMAC-SHA256 over the raw body, using your webhook's secret, in the X-BrioSync-Signature header. Reject anything that doesn't verify:

// Node.js — verify a BrioSync webhook
const crypto = require("crypto");

function verify(rawBody, signatureHeader, secret) {
  const expected = crypto.createHmac("sha256", secret)
                         .update(rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected),
                                Buffer.from(signatureHeader || ""));
}

Failed deliveries are retried automatically (a scheduled retry sweep runs every few minutes), and delivery health is monitored — inside BrioSync, the AI can diagnose a failing endpoint and tell you what's wrong in plain language.

Respond fast. Return 2xx quickly and process asynchronously — slow endpoints are what retries are for, but you'll get cleaner ordering by acknowledging immediately.

OpenAPI spec

The gateway publishes a live OpenAPI 3.0 document generated from the actual resource map — it can't drift from reality. No auth required:

GET https://us-central1-deliveryapp-a06ac.cloudfunctions.net/apiGateway/openapi.json

Import it into Postman, Insomnia, Oracle OIC, or any client generator to get typed clients and a ready-made collection for every object and verb above.

AI-built integrations

✦ The BrioSync difference

Don't write the integration. Describe it.

Inside BrioSync, tell the AI integration assistant what you want in plain language — "push our website leads into BrioSync", "create a ticket when our monitoring fires", "sync new invoices to our warehouse nightly" — and it produces a concrete plan plus ready-to-run code, grounded in this exact API surface so it never invents an endpoint.

The same AI watches your live integrations: it monitors webhook delivery health on a schedule, diagnoses failures, and explains the fix. And right here on this page, Ask Brio answers your API questions and writes snippets — try it from the button below.

Static connector marketplaces list what someone else built. BrioSync's approach: if it has an API, Brio can wire it — and the integration request form puts anything bespoke on our radar.

Base URL

EnvironmentURL
Productionhttps://us-central1-deliveryapp-a06ac.cloudfunctions.net/apiGateway/v1

All requests use HTTPS. The API accepts and returns JSON by default, XML by content negotiation. Sandbox tenants (via the guided sandbox) can use the API with their own keys — same surface, isolated data.

Need help?

  • Ask Brio — the AI docs assistant on this page answers API questions instantly (bottom-right).
  • Docs & product helpdocumentation and help & support.
  • Integration requests — need a connector we haven't wired yet? Tell us here.
  • Everything elsehello@briosync.com with subject "API"; an engineer (usually the founder) answers.

Get a sandbox & API key →