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

# Dataset Building

> One prompt in, a verified dataset out, every cell cited

**Dataset Building** agents create structured datasets from data scattered across the web. Describe what you're looking for, define the row shape, and the agent discovers, verifies, and structures the results: no scraper to build, no site list to maintain, no deduplication pipeline. [Every cell arrives cited](/nimble-sdk/web-search-agents/trust).

## Example Request

The `business-discovery` template is tuned for local-business datasets: verified addresses, phone numbers, and ratings:

<CodeGroup>
  ```python Python theme={"system"}
  agent = nimble.agents.create(template="business-discovery")

  run = nimble.agents.runs.create(
      agent.id,
      input=(
          "Find all spas and salons in New York City, real addresses, "
          "phone numbers, and ratings from actual review sites."
      ),
  )
  ```

  ```typescript TypeScript theme={"system"}
  const agent = await nimble.agents.create({ template: "business-discovery" });

  const run = await nimble.agents.runs.create(agent.id, {
    input:
      "Find all spas and salons in New York City, real addresses, " +
      "phone numbers, and ratings from actual review sites.",
  });
  ```

  ```go Go theme={"system"}
  agent, err := client.Agents.New(ctx, nimble.AgentNewParams{
      Template: param.NewOpt("business-discovery"),
  })

  run, err := client.Agents.Runs.New(ctx, agent.ID, nimble.AgentRunNewParams{
      Input: "Find all spas and salons in New York City, real addresses, " +
          "phone numbers, and ratings from actual review sites.",
  })
  ```

  ```bash CLI theme={"system"}
  AGENT_ID=$(nimble agents create --template business-discovery | jq -r .id)

  nimble agents:runs create \
    --agent-id "$AGENT_ID" \
    --input "Find all spas and salons in New York City, real addresses, phone numbers, and ratings from actual review sites."
  ```

  ```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": "Find all spas and salons in New York City, real addresses, phone numbers, and ratings from actual review sites."
    }'
  ```
</CodeGroup>

## Example Response

The result is `type: "json"`: an array of rows matching the template's schema, each with a cited source:

```json theme={"system"}
{
  "type": "json",
  "content": [
    {
      "business_name": "Haven Spa",
      "address": "150 Mercer St, New York, NY 10012",
      "phone_number": "+1 212-555-0181",
      "website": "https://havenspanyc.com",
      "rating": "4.6",
      "review_count": "412",
      "category": "Day spa",
      "source_url": "https://www.yelp.com/biz/haven-spa-new-york"
    }
  ]
}
```

Each value carries a per-path claim in the trust report:

```json theme={"system"}
{
  "path": "$[0].phone_number",
  "confidence": "high",
  "reasoning": "Supported by 2 independent sources",
  "citations": [
    { "url": "https://www.yelp.com/biz/haven-spa-new-york", "excerpts": ["(212) 555-0181"] },
    { "url": "https://havenspanyc.com/contact", "excerpts": ["Call us: (212) 555-0181"] }
  ]
}
```

The dataset gets a deterministic overall grade, the lower of its **cell fill rate** and its **per-claim trust ratio**, stated in the run's trust reasoning: *"High confidence - cells fill rate is 96% and trust per claim ratio is 91%"*. A verifiably empty cell (a business with no website) comes back as a cited `null` graded `high`: [verified absence](/nimble-sdk/web-search-agents/trust#trust-for-structured-outputs).

## Custom output schema

Define your own row shape on the agent or per run. Filters in the input are treated as hard constraints. The `company-discovery` template's first goal is *"Treat user filters (location, vertical, size, funding) as hard constraints, never dilute to inflate volume."*

Schemas must follow the hard limits below. Invalid schemas return **422** at request time.

<CodeGroup>
  ```python Python theme={"system"}
  run = nimble.agents.runs.create(
      agent.id,
      input=(
          "Find SF tech companies that have adopted AI agents and have active "
          "engineering teams, potential CRM leads, explaining why each qualifies."
      ),
      output_schema={
          "type": "object",
          "properties": {
              "leads": {
                  "type": "array",
                  "items": {
                      "type": "object",
                      "properties": {
                          "company": {"type": "string"},
                          "why_qualified": {"type": "string"},
                          "engineering_signal": {"type": "string"},
                      },
                  },
              }
          },
      },
  )
  ```

  ```typescript TypeScript theme={"system"}
  const run = await nimble.agents.runs.create(agent.id, {
    input:
      "Find SF tech companies that have adopted AI agents and have active " +
      "engineering teams, potential CRM leads, explaining why each qualifies.",
    output_schema: {
      type: "object",
      properties: {
        leads: {
          type: "array",
          items: {
            type: "object",
            properties: {
              company: { type: "string" },
              why_qualified: { type: "string" },
              engineering_signal: { type: "string" },
            },
          },
        },
      },
    },
  });
  ```

  ```go Go theme={"system"}
  run, err := client.Agents.Runs.New(ctx, agent.ID, nimble.AgentRunNewParams{
      Input: "Find SF tech companies that have adopted AI agents and have active " +
          "engineering teams, potential CRM leads, explaining why each qualifies.",
      OutputSchema: map[string]any{
          "type": "object",
          "properties": map[string]any{
              "leads": map[string]any{
                  "type": "array",
                  "items": map[string]any{
                      "type": "object",
                      "properties": map[string]any{
                          "company":            map[string]any{"type": "string"},
                          "why_qualified":      map[string]any{"type": "string"},
                          "engineering_signal": map[string]any{"type": "string"},
                      },
                  },
              },
          },
      },
  })
  ```

  ```bash CLI theme={"system"}
  nimble agents:runs create \
    --agent-id "$AGENT_ID" \
    --input "Find SF tech companies that have adopted AI agents and have active engineering teams, potential CRM leads, explaining why each qualifies." \
    --output-schema '{type: object, properties: {leads: {type: array, items: {type: object, properties: {company: {type: string}, why_qualified: {type: string}, engineering_signal: {type: string}}}}}}'
  ```

  ```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": "Find SF tech companies that have adopted AI agents and have active engineering teams, potential CRM leads, explaining why each qualifies.",
      "output_schema": {
        "type": "object",
        "properties": {
          "leads": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "company":            {"type": "string"},
                "why_qualified":      {"type": "string"},
                "engineering_signal": {"type": "string"}
              }
            }
          }
        }
      }
    }'
  ```
