Skip to main content
POST /v1/nql/execute runs one NQL statement as a workflow: send the statement, poll the run, read the result.
/v1/nql/execute replaces the retired POST /nql/run, which now returns 410 Gone. If you have existing code calling /nql/run, see Migrating from /nql/run to /v1/nql/execute.

Prerequisites

  • A Narrative API key
  • Basic familiarity with NQL syntax

1. Run the statement

The 200 response is the workflow that was created plus the id of the run that just started:
id is the workflow id; run_id is the run id. Keep both — every step below needs one of them. The endpoint runs one statement per request: CREATE MATERIALIZED VIEW, INSERT, UPDATE, DELETE, or EXPLAIN.

Request parameters

A REFRESH_SCHEDULE on a CREATE MATERIALIZED VIEW statement becomes a workflow schedule, so scheduled refreshes run as workflow runs.

Check the view name first

Datasets, views, and access rules share one namespace per company, so a CREATE MATERIALIZED VIEW fails if any of the three already uses the name. To check a name before you submit the statement, call GET /nql/name-availability:
  • Matching is case-insensitive: Active_Users_By_Region and active_users_by_region are the same name.
  • reserved_by is dataset, view, or access_rule. It says what kind of object holds the name, never which object, and it appears only when your token has read access to both datasets and views.
  • Archiving a dataset, view, or access rule frees its name.
  • The check doesn’t reserve the name. Someone else can still take it before your statement runs.
The endpoint requires read access to datasets and a token issued to a company. A name that contains anything other than letters, digits, and underscores, or is longer than 256 characters, returns 400.

2. Track the run

Poll the workflow’s runs:
The run reports running, completed, or failed. If all you need is whether the statement succeeded, this is the whole story — stop here.

When you need failure detail

The statement executes as a job inside the run. To see state transitions, failures, or the result payload, list jobs by run id:
The job identifier field is job_id, not id. Code ported from /nql/run that reads id gets undefined rather than an error.
The job is created seconds after the run starts, so an immediate query can return an empty list — poll until it appears. The job carries workflow_id and workflow_run_id pointing back, so correlation works in both directions; workflow_id alone returns every job across all runs of that workflow. See Tracking Job Status for polling patterns and backoff.

3. Get the result

The dataset created by CREATE MATERIALIZED VIEW

The dataset does not exist when the response is sent — it is created when the run executes. Once the run reaches completed, get it either way:
  1. Look it up by name. You named the view in the statement, so the name is already known to your code.
  2. Read it off the completed job. The job result carries the dataset id:
    Then fetch it with GET /datasets/42558.

The rows themselves

/v1/nql/execute does not return query results, and a bare SELECT is rejected with a 400. To read data back, materialize it with CREATE MATERIALIZED VIEW and then request a sample from the resulting dataset.

4. Cancel a run

Cancel an in-flight execution through the workflow run cancel endpoint:

Errors

Errors are returned as RFC 7807 problem documents with title, status, detail, instance, log_id, and a debug object. See Troubleshooting NQL for how to read these error bodies.

Migrating from /nql/run

Port existing callers of the retired endpoint

Workflow Orchestration

Chain multiple operations into one durable workflow

Tracking Job Status

Polling patterns, backoff, and job result handling

Materialized View Syntax

Complete reference for CREATE MATERIALIZED VIEW