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

# Create Workflows

> Create and manage workflows programmatically using SDK, CLI, MCP Server, or REST API

## Overview

Create workflows programmatically using the Kadoa SDK, CLI, MCP Server, or REST API:

* Create workflows with natural language prompts
* Use existing schemas or define custom ones
* Configure monitoring and scheduling options

## Prerequisites

Before you begin, you'll need:

* A Kadoa account
* Your [API key](https://kadoa.com/settings)
* For SDK: `npm install @kadoa/node-sdk` or `yarn add @kadoa/node-sdk` or `uv add kadoa-sdk`

## Authentication

<CodeGroup>
  ```typescript Node SDK theme={null}
  import { KadoaClient } from '@kadoa/node-sdk';

  const client = new KadoaClient({
    apiKey: 'YOUR_API_KEY'
  });

  const status = await client.status();
  console.log(status);
  console.log(status.user);
  ```

  ```python Python SDK theme={null}
  import asyncio
  from kadoa_sdk import KadoaClient, KadoaClientConfig

  client = KadoaClient(KadoaClientConfig(api_key="YOUR_API_KEY"))

  status = asyncio.run(client.status())
  print(status)
  print(status.user)
  ```

  ```bash CLI theme={null}
  # Interactive login (saves to ~/.kadoa/config.json)
  kadoa login

  # Or use environment variable
  export KADOA_API_KEY=tk-your_api_key

  # Check auth status
  kadoa whoami
  ```

  ```text MCP Server theme={null}
  The remote server at mcp.kadoa.com/mcp uses OAuth, so no API key is needed.
  For local stdio mode, set KADOA_API_KEY in your client config or run `kadoa login` (shared with the CLI).
  ```

  ```javascript REST API theme={null}
  const headers = {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json"
  };
  ```
</CodeGroup>

## Extraction Methods

Choose how you want to extract data from websites:

### Auto Mode

The simplest way of creating a workflow is by simply passing a URL. Kadoa will automatically suggest a data schema and extract all relevant data from the page.

<CodeGroup>
  ```typescript Node SDK theme={null}
  // SDK: AI automatically detects and extracts data
  const result = await client.extraction.run({
    urls: ["https://sandbox.kadoa.com/ecommerce"]
  });

  console.log(result.data);
  ```

  ```python Python SDK theme={null}
  # SDK: AI automatically detects and extracts data
  result = client.extraction.run(
      ExtractionOptions(
          urls=["https://sandbox.kadoa.com/ecommerce"]
      )
  )

  print(result.data)
  ```

  ```text MCP Server theme={null}
  > "Extract all products from https://sandbox.kadoa.com/ecommerce"
  ```

  ```javascript REST API theme={null}
  // API: Describe the extraction in plain language
  // POST https://api.kadoa.com/v4/workflows
  {
    "urls": ["https://sandbox.kadoa.com/ecommerce"],
    "name": "Auto Product Extraction",
    "userPrompt": "Extract all product information including name, price, availability, and any other relevant details"
  }

  // Or define a minimal schema:
  {
    "urls": ["https://sandbox.kadoa.com/ecommerce"],
    "name": "Auto Product Extraction",
    "entity": "Product",
    "fields": [
      {
        "name": "data",
        "dataType": "STRING",
        "description": "Extract all product information"
      }
    ]
  }
  ```
</CodeGroup>

### Custom Schema

Define exactly what fields you want to extract for precise control:

<CodeGroup>
  ```typescript Node SDK theme={null}
  const workflow = await client
    .extract({
      urls: ["https://sandbox.kadoa.com/ecommerce"],
      name: "Structured Product Extraction",
      extraction: (builder) =>
        builder
          .entity("Product")
          .field("title", "Product name", "STRING", {
            example: "iPhone 15 Pro",
          })
          .field("price", "Price in USD", "MONEY")
          .field("inStock", "Availability", "BOOLEAN")
          .field("rating", "Rating 1-5", "NUMBER")
          .field("releaseDate", "Launch date", "DATE"),
    })
    .create();

  const result = await workflow.run({ limit: 10 });

  // Use destructuring for cleaner access
  const { data } = await result.fetchData({});
  console.log(data);
  ```

  ```python Python SDK theme={null}
  workflow = (
      client.extract(
          ExtractOptions(
              urls=["https://sandbox.kadoa.com/ecommerce"],
              name="Structured Product Extraction",
              extraction=lambda builder: builder.entity("Product")
              .field("title", "Product name", "STRING", FieldOptions(example="iPhone 15 Pro"))
              .field("price", "Price in USD", "MONEY")
              .field("inStock", "Availability", "BOOLEAN")
              .field("rating", "Rating 1-5", "NUMBER")
              .field("releaseDate", "Launch date", "DATE"),
          )
      )
      .create()
  )

  result = workflow.run(RunWorkflowOptions(limit=10))

  # Use destructuring for cleaner access
  response = result.fetch_data({})
  print(response.data)
  ```

  ```text MCP Server theme={null}
  > "Extract product title, price in USD, availability, rating, and release date from https://sandbox.kadoa.com/ecommerce"
  ```

  ```javascript REST API theme={null}
  // POST https://api.kadoa.com/v4/workflows
  {
    "urls": ["https://sandbox.kadoa.com/ecommerce"],
    "name": "Structured Product Extraction",
    "entity": "Product",
    "fields": [
      {
        "name": "title",
        "dataType": "STRING",
        "description": "Product name"
      },
      {
        "name": "price",
        "dataType": "MONEY",
        "description": "Price in USD"
      },
      {
        "name": "inStock",
        "dataType": "BOOLEAN",
        "description": "Availability"
      },
      {
        "name": "rating",
        "dataType": "NUMBER",
        "description": "Rating 1-5"
      },
      {
        "name": "releaseDate",
        "dataType": "DATE",
        "description": "Launch date"
      }
    ]
  }
  ```
</CodeGroup>

**Available Data Types:** `STRING`, `NUMBER`, `BOOLEAN`, `DATE`, `DATETIME`, `MONEY`, `IMAGE`, `LINK`, `OBJECT`, `ARRAY`

[See all data types →](/docs/workflows/schemas#data-types)

### Classification

Automatically categorize content into predefined classes:

<CodeGroup>
  ```typescript Node SDK theme={null}
  const workflow = await client
    .extract({
      urls: ["https://sandbox.kadoa.com/news"],
      name: "Article Classifier",
      extraction: (builder) =>
        builder
          .entity("Article")
          .field("title", "Headline", "STRING", {
            example: "Tech Company Announces New Product",
          })
          .field("content", "Article text", "STRING", {
            example: "The article discusses the latest innovations...",
          })
          .classify("sentiment", "Content tone", [
            { title: "Positive", definition: "Optimistic tone" },
            { title: "Negative", definition: "Critical tone" },
            { title: "Neutral", definition: "Balanced tone" },
          ])
          .classify("category", "Article topic", [
            { title: "Technology", definition: "Tech news" },
            { title: "Business", definition: "Business news" },
            { title: "Politics", definition: "Political news" },
          ]),
    })
    .create();
  //Note: 'limit' here is limiting number of extracted records not fetched
  const result = await workflow.run({ limit: 10, variables: {} });
  console.log(result.jobId);
  const data = result.fetchData({ limit: 10 });
  console.log(data);
  ```

  ```python Python SDK theme={null}
  workflow = (
      client.extract(
          ExtractOptions(
              urls=["https://sandbox.kadoa.com/news"],
              name="Article Classifier",
              extraction=lambda builder: builder.entity("Article")
              .field(
                  "title",
                  "Headline",
                  "STRING",
                  FieldOptions(example="Tech Company Announces New Product"),
              )
              .field(
                  "content",
                  "Article text",
                  "STRING",
                  FieldOptions(example="The article discusses the latest innovations..."),
              )
              .classify(
                  "sentiment",
                  "Content tone",
                  [
                      {"title": "Positive", "definition": "Optimistic tone"},
                      {"title": "Negative", "definition": "Critical tone"},
                      {"title": "Neutral", "definition": "Balanced tone"},
                  ],
              )
              .classify(
                  "category",
                  "Article topic",
                  [
                      {"title": "Technology", "definition": "Tech news"},
                      {"title": "Business", "definition": "Business news"},
                      {"title": "Politics", "definition": "Political news"},
                  ],
              ),
          )
      )
      .create()
  )
  # Note: 'limit' here is limiting number of extracted records not fetched
  result = workflow.run(RunWorkflowOptions(limit=10, variables={}))
  print(result.job_id)
  data = result.fetch_data({"limit": 10})
  print(data)
  ```

  ```javascript REST API theme={null}
  // API example coming soon
  ```
</CodeGroup>

## Prompts

Every workflow is driven by a prompt: a plain-language description of what to extract and how to get there. The AI agent handles navigation, pagination, clicking, and forms automatically. For details, see [Prompts](/docs/workflows/prompts).

<Note>
  Navigation is handled automatically when you provide a prompt.
</Note>

### Using a Prompt

For multi-step or complex extractions, write a prompt in plain language. The AI agent follows your prompt to navigate, interact, and extract:

<CodeGroup>
  ```typescript Node SDK theme={null}
  const workflow = await client
    .extract({
      urls: ["https://sandbox.kadoa.com/ecommerce"],
      name: "Product Catalog",
      userPrompt: "Extract all products. Click 'Next' to continue through pagination. For each product, open the detail page and extract the full description and specifications.",
      extraction: (builder) =>
        builder
          .entity("Product")
          .field("title", "Product name", "STRING", {
            example: "Wireless Headphones",
          })
          .field("price", "Product price", "MONEY")
          .field("description", "Full description", "STRING")
          .field("specifications", "Technical specs", "STRING"),
    })
    .create();

  const result = await workflow.run({ limit: 50 });
  ```

  ```python Python SDK theme={null}
  workflow = (
      client.extract(
          ExtractOptions(
              urls=["https://sandbox.kadoa.com/ecommerce"],
              name="Product Catalog",
              user_prompt="Extract all products. Click 'Next' to continue through pagination. For each product, open the detail page and extract the full description and specifications.",
              extraction=lambda builder: builder.entity("Product")
              .field("title", "Product name", "STRING", FieldOptions(example="Wireless Headphones"))
              .field("price", "Product price", "MONEY")
              .field("description", "Full description", "STRING")
              .field("specifications", "Technical specs", "STRING"),
          )
      )
      .create()
  )

  result = workflow.run(RunWorkflowOptions(limit=50))
  ```

  ```text MCP Server theme={null}
  > "Extract all products from https://sandbox.kadoa.com/ecommerce including title, price, description, and specs. Navigate through pagination and open detail pages."
  ```

  ```javascript REST API theme={null}
  // POST https://api.kadoa.com/v4/workflows
  {
    "urls": ["https://sandbox.kadoa.com/ecommerce"],
    "name": "Product Catalog",
    "userPrompt": "Extract all products. Click 'Next' to continue through pagination. For each product, open the detail page and extract the full description and specifications.",
    "entity": "Product",
    "fields": [
      { "name": "title", "dataType": "STRING", "description": "Product name" },
      { "name": "price", "dataType": "MONEY", "description": "Product price" },
      { "name": "description", "dataType": "STRING", "description": "Full description" },
      { "name": "specifications", "dataType": "STRING", "description": "Technical specs" }
    ]
  }
  ```
</CodeGroup>

[Learn how to write effective prompts →](/docs/workflows/prompts#writing-good-prompts)

<Note type="warning">
  Complex multi-step extractions can take significantly longer to complete (usually around an hour). We recommend avoiding waiting for results synchronously.
</Note>

## Writing Prompts

Write clear, step-by-step prompts for complex extraction tasks. The AI agent follows your prompt autonomously, handling clicks, forms, pagination, and file downloads.

[Learn how to write effective prompts →](/docs/workflows/prompts#writing-good-prompts)

## Create from a Template

If your team has [templates](/docs/templates) set up, you can create a workflow and link it to a template. The template's prompt, schema, and notification settings are applied to the workflow.

<CodeGroup>
  ```text MCP Server theme={null}
  > "Create a workflow from the 'Job Listing' template for https://example.com/careers"
  ```

  ```javascript REST API theme={null}
  // Step 1: Create the workflow as usual
  // POST https://api.kadoa.com/v4/workflows
  {
    "urls": ["https://example.com/careers"],
    "name": "Example Careers"
  }

  // Step 2: Link it to a template (applies template config)
  // POST https://api.kadoa.com/v4/templates/template-123/link
  {
    "workflowIds": ["workflow-456"]
  }
  ```
</CodeGroup>

Linking applies the template's latest version. The template-managed parts become read-only on the workflow. See [Templates](/docs/sdk/templates/overview) for full details.

## Next Steps

* [Manage Workflows →](/docs/sdk/workflows/manage) - List, retrieve, pause, and delete workflows
* [Schedule & Run Workflows →](/docs/sdk/workflows/scheduling) - Configure intervals, manual execution, and check status
* [Writing Prompts →](/docs/workflows/prompts) - Write effective prompts for complex extraction tasks
* [Working with Schemas →](/docs/sdk/schemas/overview) - Create and manage reusable schemas
* [Templates →](/docs/sdk/templates/overview) - Reuse configurations across workflows
* [Data Delivery →](/docs/integrations/overview) - Retrieve extracted data
* [API Reference →](/api-reference/workflows/create-a-new-workflow)
