---
title: "Bulk Upsert Rows"
method: POST
path: "/studio/v1/audiences/{audienceId}/rows/actions/bulk/upsert"
tags: ["Audiences"]
---

# Bulk Upsert Rows

`POST /studio/v1/audiences/{audienceId}/rows/actions/bulk/upsert`

## Request

- Base URL: `https://api.zoominfo.com/gtm`
- URL: `https://api.zoominfo.com/gtm/studio/v1/audiences/{audienceId}/rows/actions/bulk/upsert`
- Auth: OAuth 2
  - Authorization code: `https://login.zoominfo.com`
  - Token URL: `https://okta-login.zoominfo.com/oauth2/default/v1/token` scopes: `api:audience:manage`

Load records into an audience — create new rows, update existing ones, or mix both in a single call. This is the primary way to populate an audience with GTM data: trade show leads, CRM exports, account lists, enrichment targets.

Each row is an array of cell values keyed by `columnId` (use the IDs returned by [Create Audience](ref:audiences_createaudience) or [Create New Columns](ref:columns_addcolumns)). Omit `id` to create a new row; include a `rowId` to update an existing one. Max 500 rows per call.

**Cell values:** Each cell's `value` must match the column's `dataType`. For example, an `EMAIL` column expects a string like `"user@example.com"`, an `INTEGER` column expects a number, a `STRING_LIST` column expects an array of strings. Sending the wrong shape will result in a validation error.

Returns `200` with the full row records including per-cell state: `RESULT` (value present), `BLANK` (no value set), `LOADING` (enrichment in progress), `ERROR` (enrichment failed — check `errorDetails`), or `NO_RESULT` (enrichment found no match).
Returns `400` if the request body is malformed or `columnId` references are invalid.

## Path parameters

- `audienceId` string, uuid, required

## Request body

- BulkRowUpsertListApiModel: JSON API model for bulk upsert Row request. Row `id` is optional — omit to create, provide to update.
  - `data` UpsertRow[], required: The primary data of the document
    - `id` string: The unique identifier for the resource
    - `type` string, required: The type of the resource
    - `attributes` RowAttributes, required: Contains all cell data for a row, organized as an array of `CellDetails` objects — one per column.
      - `values` CellDetails[], required: Array of cell details for this row. Each entry corresponds to one column identified by `columnId`.
        - `columnId` string, required: The `columnId` identifying which column this cell belongs to.
        - `value` union, required: The cell's current value. Type must match the column's `dataType`. Provide on create/update; returned on read. This could be of datatypes `string`, `number`, `boolean`, `string array`, `numeric array`, `JsonString(JsonObject, JsonArrayOfObjects)` depending on the column definition
          - string
          - number
          - boolean
          - string[]: Represents a list of string values for a field
          - number[]: Represents a list of numeric values for a field
        - `state` 'RESULT' | 'BLANK' | 'LOADING' | 'ERROR' | 'NO_RESULT', required: Processing state of a cell value within a row. Indicates whether enrichment has run and what the outcome was.
        - `errorDetails` CellErrorDetails: Describes an error that occurred during enrichment for a specific cell.
          - `summary` string, required: Short human-readable label for the error.
          - `description` string, required: Full explanation of the error — what went wrong and why.
          - `retryable` boolean, required: Whether re-running enrichment for this cell is expected to succeed. If `false`, the error is permanent until the underlying data issue is resolved.

## Response `200`

Success

- UpsertRowsJsonApiModel: JSON API response for bulk row upsert. Returns created/updated rows in `data[]`, matching the get row by ID response shape (includes `state` and `errorDetails` per cell).
  - `data` Row[], required: The primary data of the document
    - `id` string, required: The unique identifier for the resource
    - `type` string, required: The type of the resource
    - `attributes` RowAttributes, required: Contains all cell data for a row, organized as an array of `CellDetails` objects — one per column.
      - `values` CellDetails[], required: Array of cell details for this row. Each entry corresponds to one column identified by `columnId`.
        - `columnId` string, required: The `columnId` identifying which column this cell belongs to.
        - `value` union, required: The cell's current value. Type must match the column's `dataType`. Provide on create/update; returned on read. This could be of datatypes `string`, `number`, `boolean`, `string array`, `numeric array`, `JsonString(JsonObject, JsonArrayOfObjects)` depending on the column definition
          - string
          - number
          - boolean
          - string[]: Represents a list of string values for a field
          - number[]: Represents a list of numeric values for a field
        - `state` 'RESULT' | 'BLANK' | 'LOADING' | 'ERROR' | 'NO_RESULT', required: Processing state of a cell value within a row. Indicates whether enrichment has run and what the outcome was.
        - `errorDetails` CellErrorDetails: Describes an error that occurred during enrichment for a specific cell.
          - `summary` string, required: Short human-readable label for the error.
          - `description` string, required: Full explanation of the error — what went wrong and why.
          - `retryable` boolean, required: Whether re-running enrichment for this cell is expected to succeed. If `false`, the error is permanent until the underlying data issue is resolved.

## Other responses

- `400`: Bad Request
- `401`: Unauthorized
- `402`: Payment Required
- `403`: Forbidden
- `429`: Too Many Requests

---

[API](https://skmtc.dev/zoominfo/apis/gtm-studio-api-v1.md) - [All operations](https://skmtc.dev/zoominfo/apis/gtm-studio-api-v1/llms.txt) - [OpenAPI document](https://skmtc.dev/zoominfo/apis/gtm-studio-api-v1/revisions/93a0bebaaac8?raw)
