> 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-dataset-data.md).

# Read dataset data

Pull a dataset as it arrived in Abacum, or after Abacum processed it.

You can pull a dataset at two stages. You need a user with the Admin role.

| Stage     | Endpoint                                                | Content                                                                                                                                                        |
| --------- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Raw       | `GET /public-api/data-sets/{dataset_id}/raw_data`       | The dataset exactly as it came from your integration, before Abacum typed, cleaned or classified it. These are the columns that your connector produced.       |
| Processed | `GET /public-api/data-sets/{dataset_id}/processed_data` | The dataset after Abacum typed, cleaned and classified it. This is the version that feeds your models, with proper column types and readable dimension labels. |

## Step 1: Find the dataset

Call `GET /public-api/data-sets`. It lists every dataset in your organization, with:

* Its `id`, `name` and `code`.
* The integration it comes from: `connection_id` and `connection_type`.
* When it last synced (`last_synced_at`) and when Abacum last processed it (`last_processed_at`).
* Its row counts: `row_count_raw` and `row_count_processed`.
* Whether it is `restricted`.

For a dataset with no integration, for example data loaded by hand, `connection_id` and `connection_type` are `null`. Restricted datasets follow the same access rules as restricted models. See [Access and permissions](/essentials/concepts/access-and-permissions.md).

## List datasets

> Retrieve a list of datasets for the authenticated user’s organization.

