Tangible · User guidesOpen Tangible ↗

Drive: documents and live data integrations

What this page is for

Drive is your organisation's home for documents and live data. Upload files for processing, or connect a live data source so tables flow into Drive automatically — via a daily sync (Xero, Supabase) or pushed from your own systems (Push API).

Uploading documents

  1. Drag files onto the drop zone, or click Choose manually to browse.
  2. Each document shows its processing status; tag documents with a type so they are easy to find and filter.
  3. Use the search box and Filters to narrow the list.

Organising documents into folders

Folders let you arrange Drive the way your team thinks about its documents. They are shared by everyone in your organisation, and they are purely for organisation: filing a document never changes how it is processed, what the assistant and analysis can see, or what is shared with lenders. Lenders see the documents you share with them as a plain list, never your folders.

  • Create a folder with New folder next to the search box. It is created inside the folder you are viewing.
  • Open a folder by clicking it in the table; the breadcrumb above the table takes you back up. The tree-icon button to the left of the search box shows or hides a folder tree beside the table, for jumping straight to any folder.
  • Move documents by dragging rows onto a folder (in the table, the breadcrumb or the tree, when shown), or select them and click Move to…. Drag a selected row to move the whole selection.
  • Upload into a folder by opening it first — new uploads land in the folder you are viewing.
  • Rename, move or delete a folder from its actions menu. Deleting a folder never deletes documents: its documents and sub-folders move up into the folder that contained it.

Searching or filtering looks across every folder, and shows which folder each match is in.

Elsewhere in Tangible, document pickers (for example when adding a document to a credit memo) group documents under their folders, and linked documents show their folder path.

Connecting a live data source

Click Add integration on the Connect a live data source card and pick a provider:

The provider list: Xero, Supabase and Push API

  • Xero — OAuth consent; invoices, contacts and bank transactions sync daily.
  • Supabase — paste your project URL and secret API key; chosen tables sync daily.
  • Push API — your systems push rows to Tangible over HTTPS with a token you manage here. No outbound credentials, no schedule — data lands the moment you send it.

Connected integrations appear as rows at the top of the Drive table, each showing how many tables are receiving data. Open Manage connection from a row's actions menu to configure it, see its sync or POST history, and preview the stored data.

A connected Push API integration listed on Drive with its table count

The Push API

The Push API turns Drive into a destination your own systems write to. Instead of Tangible pulling from a provider on a schedule, you POST rows whenever you have them — from a nightly job, a data warehouse export, or an event in your product — and each named schema becomes a live table in Drive that the rest of Tangible (analysis, asset tapes, the assistant) can use like any other connected data.

Enabling it and getting your token

  1. Click Add integration and choose Push API → Connect. Before anything is created, the dialog shows the endpoint URL and ready-to-run examples in cURL, JavaScript and Python, so you can see exactly what an integration involves.

    The Push API setup step with endpoint and code examples

  2. Click Enable. This mints your organisation's token and shows it once — copy it now and store it like a password. Only a hash is kept on our side, so it can never be shown again. The cURL example below it already includes the token, so your first push is one paste away, and the dialog listens live: a push made from your terminal appears in it while you watch.

    The token shown once, with the dialog listening for the first push

One token exists per organisation. If you lose it, or want to replace it, open Manage connection → Rotate token: a new token is minted and the old one stops working immediately. Rotating is the only way to get a new token — re-running Connect never replaces a token that is already in use, so it is safe to click. The manage view shows the token's prefix, when it was created and when it was last used.

The integration is listed on Drive from the moment you enable it, before any data arrives. Until your first push lands, the manage view keeps the endpoint and code examples on screen — on both the Overview and Data Preview tabs — so whoever picks up the integration later has everything they need without hunting for this guide.

The manage view before any data: token status and the how-to stay on screen

Pushing data

Send an HTTPS POST to /api/external/push/ingest with your token as a bearer header:

curl -X POST https://<your-tangible-host>/api/external/push/ingest \
  -H "Authorization: Bearer tngbl_..." \
  -H "Content-Type: application/json" \
  -d '{
    "schema": "loan_tape",
    "uniqueIdField": "loan_id",
    "rows": [
      { "loan_id": "L-1", "balance": 1000.50, "active": true },
      { "loan_id": "L-2", "balance": 250.00, "active": false }
    ]
  }'
  • schema names the table the rows belong to (letters, digits and underscores only). The first POST for a schema creates a new table in Drive; every later POST with the same schema name goes into that same table.
  • uniqueIdField names the column that uniquely identifies a row. It is required on the first POST for a schema and pinned from then on — later POSTs may omit it but cannot change it. Every row in every POST must carry a non-null value for it, and values must be unique within one request.
  • rows is an array of flat JSON objects. Values may be strings, numbers, booleans or null.

Rows are upserted on the unique identifier: a row whose identifier already exists in the table is updated in place; new identifiers are appended. The response reports rowsInserted and rowsUpdated per request.

Columns may evolve additively: a POST containing a new column adds it to the table (existing rows show null for it), and a POST omitting a known column leaves existing values untouched — new rows get null. Columns are never dropped or renamed by a push.

Limits

Limit Value
Rows per request 5,000
Request body size 10 MB
Requests per minute per organisation 60

Responses and errors

A successful POST returns 200 with the schema name, the number of rows received, inserted and updated, and any columns that were newly added (newColumns). If some values could not be converted to a column's existing type they are stored as null and reported in castingIssues.

Status Meaning
400 Invalid body — e.g. a bad schema name, a missing/changed uniqueIdField, rows with missing, empty, null or duplicate identifiers, or a reserved column name (ingestId).
401 Missing, invalid or rotated token.
404 The Push API integration is not enabled for your organisation.
413 Too many rows or a body over 10 MB — split the payload into batches.
422 Your data reached storage but was rejected — e.g. a number too large for a whole-number column. The message explains which column and value; detail carries the storage engine's own wording.
429 Rate limit hit — retry after the Retry-After interval.

A push is all-or-nothing: if any row is rejected, none of that push's rows are stored and the table keeps the data from your previous successful pushes.

When a push fails

Pushes that fail validation (the 400s above) are refused outright and leave no trace. A push that is accepted but then rejected by storage (422) is recorded so you can investigate: it appears in the POST history as a red Rejected entry, with a plain-English explanation of what went wrong — which column, which value, and which row, identified by its unique id. View error opens the full explanation, with the storage engine's original message available underneath as technical detail. Fix the values and push again.

A rejected push explained: the offending column, value and row

A rejection never corrupts the table: the push is all-or-nothing, so the table keeps exactly the data from your previous successful pushes until a corrected push lands.

Seeing what was pushed

Manage connection on the Push API row shows everything the integration has received:

  • Overview — the token's status, the Tables receiving data with their row counts, and a POST history listing every request: its schema, when it arrived, and how many rows were updated or added. Successes and rejections are listed alike, so the history is a complete audit of what your systems sent.

    The manage view's overview: token, tables and POST history

  • Data Preview — browse the stored rows of any table without leaving Tangible, with the row total and the schema's unique identifier shown alongside. View data on a history entry narrows the preview to exactly the rows that one POST touched; Show all rows widens it back out.

    Previewing a pushed table's rows in the manage view

The preview and the history update live while the dialog is open, so a push made from a terminal shows up within seconds — no refresh needed.