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

# Extract Jobs

> Run any Extract Template on a schedule or on demand — at scale, hands-off.

Nimble **Jobs** turn any Extract Template into a managed, repeatable workload. Point a job at a template, hand it a list of inputs (CSV, Parquet, or JSON), pick a schedule — and Nimble runs the template across every input on cadence, tracks every execution, and delivers structured results to you.

Jobs are the right tool when you need to run a template across **thousands or millions of inputs**, on a recurring basis, without writing orchestration code. Think daily price refreshes across your full SKU catalog, hourly SERP monitoring across thousands of keywords, or weekly competitor sweeps across every product page you care about.

Create and manage jobs either in the [Nimble Platform](https://online.nimbleway.com/jobs) or programmatically through the [Jobs API](/api-reference/jobs/create-job) — both read and write the same jobs, so you can switch between them at any time.

<CardGroup cols={3}>
  <Card title="Open Jobs" icon="play" href="https://online.nimbleway.com/jobs">
    Create your first job in the Nimble Platform — no coding required
  </Card>

  <Card title="Jobs API" icon="code" href="/api-reference/jobs/create-job">
    Drive jobs from code, the terminal, or CI/CD pipelines
  </Card>

  <Card title="Browse Templates" icon="grid" href="/nimble-sdk/agentic/agent-gallery">
    Pick a pre-built template or bring your own custom template
  </Card>
</CardGroup>

## Quick Start

Create a job, trigger a run, wait for it to finish, and download the results. Every step maps to a [Jobs API](/api-reference/jobs/create-job) endpoint.

### Example Request

<CodeGroup>
  ```python Python theme={"system"}
  import time
  from nimble_python import Nimble

  nimble = Nimble(api_key="YOUR-API-KEY")

  # 1. Create a job — bind a template to inputs, a destination, and a schedule
  job = nimble.jobs.create(
      name="daily_amazon_top_skus",
      extract_template_name="amazon_pdp",
      schedule={"cron": "0 7 * * *", "enabled": True},
      inputs={
          "type": "inline",
          "data": [{"asin": "B08N5WRWNW"}, {"asin": "B0DLKFK6LR"}],
      },
      destination={
          "type": "s3",
          "path": "s3://my-bucket/amazon-skus/",
          "format": "parquet",
      },
  )

  # 2. Trigger a run now (on top of any schedule)
  run = nimble.jobs.runs.create(job.id)

  # 3. Poll until the run reaches a terminal state
  status = run.status
  while status in ("PENDING", "RUNNING"):
      time.sleep(10)
      status = nimble.jobs.runs.get(run.id).status

  # 4. Download the assembled results
  artifacts = nimble.jobs.runs.artifacts.list(run.id)
  download = nimble.jobs.runs.artifacts.download_url(
      int(artifacts.items[0].id),
      run_id=run.id,
  )
  print(download.url)
  ```

  ```typescript TypeScript theme={"system"}
  import Nimble from "@nimble-way/nimble-js";

  const nimble = new Nimble({ apiKey: "YOUR-API-KEY" });

  // 1. Create a job — bind a template to inputs, a destination, and a schedule
  const job = await nimble.jobs.create({
    name: "daily_amazon_top_skus",
    extract_template_name: "amazon_pdp",
    schedule: { cron: "0 7 * * *", enabled: true },
    inputs: {
      type: "inline",
      data: [{ asin: "B08N5WRWNW" }, { asin: "B0DLKFK6LR" }],
    },
    destination: {
      type: "s3",
      path: "s3://my-bucket/amazon-skus/",
      format: "parquet",
    },
  });

  // 2. Trigger a run now (on top of any schedule)
  const run = await nimble.jobs.runs.create(job.id);

  // 3. Poll until the run reaches a terminal state
  let status: string = run.status;
  while (status === "PENDING" || status === "RUNNING") {
    await new Promise((r) => setTimeout(r, 10000));
    status = (await nimble.jobs.runs.get(run.id)).status;
  }

  // 4. Download the assembled results
  const artifacts = await nimble.jobs.runs.artifacts.list(run.id);
  const download = await nimble.jobs.runs.artifacts.downloadURL(
    Number(artifacts.items[0].id),
    { run_id: run.id },
  );
  console.log(download.url);
  ```

  ```go Go theme={"system"}
  package main

  import (
      "context"
      "fmt"
      "strconv"
      "time"

      nimble "github.com/Nimbleway/nimble-go"
      "github.com/Nimbleway/nimble-go/option"
  )

  func main() {
      client := nimble.NewClient(option.WithAPIKey("YOUR-API-KEY"))
      ctx := context.Background()

      // 1. Create a job — bind a template to inputs, a destination, and a schedule
      job, err := client.Jobs.New(ctx, nimble.JobNewParams{
          Name:                "daily_amazon_top_skus",
          ExtractTemplateName: "amazon_pdp",
          Schedule:            nimble.JobNewParamsSchedule{Cron: "0 7 * * *", Enabled: true},
          Inputs: nimble.JobNewParamsInputs{
              Type: "inline",
              Data: []map[string]any{{"asin": "B08N5WRWNW"}, {"asin": "B0DLKFK6LR"}},
          },
          Destination: nimble.JobNewParamsDestination{
              Type:   "s3",
              Path:   "s3://my-bucket/amazon-skus/",
              Format: "parquet",
          },
      })
      if err != nil {
          panic(err)
      }

      // 2. Trigger a run now (on top of any schedule)
      run, err := client.Jobs.Runs.New(ctx, job.ID)
      if err != nil {
          panic(err)
      }

      // 3. Poll until the run reaches a terminal state
      status := string(run.Status)
      for status == "PENDING" || status == "RUNNING" {
          time.Sleep(10 * time.Second)
          polled, err := client.Jobs.Runs.Get(ctx, run.ID)
          if err != nil {
              panic(err)
          }
          status = string(polled.Status)
      }

      // 4. Download the assembled results
      artifacts, err := client.Jobs.Runs.Artifacts.List(ctx, run.ID)
      if err != nil {
          panic(err)
      }
      artifactID, _ := strconv.ParseInt(artifacts.Items[0].ID, 10, 64)
      download, err := client.Jobs.Runs.Artifacts.DownloadURL(ctx, artifactID,
          nimble.JobRunArtifactDownloadURLParams{RunID: run.ID})
      if err != nil {
          panic(err)
      }
      fmt.Println(download.URL)
  }
  ```

  ```bash CLI theme={"system"}
  # 1. Create a job
  JOB_ID=$(nimble jobs create   --name daily_amazon_top_skus   --extract-template-name amazon_pdp   --schedule '{cron: "0 7 * * *", enabled: true}'   --inputs '{type: inline, data: [{asin: B08N5WRWNW}, {asin: B0DLKFK6LR}]}'   --destination '{type: s3, path: "s3://my-bucket/amazon-skus/", format: parquet}'   | jq -r .id)

  # 2. Trigger a run now (on top of any schedule)
  RUN_ID=$(nimble jobs:runs create --job-id "$JOB_ID" | jq -r .id)

  # 3. Poll until the run reaches a terminal state
  nimble jobs:runs get --run-id "$RUN_ID"

  # 4. Download the assembled results
  nimble jobs:runs:artifacts list --run-id "$RUN_ID"
  nimble jobs:runs:artifacts download-url --run-id "$RUN_ID" --artifact-id 7
  ```

  ```bash cURL theme={"system"}
  # 1. Create a job
  curl -X POST 'https://sdk.nimbleway.com/v2/jobs' \
  --header 'Authorization: Bearer YOUR-API-KEY' \
  --header 'Content-Type: application/json' \
  --data-raw '{
      "name": "daily_amazon_top_skus",
      "extract_template_name": "amazon_pdp",
      "schedule": {"cron": "0 7 * * *", "enabled": true},
      "inputs": {
        "type": "inline",
        "data": [{"asin": "B08N5WRWNW"}, {"asin": "B0DLKFK6LR"}]
      },
      "destination": {
        "type": "s3",
        "path": "s3://my-bucket/amazon-skus/",
        "format": "parquet"
      }
  }'

  # 2. Trigger a run (returns a run with id "run_<n>")
  curl -X POST 'https://sdk.nimbleway.com/v2/jobs/job_42/runs' \
  --header 'Authorization: Bearer YOUR-API-KEY'

  # 3. Poll the run until status is SUCCESS
  curl -X GET 'https://sdk.nimbleway.com/v2/jobs/runs/run_1204' \
  --header 'Authorization: Bearer YOUR-API-KEY'

  # 4. Get a presigned download URL for an artifact
  curl -X GET 'https://sdk.nimbleway.com/v2/jobs/runs/run_1204/artifacts/7/download-url' \
  --header 'Authorization: Bearer YOUR-API-KEY'
  ```
</CodeGroup>

### Example Response

Creating a job returns a [`Job`](/api-reference/jobs/create-job) resource. Use its `id` (formatted `job_<n>`) for every follow-up call.

```json theme={"system"}
{
  "id": "job_42",
  "name": "daily_amazon_top_skus",
  "extract_template_name": "amazon_pdp",
  "schedule": { "cron": "0 7 * * *", "enabled": true },
  "inputs": { "type": "inline", "data": [{ "asin": "B08N5WRWNW" }] },
  "destination": {
    "type": "s3",
    "path": "s3://my-bucket/amazon-skus/",
    "format": "parquet"
  },
  "last_run_at": null,
  "last_run_status": null,
  "created_at": "2026-06-17T09:00:00Z",
  "updated_at": "2026-06-17T09:00:00Z"
}
```

## How it works

<Steps>
  <Step title="You define the job once">
    A job binds together a **template**, an **input set**, a **destination**, and a **trigger** (manual or scheduled). Once created, a job is a stable, named workload you can run again and again with the same configuration.
  </Step>

  <Step title="Nimble fans out runs across your inputs">
    Each execution of a job is a **run**. A run reads every row from your input set and dispatches one template invocation per row in parallel. Nimble handles concurrency, retries, anti-bot handling, and result aggregation — you don't manage workers, queues, or rate limits.
  </Step>

  <Step title="Results land in structured artifacts">
    When the run completes, Nimble assembles the per-row results into **artifacts** — the input set, the valid output rows, and the invalid output rows — downloadable as JSON, CSV, or Parquet, with success rate, completeness, and error samples surfaced per run.
  </Step>

  <Step title="The schedule keeps it fresh">
    For scheduled jobs, Nimble triggers a new run on every tick of the cadence. Each run is independent — same configuration, fresh data — so monitoring dashboards, downstream pipelines, and time-series comparisons stay current without any manual work.
  </Step>
</Steps>

## Manage Jobs programmatically

Everything you can do in the UI is available through the [Jobs API](/api-reference/jobs/create-job) — create, list, update, and delete jobs; trigger and cancel runs; and list, preview, or download artifacts.

<CardGroup cols={2}>
  <Card title="Jobs API Reference" icon="code" href="/api-reference/jobs/create-job">
    Full endpoint, parameter, and schema reference for every Jobs operation
  </Card>

  <Card title="Job Connections" icon="plug" href="/nimble-sdk/agentic/jobs-connections">
    Wire a Job's input source and destination to your S3 or Databricks storage
  </Card>
</CardGroup>

All requests use Bearer-token authentication against the base URL `https://sdk.nimbleway.com`:

```bash theme={"system"}
Authorization: Bearer YOUR-API-KEY
```

The most common endpoints:

| Action | Endpoint |
| - | - |
| Create a job | `POST /v2/jobs` |
| List jobs | `GET /v2/jobs` |
| Get / update / delete a job | `GET` · `PATCH` · `DELETE /v2/jobs/{job_id}` |
| Trigger a run | `POST /v2/jobs/{job_id}/runs` |
| List runs / get a run | `GET /v2/jobs/{job_id}/runs` · `GET /v2/jobs/runs/{run_id}` |
| Cancel a run | `POST /v2/jobs/runs/{run_id}/cancel` |
| List / preview / download artifacts | `GET /v2/jobs/runs/{run_id}/artifacts...` |

<Tip>
  Editing a job mid-run is safe — updates take effect on the next run, and runs already in progress finish on the old configuration. Calling **Trigger Run** on a scheduled job kicks off an extra run without affecting the cron cadence.
</Tip>

## Using the Nimble Platform

The [Jobs page](https://online.nimbleway.com/jobs) provides the same capabilities with no code. Click **Create Job** to get started.

<Steps>
  <Step title="Open Jobs">
    Go to [online.nimbleway.com/jobs](https://online.nimbleway.com/jobs) and click **Create Job**.
  </Step>

  <Step title="Pick a template">
    Choose any pre-built template (e.g., `amazon_pdp`, `google_search`, `chatgpt`) or one of your custom templates.
  </Step>

  <Step title="Provide inputs">
    Upload a CSV/Parquet file or paste a JSON array of inputs — one entry per template run.
  </Step>

  <Step title="Set the schedule">
    Choose **Manual Trigger Only** for on-demand runs, or **Schedule** to run every day, week, month, at a specific time, or on a custom cron expression.
  </Step>

  <Step title="Run and collect results">
    Trigger the first run manually or wait for the schedule. Download structured results as JSON, CSV, or Parquet from the run page.
  </Step>
</Steps>

### Creating a Job

The **Create Job** panel has five sections. Only Job Title, Template, and Inputs are required — everything else has sensible defaults.

#### Job Title

A human-readable name for the job. This is what you'll see in the jobs list, in run logs, and in delivered file names. Pick something descriptive — e.g., `daily-amazon-top-1000-skus` or `hourly-google-serp-priority-keywords`.

#### Template

Select the Extract Template that the job will run. Any template available in your workspace can be used:

* **Pre-built templates** from the [Gallery](/nimble-sdk/agentic/agent-gallery) (e.g., `amazon_pdp`, `google_search`, `chatgpt`, `tiktok_account`).
* **Custom templates** you've built in [Ask Nimble](https://online.nimbleway.com/workflow-builder).

A job runs exactly one template. To run multiple templates over the same input set, create one job per template.

#### Inputs

The input set defines **what the template runs against**. Each entry in the input set becomes one template invocation in every run. Jobs support four input modes:

<ParamField path="File" type="upload">
  Upload a **CSV** or **Parquet** file. Each row is one template invocation; column names must match the template's input parameters (e.g., a column `asin` for `amazon_pdp`, or `keyword` for `amazon_serp`).

  Use **Download example CSV** in the Create Job panel to get a template pre-filled with the correct columns for the selected template.
</ParamField>

<ParamField path="JSON Text" type="textarea">
  Paste a JSON array of input objects directly. Each object's keys must match the template's input parameters. Best for quick tests or smaller, ad-hoc input sets.

  ```json theme={"system"}
  [
    { "asin": "B08N5WRWNW" },
    { "asin": "B0DLKFK6LR" },
    { "asin": "B09XS7JWHH" }
  ]
  ```
</ParamField>

<ParamField path="S3 Bucket" type="s3">
  Point the job at a CSV, JSON, or Parquet file in your S3 bucket so the input set is read at run time. The path can also point to a folder - the latest file under that prefix (by `LastModified`) is used.

  Supported extensions: `.csv`, `.json`, `.parquet`.

  Grant Nimble access to the bucket via a bucket policy. See the [Amazon S3 connection](/nimble-sdk/agentic/jobs-connections/amazon-s3) for the policy template and how to apply it. Use **Test Connection** in the Job form to verify the policy.
</ParamField>

<ParamField path="Databricks" type="delta sharing">
  Read the input set directly from a table in your **Databricks Unity Catalog** via Delta Sharing. Each Job run reads the latest contents of the shared table.

  Fields: `Provider`, `Share`, `Schema`, `Table`. Set them after publishing a Delta Sharing share whose recipient is bound to Nimble's metastore (`aws:us-east-1:2f3ba1b1-429c-491f-b37d-ebb46f22f3e9`).

  See the [Databricks connection → Input](/nimble-sdk/agentic/jobs-connections/databricks#input-share-your-table-with-nimble) for the full `databricks` CLI sequence and every property.
</ParamField>

<ParamField path="Generate with AI" type="coming soon">
  Describe the input set in natural language and have Nimble generate it for you (e.g., *"the top 500 best-selling kitchen appliances on Amazon"*). Coming soon.
</ParamField>

<Tip>
  Input rows can also include the [shared params](/nimble-sdk/web-tools/extract/template#parameters) accepted by every template — `country`, `locale`, `tag`, `parse` — to control localization or tag rows for downstream filtering.
</Tip>

#### Destination

Where Nimble delivers the assembled results when each run completes.

<ParamField path="Download files" type="default">
  Results are stored on Nimble and downloadable from the run page. Each completed run produces a single file containing every successful template result for that run.
</ParamField>

<ParamField path="S3 Bucket" type="s3">
  Push results directly to your own S3 bucket as soon as a run completes. Choose any output format (JSON, CSV, or Parquet).

  Grant Nimble write access via the same bucket policy used for inputs. See [S3 bucket permissions](/nimble-sdk/agentic/jobs-connections/amazon-s3). Use **Test Connection** in the Job form to verify the policy before saving the job.
</ParamField>

<ParamField path="Databricks" type="delta sharing">
  Deliver results straight into your **Databricks Unity Catalog** as a Delta Sharing share. Each Job run refreshes the shared table; you mount it once as a UC catalog and query it like any other UC table.

  Fields: `Share name`, `Recipient name`, `Metastore ID` (your UC global metastore ID, in `<cloud>:<region>:<uuid>` form), `Shared as` (the `<schema>.<table>` alias visible on your side).

  **Retention: 14 days** from each successful run - beyond that window, the shared table is not guaranteed to remain available. To keep the data longer, materialize it into a UC table you own (see [Persisting the data](/nimble-sdk/agentic/jobs-connections/databricks#persisting-the-data)).

  See the [Databricks connection → Destination](/nimble-sdk/agentic/jobs-connections/databricks#destination-deliver-job-output-to-your-unity-catalog) for how to find your metastore ID and the `databricks` CLI sequence to mount the share.
</ParamField>

<ParamField path="Format" default="JSON" type="enum">
  Output format for the delivered file:

  * `JSON` — one JSON document per run, with all rows under a `files` array. Best for nested or unstructured template outputs.
  * `CSV` — flat tabular output, one row per template invocation. Best for spreadsheets and BI tools.
  * `Parquet` — columnar binary format. Best for analytical workloads, data lakes, and any pipeline where you'd otherwise convert CSV to Parquet later.
</ParamField>

<ParamField path="Include input" default="false" type="boolean">
  When enabled, each output row also includes the original input fields (e.g., the `asin` you submitted) alongside the parsed template result. Makes it trivial to join results back to the input set without relying on row order.
</ParamField>

#### Run On

Controls **when** the job executes.

<ParamField path="Manual Trigger Only" type="default">
  The job only runs when you click **Run** on the job page (or call the API). Use this for on-demand workloads where there's no fixed cadence — ad-hoc backfills, one-off competitor sweeps, or runs gated on an upstream event.
</ParamField>

<ParamField path="Schedule" type="cadence">
  Run the job automatically on a recurring cadence. Five preset modes are supported:

  | Cadence | Description |
  | - | - |
  | `Day` | Once every 24 hours, anchored to the job's creation time. |
  | `Week` | Once every 7 days, anchored to the job's creation time. |
  | `Month` | Once every calendar month, anchored to the job's creation date. |
  | `Day at specific time` | Once a day at a chosen time of day (HH:MM, UTC). |
  | `Custom` | A standard 5-field cron expression (UTC). e.g. `0 0 * * *` for daily at midnight UTC, `0 */6 * * *` for every 6 hours, `0 9 * * 1` for every Monday at 09:00. |

  Manually triggered runs are still allowed on scheduled jobs — pressing **Run** kicks off an extra run without affecting the schedule.
</ParamField>

### The Jobs list

The [Jobs page](https://online.nimbleway.com/jobs) shows every job in your workspace with its template, last run timestamp, and trigger type (Manual or scheduled). Use the search box to filter by job name; the list paginates server-side, so it stays responsive even with thousands of jobs.

Click any job in the list to open its detail page.

### Monitoring runs

Every job has its own detail page with two tabs.

#### Runs tab

A reverse-chronological list of every execution of the job. Each row shows:

| Column | Description |
| - | - |
| `Run ID` | Unique identifier for the run (e.g., `run_1204402`). Click to open the run detail page. |
| `Status` | `Success`, `In progress`, or `Error`. |
| `Start Time` / `End Time` | Wall-clock start and end of the run. |
| `Success Rate` | Percentage of input rows that produced a successful template result. |
| `Actions` | Direct download of the run's result file. |

#### Monitoring tab

Aggregate health and volume of the job over time:

* **Total Runs** — number of runs executed since the job was created.
* **Availability** — percentage of scheduled runs that completed (didn't fail to start).
* **Success Rate** — percentage of input rows that produced a successful template result, averaged across runs.
* **Completeness** — percentage of expected output fields that were populated, averaged across rows. A useful proxy for "is the template still healthy on this site".
* **Total Rows** — cumulative number of template invocations executed across all runs.
* **Volume Overview** — bar chart of rows per run over the recent history.

<Tip>
  Use **Completeness** as your early-warning signal. Success rate can stay at 100% even when a target site quietly stops returning a particular field — completeness will drop first.
</Tip>

#### Run detail

Clicking a Run ID opens a single run's detail page, which includes:

* **Status, # Inputs, # Results, Start Time, End Time, Job, Template** — quick metadata in the side panel.
* **Results Sample** — preview of the parsed output, plus a direct download link for the full result file.
* **Inputs Sample** — the exact input set the run executed against (useful for reproducing or debugging a specific run).
* **Errors Sample** — preview of any rows that failed, with their error reasons. Used to diagnose problems without scrolling through the full result file.

The format toggle at the top of each sample (JSON / CSV / Parquet) lets you preview the same data in any of the three supported formats.

### Header actions

From any job's detail page, three header actions control the job:

* **Run** — manually trigger a run right now. Works on both manual and scheduled jobs.
* **Edit** — open the job configuration in the same panel used to create it. Editing does not affect runs already in progress; the next run picks up the new configuration.
* **Delete** — permanently remove the job and its run history. Cannot be undone.

## Use cases

<CardGroup cols={2}>
  <Card title="Daily price & inventory refresh" icon="tag">
    Run `amazon_pdp` or `walmart_pdp` every night across your full SKU catalog. Use Parquet output and an [S3 destination](/nimble-sdk/agentic/jobs-connections/amazon-s3) to land directly in your data lake.
  </Card>

  <Card title="SERP rank tracking" icon="magnifying-glass">
    Run `google_search` hourly across your priority keywords. Track rank movement over time using the run-by-run history.
  </Card>

  <Card title="LLM answer monitoring" icon="message-bot">
    Run `chatgpt`, `perplexity`, or `gemini` daily on prompts that mention your brand or category. Watch how AI platforms describe you over time.
  </Card>

  <Card title="Competitor catalog sweeps" icon="binoculars">
    Run a custom template weekly across every competitor product page. Use **Completeness** to catch the day a competitor changes their page structure.
  </Card>
</CardGroup>

## Jobs vs other tools

| What you need | Use |
| - | - |
| Run a template **once**, on a single input | [Template.run](/nimble-sdk/web-tools/extract/template#quick-start) |
| Run a template on **a few thousand inputs**, one-time | [Template batch](/nimble-sdk/web-tools/extract/template#batch) |
| Run a template on **any size input set**, on a recurring schedule | **Jobs** |
| Get notified or have results land in cloud storage automatically | Jobs with [S3 destination](/nimble-sdk/agentic/jobs-connections/amazon-s3) or [Async + callback](/nimble-sdk/admin/callbacks-and-delivery) |

Jobs are designed for **recurring, large-scale, hands-off** work. If you're calling a template ad-hoc from your own code, the synchronous and batch APIs stay the right tool.

## Next steps

<CardGroup cols={2}>
  <Card title="Open Jobs" icon="play" href="https://online.nimbleway.com/jobs">
    Create your first job in the Nimble Platform
  </Card>

  <Card title="Jobs API" icon="code" href="/api-reference/jobs/create-job">
    Full endpoint and schema reference for driving jobs from code
  </Card>

  <Card title="Gallery" icon="grid" href="/nimble-sdk/agentic/agent-gallery">
    Browse pre-built templates to power your jobs
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.