```json
{"openapi":"3.0.0","info":{"title":"Abacum public API","version":"1.0.0"},"tags":[{"name":"Datasets","description":"List datasets, read their raw or processed data, and load actuals into them with the Import API."}],"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."}},"responses":{"ForbiddenAdminOnly":{"description":"One of two causes:\n\n- The bearer token is missing, invalid or expired. The response has an empty body.\n- The token's user is not an Admin or Super Admin. The body is `{\"detail\": \"You do not have permission to perform this action.\"}`.\n\nThe API answers `403` for a bad token, not `401`.\n","headers":{"X-Request-ID":{"$ref":"#/components/headers/XRequestID"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailMessage"}}}},"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/data-sets":{"get":{"summary":"List datasets","description":"Retrieve a list of datasets for the authenticated user’s organization.","operationId":"listDatasets","tags":["Datasets"],"responses":{"200":{"description":"A list of datasets.","content":{"application/json":{"schema":{"type":"object","required":["data","metadata"],"properties":{"data":{"type":"array","items":{"type":"object","required":["id","name","code","connection_id","connection_type","last_synced_at","last_processed_at","row_count_raw","row_count_processed","restricted","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","description":"Unique identifier of the dataset."},"name":{"type":"string","description":"Display name of the dataset."},"code":{"type":"string","description":"Stable code used to reference the dataset programmatically."},"connection_id":{"type":"string","format":"uuid","nullable":true,"description":"ID of the integration that produces this dataset. `null` if the dataset is not linked to an integration (e.g. data loaded manually)."},"connection_type":{"type":"string","nullable":true,"description":"Vendor / type of the integration that produces this dataset (e.g. `netsuite`, `gsheets`, `sftp`). `null` if the dataset is not linked to an integration."},"last_synced_at":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp of the most recent successful sync from the integration. `null` if the dataset has never synced successfully or is not linked to an integration."},"last_processed_at":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp the dataset was last processed — typed, transformed and classified into its final form. `null` if the dataset has not been processed yet."},"row_count_raw":{"type":"integer","description":"Number of rows in the raw dataset — the data as originally ingested, before any typing, transformations or classification are applied."},"row_count_processed":{"type":"integer","description":"Number of rows in the processed dataset — the data after typing, transformations and classification have been applied. This is the version consumed by models. In the vast majority of cases this matches `row_count_raw`; small deviations can occur when transformations drop or merge rows."},"restricted":{"type":"boolean","description":"Whether the dataset is restricted. Restricted datasets follow the same access rules as restricted models."},"created_at":{"type":"string","format":"date-time","description":"When the dataset was created."},"updated_at":{"type":"string","format":"date-time","description":"When the dataset was last updated."}}}},"metadata":{"type":"object","description":"Always an empty object."}}}}}},"403":{"$ref":"#/components/responses/ForbiddenAdminOnly"},"429":{"$ref":"#/components/responses/TooManyRequests20PerMinute"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```

## Step 2: Request the raw data

Call `GET /public-api/data-sets/{dataset_id}/raw_data` for the data as your integration produced it.

## Get dataset raw data

> Retrieve a pre-signed S3 URL pointing to the \*\*raw\*\* dataset file — the dataset as\
> ingested from the integration, \*\*before\*\* the Typing Layer, Transformations and\
> AIDC variable mapping have been applied.\
> \
> Schema reflects the integration output verbatim: no column type coercion,\
> no resolved dimension keys, no AIDC variables. The \`metadata\` block describes\
> the raw column structure inferred from the file.\
> \
> \`start\_date\` and \`end\_date\` cover whole months, from the first day of the start month to the\
> last day of the end month. If the dataset has no time column, the filter does nothing and\
> every row is returned.<br>

```json
{"openapi":"3.0.0","info":{"title":"Abacum public API","version":"1.0.0"},"tags":[{"name":"Datasets","description":"List datasets, read their raw or processed data, and load actuals into them with the Import API."}],"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":{"DatasetId":{"name":"dataset_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The ID of the dataset. It must be a UUID. Any other value returns a `404` with an HTML page."},"StartMonth":{"name":"start_date","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$"},"description":"Start month in `YYYY-MM` format. Both `start_date` and `end_date` are required when present."},"EndMonth":{"name":"end_date","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$"},"description":"End month in `YYYY-MM` format. Both `start_date` and `end_date` are required when present."},"FileFormat":{"name":"file_format","in":"query","required":false,"schema":{"type":"string","enum":["csv","parquet"],"default":"csv"},"description":"Output file format. Defaults to `csv` (pre-signed URL, 30 min TTL). `parquet` returns a pre-signed URL with a 2 h TTL."}},"schemas":{"ErrorMessage":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}},"DetailMessage":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}},"responses":{"ForbiddenAdminOnly":{"description":"One of two causes:\n\n- The bearer token is missing, invalid or expired. The response has an empty body.\n- The token's user is not an Admin or Super Admin. The body is `{\"detail\": \"You do not have permission to perform this action.\"}`.\n\nThe API answers `403` for a bad token, not `401`.\n","headers":{"X-Request-ID":{"$ref":"#/components/headers/XRequestID"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailMessage"}}}},"TooManyRequests10PerMinute":{"description":"Rate limit exceeded: 10 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/data-sets/{dataset_id}/raw_data":{"get":{"summary":"Get dataset raw data","description":"Retrieve a pre-signed S3 URL pointing to the **raw** dataset file — the dataset as\ningested from the integration, **before** the Typing Layer, Transformations and\nAIDC variable mapping have been applied.\n\nSchema reflects the integration output verbatim: no column type coercion,\nno resolved dimension keys, no AIDC variables. The `metadata` block describes\nthe raw column structure inferred from the file.\n\n`start_date` and `end_date` cover whole months, from the first day of the start month to the\nlast day of the end month. If the dataset has no time column, the filter does nothing and\nevery row is returned.\n","operationId":"getDatasetRawData","tags":["Datasets"],"parameters":[{"$ref":"#/components/parameters/DatasetId"},{"$ref":"#/components/parameters/StartMonth"},{"$ref":"#/components/parameters/EndMonth"},{"$ref":"#/components/parameters/FileFormat"}],"responses":{"200":{"description":"A pre-signed download link to a file (CSV by default, or Parquet) containing the dataset's raw data.","content":{"application/json":{"schema":{"type":"object","required":["data","metadata"],"properties":{"data":{"type":"string","description":"Pre-signed S3 URL for downloading the raw dataset file."},"metadata":{"type":"object","required":["properties","ingested_at","row_count"],"properties":{"properties":{"type":"object","description":"Map from source column name to type info. Each entry takes one of four shapes depending on the column's role:\n  - Time column: `{ \"type\": \"string\", \"format\": \"date\" }`\n  - Custom dimension column: `{ \"type\": \"string\", \"label\": \"<dimension name>\" }`\n  - Numeric column: `{ \"type\": \"number\", \"format\": \"float\" }`\n  - Other column: `{ \"type\": \"string\" }`\n","additionalProperties":{"type":"object","required":["type"],"properties":{"type":{"type":"string","description":"Either `string` or `number`."},"format":{"type":"string","description":"Present for time (`date`) and numeric (`float`) columns."},"label":{"type":"string","description":"Present for custom dimension columns, the dimension's display name."}}}},"ingested_at":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp the underlying raw file was ingested."},"row_count":{"type":"integer","description":"Number of rows in the returned file after any `start_date` / `end_date` filtering."}}}}}}}},"400":{"description":"Invalid request - invalid `start_date`, `end_date`, or `file_format`. `start_date` and `end_date` must be supplied together.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}},"403":{"$ref":"#/components/responses/ForbiddenAdminOnly"},"404":{"description":"Not found - the dataset does not exist, belongs to another organization, or has no raw data yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}},"429":{"$ref":"#/components/responses/TooManyRequests10PerMinute"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```

## Step 3: Request the processed data

Call `GET /public-api/data-sets/{dataset_id}/processed_data` for the data that feeds your models.

## Get dataset processed data

> Retrieve a pre-signed S3 URL pointing to the \*\*processed\*\* dataset file —\
> the dataset \*\*after\*\* the Typing Layer, Transformations and AIDC variable\
> mapping have been applied. This is the same data that feeds Models.\
> \
> Schema includes typed columns, resolved dimension codes, and AIDC-classified\
> variables. The \`metadata\` block describes the columns of the file.\
> \
> \`start\_date\` and \`end\_date\` cover whole months, from the first day of the start month to the\
> last day of the end month. If the dataset has no time column, the filter does nothing and\
> every row is returned.<br>

```json
{"openapi":"3.0.0","info":{"title":"Abacum public API","version":"1.0.0"},"tags":[{"name":"Datasets","description":"List datasets, read their raw or processed data, and load actuals into them with the Import API."}],"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":{"DatasetId":{"name":"dataset_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The ID of the dataset. It must be a UUID. Any other value returns a `404` with an HTML page."},"StartMonth":{"name":"start_date","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$"},"description":"Start month in `YYYY-MM` format. Both `start_date` and `end_date` are required when present."},"EndMonth":{"name":"end_date","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$"},"description":"End month in `YYYY-MM` format. Both `start_date` and `end_date` are required when present."},"FileFormat":{"name":"file_format","in":"query","required":false,"schema":{"type":"string","enum":["csv","parquet"],"default":"csv"},"description":"Output file format. Defaults to `csv` (pre-signed URL, 30 min TTL). `parquet` returns a pre-signed URL with a 2 h TTL."}},"schemas":{"ErrorMessage":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}},"DetailMessage":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}},"responses":{"ForbiddenAdminOnly":{"description":"One of two causes:\n\n- The bearer token is missing, invalid or expired. The response has an empty body.\n- The token's user is not an Admin or Super Admin. The body is `{\"detail\": \"You do not have permission to perform this action.\"}`.\n\nThe API answers `403` for a bad token, not `401`.\n","headers":{"X-Request-ID":{"$ref":"#/components/headers/XRequestID"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailMessage"}}}},"TooManyRequests10PerMinute":{"description":"Rate limit exceeded: 10 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/data-sets/{dataset_id}/processed_data":{"get":{"summary":"Get dataset processed data","description":"Retrieve a pre-signed S3 URL pointing to the **processed** dataset file —\nthe dataset **after** the Typing Layer, Transformations and AIDC variable\nmapping have been applied. This is the same data that feeds Models.\n\nSchema includes typed columns, resolved dimension codes, and AIDC-classified\nvariables. The `metadata` block describes the columns of the file.\n\n`start_date` and `end_date` cover whole months, from the first day of the start month to the\nlast day of the end month. If the dataset has no time column, the filter does nothing and\nevery row is returned.\n","operationId":"getDatasetProcessedData","tags":["Datasets"],"parameters":[{"$ref":"#/components/parameters/DatasetId"},{"$ref":"#/components/parameters/StartMonth"},{"$ref":"#/components/parameters/EndMonth"},{"$ref":"#/components/parameters/FileFormat"}],"responses":{"200":{"description":"A pre-signed download link to a file (CSV by default, or Parquet) containing the dataset's processed data.","content":{"application/json":{"schema":{"type":"object","required":["data","metadata"],"properties":{"data":{"type":"string","description":"Pre-signed S3 URL for downloading the processed dataset file."},"metadata":{"type":"object","required":["properties","processed_at","row_count"],"properties":{"properties":{"type":"object","description":"Map from processed column name (dynamic — depends on dataset schema) to type info.\nEach entry takes one of four shapes depending on the column's role:\n  - Time dimension column: `{ \"type\": \"string\", \"format\": \"date\" }`\n  - Custom dimension column: `{ \"type\": \"string\", \"label\": \"<dimension name>\" }`\n  - Numeric column (int / float / decimal): `{ \"type\": \"number\", \"format\": \"float\" }`\n  - Other column: `{ \"type\": \"string\" }`\n","additionalProperties":{"type":"object","required":["type"],"properties":{"type":{"type":"string","description":"Either `string` or `number`."},"format":{"type":"string","description":"Present for time (`date`) and numeric (`float`) columns."},"label":{"type":"string","description":"Present for custom dimension columns — the dimension's display name."}}}},"processed_at":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp the processed file was last generated."},"row_count":{"type":"integer","description":"Number of rows in the returned file after any `start_date` / `end_date` filtering."}}}}}}}},"400":{"description":"Invalid request - invalid `start_date`, `end_date`, or `file_format`. `start_date` and `end_date` must be supplied together.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}},"403":{"$ref":"#/components/responses/ForbiddenAdminOnly"},"404":{"description":"Not found - the dataset does not exist, belongs to another organization, or has no processed data yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorMessage"}}}},"429":{"$ref":"#/components/responses/TooManyRequests10PerMinute"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```

## Parameters

| Parameter                | Values                                                        | Default |
| ------------------------ | ------------------------------------------------------------- | ------- |
| `start_date`, `end_date` | `YYYY-MM` only. Send both, or neither.                        | -       |
| `file_format`            | `csv` (link lasts 30 minutes), `parquet` (link lasts 2 hours) | `csv`   |

## Example

```
GET https://api.abacum.io/public-api/data-sets/9c2f4190-a020-463b-b97b-f19db9c4566f/processed_data?start_date=2026-01&end_date=2026-03
```

```json
{
  "data": "https://files.example.com/data-sets/9c2f4190-a020-463b-b97b-f19db9c4566f/processed_data/file.csv?pre-signed-url-token",
  "metadata": {
    "properties": {
      "time": { "type": "string", "format": "date" },
      "department_level_1": { "type": "string", "label": "Department" },
      "value": { "type": "number", "format": "float" },
      "note": { "type": "string" }
    },
    "processed_at": "2026-04-30T10:18:00Z",
    "row_count": 124501
  }
}
```

For raw data, the metadata shows the original source columns:

```json
{
  "data": "https://files.example.com/data-sets/9c2f4190-a020-463b-b97b-f19db9c4566f/raw_data/file.csv?pre-signed-url-token",
  "metadata": {
    "properties": {
      "date": { "type": "string", "format": "date" },
      "country": { "type": "string" },
      "amount": { "type": "number", "format": "float" }
    },
    "ingested_at": "2026-04-30T10:14:00Z",
    "row_count": 124501
  }
}
```