</CodeGroup>

## Output schema limits

### Allowed roots

The root must be one of:

* An **object** with non-empty `properties`
* An **array of objects** (`items.type` must be `"object"` with `properties`)

Omit `output_schema` (or pass `{}`) to let the generator infer the shape from the prompt.

### Supported examples

**Object root with nullable fields:**

```json theme={"system"}
{
  "type": "object",
  "properties": {
    "company_name": { "type": "string" },
    "website": { "type": ["string", "null"] }
  }
}
```

**Array root (table shape):**

```json theme={"system"}
{
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "company_name": { "type": "string" },
      "hq_city": { "type": ["string", "null"] }
    }
  }
}
```

**Nested array of objects:**

```json theme={"system"}
{
  "type": "object",
  "properties": {
    "key_contacts": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "email": { "type": ["string", "null"] }
        }
      }
    }
  }
}
```

### Rejected patterns

The API returns **422** when a schema violates these hard limits:

| Limit | Rule |
| - | - |
| Root shape | No scalar roots, empty objects, or root `anyOf` |
| Array root | Must be an array of objects, not primitives |
| Nullable fields | Use `{"type": ["string", "null"]}`, not standalone `{"type": "null"}` |
| Nesting depth | At most **5** levels (objects and arrays count) |
| Property count | At most **100** properties across all levels |
| Enum size | At most **500** enum values total; enums with more than 250 values are also capped at 7,500 combined characters |
| Unsupported keywords | `format`, `pattern`, `minLength`, `maxLength`, `minimum`, `maximum`, `multipleOf`, `minItems`, `maxItems`, `uniqueItems`, `minProperties`, `maxProperties`, `patternProperties`, `propertyNames`, `contains`, `minContains`, `maxContains`, `unevaluatedItems`, `unevaluatedProperties` |

Move validation constraints into field `description` text instead of JSON Schema keywords.

**Unsupported examples:**

```json theme={"system"}
{ "type": "array", "items": { "type": "string" } }
```

```json theme={"system"}
{
  "type": "object",
  "properties": {
    "email": { "type": "string", "format": "email" }
  }
}
```

```json theme={"system"}
{
  "type": "object",
  "properties": {
    "x": { "type": "null" }
  }
}
```

```json theme={"system"}
{
  "type": "object",
  "properties": { "name": { "type": "string" } },
  "anyOf": [{ "required": ["name"] }]
}
```

### Still accepted

These are **not** hard-failed:

* `required` arrays on objects
* `additionalProperties: false`
* Nested `anyOf` / `oneOf` for nullability (not at the root)
* Enums within the size limits above
* Nested arrays of objects or primitives under an object root

### Field maps are invalid

Each field must be a JSON Schema subschema, not a bare type string:

```json theme={"system"}
{ "properties": { "city": { "type": "string" } } }
```

Not:

```json theme={"system"}
{ "city": "string" }
```

### Agent generation behavior

When creating or updating a Web Search Agent, the design path can infer and sanitize a schema from your goals and template. The generator strips unsupported keywords and fixes common mistakes (such as standalone `null`) before validation.

When you pass an explicit `output_schema` on create, update, or run, it is validated immediately. Fix the schema and retry on **422**.

### Common validation errors

| Error fragment | Cause |
| - | - |
| `must not use "anyOf"` | Root-level `anyOf` |
| `array of objects` | Root array whose `items` is not an object |
| `standalone "null" type` | Property typed as `"null"` alone |
| `unsupported keyword(s)` | A rejected keyword such as `format` or `pattern` |
| `nesting depth` | More than 5 nested object/array levels |
| `maximum of 100 properties` | Too many properties across the schema |
| `non-empty "properties"` | Object root with missing or empty `properties` |
| `declares nothing to write` | Field map syntax instead of proper subschemas |

Example **422** response:

```json theme={"system"}
{
  "detail": [
    {
      "type": "value_error",
      "loc": ["body", "output_schema"],
      "msg": "Value error, output_schema uses unsupported keyword(s): format. Remove them (or move constraints into field descriptions).",
      "input": {
        "type": "object",
        "properties": {
          "email": { "type": "string", "format": "email" }
        }
      }
    }
  ]
}
```

## Run it on a schedule

A dataset run produces a snapshot. To turn it into a recurring feed, point a [Job](/nimble-sdk/agentic/jobs) at the same agent with a list of inputs (one per market, category, or account), and Nimble runs it on a schedule and delivers results to S3, Databricks, or your warehouse.

## Templates

| Template | Built for |
| - | - |
| `business-discovery` | Local businesses with verified contact details and ratings |
| `company-discovery` | Companies matching hard filters: location, vertical, size, funding |
| `gtm-lead-discovery` | Qualified sales leads with the reason each qualifies |
| `open-positions-search` | Live job openings across companies and markets |
| `social-media-monitor` | Structured social activity around brands and topics |

<Card title="Web Search Agents overview" icon="bullseye-pointer" href="/nimble-sdk/web-search-agents/overview">
  Research, Enrichment, and Dataset Building side by side
</Card>


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