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

# Quickstart

> Authenticate, upload your first dataset, train a model, and run inference using the Wood Wide AI API.

The Wood Wide AI API lets you upload tabular data, train models, and run inference without managing infrastructure, feature engineering, or model tuning.

This guide walks you through authentication, uploading a dataset, training a model, and running your first prediction. Each step includes **Python (requests)**, **Python (SDK)**, JavaScript, and curl. SDK install and configuration: [Python SDK](/sdk-quickstart).

<Info>
  **HTTP vs Python SDK.** Both tabs run the same workflow. Both use `WOODWIDE_API_KEY`, model status is `processing`, `ready`, or `failed`, and synchronous inference uploads a file. See the [Python SDK](/sdk-quickstart) page for details.
</Info>

***

## 1. Get Your API Key

1. Go to [console.woodwide.ai](https://console.woodwide.ai) and sign in to your Wood Wide AI account.
2. Navigate to **API keys**.
3. Click **CREATE KEY**.
4. Copy the key securely.

<Warning>
  Your API key grants full API access to your account. Store it securely and **never share or commit it to version control**.
</Warning>

## 2. Set Up Authentication

Store your API key in an environment variable and configure the base URL. All API requests require a `Bearer` token in the `Authorization` header.

<CodeGroup>
  ```python Python theme={null}
  import os
  import requests

  api_key = os.getenv("WOODWIDE_API_KEY")
  base_url = "https://api.woodwide.ai"

  headers = {"Authorization": f"Bearer {api_key}"}
  ```

  ```python Python (SDK) theme={null}
  # pip install "woodwide==0.9.0"
  from woodwide import WoodWide

  client = WoodWide()  # reads WOODWIDE_API_KEY
  ```

  ```javascript JavaScript theme={null}
  const apiKey = process.env.WOODWIDE_API_KEY;
  const baseUrl = "https://api.woodwide.ai";

  const headers = { Authorization: `Bearer ${apiKey}` };
  ```

  ```bash curl theme={null}
  export WOODWIDE_API_KEY="your_api_key_here"
  export BASE_URL="https://api.woodwide.ai"
  ```
</CodeGroup>

## 3. Upload a Dataset

Upload a CSV or Parquet file to create a new dataset. The response contains a nested `dataset` object with the `id` you will use for training.

Direct file uploads are limited to **30 MB**. For larger files, see the [signed-URL upload flow](/api-reference/datasets#large-file-uploads).

<CodeGroup>
  ```python Python theme={null}
  with open("train.csv", "rb") as f:
      response = requests.post(
          f"{base_url}/datasets",
          headers=headers,
          files={"file": ("train.csv", f, "text/csv")},
          data={"dataset_name": "my_dataset"},
      )

  result = response.json()
  dataset_id = result["dataset"]["id"]
  print(f"Dataset created: {dataset_id}")
  ```

  ```python Python (SDK) theme={null}
  from pathlib import Path

  train_dataset = client.datasets.create(
      file=Path("train.csv"),
      dataset_name="my_dataset",
      override=True,
  )
  dataset_id = train_dataset.id
  print(f"Dataset created: {dataset_id}")
  ```

  ```javascript JavaScript theme={null}
  const fs = require("fs");
  const FormData = require("form-data");

  const form = new FormData();
  form.append("file", fs.createReadStream("train.csv"), "train.csv");
  form.append("dataset_name", "my_dataset");

  const response = await fetch(`${baseUrl}/datasets`, {
    method: "POST",
    headers: { ...headers, ...form.getHeaders() },
    body: form,
  });

  const result = await response.json();
  const datasetId = result.dataset.id;
  console.log(`Dataset created: ${datasetId}`);
  ```

  ```bash curl theme={null}
  curl -s -X POST "$BASE_URL/datasets" \
    -H "Authorization: Bearer $WOODWIDE_API_KEY" \
    -F "file=@train.csv" \
    -F "dataset_name=my_dataset"

  # Response:
  # {
  #   "dataset": { "id": "...", "version_id": "...", "version_number": 1 },
  #   "job_id": "...",
  #   "status": "queued"
  # }
  ```
</CodeGroup>

## 4. Train a Model

Start a training job by specifying the dataset, a model name, the model type, and the target column. The response contains a nested `model` object with the `id`.

<CodeGroup>
  ```python Python theme={null}
  response = requests.post(
      f"{base_url}/models/train",
      headers=headers,
      json={
          "model_name": "my_model",
          "model_type": "prediction",
          "dataset_id": dataset_id,
          "label_column": "target",
      },
  )

  result = response.json()
  model_id = result["model"]["id"]
  print(f"Training started: {model_id}")
  ```

  ```python Python (SDK) theme={null}
  model = client.models.train(
      model_type="prediction",
      label_column="target",
      dataset_id=dataset_id,
  )
  model_id = model.id
  print(f"Training started: {model_id}")
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(`${baseUrl}/models/train`, {
    method: "POST",
    headers: { ...headers, "Content-Type": "application/json" },
    body: JSON.stringify({
      model_name: "my_model",
      model_type: "prediction",
      dataset_id: datasetId,
      label_column: "target",
    }),
  });

  const result = await response.json();
  const modelId = result.model.id;
  console.log(`Training started: ${modelId}`);
  ```

  ```bash curl theme={null}
  curl -s -X POST "$BASE_URL/models/train" \
    -H "Authorization: Bearer $WOODWIDE_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model_name": "my_model",
      "model_type": "prediction",
      "dataset_id": "YOUR_DATASET_ID",
      "label_column": "target"
    }'

  # Response:
  # {
  #   "model": { "id": "...", "version_id": "...", "version_number": 1 },
  #   "job_id": "...",
  #   "status": "queued",
  #   "woodwide_runtime_version": "..."
  # }
  ```
</CodeGroup>

<Note>
  Training a second model on the same dataset -- even if it is a different model type -- is significantly faster than the first training run.
</Note>

## 5. Wait for Training to Complete

Poll the model status until it transitions to `ready`. Model status progresses through `queued` -> `processing` -> `ready` (or `failed`).

<CodeGroup>
  ```python Python theme={null}
  import time

  while True:
      status_response = requests.get(
          f"{base_url}/models/{model_id}",
          headers=headers,
      )
      status = status_response.json()["status"]

      if status == "ready":
          print("Model is ready.")
          break
      elif status == "failed":
          print("Training failed.")
          break

      print(f"Status: {status} - waiting...")
      time.sleep(5)
  ```

  ```python Python (SDK) theme={null}
  import time

  while True:
      model = client.models.retrieve(model_id)
      status = model.status
      if status in {"ready", "failed"}:
          break
      print(f"Status: {status} — waiting...")
      time.sleep(5)

  if model.status == "failed":
      raise RuntimeError("Training failed")
  print("Model is ready.")
  ```

  ```javascript JavaScript theme={null}
  async function waitForModel(modelId) {
    while (true) {
      const response = await fetch(`${baseUrl}/models/${modelId}`, {
        headers,
      });
      const { status } = await response.json();

      if (status === "ready") {
        console.log("Model is ready.");
        break;
      } else if (status === "failed") {
        console.log("Training failed.");
        break;
      }

      console.log(`Status: ${status} - waiting...`);
      await new Promise((r) => setTimeout(r, 5000));
    }
  }

  await waitForModel(modelId);
  ```

  ```bash curl theme={null}
  # Poll until status is "ready"
  while true; do
    STATUS=$(curl -s "$BASE_URL/models/$MODEL_ID" \
      -H "Authorization: Bearer $WOODWIDE_API_KEY" | jq -r '.status')

    echo "Status: $STATUS"

    if [ "$STATUS" = "ready" ]; then break; fi
    if [ "$STATUS" = "failed" ]; then echo "Training failed."; exit 1; fi

    sleep 5
  done
  ```
</CodeGroup>

## 6. Run Inference

Send a test CSV to the trained model for synchronous predictions. File uploads for inference are limited to **30 MB**.

<CodeGroup>
  ```python Python theme={null}
  with open("test.csv", "rb") as f:
      response = requests.post(
          f"{base_url}/models/{model_id}/infer",
          headers=headers,
          files={"file": ("test.csv", f, "text/csv")},
          data={"output_type": "json"},
      )

  results = response.json()
  print(results["data"])
  ```

  ```python Python (SDK) theme={null}
  from pathlib import Path

  result = client.models.infer(
      model_id,
      file=Path("test.csv"),
      output_type="json",
  )
  print(result["data"])
  ```

  ```javascript JavaScript theme={null}
  const form = new FormData();
  form.append("file", fs.createReadStream("test.csv"), "test.csv");
  form.append("output_type", "json");

  const response = await fetch(`${baseUrl}/models/${modelId}/infer`, {
    method: "POST",
    headers: { ...headers, ...form.getHeaders() },
    body: form,
  });

  const results = await response.json();
  console.log(results.data);
  ```

  ```bash curl theme={null}
  curl -s -X POST "$BASE_URL/models/$MODEL_ID/infer" \
    -H "Authorization: Bearer $WOODWIDE_API_KEY" \
    -F "file=@test.csv" \
    -F "output_type=json"

  # Response:
  # {
  #   "job_id": "...",
  #   "status": "succeeded",
  #   "latency_ms": 1523,
  #   "model_id": "...",
  #   "model_name": "my_model",
  #   "model_type": "prediction",
  #   "data": { "id": [0, 1], "prediction": [1, 0], "prediction_prob": [0.88, 0.95] }
  # }
  ```
</CodeGroup>

***

## Next Steps

* [Python SDK](/sdk-quickstart) — async client, errors, and all model types
* [CLI](/cli) — script the same workflow with `wwai`

Explore the full API reference:

* **Datasets** — Upload, list, and manage your datasets and dataset versions
* **Models** — Train, retrain, and inspect models across six model types (`prediction`, `anomaly`, `embedding`, `clustering`, `factors`, `search`)
* **Inference** — Synchronous, asynchronous, and batch inference
* **Jobs** — Monitor training and inference job status and retrieve results

***

### Security Reminder

* Keep your API key private and rotate it periodically.
* All requests are encrypted in transit (TLS 1.2+).
* For questions about authentication or API onboarding, contact [support@woodwide.ai](mailto:support@woodwide.ai).
