API and webhooks (Beta)
Connect BravaSpace to your own tools.
Use the API and webhooks to link BravaSpace with the way your team works. Read and change your account with an API key. Get a signed request the moment something happens.
Free for 14 days. No credit card needed.
One event, start to finish
Watch a webhook get delivered, and retried.
Click a step, or let it play.
It also goes out as task.status_changed, to endpoints that picked that event.
API keys
One key per place that uses it.
Make a key under Apps, then API & webhooks. Name it, tick only the permissions it needs, and add an expiry if you want one. Revoke one and the others keep working.
- Keys start with
bsk_live_and are shown once. BravaSpace stores a hash, never the key. - Only the owner and admins can make or revoke keys. Up to 25 active keys per workspace.
- A key reaches its own workspace only, and only what its permissions allow.
List clients and read one client’s details, without internal notes.
List and read client tasks. The team’s own to-dos are not shared.
Create tasks for a client, and change a status, title, description or due date.
List and read invoices, drafts included and marked draft.
Read a client’s message thread.
Post a message to a client as the agency.
List file details: name, size, type and who uploaded it. Never the file or a download link.
The REST API
Thirteen endpoints, one shape.
JSON in and out. Dates are YYYY-MM-DD, times are ISO 8601 in UTC and money is in cents. Every error looks the same, with a code and a request id.
/v1/meThe key, its workspace and what is left of the rate limitno scope/v1/clientsList clients, filter by statusread:clients/v1/clients/{id}Get a clientread:clients/v1/tasksList tasks, by client or statusread:tasks/v1/tasks/{id}Get a taskread:tasks/v1/tasksCreate a task on a client’s planwrite:tasks/v1/tasks/{id}Change a task’s status, title, description or due datewrite:tasks/v1/invoicesList invoices, by client or statusread:invoices/v1/invoices/{id}Get an invoiceread:invoices/v1/clients/{id}/messagesList a client’s messagesread:messages/v1/clients/{id}/messagesPost a message as the agencywrite:messages/v1/filesList file detailsread:files/v1/openapi.jsonThe whole API as OpenAPI 3, no key neededno scope120 requests a minute
Per key. Each reply says how many are left; above it you get a 429 with Retry-After.
Cursor paging
25 per page by default, up to 100. Follow next_cursor while has_more is true.
OpenAPI 3
The whole API at /v1/openapi.json, for Postman, Insomnia or a code generator. It needs no key.
Try it
A request, and a signature check.
Your API address is on the Docs and guides tab in the app, with a curl example for every endpoint.
curl "$BRAVASPACE_API/v1/tasks?status=Client%20Review&limit=10" \
-H "Authorization: Bearer $BRAVASPACE_API_KEY"
# 200 OK
{
"object": "list",
"data": [
{
"object": "task",
"id": "9f2c41d7a0b3e6c1",
"client_id": "acme-k3f9x2",
"title": "Approve the October social calendar",
"status": "Client Review",
"due": "2026-10-20"
}
],
"has_more": true,
"next_cursor": "WyIyMDI2LTEwLTAx..."
}import crypto from 'node:crypto'
// rawBody: the request body exactly as received, before JSON.parse.
export function verifyBravaSignature(secret, header, rawBody) {
const parts = Object.fromEntries(header.split(',').map(p => p.trim().split('=')))
const t = Number(parts.t)
if (!t || !parts.v1) return false
if (Math.abs(Date.now() / 1000 - t) > 300) return false // older than 5 minutes
const expected = crypto.createHmac('sha256', secret)
.update(`${t}.${rawBody}`).digest('hex')
return expected.length === parts.v1.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))
}Webhooks
Told the moment it happens.
Add an https address and pick its events. BravaSpace sends a signed JSON request within about a minute. Answer with any 2xx within 10 seconds; anything else, a redirect included, counts as a failure.
- Signed:
X-Brava-Signature: t=…,v1=…, an HMAC-SHA256 oft.bodywith the endpoint’s signing secret. - Retried after 1m, 5m, 30m, 2h, 6h, 12h and 24h, then marked failed.
- A delivery log per endpoint, kept 30 days: the result, tries and time of each one, and the payload.
- Switched off after 15 failures in a row over more than a day, with the reason shown.
- Up to 10 endpoints. Public https addresses only, checked when saved and on every send.
A client was added.
A task was added for a client.
A task moved to another status.
A task moved to Completed.
An invoice left draft and is due.
An invoice was marked paid, by hand or by a card payment.
A client wrote to the agency.
A file was added to a client’s files.
A client sent a request from their Requests tab.
A prospect or client signed and accepted a proposal.
Send test event
Pick an event type and send an example now. Test events carry "test": true and example data, never a real client.
Resend
Send a failed delivery again from the log. If it fails, it carries on the retry schedule from where it was.
Roll secret
Make a new signing secret, shown once. The old one stops working at once, so update your server first.
Zapier and Make
No code? Follow the guides.
The Docs and guides tab walks through both, step by step, on each side: start a Zap or a scenario when something happens in BravaSpace, and create a task or post a message from one.
Both guides add a filter on test, so test events never run your actions.
Questions
API and webhooks, answered.
The workspace owner and admins. They do it in the app under Apps, then API & webhooks. Each key has a name, the permissions you tick and, if you want, an expiry date up to three years ahead.
Make a new one and revoke the old one. A key is shown once, when it is made. BravaSpace keeps only a hash of it and its last four characters, so nobody can show it to you again.
Only its own. The workspace always comes from the key, never from a parameter, so an id from another workspace is simply not found.
120 requests a minute per key. Every reply carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Above the limit you get a 429 with Retry-After in seconds.
Newest first, 25 at a time by default and up to 100 with limit. When has_more is true, ask again with cursor set to the next_cursor you got.
Each failed delivery is tried again after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, 12 hours and 24 hours, eight tries in all. After that it is marked failed and you can still resend it. An endpoint that fails 15 times in a row for more than 24 hours is switched off, and the Webhooks tab says why.
Yes, after a retry. X-Brava-Delivery carries the event id and stays the same on every try, so skip one you have already handled. Events are not promised in order: use created_at.
No. The app has step-by-step guides for both: Webhooks by Zapier (Catch Hook and Custom Request) and Make’s Custom webhook and HTTP modules. Zapier’s webhooks need a paid Zapier plan; Make’s are on every Make plan.
What it does not do
- The API never returns key hashes, signing secrets, internal client notes, file contents or download links.
- It cannot delete anything. Writes are limited to tasks and posting a message to a client.
- A read-only workspace (a trial that ended, a canceled plan) can still read, not write.
- It is not for web pages: a key belongs on a server or in Zapier or Make.
Try it with one client.
Add some work. Share a file. Ask for feedback. See what your client sees, with your name on it. Free for 14 days. No credit card needed.