HTTP API of the BI feed
The BI feed is not only for Tableau. It is an ordinary read-only HTTP endpoint — and the one supported way to fetch data out of the lakehouse programmatically without stepping around the governance.
On this page
The supported route
The BI feed carries a contract version of its own and stays stable. The other paths under /api/agent/ belong to the console — if you need one of them, let us know and we can talk about it.
Basics
| Item | Value |
|---|---|
| Base | https://<host>/api/agent/tableau/ |
| Contract version | 1 — reported by /info, raised only on an incompatible change. |
| Authentication | Bearer. A Keycloak access token of the realm with audience (aud) agent. Another audience: 401. |
| Methods | GET only on the data endpoints. The feed accepts no SQL. |
| Caching | Every response carries Cache-Control: no-store. |
| Auditing | One WORM entry per fetched page and per schema lookup — without row values, but with the target object and page parameters. |
The feed is off as shipped
Letting data out is a deliberate act: until an administrator flips the switch under Daten → BI-Anbindung, the feed answers 403.
The endpoints
| Endpoint | Purpose | Who |
|---|---|---|
| GET /tableau/info | Self-description: endpoints, limits, authentication, the JSONPath to the records. | Any signed-in user |
| GET /tableau/schema | An object's columns with Trino type, Tableau type and the projection used to convert them. | Anyone allowed to see the object |
| GET /tableau/rows | One page of data, as JSON or CSV. | Anyone allowed to see the object |
| GET /tableau/settings | State of the switch, the row cap and the catalog allowlist. | Platform administrators |
| PUT /tableau/settings | Change those settings. Audited. | Platform administrators |
Fetching an object's columns
The schema endpoint says what can be delivered from an object at all. Columns whose types the target tool does not know are omitted rather than guessed — they are listed in unsupportedColumns. The recommendedOrderBy field names a usable sort column for paging.
curl -sS \
-H "Authorization: Bearer $TOKEN" \
"https://lakehouse.example.invalid/api/agent/tableau/schema\
?catalog=iceberg&schema=produkte&table=produkte" | jq .Fetching data page by page
# Erste Seite. Ab der zweiten ist orderBy Pflicht – deshalb gleich setzen.
curl -sS \
-H "Authorization: Bearer $TOKEN" \
"https://lakehouse.example.invalid/api/agent/tableau/rows\
?catalog=iceberg&schema=produkte&table=produkte\
&limit=1000&offset=0&orderBy=artikelnummer" | jq '.meta, .data[0]'
# Als CSV, etwa zum Weiterreichen an ein Skript
curl -sS \
-H "Authorization: Bearer $TOKEN" \
"https://lakehouse.example.invalid/api/agent/tableau/rows\
?catalog=iceberg&schema=produkte&table=produkte\
&limit=1000&orderBy=artikelnummer&format=csv" > produkte.csvParameters of /tableau/rows
| Parameter | Required | Meaning |
|---|---|---|
| catalog, schema, table | yes | The object — table or view. |
| limit | no | Rows per page. Default 10,000, hard cap 50,000, lowerable by setting. |
| offset | no | First row of the page. |
| orderBy | when offset > 0 | column, column:desc, several comma-separated, or * for all columns. |
| format | no | json (default) or csv. |
Without orderBy, the second page does not come back unsorted — it does not come back at all: 400 order_required. OFFSET without ORDER BY is unstable in a parallel engine; a page could return rows twice and skip others without any error surfacing.
Response shape
The records sit under data — the same JSONPath Tableau reads. Alongside it, meta describes the page; if you only want the rows, ignore it.
{
"data": [
{ "artikelnummer": "A-1001", "bezeichnung": "Rohrschelle 20 mm", "lagerbestand": 412 }
],
"meta": {
"object": { "catalog": "iceberg", "schema": "produkte", "table": "produkte" },
"columns": [
{ "name": "artikelnummer", "tableauType": "string" },
{ "name": "lagerbestand", "tableauType": "int" }
],
"unsupportedColumns": [],
"limit": 1000,
"offset": 0,
"rowCount": 1000,
"hasMore": true,
"order": ["artikelnummer"],
"orderAll": false,
"deterministicPaging": true
}
}hasMore needs no counting query
It is derived from rowCount === limit. A loop that checks it is always right — the last page may simply come back empty once.
Error codes
| Response | Meaning | Remedy |
|---|---|---|
| 401 | Missing or expired token, or wrong audience. | Renew the token; aud must be agent. |
| 403 bridge_disabled | The feed is switched off. | Administrator: console → BI-Anbindung. |
| 403 catalog_not_allowed | The catalog is not on the allowlist. | Administrator: maintain the allowlist. |
| 404 not_found | The object does not exist — or is not visible to you. | Check the grants in Trino. The two look identical on purpose, so the answer reveals nothing about objects you may not see. |
| 400 order_required | Paging without a sort key. | Set orderBy. |
| 400 invalid_page | limit, offset or orderBy out of bounds. | Respect the limits — limit is not silently truncated. |
| 400 query_error | Trino could not run the query. | Read the message; usually an exotically typed field. Create a view with a converted column. |
| 422 no_deliverable_columns | No column of the object can be delivered. | Create a view with converted columns. |
| 502 upstream_error | Trino or the token exchange was unreachable. | Check operations. Details are in the service log, not in the response. |
Getting a token
The feed issues no tokens of its own — it verifies the realm's. For a one-off fetch, an access token from a signed-in session is enough. For scheduled fetches, an administrator creates a dedicated public client in the realm and lets the calling tool run the authorization code flow with PKCE; that client needs an audience mapper to agent. GET /tableau/info reports the authorization and token endpoint addresses.
A token carries an identity
There is no service account here either: a token carries one person's rights — and their name on every audit entry.
Applies to: This page describes lavalake 0.16.0. Product and documentation live in separate repositories — when in doubt, what the console shows is authoritative.
Something missing?
If these pages do not answer your question, we will walk through the platform against your own case in half an hour.
Book a demo