> ## Documentation Index
> Fetch the complete documentation index at: https://developers.hubspot.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

---
id: b4888d64-a1dd-44cc-8c35-ee4b82026701
---

# Data source ingestion API

> Upload JSON data or other local files directly into HubSpot Data Studio as independent datasets.

export const RequiredIndicator = () => {
  return <span className="required-indicator">
      required
    </span>;
};

export const ScopesList = ({scopes = [], description = "This API requires one of the following scopes:"}) => {
  if (!scopes || scopes.length === 0) {
    return null;
  }
  const sortedScopes = scopes.sort((a, b) => a.localeCompare(b));
  return <div>
      <div className="text-sm mb-2">{description}</div>
      <div>
        {sortedScopes.map((scope, index) => <div key={index}>
            <code>
              <span className="text-xs">{scope}</span>
            </code>
          </div>)}
      </div>
    </div>;
};

<Accordion title="Required Scopes" icon="key">
  <ScopesList
    scopes={[
  'data_integration.data_source.file.read',
  'data_integration.data_source.file.write',
  'data_integration.data_source.json.read',
  'data_integration.data_source.json.write'
]}
  />
</Accordion>

These endpoints provide a flexible way to ingest and manage external data without the need to map it to standard HubSpot CRM object schemas.

Learn more about [managing external datasets](https://knowledge.hubspot.com/data-management/build-and-activate-datasets-in-data-studio-management/build-and-activate-datasets-in-data-studio).

## Create a data source

To create a data source, follow the instructions in the sections below based on whether you're uploading JSON or another file format (including CSV, XLS, XLSX, or TSV).

### Upload JSON data

To upload JSON as a data source, ensure you've authorized the `data_integration.data_source.json.write` scope for your app, then make a `POST` request to `/data-studio/data-source/2026-09/json`.

The code block below demonstrates an example `cURL` request:

```shell theme={null}
curl --request POST \
  --url https://api.hubapi.com/data-studio/data-source/2026-09/json \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
  "datasourceName": "Sample Data",
  "config": {
    "json": {
      "columns": [
        {"name": "id", "type": "INTEGER"},
        {"name": "first_name", "type": "STRING"},
        {"name": "signup_date", "type": "DATE"}
      ],
      "recordId": "id",
      "data": [
        {"id": 1, "first_name": "Alice", "signup_date": "2025-01-01"},
        {"id": 2, "first_name": "Bob", "signup_date": "2025-01-02"}
      ]
    }
  }
}'
```

When creating a data source from JSON data, the following parameters must be included in your request:

| Parameter                              | Type        | Description                                                                                                                             |
| -------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `datasourceName` <RequiredIndicator /> | String      | A custom name for the data source, which must be unique in your HubSpot account. When you delete a data source, its name can be reused. |
| `config` <RequiredIndicator />         | JSON object | A configuration object describing the structure of the data source, detailed in the table below.                                        |

<a id="json-request-properties" />

The properties of the `config` parameter are detailed below:

| Property               | Type        | Description                                                                                                                                                                                                                                                                                                                                                                                  |
| ---------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `config.json`          | JSON object | The top-level container property of your JSON data source.                                                                                                                                                                                                                                                                                                                                   |
| `config.json.columns`  | Array       | An array of column definitions. A minimum of one column definition is required, with a maximum of 200 columns. Each definition must include the following two fields: <ul><li>`name`: The column name. This name cannot be blank and must be unique.</li><li>`type`: The data type of the column. Valid values are: `STRING`, `BOOL`, `DATETIME`, `DATE`, `INTEGER`, or `DECIMAL`.</li></ul> |
| `config.json.recordId` | String      | The name of the column to use as a unique record identifier. Must be either `STRING` or `INTEGER`. If specified, this field must be present on every record.                                                                                                                                                                                                                                 |
| `config.json.data`     | Array       | An array of records to load into the updated data source. A maximum of 100,000 records is allowed. Each record must be a flat object: nested objects or arrays are not supported.                                                                                                                                                                                                            |

A successful response resembles the following:

```json theme={null}
{
  "datasourceId": "12354",
  "datasourceName": "Sample Data",
  "previewLink": "https://app.hubspot.com/data-studio-home/891585663/external-data-sources/12354/preview"
}
```

The table below provides more details on each of the response fields:

| Field            | Type   | Description                                                         |
| ---------------- | ------ | ------------------------------------------------------------------- |
| `datasourceId`   | String | The ID of the new data source.                                      |
| `datasourceName` | String | The name assigned to the new data source.                           |
| `previewLink`    | String | A URL link to a preview of the data source in your HubSpot account. |

### Upload a CSV, XLS, XLSX, or TSV file

To upload a CSV, XLS, XLSX, or TSV file to create a reusable data source, make a `POST` request to `/data-studio/data-source/2026-09`.

```shell theme={null}
curl --request POST \
  --url https://api.hubapi.com/data-studio/data-source/2026-09 \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --form 'file=@sample-data.csv' \
  --form 'request={
  "datasourceName": "Sample Data",
  "datasourceType": "FILE",
  "config":{
    "file": {
    	 	"headerRowIndex": 1,
    		"columns": [
      		{
        			"name": "string",
        			"type": "STRING"
      		}
    				],
    	"sheetIndex": 0
  }
}
}'
```

When creating a data source, the following `multipart/form-data` parameters must be included in your request:

| Parameter                       | Type        | Description                                                                                                                     |
| ------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `file` <RequiredIndicator />    | File        | Required for file data source type. The CSV, XLS, XLSX, or TSV file to upload. Maximum size: 512 MB. Only one file per request. |
| `request` <RequiredIndicator /> | JSON object | Configuration object describing the data source structure.                                                                      |

The `request` form parameter should be a JSON object that includes the following fields:

| Field                                  | Type        | Description                                                                                                                                                                                                                                                                                                                                                 |
| -------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `datasourceName`                       | String      | A custom name for the data source. It must be unique within the portal. For file data source type, if not provided, it defaults to the filename. If you need to create multiple data sources using the same file, use different `datasourceName` values in each request. When you delete a data source, its name is immediately released and can be reused. |
| `datasourceType` <RequiredIndicator /> | String      | This currently only support `FILE` data source type.                                                                                                                                                                                                                                                                                                        |
| `config` <RequiredIndicator />         | JSON object | The configuration object describing the data source structure. Contents vary based on `datasourceType`.                                                                                                                                                                                                                                                     |

Below is a description of the request body fields for the `FILE` data source type:

| Field                                              | Type        | Description                                                                                                                            |
| -------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `config.file` <RequiredIndicator />                | JSON object | The file configuration details.                                                                                                        |
| `config.file.headerRowIndex`                       | Integer     | The 1-based row index containing column headers. This defaults to 1.                                                                   |
| `config.file.sheetIndex`                           | Integer     | For XLS and XLSX files, the zero-based index of the sheet to ingest.  This defaults to 0, which refers to the first sheet in the file. |
| `config.file.columns` <RequiredIndicator />        | Array       | An array of column definitions. At least one column is required.                                                                       |
| `config.file.columns[].name` <RequiredIndicator /> | String      | The header name of the column. This cannot be blank or duplicated.                                                                     |
| `config.file.columns[].type` <RequiredIndicator /> | String      | The data type of the column. Valid values include: `STRING`, `BOOL`, `DATETIME`, `DATE`, `INTEGER`, `DECIMAL`.                         |

A response would look like this:

```json theme={null}
{
  "datasourceId": "12354",
  "datasourceName": "Sample Data",
  "previewLink": "https://app.hubspot.com/data-studio-home/12345678/external-data-sources/[datasourceID]/preview"
}
```

Below is a description of the response body fields:

| Field            | Type   | Description                                                                                           |
| ---------------- | ------ | ----------------------------------------------------------------------------------------------------- |
| `datasourceId`   | String | The unique identifier for the created data source. Use this ID to retrieve or delete the data source. |
| `datasourceName` | String | The name assigned to the data source.                                                                 |
| `previewLink`    | String | A direct link to preview the data source in Data Studio.                                              |

## Retrieve a data source

To get details about a data source, including ingestion status and file structure, make a `GET` request to `/data-studio/data-source/2026-09/{datasourceId}`, providing the ID of the data source as the `datasourceId` path parameter.

For example, the following request would retrieve a data source:

```shell theme={null}
curl --request GET \
  --url https://api.hubapi.com/data-studio/data-source/2026-09/12354 \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
```

A response would look like this:

```json theme={null}
{
  "datasourceId": "12354",
  "datasourceName": "Sample Data",
  "lastIngestionStatus": "SUCCESSFUL",
  "createdAt": "2025-09-24T10:50:00.000Z",
  "datasourceType": "FILE",
  "columns": [
      {"name": "first_name", "type": "STRING"},
      {"name": "last_name", "type": "STRING"},
      {"name": "email", "type": "STRING"},
      {"name": "signup_date", "type": "DATE"}
    ]
}
```

Below is a description of the response body fields:

| Field                 | Type   | Description                                                                                              |
| --------------------- | ------ | -------------------------------------------------------------------------------------------------------- |
| `datasourceId`        | String | The unique identifier for the created data source. Use this ID to retrieve or delete the data source.    |
| `datasourceName`      | String | The name assigned to the data source.                                                                    |
| `datasourceType`      | String | The type of data source.                                                                                 |
| `lastIngestionStatus` | String | The status of the most recent file ingestion. Values can include: `SUCCESSFUL`, `FAILED`, `IN_PROGRESS`. |
| `createdAt`           | String | The timestamp when the data source was created.                                                          |
| `columns`             | Array  | An array of column definitions matching the uploaded file structure.                                     |

## Push JSON data to an existing data source

To add records to an existing JSON data source without replacing its schema, make a `POST` request to `/data-studio/data-source/2026-09/{datasourceId}/data-push`, providing the ID of the data source as the `datasourceId` path parameter.

If a `recordId` was specified when creating or updating the data source, records with a matching ID will be updated. Records with no matching ID will be appended. If no `recordId` is configured, all records are appended.

The code block below demonstrates an example `cURL` request to append two new records to an existing JSON-based data source:

```shell theme={null}
curl --request POST \
  --url https://api.hubapi.com/data-studio/data-source/2026-09/12354/data-push \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
  "data": [
    {"id": 3, "first_name": "Carol", "signup_date": "2025-01-03"},
    {"id": 4, "first_name": "Dave", "signup_date": "2025-01-04"}
  ]
}'
```

The one required request body field, `data`, is detailed below:

| Field                        | Type  | Description                                                                                                                                                                       |
| ---------------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` <RequiredIndicator /> | Array | An array of records to load into the updated data source. A maximum of 100,000 records is allowed. Each record must be a flat object: nested objects or arrays are not supported. |

## Update the schema for an existing data source

To update the schema or upload additional data to an existing data source, consult the sections below based on the format of the data source you created (i.e., JSON data or an uploaded file).

### Update an existing JSON-based data source

To replace the schema and optionally load new data into an existing JSON data source, make a PUT request to `/data-studio/data-source/2026-09/{datasourceId}/json`, providing the ID of the data source as the `datasourceId` path parameter.

When providing a new schema, it must include all existing columns in use, otherwise the request will be rejected. Any columns not included in the new schema are dropped.

The code block below demonstrates an example request body to update a JSON-based data source:

```shell theme={null}
{
  "datasourceName": "updated-name",
  "config": {
    "json": {
      "columns": [
        {"name": "id", "type": "INTEGER"},
        {"name": "first_name", "type": "STRING"},
        {"name": "signup_date", "type": "DATE"},
        {"name": "country", "type": "STRING"}
      ],
      "recordId": "id",
      "data": [
        {"id": 1, "first_name": "Alice", "signup_date": "2025-01-01", "country": "US"}
      ]
    }
  }
}
```

The request body should include the following parameters:

| Parameter                      | Type        | Description                                                                                                                                                       |
| ------------------------------ | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `datasourceName`               | String      | A new name for the existing data source. If this parameter isn't provided, the existing name will be used.                                                        |
| `config` <RequiredIndicator /> | JSON object | A configuration object describing the updated structure of the data source. The available properties are detailed in the [table above](#json-request-properties). |

### Update an existing file-based data source

To upload a new file to overwrite an existing file-based data source in Data Studio, make a `PUT` request to `/data-studio/data-source/2026-09/{datasourceId}`, providing the ID of the data source as the `datasourceId` path parameter.

When providing a new schema, it must include all existing fields in use, otherwise the request will be rejected. Any missing fields in the new schema are dropped.

When updating a data source, you can [provide the same parameters](#create-a-data-source) as when you create a data source.

For example, the following request body would update a data source:

```json theme={null}
{
 "datasourceName": "new-name",
  "config": {
    "file": {
      "headerRowIndex": 1,
      "columns": [
        {
          "name": "string",
          "type": "STRING"
        }
      ],
      "sheetIndex": 0
    }
  }
}
```

Below is a description of the request body fields:

| Field    | Type        | Description                                                                                                                |
| -------- | ----------- | -------------------------------------------------------------------------------------------------------------------------- |
| `config` | JSON object | The configuration object describing the data source structure. If not provided, it defaults to the existing configuration. |

Below is a description of the request body fields for the `config` object when updating a `FILE` data source type, which is the only currently supported type:

| Field                        | Type        | Description                                                                                                                         |
| ---------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `config.file`                | JSON object | The file configuration details.                                                                                                     |
| `config.file.headerRowIndex` | Integer     | The 1-based row index containing column headers. It defaults to 1.                                                                  |
| `config.file.sheetIndex`     | Integer     | For XLS and XLSX files, the zero-based index of the sheet to ingest. It defaults to 0, which refers to the first sheet in the file. |
| `config.file.columns`        | Array       | An array of column definitions. At least one column is required.                                                                    |
| `config.file.columns[].name` | String      | The header name of the column. It cannot be blank or duplicated.                                                                    |
| `config.file.columns[].type` | String      | The data type of the column. Valid values include: `STRING`, `BOOL`, `DATETIME`, `DATE`, `INTEGER`, `DECIMAL`.                      |

A successful response will resemble the following:

```JSON theme={null}
{
  "datasourceId": "12354",
  "datasourceName": "datasourcename",
  "previewLink": "https://app.hubspot.com/data-studio-home/891585663/external-data-sources/apps/2147586523/preview"
}
```

Below is a description of the response body fields:

| Field            | Type   | Description                           |
| ---------------- | ------ | ------------------------------------- |
| `datasourceId`   | String | The ID of the updated datasource.     |
| `datasourceName` | String | The name assigned to the data source. |
| `previewLink`    | String | The link to the datasource preview.   |

## Rename an existing data source

To rename a data source, make a `PATCH` request to `/data-studio/data-source/2026-09/{datasourceId}`, providing the ID of the data source as the `datasourceId` path parameter, and the `datasourceName` field in the request body with the new name for the data source. The new data source name cannot be blank and must be unique.

This endpoint is supported for both JSON and file based data sources, but you'll need to ensure you've authorized the corresponding `data_integration.data_source.json.write` scope or `data_integration.data_source.file.write` scope based on the format of the existing data source.

The code block below demonstrates an example `cURL` request to rename an existing data source with an ID of `12354`:

```shell theme={null}
curl --request PATCH \
  --url https://api.hubapi.com/data-studio/data-source/2026-09/12354 \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
  "datasourceName": "new-name"
}'
```

## Delete a data source

To delete a data source, make a `DELETE` request to `/data-studio/data-source/2026-09/{datasourceId}`, providing the ID of the data source as the `datasourceId` path parameter.

A data source cannot be deleted if it's actively used by datasets.

You'll receive a `204 No Content` response on successful deletion with no response body.

Status codes you could receive include:

| Code  | Description                                                                                                                                                             |
| ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `204` | The data source deleted successfully.                                                                                                                                   |
| `401` | Unauthorized. Missing or invalid access token.                                                                                                                          |
| `403` | Forbidden. Insufficient permissions (missing required scope).                                                                                                           |
| `404` | The data source was not found.                                                                                                                                          |
| `409` | There was a conflict. The data source cannot be deleted because it's in use by one or more datasets. You must remove the data source from all datasets before deleting. |

## Rate limits

Standard HubSpot API rate limits apply. Learn more about [rate limits](https://developers.hubspot.com/docs/developer-tooling/platform/usage-guidelines#rate-limits).
