# Submit SQL Query

Use the `POST /api/v3/query` endpoint of the Data 360 Query API to execute a SQL query against your Data 360 data. Submit a query in ASYNC mode to receive a `queryId` for polling, or use ADAPTIVE mode to receive results immediately when the query completes quickly. Both modes support JSON and Apache Arrow response formats.

:::important
This API is the recommended interface for new integrations. See [Migrate from Query API V1 and V2](/docs/data/data-cloud-query-guide/references/data-cloud-query-api-reference/query-api-migration.md) for guidance on updating existing code.
:::

## Syntax

- **HTTP Method**: POST
- **Format**: REST
- **URI**: `/api/v3/query`

## Request Headers

| Header          | Value                                                                 |
| --------------- | --------------------------------------------------------------------- |
| `Authorization` | `Bearer {accessToken}`                                                |
| `Content-Type`  | `application/json`                                                    |
| `Accept`        | `application/json` (default) or `application/vnd.apache.arrow.stream` |

## Request Body

| Field           | Type    | Required | Description                                                                                                                                                                                               |
| --------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sql`           | string  | Yes      | SQL query to execute. Uses Data 360 SQL syntax.                                                                                                                                                           |
| `transferMode`  | string  | No       | Execution mode. Accepted values: `ASYNC`, `ADAPTIVE` (default).                                                                                                                                           |
| `paramStyle`    | string  | No       | Parameter binding style. Accepted values: `QUESTION_MARK` (default), `NAMED`, `DOLLAR_NUMBERED`. See [Parameterized Queries](#parameterized-queries).                                                     |
| `parameters`    | array   | No       | Array of parameter objects for parameterized queries. Each object requires `type` (a Data 360 SQL type name) and `value` (a JSON string). See [Parameterized Queries](#parameterized-queries).            |
| `settings`      | object  | No       | See [Query Settings](#query-settings) for supported keys.                                                                                                                                                 |
| `resultRange`   | object  | No       | Controls what is returned within the REST response. ADAPTIVE mode only. Supported keys: `rowLimit` (integer), `byteLimit` (integer, default and maximum 20 MB).                                           |
| `queryRowLimit` | integer | No       | Maximum number of rows to produce by the query. Acts as an implicit `LIMIT` clause. The query won't produce more rows than this value. Set to `0` to retrieve only the schema without producing any rows. |

### Query Settings

The `settings` object accepts the following keys:

- `timezone` — Time zone identifier for date and time values, for example `"Etc/UTC"`.
- `language` — Language identifier for locale-specific formatting, for example `"de_DE"`.
- `date_style` — Order of year, month, and day for parsing date strings. Accepted values: `MDY`, `DMY`, `YMD`. See [Date/Time Input](/docs/data/data-cloud-query-guide/references/dc-sql-reference/datetime.md#date-time-input).
- `lc_time` — Locale for date literals, as an ISO language and country code, for example `"en_US"` or `"de_AT"`.
- `query_timeout` — Execution limit in milliseconds before the query is terminated, for example `1800000` (30 minutes).

### Parameterized Queries

The `paramStyle` request field controls how parameters are bound in your SQL:

- `QUESTION_MARK` (default) — Use `?` placeholders
- `NAMED` — Use named placeholders (`:paramName`)
- `DOLLAR_NUMBERED` — Use positional placeholders (`$1`, `$2`, ...)

Each object in the `parameters` array requires a `type` and a `value`.

- `type` — A [Data 360 SQL type](/docs/data/data-cloud-query-guide/references/dc-sql-reference/datatypes.md) name, such as `varchar`, `bigint`, or `boolean`. For types that take a length or precision, include the relevant field, for example `{ "type": "varchar", "length": 10, "value": "abc" }`.
- `value` — The parameter value, always passed as a JSON string. Even for numeric types, pass the value as a string, for example `"42"`, not `42`.

:::note
`type` takes SQL type names, not JSON type names. Use `varchar` rather than `string`.
:::

## Response Structure

Both ASYNC and ADAPTIVE modes share a common response structure.

### Response Headers

Both ASYNC and ADAPTIVE modes return these response headers.

| Header             | Description                                                                                                                                                                                                                           |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Date`             | Timestamp when the response was generated.                                                                                                                                                                                            |
| `Content-Type`     | `application/json` or `application/vnd.apache.arrow.stream` depending on the `Accept` request header.                                                                                                                                 |
| `x-hyperdb-status` | JSON-serialized string containing the full query status. Fields: `queryId`, `completionStatus`, `chunkCount`, `rowCount`, `progress`, `expirationTime`, and `executionStats`. Use the `queryId` from this header to poll for results. |

