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

# Quickstart

> Create a run, wait for completion, and retrieve the result

Every Web Search Agent task follows the same three steps: **create** a run, **wait** for it to complete, and **retrieve** the result. This page walks through the full loop.

You need an API key from the [Nimble Platform](https://online.nimbleway.com) and a client:

<CodeGroup>
  ```bash Python theme={"system"}
  pip install nimble_python
  ```

  ```bash TypeScript theme={"system"}
  npm install @nimble-way/nimble-js
  ```

  ```bash Go theme={"system"}
  go get github.com/Nimbleway/nimble-go@latest
  ```

  ```bash CLI theme={"system"}
  npm install -g @nimble-way/nimble-cli
  export NIMBLE_API_KEY="YOUR-API-KEY"
  ```
</CodeGroup>

<Steps>
  <Step title="Create a run">
    Send the task in plain language. `agents.run` generates an agent with default settings (`research` mode, `high` [effort](/nimble-sdk/web-search-agents/efforts)) and starts the run asynchronously:

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

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

      run = nimble.agents.run(
          input=(
              "Compare the pricing and positioning of Datadog, Grafana Cloud, "
              "and New Relic for a mid-size SaaS team."
          ),
      )
      ```

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

      const nimble = new Nimble({ apiKey: process.env.NIMBLE_API_KEY });

      const run = await nimble.agents.run({
        input:
          "Compare the pricing and positioning of Datadog, Grafana Cloud, " +
          "and New Relic for a mid-size SaaS team.",
      });
      ```

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

      import (
          "context"
          "fmt"

          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()

          run, err := client.Agents.Run(ctx, nimble.AgentRunParams{
              Input: "Compare the pricing and positioning of Datadog, Grafana Cloud, " +
                  "and New Relic for a mid-size SaaS team.",
          })
          if err != nil {
              panic(err)
          }
          fmt.Println(run.ID, run.Status)
      }
      ```

      ```bash CLI theme={"system"}
      RUN=$(nimble agents run \
        --input "Compare the pricing and positioning of Datadog, Grafana Cloud, and New Relic for a mid-size SaaS team.")

      RUN_ID=$(echo "$RUN" | jq -r .id)
      AGENT_ID=$(echo "$RUN" | jq -r .web_search_agent_id)
      ```

      ```bash cURL theme={"system"}
      curl -X POST 'https://sdk.nimbleway.com/v2/agents/runs' \
        --header 'Authorization: Bearer <YOUR-API-KEY>' \
        --header 'Content-Type: application/json' \
        --data '{
          "input": "Compare the pricing and positioning of Datadog, Grafana Cloud, and New Relic for a mid-size SaaS team."
        }'
      ```
    </CodeGroup>

    The response contains the run id and the generated agent's id. Both are needed to poll and fetch the result:

    ```json theme={"system"}
    {
      "id": "task_run_01j9x8...",
      "web_search_agent_id": "wsa_01j9x8...",
      "status": "queued",
      "is_active": true,
      "effort": "high",
      "created_at": "2026-07-22T10:15:00Z"
    }
    ```

    <Tip>
      Add an `output_schema` to the request to get structured JSON back instead of prose. See [Dataset Building](/nimble-sdk/web-search-agents/use-cases/dataset-building).
    </Tip>
  </Step>

  <Step title="Wait for completion">
    Poll while `is_active` is true. Alternatively, create the run with `enable_events: true` and stream `GET .../runs/{run_id}/events` as [server-sent events](/api-reference/public-api/stream-agent-run-events):

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

      agent_id = run.web_search_agent_id

      while run.is_active:
          time.sleep(10)
          run = nimble.agents.runs.get(run.id, agent_id=agent_id)
      print(run.status)  # completed
      ```

      ```typescript TypeScript theme={"system"}
      const agentId = run.web_search_agent_id;

      let polled = run;
      while (polled.is_active) {
        await new Promise((r) => setTimeout(r, 10000));
        polled = await nimble.agents.runs.get(run.id, { agent_id: agentId });
      }
      console.log(polled.status); // completed
      ```

      ```go Go theme={"system"}
      for run.IsActive {
          time.Sleep(10 * time.Second)
          polled, err := client.Agents.Runs.Get(ctx, run.ID, nimble.AgentRunGetParams{
              AgentID: run.WebSearchAgentID,
          })
          if err != nil {
              panic(err)
          }
          run.IsActive = polled.IsActive
      }
      ```

      ```bash CLI theme={"system"}
      nimble agents:runs get --agent-id "$AGENT_ID" --run-id "$RUN_ID"
      # repeat while "is_active" is true
      ```

      ```bash cURL theme={"system"}
      curl "https://sdk.nimbleway.com/v2/agents/$AGENT_ID/runs/$RUN_ID" \
        --header 'Authorization: Bearer <YOUR-API-KEY>'
      ```
    </CodeGroup>
  </Step>

  <Step title="Retrieve the result">
    <CodeGroup>
      ```python Python theme={"system"}
      result = nimble.agents.runs.result(run.id, agent_id=agent_id)

      print(result.output.content)             # the answer
      print(result.output.trust.confidence)    # high / medium / low
      for claim in result.output.trust.claims:
          print(claim.citations[0].url)        # sources behind each claim
      ```

      ```typescript TypeScript theme={"system"}
      const result = await nimble.agents.runs.result(run.id, { agent_id: agentId });

      if ("output" in result) {
        console.log(result.output.content);          // the answer
        console.log(result.output.trust.confidence); // high / medium / low
        for (const claim of result.output.trust.claims) {
          console.log(claim.citations[0].url);       // sources behind each claim
        }
      }
      ```

      ```go Go theme={"system"}
      result, err := client.Agents.Runs.Result(ctx, run.ID, nimble.AgentRunResultParams{
          AgentID: run.WebSearchAgentID,
      })
      if err != nil {
          panic(err)
      }
      fmt.Println(result.Output.Content.OfString) // the answer
      fmt.Println(result.Output.Trust.Confidence) // high / medium / low
      ```

      ```bash CLI theme={"system"}
      nimble agents:runs result --agent-id "$AGENT_ID" --run-id "$RUN_ID"
      ```

      ```bash cURL theme={"system"}
      curl "https://sdk.nimbleway.com/v2/agents/$AGENT_ID/runs/$RUN_ID/result" \
        --header 'Authorization: Bearer <YOUR-API-KEY>'
      ```
    </CodeGroup>

    The output contains the answer and its trust report:

    ```text theme={"system"}
    Datadog anchors the premium end of the market, with Pro pricing from
    $15 per host per month [1]. Grafana Cloud undercuts it with a free
    tier and usage-based pricing [2], positioning itself for teams that
    want to start small...
    ```

    Every `[n]` maps to a claim in `trust.claims`, with source URLs, verbatim excerpts, and a confidence grade. See [Trust](/nimble-sdk/web-search-agents/trust).

    <Note>
      Fetching the result while the run is still active returns `409` — keep polling. A `failed` run returns `422` with error details.
    </Note>
  </Step>
