TradieBridge docs
TradieBridge keeps a copy of your business's systems that you own. Read it from your own code with the data API, or from an AI assistant with the MCP server. Neither changes a source.
Sources
Data API
Authenticate
A company admin makes an API key in Settings → API keys and chooses the sources it reads.
curl -H "Authorization: Bearer tbk_…" https://app.tradiebridge.com/api/v1/connections
Endpoints
GET/connections
Your sources. A source that leaves this list was removed, with every record it held.
GET/changes
The IDs that changed after a cursor, across your sources. Keep the cursor it returns and send it next time. A webhook only says when to ask.
- cursor
- query · string. The cursor the last call answered. Leave it out to start from the oldest change held.
- resources
- query · string. Resource keys, comma-separated, to hear about those only.
- limit
- query · integer. How many changes a page: default 500, at most 1000.
GET/connections/{connection_id}/resources
What a source holds, with the columns a list filters and sorts by.
- connection_id*
- path · string. A source's id, from /connections.
GET/connections/{connection_id}/records/{resource}
A list of records by their stored columns: query, filters, sort, cursor, limit.
- connection_id*
- path · string. A source's id, from /connections.
- resource*
- path · string. A resource key, from that source's /resources.
- query
- query · string. Matches a source ID as a prefix, or a name holding every word.
- filters
- query · string. A JSON object keyed by stored column, e.g. {"stage": "Progress"}. A value, a list, or an object of operators: eq, ne, in, not_in, gte, lte, contains, null.
- modified_since
- query · string. An ISO 8601 time. Only records modified at or after it.
- sort
- query · string. A stored column, with - before it to sort descending, e.g. -modified_at.
- cursor
- query · string. The cursor the last page answered.
- limit
- query · integer. How many records a page: default 50, at most 200.
GET/connections/{connection_id}/documents/{resource}
Up to 100 whole documents by key, and the keys not held.
- connection_id*
- path · string. A source's id, from /connections.
- resource*
- path · string. A resource key, from that source's /resources.
- keys*
- query · string. Keys, comma-separated, at most 100.
GET/connections/{connection_id}/documents/{resource}/{key}
One whole document, exactly as the source sent it.
- connection_id*
- path · string. A source's id, from /connections.
- resource*
- path · string. A resource key, from that source's /resources.
- key*
- path · string. The record's key, as a list or the change feed answered it.
GET/connections/{connection_id}/answers/{question}
The common questions, answered from the backup. Each question takes its own arguments as query parameters.
- connection_id*
- path · string. A source's id, from /connections.
- question*
- path · string. A question the source answers, from that source's page in these docs.
GET/openapi.json
This reference as an OpenAPI 3.1 document. It needs no key.
Every path starts https://app.tradiebridge.com/api/v1.
Errors
An error answers JSON with one error string that says what to change.
- 401: no key, or a key that was revoked.
- 404: no such record, or a source this key does not read.
- 422: refused, such as an unknown resource or column, or too many keys.
- 429: more than 600 requests a minute or 20,000 requests an hour from one key. Wait the seconds in
Retry-After.
Webhooks
When a sync writes records a webhook listens for, we POST one event per source and resource to it. An event carries IDs, never documents.
{
"id": "evt_3kQ9xWm2PzR7vT4bN8cY1dLh",
"type": "records.changed",
"connection_id": 12,
"resource": "jobs",
"keys": [2111, 2746],
"removed_keys": [],
"created_at": "2026-10-03T04:12:55.120Z"
}
- Answer with any 2xx within 10 seconds. We do not follow a redirect.
- A failed delivery is sent again, less often each time, for three days. Then the webhook turns off and we email your admins.
- Events can arrive twice or out of order. Use the event's
idto drop a repeat, and read the current documents each time. - If your app was down, the change feed still holds every change since your cursor.
Check the signature
Every delivery carries a TradieBridge-Signature header:
TradieBridge-Signature: t=1790999575,v1=5f0c…
v1 is the hex HMAC-SHA256 of t.body, keyed with the signing secret shown once when the webhook was added.
Compare in constant time, and refuse a t more than 300 seconds old.
timestamp, signature = header.split(",").map { _1.split("=", 2).last }
expected = OpenSSL::HMAC.hexdigest("SHA256", secret, "#{timestamp}.#{raw_body}")
valid = ActiveSupport::SecurityUtils.secure_compare(expected, signature) &&
(Time.now.to_i - timestamp.to_i).abs < 300
Exports
Any member can export a source's whole copy from its page in the app, as a zip file in one of three formats:
- Documents
- Every record exactly as the source sent it, in .ndjson files.
- Spreadsheets
- The searchable columns of every record, in .csv files.
- Postgres
- One .sql file that psql loads into any Postgres database, Supabase included.
AI assistants
For Claude, ChatGPT or any MCP assistant.
Connect
https://app.tradiebridge.com/mcp
- In Claude, open Settings → Connectors → Add custom connector.
- Paste the server URL. Claude sends you to TradieBridge to sign in and approve the connection.
- Turn it on in a chat from the + menu.
Any MCP client that supports OAuth connects the same way: the server publishes its protected resource metadata and authorization server metadata, and registers clients dynamically. A client without OAuth sends a bearer token from Connect to AI in the app.
An assistant reads as the person who connected it. It never sees tax file numbers, bank details or birth dates.
More than 120 requests a minute or 3,000 requests an hour from one assistant answers 429. Wait the seconds in Retry-After.
Tools
whoami
Return the authenticated TradieBridge user and company. Use to confirm the connection works.
No arguments.
list_connections
List the company's builds, each a copy of one source: id (pass it as build_id to the other tools), name, source, web address, the company or organisation backed up, sync health, when it last synced and how many records the backup holds.
No arguments.
describe_resources
What a build's backup holds. Without resource: every resource key with what it means, how many records it holds and what it hangs off, and the keys that hold none. Name one resource or several to add when each last synced and the columns search_records filters and orders by and summarize_records sums and groups by.
- build_id
- integer. Omit when only one of the company's builds holds the resource; list_connections names them.
- resource
- any. A resource key, or several, e.g. ["invoices", "customer_payments"].
search_records
Find records of one resource in a build's backup, of any source, highest source ID first, or largest first by order_by (ascending: true for smallest or oldest; empty values last). query matches a source ID as a prefix or a name holding every word; filters and order_by take the columns describe_resources lists. Answers the total that match and, when more remain, next_before_id to pass back as before_id (with order_by, raise limit instead). Each result's id is what get_record takes. For totals and counts use summarize_records instead of paging.
- build_id
- integer. Omit when only one of the company's builds holds the resource; list_connections names them.
- resource*
- string. A resource key from describe_resources, e.g. invoices.
- query
- string.
- filters
- object. Column filters, from the columns describe_resources lists for the resource: {"<column>": "value"}, {"<column>": ["one", "another"]}, {"<column>": {"contains": "acme"}}, {"<date column>": {"gte": "2026-04-01", "lte": "2026-06-30"}}. Operators: eq, ne, in, not_in, gte, lte, contains, null.
- modified_since
- string. ISO 8601 time; only records the source changed since then.
- order_by
- string. A number or date column describe_resources lists, to rank by.
- ascending
- boolean.
- before_id
- string. The next_before_id a previous page answered.
- limit
- integer. Default 25, at most 200.
summarize_records
Count, sum, average, min or max over one resource's records in one call, of any source, optionally per group. Takes the same query and filters as search_records. column is a number column from describe_resources (min and max also take a date). measures asks several figures at once, e.g. ["count", "sum", "avg"] over column, or "sum:<column>" for another column; the answer is then values, keyed as asked. group_by is a column, week:/month:/quarter:/year:<date column>, or a list of two, e.g. ["<column>", "month:<date column>"]. A week is named by its Monday. Groups come largest first, or in date order when a date is bucketed, at most 100.
- build_id
- integer. Omit when only one of the company's builds holds the resource; list_connections names them.
- resource*
- string. A resource key from describe_resources, e.g. invoices.
- measure
- string. Default count.
- measures
- array. Several figures in one call, in place of measure.
- column
- string. What to sum, average, min or max: a column describe_resources lists.
- group_by
- any. e.g. <column>, month:<date column>, or ["<column>", "quarter:<date column>"].
- query
- string.
- filters
- object. Column filters, from the columns describe_resources lists for the resource: {"<column>": "value"}, {"<column>": ["one", "another"]}, {"<column>": {"contains": "acme"}}, {"<date column>": {"gte": "2026-04-01", "lte": "2026-06-30"}}. Operators: eq, ne, in, not_in, gte, lte, contains, null.
- modified_since
- string. ISO 8601 time; only records the source changed since then.
- limit
- integer. Groups to answer. Default and most 100.
get_record
Records from a build's backup, of any source, exactly as the source sent them, with the records each one names (links) and the records hanging off it (related, first 50 of each). id is the source's own ID, or the id search_records returned; ids reads up to 20 at once. fields keeps only those keys of each document: top-level keys or dotted paths such as Contact.Name.
- build_id
- integer. Omit when only one of the company's builds holds the resource; list_connections names them.
- resource*
- string. A resource key from describe_resources.
- id
- string.
- ids
- array. Several ids, instead of id.
- fields
- array. Keys or dotted paths to keep, e.g. ["Name", "Contact.Name"].
- related
- boolean. Default true. False leaves out links and related records.
discover_questions
The questions ask_question answers in one call, for the sources this company holds: each one's name, what it answers and the arguments it takes, as a JSON schema. A question two sources share is listed under each, answered from that source's own records. Filter by source, or by a word or topic (money, tax, jobs, customers, sales, schedule, staff).
- source
- string. Only this source's questions, as list_connections names it.
- topic
- string. Only questions whose name, topic or description holds this word.
ask_question
Answer one of the questions the instructions name (discover_questions describes them) in one call, reading the build's copy server-side. arguments are the question's own; a missing or wrong one answers with the arguments it takes. Without build_id every build that answers the question answers it, each under answers with its build_id, build, source and as_of: two sources measure different ledgers, so read them side by side and never add them. build_id narrows to one build.
- name*
- string. The question's name, e.g. receivables.
- arguments
- object. The question's arguments. Omit for none.
- build_id
- integer. Only this build's answer; list_connections names them.
discover_operations
Search everything else TradieBridge can do, beyond the tools listed here — every screen and action in the app, named as "controller#action", with the arguments each one takes and the tool that runs it: call_read_operation for a read, call_write_operation for a write. Each refuses the other kind. Use it when no dedicated tool fits. Search by word: "export", "sync", "member".
- query
- string. Filter by substring, e.g. "invoice". Omit for all.
call_read_operation
Run one of the read-only operations discover_operations lists, with the arguments it named. A path argument goes at the top level ({"id": 7}). It changes nothing. You never name a company: the tenant comes from your token.
- operation*
- string. As listed by discover_operations, e.g. "connections#show".
- params
- object. Arguments for the operation. Omit for none.
call_write_operation
Run one of the write or destructive operations discover_operations lists, with the arguments it named. It changes data in TradieBridge. A path argument goes at the top level ({"id": 7}); a write's fields go nested under the key discover_operations printed them against ({"connection": {"name": "Main"}}). You never name a company: the tenant comes from your token.
- operation*
- string. As listed by discover_operations, e.g. "connections/syncs#create".
- params
- object. Arguments for the operation. Omit for none.
A tool's build_id is the data API's connection_id. Each source's page lists the questions ask_question answers.