Rust snippets use ureq and serde_json. Tab titles (cURL, Go, TypeScript, Python, Rust) match Authentication and Use the Task Service API so your language choice stays in sync across pages.
What you will do
By the end of this guide, you will:- Configure your API connection
- Create a task
- Start an execution
- Check execution state
- Export the result
Before you begin
| Requirement | Notes |
|---|---|
| Task Service URL | https://api.webscraping.titannet.io (set as TITAN_API_URL without /api/v1) |
| Bearer token | JWT or API key with tasks:write, executions:write, executions:read, and data:read (see Authentication and API keys) |
| JSON-capable HTTP client | curl, Postman, or your own code |
- cURL
- Go
- TypeScript
- Python
- Rust
export TITAN_API_URL="https://api.webscraping.titannet.io"
export TITAN_TOKEN="your-bearer-token"
// os.Setenv("TITAN_API_URL", "https://api.webscraping.titannet.io")
// os.Setenv("TITAN_TOKEN", "your-bearer-token")
process.env.TITAN_API_URL ??= "https://api.webscraping.titannet.io";
process.env.TITAN_TOKEN ??= "your-bearer-token";
import os
os.environ.setdefault("TITAN_API_URL", "https://api.webscraping.titannet.io")
os.environ.setdefault("TITAN_TOKEN", "your-bearer-token")
// std::env::set_var("TITAN_API_URL", "https://api.webscraping.titannet.io");
// std::env::set_var("TITAN_TOKEN", "your-bearer-token");
Quickstart architecture
The sequence below is schematic: real responses wrap payloads in{ "success": true, "data": … } except for file exports, which return raw bytes (see Step 4).
Step 1: create a task
- cURL
- Go
- TypeScript
- Python
- Rust
curl -sS -X POST "$TITAN_API_URL/api/v1/tasks" \
-H "Authorization: Bearer $TITAN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "My first Titan task",
"urls": ["https://example.com/product/123"],
"objective": "Extract the product name, price, and description",
"output_schema": {
"type": "object",
"properties": {
"product_name": { "type": "string" },
"price": { "type": "string" },
"description": { "type": "string" }
}
},
"execution_type": "single"
}'
body := map[string]any{
"name": "My first Titan task",
"urls": []string{"https://example.com/product/123"},
"objective": "Extract the product name, price, and description",
"output_schema": map[string]any{
"type": "object",
"properties": map[string]any{
"product_name": map[string]string{"type": "string"},
"price": map[string]string{"type": "string"},
"description": map[string]string{"type": "string"},
},
},
"execution_type": "single",
}
b, _ := json.Marshal(body)
req, _ := http.NewRequest("POST", os.Getenv("TITAN_API_URL")+"/api/v1/tasks", bytes.NewReader(b))
req.Header.Set("Authorization", "Bearer "+os.Getenv("TITAN_TOKEN"))
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(string(out))
const base = process.env.TITAN_API_URL!;
const token = process.env.TITAN_TOKEN!;
const res = await fetch(`${base}/api/v1/tasks`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "My first Titan task",
urls: ["https://example.com/product/123"],
objective: "Extract the product name, price, and description",
output_schema: {
type: "object",
properties: {
product_name: { type: "string" },
price: { type: "string" },
description: { type: "string" },
},
},
execution_type: "single",
}),
});
console.log(await res.text());
import json
import os
import urllib.request
payload = {
"name": "My first Titan task",
"urls": ["https://example.com/product/123"],
"objective": "Extract the product name, price, and description",
"output_schema": {
"type": "object",
"properties": {
"product_name": {"type": "string"},
"price": {"type": "string"},
"description": {"type": "string"},
},
},
"execution_type": "single",
}
req = urllib.request.Request(
f"{os.environ['TITAN_API_URL']}/api/v1/tasks",
data=json.dumps(payload).encode(),
headers={
"Authorization": f"Bearer {os.environ['TITAN_TOKEN']}",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(req) as resp:
print(resp.read().decode())
use serde_json::json;
let base = std::env::var("TITAN_API_URL").expect("TITAN_API_URL");
let token = std::env::var("TITAN_TOKEN").expect("TITAN_TOKEN");
let body = json!({
"name": "My first Titan task",
"urls": ["https://example.com/product/123"],
"objective": "Extract the product name, price, and description",
"output_schema": {
"type": "object",
"properties": {
"product_name": { "type": "string" },
"price": { "type": "string" },
"description": { "type": "string" }
}
},
"execution_type": "single"
});
let resp = ureq::post(format!("{base}/api/v1/tasks"))
.set("Authorization", &format!("Bearer {token}"))
.set("Content-Type", "application/json")
.send_json(body).expect("http");
println!("{}", resp.into_string().expect("body"));
data.id:
{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "My first Titan task",
"status": "active",
"execution_type": "single",
"created_at": "2025-01-01T00:00:00Z"
}
}
Capture TASK_ID
- cURL
- Go
- TypeScript
- Python
- Rust
export TASK_ID="$(
curl -sS -X POST "$TITAN_API_URL/api/v1/tasks" \
-H "Authorization: Bearer $TITAN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "My first Titan task",
"urls": ["https://example.com/product/123"],
"objective": "Extract the product name, price, and description",
"output_schema": {
"type": "object",
"properties": {
"product_name": { "type": "string" },
"price": { "type": "string" },
"description": { "type": "string" }
}
},
"execution_type": "single"
}' | jq -r '.data.id'
)"
echo "$TASK_ID"
// Let `body` be the []byte response body from your POST /api/v1/tasks call.
var env struct{ Data struct{ ID string `json:"id"` } `json:"data"` }
json.Unmarshal(body, &env)
taskID := env.Data.ID
os.Setenv("TASK_ID", taskID)
fmt.Println(taskID)
// const text = await res.text(); // response from POST /api/v1/tasks
const created = JSON.parse(text);
const taskId = created.data.id as string;
console.log(taskId);
import json
import os
# `text` is the response body string from your POST /api/v1/tasks call.
created = json.loads(text)
os.environ["TASK_ID"] = created["data"]["id"]
print(os.environ["TASK_ID"])
// `s` holds the response body string from POST /api/v1/tasks.
let v: serde_json::Value = serde_json::from_str(&s).expect("json");
let task_id = v["data"]["id"].as_str().unwrap();
println!("{task_id}");
Step 2: run the task
- cURL
- Go
- TypeScript
- Python
- Rust
curl -sS -X POST "$TITAN_API_URL/api/v1/tasks/$TASK_ID/run" \
-H "Authorization: Bearer $TITAN_TOKEN"
req, _ := http.NewRequest(
"POST",
fmt.Sprintf("%s/api/v1/tasks/%s/run", os.Getenv("TITAN_API_URL"), os.Getenv("TASK_ID")),
nil,
)
req.Header.Set("Authorization", "Bearer "+os.Getenv("TITAN_TOKEN"))
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(string(out))
const base = process.env.TITAN_API_URL!;
const token = process.env.TITAN_TOKEN!;
const taskId = process.env.TASK_ID!;
const res = await fetch(`${base}/api/v1/tasks/${taskId}/run`, {
method: "POST",
headers: { Authorization: `Bearer ${token}` },
});
console.log(await res.text());
import os
import urllib.request
tid = os.environ["TASK_ID"]
req = urllib.request.Request(
f"{os.environ['TITAN_API_URL']}/api/v1/tasks/{tid}/run",
headers={"Authorization": f"Bearer {os.environ['TITAN_TOKEN']}"},
method="POST",
)
with urllib.request.urlopen(req) as resp:
print(resp.read().decode())
let base = std::env::var("TITAN_API_URL").expect("TITAN_API_URL");
let token = std::env::var("TITAN_TOKEN").expect("TITAN_TOKEN");
let task_id = std::env::var("TASK_ID").expect("TASK_ID");
let resp = ureq::post(format!("{base}/api/v1/tasks/{task_id}/run"))
.set("Authorization", &format!("Bearer {token}"))
.send_json(serde_json::json!({})).expect("http");
println!("{}", resp.into_string().expect("body"));
ExecutionResponse inside data. The execution UUID is data.id (not execution_id):
{
"success": true,
"data": {
"id": "e5f6a7b8-c9d0-4123-ef45-678901abcdef",
"task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "queued",
"created_at": "2025-01-01T00:01:00Z"
}
}
Capture EXECUTION_ID
- cURL
- Go
- TypeScript
- Python
- Rust
export EXECUTION_ID="$(
curl -sS -X POST "$TITAN_API_URL/api/v1/tasks/$TASK_ID/run" \
-H "Authorization: Bearer $TITAN_TOKEN" | jq -r '.data.id'
)"
echo "$EXECUTION_ID"
// `body` is the []byte from POST /api/v1/tasks/:id/run
var runEnv struct {
Data struct{ ID string `json:"id"` } `json:"data"`
}
json.Unmarshal(body, &runEnv)
os.Setenv("EXECUTION_ID", runEnv.Data.ID)
fmt.Println(runEnv.Data.ID)
// const text = await res.text(); // from POST .../tasks/:id/run
const run = JSON.parse(text);
console.log(run.data.id);
import json
import os
# `text` is the response body from POST /api/v1/tasks/:id/run
run = json.loads(text)
os.environ["EXECUTION_ID"] = run["data"]["id"]
print(os.environ["EXECUTION_ID"])
let v: serde_json::Value = serde_json::from_str(&s).expect("json");
println!("{}", v["data"]["id"].as_str().unwrap());
Step 3: poll execution status
- cURL
- Go
- TypeScript
- Python
- Rust
curl -sS "$TITAN_API_URL/api/v1/executions/$EXECUTION_ID" \
-H "Authorization: Bearer $TITAN_TOKEN"
req, _ := http.NewRequest(
"GET",
fmt.Sprintf("%s/api/v1/executions/%s", os.Getenv("TITAN_API_URL"), os.Getenv("EXECUTION_ID")),
nil,
)
req.Header.Set("Authorization", "Bearer "+os.Getenv("TITAN_TOKEN"))
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(string(out))
const base = process.env.TITAN_API_URL!;
const token = process.env.TITAN_TOKEN!;
const executionId = process.env.EXECUTION_ID!;
const res = await fetch(`${base}/api/v1/executions/${executionId}`, {
headers: { Authorization: `Bearer ${token}` },
});
console.log(await res.text());
import os
import urllib.request
eid = os.environ["EXECUTION_ID"]
req = urllib.request.Request(
f"{os.environ['TITAN_API_URL']}/api/v1/executions/{eid}",
headers={"Authorization": f"Bearer {os.environ['TITAN_TOKEN']}"},
method="GET",
)
with urllib.request.urlopen(req) as resp:
print(resp.read().decode())
let base = std::env::var("TITAN_API_URL").expect("TITAN_API_URL");
let token = std::env::var("TITAN_TOKEN").expect("TITAN_TOKEN");
let execution_id = std::env::var("EXECUTION_ID").expect("EXECUTION_ID");
let resp = ureq::get(format!("{base}/api/v1/executions/{execution_id}"))
.set("Authorization", &format!("Bearer {token}"))
.call().expect("http");
println!("{}", resp.into_string().expect("body"));
data.status until it reaches a terminal value.
Typical statuses include:
| Status | Meaning |
|---|---|
queued | Execution was created and is waiting for work |
running | Work is actively being processed |
paused | Execution was paused |
completed | Execution finished successfully |
completed_with_errors | Finished with partial failures |
failed | Execution finished with an error |
cancelled | Execution was stopped |
Step 4: export the result
Once the execution iscompleted (or completed_with_errors when data still exists), export the dataset.
GET /api/v1/executions/:id/results/export returns a file attachment (raw JSON, NDJSON, or CSV per the format query parameter). It does not use the { success, data } envelope. The default format is json.
Export JSON to a file
- cURL
- Go
- TypeScript
- Python
- Rust
curl -sS "$TITAN_API_URL/api/v1/executions/$EXECUTION_ID/results/export" \
-H "Authorization: Bearer $TITAN_TOKEN" \
-o results.json
req, _ := http.NewRequest(
"GET",
fmt.Sprintf("%s/api/v1/executions/%s/results/export", os.Getenv("TITAN_API_URL"), os.Getenv("EXECUTION_ID")),
nil,
)
req.Header.Set("Authorization", "Bearer "+os.Getenv("TITAN_TOKEN"))
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
os.WriteFile("results.json", out, 0o644)
const base = process.env.TITAN_API_URL!;
const token = process.env.TITAN_TOKEN!;
const executionId = process.env.EXECUTION_ID!;
const res = await fetch(`${base}/api/v1/executions/${executionId}/results/export`, {
headers: { Authorization: `Bearer ${token}` },
});
const fs = await import("node:fs/promises");
await fs.writeFile("results.json", Buffer.from(await res.arrayBuffer()));
import os
import urllib.request
eid = os.environ["EXECUTION_ID"]
req = urllib.request.Request(
f"{os.environ['TITAN_API_URL']}/api/v1/executions/{eid}/results/export",
headers={"Authorization": f"Bearer {os.environ['TITAN_TOKEN']}"},
method="GET",
)
with urllib.request.urlopen(req) as resp, open("results.json", "wb") as f:
f.write(resp.read())
use std::io::Read;
let base = std::env::var("TITAN_API_URL").expect("TITAN_API_URL");
let token = std::env::var("TITAN_TOKEN").expect("TITAN_TOKEN");
let execution_id = std::env::var("EXECUTION_ID").expect("EXECUTION_ID");
let resp = ureq::get(format!("{base}/api/v1/executions/{execution_id}/results/export"))
.set("Authorization", &format!("Bearer {token}"))
.call().expect("http");
let mut body = Vec::new();
resp.into_reader().read_to_end(&mut body).expect("read");
std::fs::write("results.json", body).expect("write");
Download CSV
- cURL
- Go
- TypeScript
- Python
- Rust
curl -sS "$TITAN_API_URL/api/v1/executions/$EXECUTION_ID/results/download" \
-H "Authorization: Bearer $TITAN_TOKEN" \
-o results.csv
req, _ := http.NewRequest(
"GET",
fmt.Sprintf("%s/api/v1/executions/%s/results/download", os.Getenv("TITAN_API_URL"), os.Getenv("EXECUTION_ID")),
nil,
)
req.Header.Set("Authorization", "Bearer "+os.Getenv("TITAN_TOKEN"))
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
os.WriteFile("results.csv", out, 0o644)
const base = process.env.TITAN_API_URL!;
const token = process.env.TITAN_TOKEN!;
const executionId = process.env.EXECUTION_ID!;
const res = await fetch(`${base}/api/v1/executions/${executionId}/results/download`, {
headers: { Authorization: `Bearer ${token}` },
});
const fs = await import("node:fs/promises");
await fs.writeFile("results.csv", Buffer.from(await res.arrayBuffer()));
import os
import urllib.request
eid = os.environ["EXECUTION_ID"]
req = urllib.request.Request(
f"{os.environ['TITAN_API_URL']}/api/v1/executions/{eid}/results/download",
headers={"Authorization": f"Bearer {os.environ['TITAN_TOKEN']}"},
method="GET",
)
with urllib.request.urlopen(req) as resp, open("results.csv", "wb") as f:
f.write(resp.read())
use std::io::Read;
let base = std::env::var("TITAN_API_URL").expect("TITAN_API_URL");
let token = std::env::var("TITAN_TOKEN").expect("TITAN_TOKEN");
let execution_id = std::env::var("EXECUTION_ID").expect("EXECUTION_ID");
let resp = ureq::get(format!("{base}/api/v1/executions/{execution_id}/results/download"))
.set("Authorization", &format!("Bearer {token}"))
.call().expect("http");
let mut body = Vec::new();
resp.into_reader().read_to_end(&mut body).expect("read");
std::fs::write("results.csv", body).expect("write");
GET /api/v1/executions/:id/results (metadata) does use the standard success envelope; see the Task Service API group in the API Reference tab (OpenAPI) for the exact data shape.
Step 5: access media if present
If your output schema includes media fields, those fields will contain Titan-managed URLs. Use the execution media download endpoint when you want to resolve those assets directly.End-to-end (one script)
- cURL
- Go
- TypeScript
- Python
- Rust
set -euo pipefail
TASK_ID="$(
curl -sS -X POST "$TITAN_API_URL/api/v1/tasks" \
-H "Authorization: Bearer $TITAN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Quick test",
"urls": ["https://example.com"],
"objective": "Extract the page title",
"output_schema": { "type": "object", "properties": { "title": { "type": "string" } } },
"execution_type": "single"
}' | jq -r '.data.id'
)"
EXECUTION_ID="$(
curl -sS -X POST "$TITAN_API_URL/api/v1/tasks/$TASK_ID/run" \
-H "Authorization: Bearer $TITAN_TOKEN" | jq -r '.data.id'
)"
while true; do
ST=$(curl -sS "$TITAN_API_URL/api/v1/executions/$EXECUTION_ID" \
-H "Authorization: Bearer $TITAN_TOKEN" | jq -r '.data.status')
echo "status=$ST"
echo "$ST" | grep -qE 'completed|failed|cancelled|completed_with_errors' && break
sleep 3
done
curl -sS "$TITAN_API_URL/api/v1/executions/$EXECUTION_ID/results/export" \
-H "Authorization: Bearer $TITAN_TOKEN" -o results.json
// package main; imports: bytes, encoding/json, fmt, io, net/http, os, time
func main() {
base := os.Getenv("TITAN_API_URL")
tok := os.Getenv("TITAN_TOKEN")
createBody, _ := json.Marshal(map[string]any{
"name": "Quick test", "urls": []string{"https://example.com"},
"objective": "Extract the page title",
"output_schema": map[string]any{"type": "object", "properties": map[string]any{"title": map[string]string{"type": "string"}}},
"execution_type": "single",
})
cr, _ := http.NewRequest("POST", base+"/api/v1/tasks", bytes.NewReader(createBody))
cr.Header.Set("Authorization", "Bearer "+tok)
cr.Header.Set("Content-Type", "application/json")
crResp, _ := http.DefaultClient.Do(cr)
crBytes, _ := io.ReadAll(crResp.Body)
crResp.Body.Close()
var c1 struct{ Data struct{ ID string `json:"id"` } `json:"data"` }
json.Unmarshal(crBytes, &c1)
taskID := c1.Data.ID
rr, _ := http.NewRequest("POST", base+"/api/v1/tasks/"+taskID+"/run", nil)
rr.Header.Set("Authorization", "Bearer "+tok)
runResp, _ := http.DefaultClient.Do(rr)
runBytes, _ := io.ReadAll(runResp.Body)
runResp.Body.Close()
var r1 struct {
Data struct {
ID string `json:"id"`
Status string `json:"status"`
} `json:"data"`
}
json.Unmarshal(runBytes, &r1)
execID, status := r1.Data.ID, r1.Data.Status
for status == "queued" || status == "running" || status == "paused" {
time.Sleep(3 * time.Second)
pr, _ := http.NewRequest("GET", base+"/api/v1/executions/"+execID, nil)
pr.Header.Set("Authorization", "Bearer "+tok)
pResp, _ := http.DefaultClient.Do(pr)
pBytes, _ := io.ReadAll(pResp.Body)
pResp.Body.Close()
json.Unmarshal(pBytes, &r1)
status = r1.Data.Status
}
er, _ := http.NewRequest("GET", base+"/api/v1/executions/"+execID+"/results/export", nil)
er.Header.Set("Authorization", "Bearer "+tok)
eResp, _ := http.DefaultClient.Do(er)
exportBytes, _ := io.ReadAll(eResp.Body)
eResp.Body.Close()
os.WriteFile("results.json", exportBytes, 0o644)
fmt.Println("wrote results.json", taskID, execID, status)
}
const base = process.env.TITAN_API_URL!;
const token = process.env.TITAN_TOKEN!;
type SuccessEnvelope<T> = { success: true; data: T };
type ErrorEnvelope = {
success: false;
error: { code: string; message: string };
};
async function readEnvelope<T>(res: Response): Promise<T> {
const body = (await res.json()) as SuccessEnvelope<T> | ErrorEnvelope;
if (!res.ok || body.success === false) {
throw new Error(`HTTP ${res.status}: ${JSON.stringify(body)}`);
}
return body.data;
}
const task = await readEnvelope<{ id: string }>(
await fetch(`${base}/api/v1/tasks`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Quick test",
urls: ["https://example.com"],
objective: "Extract the page title",
output_schema: { type: "object", properties: { title: { type: "string" } } },
execution_type: "single",
}),
}),
);
const runRes = await fetch(`${base}/api/v1/tasks/${task.id}/run`, {
method: "POST",
headers: { Authorization: `Bearer ${token}` },
});
const execution = await readEnvelope<{ id: string; status: string }>(runRes);
let status = execution.status;
while (!["completed", "failed", "cancelled", "completed_with_errors"].includes(status)) {
await new Promise((r) => setTimeout(r, 3000));
const exec = await readEnvelope<{ status: string }>(
await fetch(`${base}/api/v1/executions/${execution.id}`, {
headers: { Authorization: `Bearer ${token}` },
}),
);
status = exec.status;
}
const exportRes = await fetch(`${base}/api/v1/executions/${execution.id}/results/export`, {
headers: { Authorization: `Bearer ${token}` },
});
if (!exportRes.ok) throw new Error(await exportRes.text());
const records = JSON.parse(await exportRes.text());
console.log(records);
import json
import os
import time
import urllib.request
base = os.environ["TITAN_API_URL"]
tok = os.environ["TITAN_TOKEN"]
def envelope(resp):
data = json.loads(resp.read().decode())
if not data.get("success"):
raise RuntimeError(data)
return data["data"]
payload = {
"name": "Quick test",
"urls": ["https://example.com"],
"objective": "Extract the page title",
"output_schema": {"type": "object", "properties": {"title": {"type": "string"}}},
"execution_type": "single",
}
req = urllib.request.Request(
f"{base}/api/v1/tasks",
data=json.dumps(payload).encode(),
headers={"Authorization": f"Bearer {tok}", "Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(req) as resp:
task = envelope(resp)
task_id = task["id"]
req = urllib.request.Request(
f"{base}/api/v1/tasks/{task_id}/run",
headers={"Authorization": f"Bearer {tok}"},
method="POST",
)
with urllib.request.urlopen(req) as resp:
execution = envelope(resp)
exec_id, status = execution["id"], execution["status"]
while status not in ("completed", "failed", "cancelled", "completed_with_errors"):
time.sleep(3)
req = urllib.request.Request(
f"{base}/api/v1/executions/{exec_id}",
headers={"Authorization": f"Bearer {tok}"},
method="GET",
)
with urllib.request.urlopen(req) as resp:
status = envelope(resp)["status"]
req = urllib.request.Request(
f"{base}/api/v1/executions/{exec_id}/results/export",
headers={"Authorization": f"Bearer {tok}"},
method="GET",
)
with urllib.request.urlopen(req) as resp:
records = json.loads(resp.read().decode())
print(records)
use serde_json::json;
use std::io::Read;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let base = std::env::var("TITAN_API_URL").expect("TITAN_API_URL");
let token = std::env::var("TITAN_TOKEN").expect("TITAN_TOKEN");
let task: serde_json::Value = {
let body = json!({
"name": "Quick test",
"urls": ["https://example.com"],
"objective": "Extract the page title",
"output_schema": { "type": "object", "properties": { "title": { "type": "string" } } },
"execution_type": "single"
});
let resp = ureq::post(format!("{base}/api/v1/tasks"))
.set("Authorization", &format!("Bearer {token}"))
.set("Content-Type", "application/json")
.send_json(body).expect("http");
let v: serde_json::Value = serde_json::from_str(&resp.into_string().expect("body")).expect("json");
v["data"].clone()
};
let task_id = task["id"].as_str().unwrap();
let run: serde_json::Value = {
let resp = ureq::post(format!("{base}/api/v1/tasks/{task_id}/run"))
.set("Authorization", &format!("Bearer {token}"))
.send_json(json!({})).expect("http");
let v: serde_json::Value = serde_json::from_str(&resp.into_string().expect("body")).expect("json");
v["data"].clone()
};
let exec_id = run["id"].as_str().unwrap().to_string();
let mut status = run["status"].as_str().unwrap().to_string();
while !matches!(
status.as_str(),
"completed" | "failed" | "cancelled" | "completed_with_errors"
) {
std::thread::sleep(std::time::Duration::from_secs(3));
let resp = ureq::get(format!("{base}/api/v1/executions/{exec_id}"))
.set("Authorization", &format!("Bearer {token}"))
.call().expect("http");
let v: serde_json::Value = serde_json::from_str(&resp.into_string().expect("body")).expect("json");
status = v["data"]["status"].as_str().unwrap().to_string();
}
let resp = ureq::get(format!("{base}/api/v1/executions/{exec_id}/results/export"))
.set("Authorization", &format!("Bearer {token}"))
.call().expect("http");
let mut body = Vec::new();
resp.into_reader().read_to_end(&mut body).expect("read");
let records: serde_json::Value = serde_json::from_slice(&body).expect("json");
println!("{records}");
Ok(())
}
Troubleshooting
| Problem | Check first |
|---|---|
401 Unauthorized or 403 Forbidden | Token validity and scopes |
| Task created but execution stays queued | Worker availability and scheduler health |
| Execution completed but no data is available | Result export path and ingestion completion |
| Confusing response shapes | API reference overview and HTTP errors and exceptions |