</Steps>

## Run lifecycle

| Status      | Meaning                                                                 |
| ----------- | ----------------------------------------------------------------------- |
| `queued`    | Accepted, waiting to start                                              |
| `running`   | The agent is working — `is_active` is `true`                            |
| `completed` | The result is ready at `.../result`                                     |
| `failed`    | The run stopped with an error — `.../result` returns `422` with details |
| `cancelled` | The run was stopped before completion                                   |

## Follow-up runs

Every run carries an `interaction_id`. Pass it as `previous_interaction_id` on the next run to continue the same task with full context — a follow-up question, a refinement, or a drill-down:

<CodeGroup>
  ```python Python theme={"system"}
  followup = nimble.agents.runs.create(
      agent_id,
      input="Now break down the enterprise tiers only.",
      previous_interaction_id=run.interaction_id,
  )
  ```

  ```typescript TypeScript theme={"system"}
  const followup = await nimble.agents.runs.create(agentId, {
    input: "Now break down the enterprise tiers only.",
    previous_interaction_id: run.interaction_id,
  });
  ```

  ```go Go theme={"system"}
  followup, err := client.Agents.Runs.New(ctx, agentID, nimble.AgentRunNewParams{
      Input:                 "Now break down the enterprise tiers only.",
      PreviousInteractionID: param.NewOpt(run.InteractionID),
  })
  ```

  ```bash CLI theme={"system"}
  nimble agents:runs create \
    --agent-id "$AGENT_ID" \
    --input "Now break down the enterprise tiers only." \
    --previous-interaction-id "$INTERACTION_ID"
  ```

  ```bash cURL theme={"system"}
  curl -X POST "https://sdk.nimbleway.com/v2/agents/$AGENT_ID/runs" \
    --header 'Authorization: Bearer <YOUR-API-KEY>' \
    --header 'Content-Type: application/json' \
    --data '{
      "input": "Now break down the enterprise tiers only.",
      "previous_interaction_id": "'$INTERACTION_ID'"
    }'
  ```
