> ## Documentation Index
> Fetch the complete documentation index at: https://webscraping.titannet.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Authenticate, create a task, run it, and export results in five minutes.

This guide shows the shortest useful Titan workflow: authenticate, create a task, run it once, poll the execution, and export the result. It uses the **classic** pattern—**URLs**, **objective**, and **output schema**—which matches most product monitors and extraction jobs. Titan also supports **modular** actions and **multi-step** tasks; see [What is Titan Web Scraping?](/get-started/what-is-titan-web-scraping) and [Action types overview](/about-platform/action-types/overview) when you need search, crawl, or API steps in the same model.

It is written as a practical API walkthrough, not a conceptual tour.

<Note>
  **Rust** snippets use **ureq** and **serde\_json**. Tab titles (**cURL**, **Go**, **TypeScript**, **Python**, **Rust**) match [Authentication](/get-started/authentication-and-api-keys) and [Use the Task Service API](/use-the-platform/use-the-task-service-api) so your language choice stays in sync across pages.
</Note>

## What you will do

By the end of this guide, you will:

1. Configure your API connection
2. Create a task
3. Start an execution
4. Check execution state
5. 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](/get-started/authentication-and-api-keys)) |
| JSON-capable HTTP client | `curl`, Postman, or your own code                                                                                                                                                       |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    export TITAN_API_URL="https://api.webscraping.titannet.io"
    export TITAN_TOKEN="your-bearer-token"
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    // os.Setenv("TITAN_API_URL", "https://api.webscraping.titannet.io")
    // os.Setenv("TITAN_TOKEN", "your-bearer-token")
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    process.env.TITAN_API_URL ??= "https://api.webscraping.titannet.io";
    process.env.TITAN_TOKEN ??= "your-bearer-token";
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os

    os.environ.setdefault("TITAN_API_URL", "https://api.webscraping.titannet.io")
    os.environ.setdefault("TITAN_TOKEN", "your-bearer-token")
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    // std::env::set_var("TITAN_API_URL", "https://api.webscraping.titannet.io");
    // std::env::set_var("TITAN_TOKEN", "your-bearer-token");
    ```
  </Tab>
</Tabs>

## 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).

```mermaid theme={null}
sequenceDiagram
    participant User
    participant TaskService as Task Service
    participant Worker
    User->>TaskService: POST /api/v1/tasks (create task)
    TaskService-->>User: 201 JSON envelope, data.id = task_id
    User->>TaskService: POST /api/v1/tasks/:id/run
    TaskService-->>User: 202 JSON envelope, data.id = execution_id
    TaskService->>Worker: Dispatch work
    Worker->>TaskService: Return results
    User->>TaskService: GET /api/v1/executions/:id
    TaskService-->>User: 200 JSON envelope, data.status
    User->>TaskService: GET /api/v1/executions/:id/results/export
    TaskService-->>User: 200 file body (no JSON envelope)
```

## Step 1: create a task

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    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"
      }'
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    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))
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    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());
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    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())
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    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"));
    ```
  </Tab>
</Tabs>

Successful responses use the standard Titan envelope. The task identifier is **`data.id`**:

```json theme={null}
{
  "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`

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    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"
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    // 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)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    // 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);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    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"])
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    // `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}");
    ```
  </Tab>
</Tabs>

## Step 2: run the task

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -sS -X POST "$TITAN_API_URL/api/v1/tasks/$TASK_ID/run" \
      -H "Authorization: Bearer $TITAN_TOKEN"
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    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))
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    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());
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    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())
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    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"));
    ```
  </Tab>
</Tabs>

The run endpoint returns **202 Accepted** with an **`ExecutionResponse`** inside **`data`**. The execution UUID is **`data.id`** (not `execution_id`):

```json theme={null}
{
  "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`

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    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"
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    // `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)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    // const text = await res.text(); // from POST .../tasks/:id/run
    const run = JSON.parse(text);
    console.log(run.data.id);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    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"])
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    let v: serde_json::Value = serde_json::from_str(&s).expect("json");
    println!("{}", v["data"]["id"].as_str().unwrap());
    ```
  </Tab>
</Tabs>

## Step 3: poll execution status

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -sS "$TITAN_API_URL/api/v1/executions/$EXECUTION_ID" \
      -H "Authorization: Bearer $TITAN_TOKEN"
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    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))
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    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());
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    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())
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    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"));
    ```
  </Tab>
</Tabs>

The JSON body is again the standard envelope; poll **`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                         |

Keep polling until the execution reaches a terminal state.

## Step 4: export the result

Once the execution is **`completed`** (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

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -sS "$TITAN_API_URL/api/v1/executions/$EXECUTION_ID/results/export" \
      -H "Authorization: Bearer $TITAN_TOKEN" \
      -o results.json
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    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)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    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()));
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    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())
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    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");
    ```
  </Tab>
</Tabs>

### Download CSV

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -sS "$TITAN_API_URL/api/v1/executions/$EXECUTION_ID/results/download" \
      -H "Authorization: Bearer $TITAN_TOKEN" \
      -o results.csv
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    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)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    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()));
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    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())
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    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");
    ```
  </Tab>
</Tabs>

`GET /api/v1/executions/:id/results` (metadata) **does** use the standard success envelope; see the **Task Service API** group in the [API Reference](/api-reference/overview) 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)

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    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
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    // 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)
    }
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    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);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    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)
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    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(())
    }
    ```
  </Tab>
</Tabs>

## 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](/api-reference/overview) and [HTTP errors and exceptions](/api-reference/errors) |

## Next steps

* [Authentication and API keys](/get-started/authentication-and-api-keys)
* [Use the Task Service API](/use-the-platform/use-the-task-service-api)
* [Example: single URL extraction](/examples/example-single-url-extraction)
