# Statements

[Read this page in HTML](https://www.scopedb.io/docs/api-reference/statements)

Run ScopeQL from any backend that can send HTTPS requests. Submit a statement, inspect its state, and poll or cancel it as needed. For writes, [append rows over HTTP](https://www.scopedb.io/docs/api-reference/append.md); for table definitions, use the [Catalog API](https://www.scopedb.io/docs/api-reference/catalog.md).

Before running the examples, [set the base URL and API key](https://www.scopedb.io/docs/api-reference.md#base-url-and-authentication). Follow the shared [errors and retries contract](https://www.scopedb.io/docs/api-reference.md#errors-and-retries) when a request fails or its outcome is uncertain.

## Submit a statement

This query verifies access without creating a table or writing data:

```bash
curl --fail-with-body --silent --show-error \
  "$SCOPEDB_ENDPOINT/v1/statements" \
  -H "Authorization: Bearer $SCOPEDB_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON'
{
  "statement": "SELECT 1 AS ready",
  "format": "json",
  "max_elapsed_seconds": 30
}
JSON
```

Inspect `status` in the response. When it is `finished`, the result has one `ready` column and a row containing `"1"`. When it is `pending` or `running`, [poll the returned statement ID](#poll-a-statement). An HTTP success response alone does not mean the query finished successfully.

The request body accepts these fields:

| Field                   | Required | Description                                                                                                        |
| ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------------ |
| `statement`             | Yes      | One ScopeQL statement.                                                                                             |
| `format`                | Yes      | Use `json` for the result format documented here.                                                                  |
| `statement_id`          | No       | A caller-selected UUID. ScopeDB creates one if omitted. This identifies execution; it is not an idempotency key.   |
| `max_elapsed_seconds`   | No       | Positive, finite seconds from submission, including queueing and execution. Defaults to 3,600 seconds.             |
| `max_estimated_seconds` | No       | Positive, finite seconds allowed for the estimated execution duration. Omit it to leave this estimate limit unset. |

Use `max_elapsed_seconds` for new clients. The older `exec_timeout` duration field is a compatibility alias and cannot be combined with it. A client-side HTTP timeout stops waiting for a response; it does not cancel execution in ScopeDB.

The response is a snapshot of the statement's current state:

| Field          | Description                                                                            |
| -------------- | -------------------------------------------------------------------------------------- |
| `statement_id` | UUID used to poll or cancel the statement.                                             |
| `status`       | One of the five states below.                                                          |
| `created_at`   | Timestamp for the statement.                                                           |
| `progress`     | Completion and scan counters reported while the statement runs.                        |
| `result_set`   | Present when `status` is `finished`.                                                   |
| `error`        | Present when `status` is `failed`; contains `code`, `message`, and optional `details`. |

### Statement states

| State       | Meaning                           | What the client should do                               |
| ----------- | --------------------------------- | ------------------------------------------------------- |
| `pending`   | Accepted and waiting to run.      | Poll the statement ID.                                  |
| `running`   | Execution is in progress.         | Continue polling with a delay.                          |
| `finished`  | Execution completed successfully. | Read `result_set`.                                      |
| `failed`    | Execution ended with an error.    | Inspect `error.code` and `error.message`; stop polling. |
| `cancelled` | Execution was cancelled.          | Stop polling. A cancellation message is not required.   |

`finished`, `failed`, and `cancelled` are terminal. An HTTP `2xx` response only means the API request succeeded; it does not make `failed` or `cancelled` statements successful. Always inspect `status`.

### Poll a statement

Poll only while the submit response is `pending` or `running`:

```bash
curl --fail-with-body --silent --show-error \
  "$SCOPEDB_ENDPOINT/v1/statements/<statement-id>?format=json" \
  -H "Authorization: Bearer $SCOPEDB_API_KEY"
```

Replace `<statement-id>` with the UUID from submission. Use an increasing delay with jitter instead of a tight loop. Keep the `statement_id` with application logs or active job state so later polling and support reports can be correlated. Stop when the state is terminal or the application's waiting deadline is reached.

If the submit response is already terminal, consume that response directly. Statements that finish within the submit request are not necessarily retained for a later `GET`. In particular, a `VALUES ... INSERT INTO` statement returns its terminal result without creating a pollable statement record.

For the connection test, the finished snapshot contains this `result_set`:

```json
{
  "metadata": {
    "fields": [
      { "name": "ready", "data_type": "int" }
    ],
    "num_rows": 1
  },
  "format": "json",
  "rows": [
    ["1"]
  ]
}
```

`metadata.fields` defines the column order and type. Each entry in `rows` is an array in that order. JSON cell values are strings or `null`; convert them using the corresponding `data_type` in your client. For example, the integer result above is `"1"`, not the JSON number `1`. Empty `rows` means the query succeeded without returning rows. The SDKs provide result conversion helpers.

### Cancel a statement

```bash
curl --fail-with-body --silent --show-error -X POST \
  "$SCOPEDB_ENDPOINT/v1/statements/<statement-id>/cancel?format=json" \
  -H "Authorization: Bearer $SCOPEDB_API_KEY"
```

Passing `format=json` returns a statement snapshot in the same shape as submission and polling. Treat cancellation as a request and inspect `status`: execution can race with cancellation. Only `cancelled` confirms cancellation; if the snapshot is still active, continue polling. Closing the HTTP connection does not cancel the server statement.

## Related contents

* [API reference](https://www.scopedb.io/docs/api-reference.md)

* [Query syntax](https://www.scopedb.io/docs/reference/commands/stmt-query.md)

* [Append rows over HTTP](https://www.scopedb.io/docs/api-reference/append.md)

* [Catalog over HTTP](https://www.scopedb.io/docs/api-reference/catalog.md)