</CodeGroup>

## Create a persistent agent

`agents.run` generates a one-off agent with default settings. For recurring tasks, create a persistent agent with a skill, goals, sources, and a default effort. A persistent agent keeps its memory across runs and improves over time:

<CodeGroup>
  ```python Python theme={"system"}
  agent = nimble.agents.create(
      display_name="SaaS Pricing Watcher",
      skill="SaaS pricing analyst: compare tiers, flag recent changes, cite vendor pages.",
      goals=[
          "Compare pricing tiers with plan names and price ranges",
          "Call out pricing changes announced in the last quarter",
      ],
      sources={
          "prioritize": "official vendor pricing pages over third-party summaries",
          "block": [{"title": "Aggregators", "domains": ["g2.com"]}],
      },
      effort="x-high",
  )
  ```

  ```typescript TypeScript theme={"system"}
  const agent = await nimble.agents.create({
    display_name: "SaaS Pricing Watcher",
    skill: "SaaS pricing analyst: compare tiers, flag recent changes, cite vendor pages.",
    goals: [
      "Compare pricing tiers with plan names and price ranges",
      "Call out pricing changes announced in the last quarter",
    ],
    sources: {
      prioritize: "official vendor pricing pages over third-party summaries",
      block: [{ title: "Aggregators", domains: ["g2.com"] }],
    },
    effort: "x-high",
  });
  ```

  ```go Go theme={"system"}
  agent, err := client.Agents.New(ctx, nimble.AgentNewParams{
      DisplayName: param.NewOpt("SaaS Pricing Watcher"),
      Skill:       param.NewOpt("SaaS pricing analyst: compare tiers, flag recent changes, cite vendor pages."),
      Goals: []string{
          "Compare pricing tiers with plan names and price ranges",
          "Call out pricing changes announced in the last quarter",
      },
      Sources: nimble.AgentNewParamsSources{
          Prioritize: param.NewOpt("official vendor pricing pages over third-party summaries"),
          Block: []nimble.AgentNewParamsSourcesBlock{
              {Title: "Aggregators", Domains: []string{"g2.com"}},
          },
      },
      Effort: nimble.AgentNewParamsEffortXHigh,
  })
  ```

  ```bash CLI theme={"system"}
  nimble agents create \
    --display-name "SaaS Pricing Watcher" \
    --skill "SaaS pricing analyst: compare tiers, flag recent changes, cite vendor pages." \
    --goal "Compare pricing tiers with plan names and price ranges" \
    --goal "Call out pricing changes announced in the last quarter" \
    --sources '{prioritize: "official vendor pricing pages over third-party summaries", block: [{title: "Aggregators", domains: ["g2.com"]}]}' \
    --effort x-high
  ```

  ```bash cURL theme={"system"}
  curl -X POST 'https://sdk.nimbleway.com/v2/agents' \
    --header 'Authorization: Bearer <YOUR-API-KEY>' \
    --header 'Content-Type: application/json' \
    --data '{
      "display_name": "SaaS Pricing Watcher",
      "skill": "SaaS pricing analyst: compare tiers, flag recent changes, cite vendor pages.",
      "goals": [
        "Compare pricing tiers with plan names and price ranges",
        "Call out pricing changes announced in the last quarter"
      ],
      "sources": {
        "prioritize": "official vendor pricing pages over third-party summaries",
        "block": [{"title": "Aggregators", "domains": ["g2.com"]}]
      },
      "effort": "x-high"
    }'
  ```
</CodeGroup>

## Next Steps

<CardGroup cols={3}>
  <Card title="Trust" icon="badge-check" href="/nimble-sdk/web-search-agents/trust">
    Per-claim citations and confidence grades
  </Card>

  <Card title="Use Cases" icon="lightbulb" href="/nimble-sdk/web-search-agents/use-cases/research">
    Research, Enrichment, and Dataset Building
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/introduction">
    Every endpoint, field, and response
  </Card>
</CardGroup>
