curl --request POST \
--url https://api-dev.narrative.io/v1/nql/execute \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"nql": "INSERT INTO \"company_data\".\"1\" (\"id\") VALUES (1)"
}
'import requests
url = "https://api-dev.narrative.io/v1/nql/execute"
payload = { "nql": "INSERT INTO \"company_data\".\"1\" (\"id\") VALUES (1)" }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({nql: 'INSERT INTO "company_data"."1" ("id") VALUES (1)'})
};
fetch('https://api-dev.narrative.io/v1/nql/execute', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-dev.narrative.io/v1/nql/execute",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'nql' => 'INSERT INTO "company_data"."1" ("id") VALUES (1)'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api-dev.narrative.io/v1/nql/execute"
payload := strings.NewReader("{\n \"nql\": \"INSERT INTO \\\"company_data\\\".\\\"1\\\" (\\\"id\\\") VALUES (1)\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api-dev.narrative.io/v1/nql/execute")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"nql\": \"INSERT INTO \\\"company_data\\\".\\\"1\\\" (\\\"id\\\") VALUES (1)\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-dev.narrative.io/v1/nql/execute")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"nql\": \"INSERT INTO \\\"company_data\\\".\\\"1\\\" (\\\"id\\\") VALUES (1)\"\n}"
response = http.request(request)
puts response.read_body{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "my-etl-workflow",
"specification": "document:\n dsl: '1.0.0'\n namespace: test\n name: test-workflow\n version: '1.0.0'\ndo:\n - createView:\n call: CreateMaterializedViewIfNotExists\n with:\n nql: \"CREATE MATERIALIZED VIEW workflow_output AS SELECT track_id FROM company_data.workflow_input\"\n - refreshView:\n call: RefreshMaterializedView\n with:\n datasetName: workflow_output\n - insertData:\n call: ExecuteDml\n with:\n nql: \"INSERT INTO company_data.workflow_input (track_id) VALUES ('test')\"\n",
"data_plane_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890",
"company_id": 100,
"created_at": "2025-01-15T10:30:00Z",
"created_by": 20,
"updated_at": "2025-01-15T10:30:00Z",
"status": "active",
"tags": [
"<string>"
],
"run_id": "b7e3f1a2-4c5d-6e7f-8a9b-0c1d2e3f4a5b",
"archived_at": null
}{
"type": null,
"title": "Failed to Parse Query",
"status": 400,
"detail": "Invalid query format.",
"instance": "/nql/validate",
"log_id": "c06fea02-0950-45c6-aaff-07ab07c0d04c",
"debug": null
}{
"type": null,
"title": "Table Already Exists",
"status": 403,
"detail": "The table or materialized view name 'test_stats' already exists. Please choose another name.",
"instance": "/v1/nql/execute",
"log_id": "5f1c9b2e-7a44-4d18-9c3f-2b6e0a15d7c4",
"debug": null
}{
"title": "Unsupported Type Error: DECIMAL",
"status": 422,
"detail": "Column 'decimal_value' has type DECIMAL, which is not supported as an output column of a materialized view. CAST the column to a supported type such as DOUBLE, BIGINT, VARCHAR, BOOLEAN, or TIMESTAMP.",
"instance": "/v1/nql/execute",
"log_id": "c904b703-d41e-4372-9276-9f4bdc8ad031",
"debug": {
"column": "decimal_value",
"type_name": "DECIMAL"
}
}Execute an NQL statement
The execute endpoint in the NQL API allows users to execute their NQL queries. This endpoint processes the query and performs the specified operations within the specified data plane. The query runs as a workflow, and the response carries the ID of that workflow run. Follow the run through the workflows endpoints.
Supported statements: INSERT, UPDATE, DELETE, EXPLAIN, and CREATE MATERIALIZED VIEW.
Set create_as_view to create a view rather than a materialized table; it applies only to
CREATE MATERIALIZED VIEW and is ignored for other statements.
curl --request POST \
--url https://api-dev.narrative.io/v1/nql/execute \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"nql": "INSERT INTO \"company_data\".\"1\" (\"id\") VALUES (1)"
}
'import requests
url = "https://api-dev.narrative.io/v1/nql/execute"
payload = { "nql": "INSERT INTO \"company_data\".\"1\" (\"id\") VALUES (1)" }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({nql: 'INSERT INTO "company_data"."1" ("id") VALUES (1)'})
};
fetch('https://api-dev.narrative.io/v1/nql/execute', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-dev.narrative.io/v1/nql/execute",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'nql' => 'INSERT INTO "company_data"."1" ("id") VALUES (1)'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api-dev.narrative.io/v1/nql/execute"
payload := strings.NewReader("{\n \"nql\": \"INSERT INTO \\\"company_data\\\".\\\"1\\\" (\\\"id\\\") VALUES (1)\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api-dev.narrative.io/v1/nql/execute")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"nql\": \"INSERT INTO \\\"company_data\\\".\\\"1\\\" (\\\"id\\\") VALUES (1)\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-dev.narrative.io/v1/nql/execute")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"nql\": \"INSERT INTO \\\"company_data\\\".\\\"1\\\" (\\\"id\\\") VALUES (1)\"\n}"
response = http.request(request)
puts response.read_body{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "my-etl-workflow",
"specification": "document:\n dsl: '1.0.0'\n namespace: test\n name: test-workflow\n version: '1.0.0'\ndo:\n - createView:\n call: CreateMaterializedViewIfNotExists\n with:\n nql: \"CREATE MATERIALIZED VIEW workflow_output AS SELECT track_id FROM company_data.workflow_input\"\n - refreshView:\n call: RefreshMaterializedView\n with:\n datasetName: workflow_output\n - insertData:\n call: ExecuteDml\n with:\n nql: \"INSERT INTO company_data.workflow_input (track_id) VALUES ('test')\"\n",
"data_plane_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890",
"company_id": 100,
"created_at": "2025-01-15T10:30:00Z",
"created_by": 20,
"updated_at": "2025-01-15T10:30:00Z",
"status": "active",
"tags": [
"<string>"
],
"run_id": "b7e3f1a2-4c5d-6e7f-8a9b-0c1d2e3f4a5b",
"archived_at": null
}{
"type": null,
"title": "Failed to Parse Query",
"status": 400,
"detail": "Invalid query format.",
"instance": "/nql/validate",
"log_id": "c06fea02-0950-45c6-aaff-07ab07c0d04c",
"debug": null
}{
"type": null,
"title": "Table Already Exists",
"status": 403,
"detail": "The table or materialized view name 'test_stats' already exists. Please choose another name.",
"instance": "/v1/nql/execute",
"log_id": "5f1c9b2e-7a44-4d18-9c3f-2b6e0a15d7c4",
"debug": null
}{
"title": "Unsupported Type Error: DECIMAL",
"status": 422,
"detail": "Column 'decimal_value' has type DECIMAL, which is not supported as an output column of a materialized view. CAST the column to a supported type such as DOUBLE, BIGINT, VARCHAR, BOOLEAN, or TIMESTAMP.",
"instance": "/v1/nql/execute",
"log_id": "c904b703-d41e-4372-9276-9f4bdc8ad031",
"debug": {
"column": "decimal_value",
"type_name": "DECIMAL"
}
}Authorizations
Body
A dataplane represent where you would run the query. Your query get compiled to the SQL dialect that your data engine understands. If you leave it blank, your query will target Narrative's dataplane on AWS using Apache Spark. We currently support Snowflake and we plan to support other dataplanes in the future. See https://next.narrative.io/products/narrative-anywhere for more details.
The ID of the compute pool to run on. The compute pool must be active, belong to your company, and be associated with the target data plane. If not specified, the default compute pool for the data plane will be used (if one is configured).
"5c8f4a2e-3b1d-4f6a-9c7e-2d8b1a0f5e93"
When true, a CREATE MATERIALIZED VIEW statement creates a view over the query rather than a
materialized table, so reads run the query instead of returning stored rows. Ignored for any other
statement type, and not compatible with MERGE, DELTA, CHUNKING_STRATEGY, or PARTITIONED_BY.
false
Response
The created workflow and the id of the run started for it.
A created workflow whose run was started, so the run ID is always present.
The workflow specification in YAML format.
"document:\n dsl: '1.0.0'\n namespace: test\n name: test-workflow\n version: '1.0.0'\ndo:\n - createView:\n call: CreateMaterializedViewIfNotExists\n with:\n nql: \"CREATE MATERIALIZED VIEW workflow_output AS SELECT track_id FROM company_data.workflow_input\"\n - refreshView:\n call: RefreshMaterializedView\n with:\n datasetName: workflow_output\n - insertData:\n call: ExecuteDml\n with:\n nql: \"INSERT INTO company_data.workflow_input (track_id) VALUES ('test')\"\n"