### Response Body — ASYNC Mode

In ASYNC mode, the response body omits the `data` field and `returnedRows` is `0`. Use the `queryId` from the `x-hyperdb-status` response header to poll `GET /api/v3/query/{queryId}` for completion.

| Field          | Description                     |
| -------------- | ------------------------------- |
| `metadata`     | Object containing column schema |
| `data`         | Omitted in ASYNC mode           |
| `returnedRows` | Always `0` in ASYNC mode        |

### Response Body — ADAPTIVE Mode

If the query completes within the adaptive timeout, `data` contains the result rows. If the query exceeds the adaptive timeout without producing rows, the response mimics ASYNC mode: the `data` field is omitted and `returnedRows` is `0`. Use the `queryId` from the `x-hyperdb-status` response header to poll `GET /api/v3/query/{queryId}` for completion.

| Field          | Description                                                                      |
| -------------- | -------------------------------------------------------------------------------- |
| `metadata`     | Object containing column schema                                                  |
| `data`         | Array of result rows (each row is an array); omitted if adaptive timeout reached |
| `returnedRows` | Number of rows returned (`0` if adaptive timeout reached)                        |

## Examples

These examples show ASYNC and ADAPTIVE requests and responses.

### ASYNC Request

```http
POST https://{dne_cdpInstanceUrl}/api/v3/query
Authorization: Bearer {accessToken}
Content-Type: application/json

{
  "sql": "SELECT ssot__FirstName__c, ssot__LastName__c FROM ssot__Individual__dlm LIMIT 10",
  "transferMode": "ASYNC"
}
```

### ASYNC Response

Response headers (excerpt):

```
x-hyperdb-status: {"queryId":"MTAuMjcuMTgxLjE0OTo3NDg0_1cfc8d35-464c-9185-1f41-3eb638a71f7a","completionStatus":"RUNNING","chunkCount":0,"rowCount":0,"progress":0.0,"expirationTime":"2025-09-26T10:55:07.438Z","executionStats":{"wallClockTime":0.0,"rowsProcessed":0}}
```

Response body:

```json
{
  "metadata": {
    "columns": [
      {
        "name": "ssot__FirstName__c",
        "type": "varchar",
        "nullable": true
      },
      { "name": "ssot__LastName__c", "type": "varchar", "nullable": true }
    ]
  },
  "returnedRows": 0
}
```

### ADAPTIVE Request

```http
POST https://{dne_cdpInstanceUrl}/api/v3/query
Authorization: Bearer {accessToken}
Content-Type: application/json

{
  "sql": "SELECT ssot__FirstName__c, ssot__LastName__c FROM ssot__Individual__dlm LIMIT 10",
  "transferMode": "ADAPTIVE"
}
```

### ADAPTIVE Response

```json
{
  "metadata": {
    "columns": [
      {
        "name": "ssot__FirstName__c",
        "type": "varchar",
        "nullable": true
      },
      { "name": "ssot__LastName__c", "type": "varchar", "nullable": true }
    ]
  },
  "data": [
    ["Alice", "Johnson"],
    ["Bob", "Smith"]
  ],
  "returnedRows": 2
}
```

### Parameterized Request

This ADAPTIVE request binds two parameters. The `paramStyle` is `QUESTION_MARK`, so each `?` placeholder is filled from the `parameters` array in order.

