> For the complete documentation index, see [llms.txt](https://developer.abacum.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.abacum.ai/guides/public-api-guides/read-a-space-table.md).

# Read a Space table

Find a table in a Space and pull the numbers behind it.

Spaces are the reporting layer in Abacum. They hold Tables, Charts and KPI cards. Any user with a valid token can call these endpoints. Each call returns only what that user can view.

| Endpoint                                                   | Returns                                                     | Use it to                                    |
| ---------------------------------------------------------- | ----------------------------------------------------------- | -------------------------------------------- |
| `GET /public-api/spaces`                                   | The spaces you can view: `id`, `title`, `emoji`, `parent`   | Find the space IDs.                          |
| `GET /public-api/spaces/{space_id}`                        | The details of one space                                    | Read the metadata of one space.              |
| `GET /public-api/spaces/{space_id}/tables`                 | The tables and charts in a space: `id`, `name`, `view_mode` | Find the table IDs in a space.               |
| `GET /public-api/spaces/{space_id}/tables/{table_id}`      | The variables, versions and time periods of one table       | See what a table holds before you pull data. |
| `GET /public-api/spaces/{space_id}/tables/{table_id}/data` | A download link, CSV or Parquet                             | Pull the numbers behind a table.             |

## Step 1: List the spaces

Call `GET /public-api/spaces`. The list is paginated. Use `page` (starts at 1) and `page_size` (default 25, maximum 100). The `metadata.pagination` object holds `count`, `next` and `previous`. A `page` beyond the last page returns `404`.

## List Spaces

> Retrieve a paginated list of spaces the authenticated user has view access to.

```json
{"openapi":"3.0.0","info":{"title":"Abacum public API","version":"1.0.0"},"tags":[{"name":"Spaces","description":"List the Spaces a user can view, find their tables, and read table data."}],"servers":[{"url":"https://api.abacum.io","description":"Prod environment"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An access token from the token endpoint, sent as `Authorization: Bearer <access_token>`. Use it to try an endpoint from this page. The token carries the permissions of its user, so use a user with the lowest role that fits the call."}},"schemas":{"Space":{"type":"object","required":["id","parent","title","emoji","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","description":"Unique identifier of the Space."},"parent":{"type":"string","format":"uuid","nullable":true,"description":"ID of the parent Space. `null` for a top-level Space, or when you cannot view the parent."},"title":{"type":"string","description":"Title of the Space."},"emoji":{"type":"string","description":"Emoji shown next to the title of the Space."},"created_at":{"type":"string","format":"date-time","description":"When the Space was created."},"updated_at":{"type":"string","format":"date-time","description":"When the Space was last updated."}}},"DetailMessage":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}},"responses":{"Forbidden":{"description":"The bearer token is missing, invalid or expired. The response has an empty body. The API answers `403` for these cases, not `401`.","headers":{"X-Request-ID":{"$ref":"#/components/headers/XRequestID"}}},"TooManyRequests20PerMinute":{"description":"Rate limit exceeded: 20 requests per minute for the same user and URL. Wait the number of seconds in the `Retry-After` header, then retry.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","schema":{"type":"integer"}},"X-Request-ID":{"$ref":"#/components/headers/XRequestID"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailMessage"}}}},"InternalServerError":{"description":"An unexpected error on our side. The response has an empty body. Repeat the request, and contact support if it keeps failing.","headers":{"X-Request-ID":{"$ref":"#/components/headers/XRequestID"}}}},"headers":{"XRequestID":{"description":"Identifier of this request. Quote it when you contact support so they can find the exact request. A server-side client can set it by sending an `X-Request-ID` request header of 1 to 64 characters from `A-Za-z0-9_-`; any other value is replaced by a generated one. Browsers can read this header but cannot send their own. The value identifies a request for support, but it is not proof that only one request used it.","schema":{"type":"string"}}}},"paths":{"/public-api/spaces":{"get":{"summary":"List Spaces","description":"Retrieve a paginated list of spaces the authenticated user has view access to.","operationId":"listSpaces","tags":["Spaces"],"parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1},"description":"Page number (1-indexed). A value that is not a positive integer, or that is beyond the last page, returns `404`."},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Items per page. A value above 100 is capped at 100, and a value that is not a positive integer is ignored, so the default applies."}],"responses":{"200":{"description":"A paginated list of spaces.","content":{"application/json":{"schema":{"type":"object","required":["data","metadata"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Space"}},"metadata":{"type":"object","required":["pagination"],"properties":{"pagination":{"type":"object","required":["count","next","previous"],"properties":{"count":{"type":"integer"},"next":{"type":"string","format":"uri","nullable":true},"previous":{"type":"string","format":"uri","nullable":true}}}}}}}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Not found - `page` is not a valid page number or is beyond the last page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailMessage"}}}},"429":{"$ref":"#/components/responses/TooManyRequests20PerMinute"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```

## Step 2: List the tables in a space

Call `GET /public-api/spaces/{space_id}/tables`. The list holds every table and chart in the space. The `view_mode` field tells them apart. Access to the space gives access to all of its items. A space that the user cannot view returns `404`.

## List Space tables

> List every table and chart placed in the given space. Access to the space grants access to all of its items, whatever model restrictions apply. The \`view\_mode\` field tells tables and charts apart.

```json
{"openapi":"3.0.0","info":{"title":"Abacum public API","version":"1.0.0"},"tags":[{"name":"Spaces","description":"List the Spaces a user can view, find their tables, and read table data."}],"servers":[{"url":"https://api.abacum.io","description":"Prod environment"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An access token from the token endpoint, sent as `Authorization: Bearer <access_token>`. Use it to try an endpoint from this page. The token carries the permissions of its user, so use a user with the lowest role that fits the call."}},"parameters":{"SpaceId":{"name":"space_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The ID of the Space. It must be a UUID. Any other value returns a `404` with an HTML page."}},"schemas":{"SpaceTableSummary":{"type":"object","required":["id","name","view_mode","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","description":"Unique identifier of the table or chart."},"name":{"type":"string","description":"Name of the table or chart."},"view_mode":{"type":"string","enum":["table","barChart","lineChart","mixedChart","waterfallChart","pieChart","chart"],"description":"How the item is displayed. `table` is a table; every other value is a chart."},"created_at":{"type":"string","format":"date-time","description":"When the item was created."},"updated_at":{"type":"string","format":"date-time","description":"When the item was last updated."}}},"DetailMessage":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}},"responses":{"Forbidden":{"description":"The bearer token is missing, invalid or expired. The response has an empty body. The API answers `403` for these cases, not `401`.","headers":{"X-Request-ID":{"$ref":"#/components/headers/XRequestID"}}},"TooManyRequests20PerMinute":{"description":"Rate limit exceeded: 20 requests per minute for the same user and URL. Wait the number of seconds in the `Retry-After` header, then retry.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","schema":{"type":"integer"}},"X-Request-ID":{"$ref":"#/components/headers/XRequestID"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailMessage"}}}},"InternalServerError":{"description":"An unexpected error on our side. The response has an empty body. Repeat the request, and contact support if it keeps failing.","headers":{"X-Request-ID":{"$ref":"#/components/headers/XRequestID"}}}},"headers":{"XRequestID":{"description":"Identifier of this request. Quote it when you contact support so they can find the exact request. A server-side client can set it by sending an `X-Request-ID` request header of 1 to 64 characters from `A-Za-z0-9_-`; any other value is replaced by a generated one. Browsers can read this header but cannot send their own. The value identifies a request for support, but it is not proof that only one request used it.","schema":{"type":"string"}}}},"paths":{"/public-api/spaces/{space_id}/tables":{"get":{"summary":"List Space tables","description":"List every table and chart placed in the given space. Access to the space grants access to all of its items, whatever model restrictions apply. The `view_mode` field tells tables and charts apart.","operationId":"listSpaceTables","tags":["Spaces"],"parameters":[{"$ref":"#/components/parameters/SpaceId"}],"responses":{"200":{"description":"List of tables in the space.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SpaceTableSummary"}}}}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Not found - space does not exist or is not viewable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailMessage"}}}},"429":{"$ref":"#/components/responses/TooManyRequests20PerMinute"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```

## Step 3: Read the table

Call `GET /public-api/spaces/{space_id}/tables/{table_id}`. The response adds:

* `variables`: each with `id`, `name` and `description`.
* `versions`: each with `id`, `name` and `category`.
* `time_periods`: the periods that the table shows. The shape depends on `preset_type`, for example `BETWEEN`, `RELATIVE`, `MTD`, `QTD`, `YTD` or `FYE`.

## Get Space table

> Retrieve a single table inside a space, including its variables, versions and time periods.

```json
{"openapi":"3.0.0","info":{"title":"Abacum public API","version":"1.0.0"},"tags":[{"name":"Spaces","description":"List the Spaces a user can view, find their tables, and read table data."}],"servers":[{"url":"https://api.abacum.io","description":"Prod environment"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An access token from the token endpoint, sent as `Authorization: Bearer <access_token>`. Use it to try an endpoint from this page. The token carries the permissions of its user, so use a user with the lowest role that fits the call."}},"parameters":{"SpaceId":{"name":"space_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The ID of the Space. It must be a UUID. Any other value returns a `404` with an HTML page."},"TableId":{"name":"table_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The ID of the table. It must be a UUID. Any other value returns a `404` with an HTML page."}},"schemas":{"SpaceTableDetail":{"allOf":[{"$ref":"#/components/schemas/SpaceTableSummary"},{"type":"object","required":["variables","versions","time_periods"],"properties":{"variables":{"type":"array","description":"Variables the table shows.","items":{"type":"object","required":["id","name","description"],"properties":{"id":{"type":"string","format":"uuid","description":"Unique identifier of the variable."},"name":{"type":"string","description":"Name of the variable."},"description":{"type":"string","description":"Free-text description of the variable."}}}},"versions":{"type":"array","description":"Versions the table shows.","items":{"type":"object","required":["id","name","category"],"properties":{"id":{"type":"string","format":"uuid","description":"Unique identifier of the version."},"name":{"type":"string","description":"Name of the version."},"category":{"type":"string","enum":["Budget","Forecast","Scenario"],"description":"Category of the version."}}}},"time_periods":{"description":"Configured time periods that drive the table's column layout. Shape varies by `preset_type` (e.g. BETWEEN, RELATIVE, MTD, QTD, YTD, FYE).","type":"array","items":{"type":"object","additionalProperties":true,"required":["preset_type"],"properties":{"preset_type":{"type":"string","enum":["MTD","YTD","QTD","FYE","WFC","CTF","LAST_N_MONTHS","BETWEEN","RELATIVE"],"description":"Kind of time period."},"start_date":{"type":"string","description":"Inclusive period start (BETWEEN only)."},"end_date":{"type":"string","description":"Inclusive period end (BETWEEN only)."},"timescale":{"type":"string","enum":["weekly","monthly","quarterly","yearly","full"],"description":"Time grain of the period (BETWEEN only)."},"start_of":{"type":"string","description":"Time placeholder for RELATIVE start anchor."},"start_of_offset":{"type":"number"},"end_of":{"type":"string"},"end_of_offset":{"type":"number"},"timescales":{"type":"array","items":{"type":"string","enum":["weekly","monthly","quarterly","yearly","full"]}},"date":{"type":"string","description":"Reference date for MTD/QTD/YTD/FYE presets."},"version":{"type":"string","description":"Version id or placeholder (e.g. $actuals)."},"version_to_compare":{"type":"string","description":"Comparison version (for variance presets)."},"base_date":{"type":"string","description":"Reference base date for some presets."},"name":{"type":"string"},"scenario":{"type":"string"},"versions_to_include":{"type":"array","items":{"type":"string"}},"scenarios_to_include":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"version_id":{"type":"string"},"scenario_id":{"type":"string"}}}}}}}}}]},"SpaceTableSummary":{"type":"object","required":["id","name","view_mode","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","description":"Unique identifier of the table or chart."},"name":{"type":"string","description":"Name of the table or chart."},"view_mode":{"type":"string","enum":["table","barChart","lineChart","mixedChart","waterfallChart","pieChart","chart"],"description":"How the item is displayed. `table` is a table; every other value is a chart."},"created_at":{"type":"string","format":"date-time","description":"When the item was created."},"updated_at":{"type":"string","format":"date-time","description":"When the item was last updated."}}},"DetailMessage":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}},"responses":{"Forbidden":{"description":"The bearer token is missing, invalid or expired. The response has an empty body. The API answers `403` for these cases, not `401`.","headers":{"X-Request-ID":{"$ref":"#/components/headers/XRequestID"}}},"TooManyRequests20PerMinute":{"description":"Rate limit exceeded: 20 requests per minute for the same user and URL. Wait the number of seconds in the `Retry-After` header, then retry.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","schema":{"type":"integer"}},"X-Request-ID":{"$ref":"#/components/headers/XRequestID"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailMessage"}}}},"InternalServerError":{"description":"An unexpected error on our side. The response has an empty body. Repeat the request, and contact support if it keeps failing.","headers":{"X-Request-ID":{"$ref":"#/components/headers/XRequestID"}}}},"headers":{"XRequestID":{"description":"Identifier of this request. Quote it when you contact support so they can find the exact request. A server-side client can set it by sending an `X-Request-ID` request header of 1 to 64 characters from `A-Za-z0-9_-`; any other value is replaced by a generated one. Browsers can read this header but cannot send their own. The value identifies a request for support, but it is not proof that only one request used it.","schema":{"type":"string"}}}},"paths":{"/public-api/spaces/{space_id}/tables/{table_id}":{"get":{"summary":"Get Space table","description":"Retrieve a single table inside a space, including its variables, versions and time periods.","operationId":"getSpaceTable","tags":["Spaces"],"parameters":[{"$ref":"#/components/parameters/SpaceId"},{"$ref":"#/components/parameters/TableId"}],"responses":{"200":{"description":"The table metadata.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/SpaceTableDetail"}}}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Not found - space or table does not exist or is not viewable. The message names the missing resource, `Space` or `Table`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailMessage"}}}},"429":{"$ref":"#/components/responses/TooManyRequests20PerMinute"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```

## Step 4: Pull the data

Call `GET /public-api/spaces/{space_id}/tables/{table_id}/data`. Set `output_format` to `csv` (the default) or `parquet`. The link lasts 2 hours. When the table has no data, `data` is `null`.

## Get Space table data

> Retrieve a presigned download URL for the table's data. Returns a time-limited S3 URL (2h TTL) for downloading the table in CSV or Parquet format.

```json
{"openapi":"3.0.0","info":{"title":"Abacum public API","version":"1.0.0"},"tags":[{"name":"Spaces","description":"List the Spaces a user can view, find their tables, and read table data."}],"servers":[{"url":"https://api.abacum.io","description":"Prod environment"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An access token from the token endpoint, sent as `Authorization: Bearer <access_token>`. Use it to try an endpoint from this page. The token carries the permissions of its user, so use a user with the lowest role that fits the call."}},"parameters":{"SpaceId":{"name":"space_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The ID of the Space. It must be a UUID. Any other value returns a `404` with an HTML page."},"TableId":{"name":"table_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The ID of the table. It must be a UUID. Any other value returns a `404` with an HTML page."}},"responses":{"Forbidden":{"description":"The bearer token is missing, invalid or expired. The response has an empty body. The API answers `403` for these cases, not `401`.","headers":{"X-Request-ID":{"$ref":"#/components/headers/XRequestID"}}},"TooManyRequests20PerMinute":{"description":"Rate limit exceeded: 20 requests per minute for the same user and URL. Wait the number of seconds in the `Retry-After` header, then retry.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","schema":{"type":"integer"}},"X-Request-ID":{"$ref":"#/components/headers/XRequestID"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailMessage"}}}},"InternalServerError":{"description":"An unexpected error on our side. The response has an empty body. Repeat the request, and contact support if it keeps failing.","headers":{"X-Request-ID":{"$ref":"#/components/headers/XRequestID"}}}},"headers":{"XRequestID":{"description":"Identifier of this request. Quote it when you contact support so they can find the exact request. A server-side client can set it by sending an `X-Request-ID` request header of 1 to 64 characters from `A-Za-z0-9_-`; any other value is replaced by a generated one. Browsers can read this header but cannot send their own. The value identifies a request for support, but it is not proof that only one request used it.","schema":{"type":"string"}}},"schemas":{"DetailMessage":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}},"paths":{"/public-api/spaces/{space_id}/tables/{table_id}/data":{"get":{"summary":"Get Space table data","description":"Retrieve a presigned download URL for the table's data. Returns a time-limited S3 URL (2h TTL) for downloading the table in CSV or Parquet format.","operationId":"getSpaceTableData","tags":["Spaces"],"parameters":[{"$ref":"#/components/parameters/SpaceId"},{"$ref":"#/components/parameters/TableId"},{"name":"output_format","in":"query","required":false,"schema":{"type":"string","enum":["csv","parquet"],"default":"csv"},"description":"Output format for the table data download."}],"responses":{"200":{"description":"Table data reference with presigned download URL.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id","data"],"properties":{"id":{"type":"string","format":"uuid"},"data":{"type":"string","format":"uri","nullable":true,"description":"Presigned S3 download URL (2h TTL). Null if table has no data."}}}}}}}},"400":{"description":"Invalid request - `output_format` is not `csv` or `parquet`. The body maps the parameter to a list of messages.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Not found - space or table does not exist or is not viewable. The message names the missing resource, `Space` or `Table`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailMessage"}}}},"429":{"$ref":"#/components/responses/TooManyRequests20PerMinute"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```

## Example

```
GET https://api.abacum.io/public-api/spaces/7b1c3d2e-4f5a-6b7c-8d9e-0f1a2b3c4d5e/tables/b3c1a2d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d/data?output_format=csv
```

```json
{
  "data": {
    "id": "b3c1a2d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
    "data": "https://files.example.com/...presigned-url"
  }
}
```