```http
POST https://{dne_cdpInstanceUrl}/api/v3/query
Authorization: Bearer {accessToken}
Content-Type: application/json

{
  "sql": "SELECT ssot__FirstName__c, ssot__LastName__c FROM ssot__Individual__dlm WHERE ssot__CountryCode__c = ? AND ssot__Age__c >= ? LIMIT 10",
  "transferMode": "ADAPTIVE",
  "paramStyle": "QUESTION_MARK",
  "parameters": [
    { "type": "varchar", "value": "US" },
    { "type": "bigint", "value": "18" }
  ]
}
```

### ADAPTIVE Request with Query Settings

This ADAPTIVE request sets `date_style`, `lc_time`, and `query_timeout` to control date parsing, locale, and the execution timeout. Without an explicit `date_style`, the `01/08/1999` literal is ambiguous.

```http
POST https://{dne_cdpInstanceUrl}/api/v3/query
Authorization: Bearer {accessToken}
Content-Type: application/json

{
  "sql": "SELECT ssot__FirstName__c, ssot__LastName__c FROM ssot__Individual__dlm WHERE ssot__BirthDate__c > '01/08/1999' LIMIT 10",
  "transferMode": "ADAPTIVE",
  "settings": {
    "date_style": "MDY",
    "lc_time": "en_US",
    "query_timeout": "1800000"
  }
}
```

## Apache Arrow Responses

Set `Accept: application/vnd.apache.arrow.stream` to request a binary Arrow IPC stream instead of JSON. Use an Arrow-compatible client library (such as [PyArrow](https://arrow.apache.org/docs/python/) or the [Apache Arrow Java library](https://arrow.apache.org/docs/java/)) to read the stream.

### ASYNC Mode (Apache Arrow)

In ASYNC mode, the response body always contains only schema metadata with no data rows, regardless of the `Accept` header. Retrieve the `queryId` from the `x-hyperdb-status` response header and poll `GET /api/v3/query/{queryId}` for completion, then use `GET /api/v3/query/{queryId}/rows` or `/chunks/{chunkId}` with `Accept: application/vnd.apache.arrow.stream` to retrieve results.

### ADAPTIVE Mode (Apache Arrow)

Set `Accept: application/vnd.apache.arrow.stream` to receive an inline ADAPTIVE result as a binary Arrow IPC stream. If the query exceeds the adaptive timeout and falls back to ASYNC mode, the response body contains only schema metadata with no data rows. Retrieve the `queryId` from the `x-hyperdb-status` response header and poll `GET /api/v3/query/{queryId}` for completion.

## Error Handling

V3 returns structured error objects with HTTP status codes.

| Status | Meaning                           |
| ------ | --------------------------------- |
| 400    | Invalid SQL or request payload    |
| 401    | Missing or invalid authentication |
| 408    | Request timed out                 |
| 429    | Rate limit exceeded               |
| 500    | Internal server error             |

Error responses include a rich error model with SQLSTATE codes and human-readable detail.

```json
{
  "error": "42601",
  "message": "syntax error [TraceId:03d7d84a302b827ea8f0fe1d251f4eaf]",
  "details": {
    "customerDetail": "line 1, column 49: ...",
    "errorSource": "User",
    "position": {
      "errorBeginCharacterOffset": "48",
      "errorEndCharacterOffset": "53"
    }
  }
}
```

The `position` field is included for syntax errors. `errorSource` indicates whether the error originated from user input (`"User"`) or the system. See [Query Services Status Codes](/docs/data/data-cloud-query-guide/references/data-cloud-query-api-reference/c360a-api-queryservices-statuscodes.md) for the full reference.

## Related Resources

- [Query Data using Query API](/docs/data/data-cloud-query-guide/references/data-cloud-query-api-reference/c360a-api-queryservices-overview.md) — Connect REST API (recommended for most integrations)
- [Query V1 and V2 API](/docs/data/data-cloud-query-guide/references/data-cloud-query-api-reference/c360a-api-queryservices-legacy.md) — Legacy API reference
- [Query Services Status Codes](/docs/data/data-cloud-query-guide/references/data-cloud-query-api-reference/c360a-api-queryservices-statuscodes.md) — Error code reference
- [API Limits and Guidelines](https://help.salesforce.com/s/articleView?id=data.c360\_a_limits_and_guidelines.htm\&type=5)
