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

# Research the web with Answers

> Turn a research task into structured JSON with source URLs using Fast or Ultra mode.

Use [Answers](/api-reference/web-extraction/answers) when your input is a question or research task and you want the service to find relevant evidence on the web. Give the task a domain or page URL when you want it to start with a specific site.

## Choose a mode

| Mode              | Credits per successful answer | Research budget | Best fit                                            |
| ----------------- | ----------------------------: | --------------- | --------------------------------------------------- |
| `fast`            |                            10 | 30 seconds      | Focused factual lookups.                            |
| `ultra` (default) |                           100 | 50 seconds      | Deeper questions, comparisons, and several sources. |

Set the mode in the JSON body. A valid answer with unknown values is still billable. Validation, research, and timeout failures are not charged; inspect `key_metadata` and `X-Credits-Used` for the actual charge.

## Ask for a structured answer

Copy an API key from the [dashboard](https://context.dev/dashboard), set `CONTEXT_DEV_API_KEY` on your server, and [install an SDK](/sdks) if needed. A restricted key needs `data:execute`; see [API key permissions](/guides/manage-api-keys).

This request accepts a valid answer from the evidence collected within 30 seconds:

<Note>
  These examples use the SDKs' low-level request methods to send the current API contract, including fields not yet exposed by the 2.14.0 typed helpers. Authentication, retries, and error handling still come from the SDK. See [SDK compatibility](/optimization/api-stability#sdks-can-lag-the-server-contract).
</Note>

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.context.dev/v1/web/answers \
    --request POST \
    --header "Authorization: Bearer $CONTEXT_DEV_API_KEY" \
    --header "Content-Type: application/json" \
    --data '{
    "mode": "fast",
    "task": "Find the pricing page URL and plan names for context.dev.",
    "json_format": {
      "pricing_page_url": "",
      "plans": [
        {
          "name": ""
        }
      ]
    },
    "timeoutOpts": {
      "milliseconds": 30000,
      "behavior": "return-partial"
    }
  }'
  ```

  ```typescript TypeScript theme={null}
  import ContextDev from "context.dev";

  const client = new ContextDev({ apiKey: process.env.CONTEXT_DEV_API_KEY });

  const response = await client.post<Record<string, unknown>>("/web/answers", {
    body: {
      "mode": "fast",
      "task": "Find the pricing page URL and plan names for context.dev.",
      "json_format": {
        "pricing_page_url": "",
        "plans": [
          {
            "name": ""
          }
        ]
      },
      "timeoutOpts": {
        "milliseconds": 30000,
        "behavior": "return-partial"
      }
    }
  });

  console.log(response.json_content, response.sources, response.partial);
  ```

  ```python Python theme={null}
  import os
  from context.dev import ContextDev

  client = ContextDev(api_key=os.environ["CONTEXT_DEV_API_KEY"])

  response = client.post(
      "/web/answers",
      cast_to=dict[str, object],
      body={'mode': 'fast',
       'task': 'Find the pricing page URL and plan names for context.dev.',
       'json_format': {'pricing_page_url': '', 'plans': [{'name': ''}]},
       'timeoutOpts': {'milliseconds': 30000, 'behavior': 'return-partial'}},
  )

  print(response["json_content"], response["sources"], response.get("partial", False))
  ```

  ```ruby Ruby theme={null}
  require "cgi/core"
  require "context_dev"

  client = ContextDev::Client.new(api_key: ENV.fetch("CONTEXT_DEV_API_KEY"))

  response = client.request(
    method: :post,
    path: "web/answers",
    body: {
      "mode": "fast",
      "task": "Find the pricing page URL and plan names for context.dev.",
      "json_format": {
        "pricing_page_url": "",
        "plans": [
          {
            "name": ""
          }
        ]
      },
      "timeoutOpts": {
        "milliseconds": 30000,
        "behavior": "return-partial"
      }
    }
  )

  pp response[:json_content], response[:sources], response[:partial]
  ```

  ```go Go theme={null}
  package main

  import (
  	"context"
  	"fmt"
  	"os"

  	contextdev "github.com/context-dot-dev/context-go-sdk/v2"
  	"github.com/context-dot-dev/context-go-sdk/v2/option"
  )

  func main() {
  	client := contextdev.NewClient(option.WithAPIKey(os.Getenv("CONTEXT_DEV_API_KEY")))
  	var response map[string]any
  	err := client.Post(context.Background(), "/web/answers", map[string]any{
  		"mode": "fast",
  		"task": "Find the pricing page URL and plan names for context.dev.",
  		"json_format": map[string]any{
  			"pricing_page_url": "",
  			"plans": []any{map[string]any{
  				"name": "",
  			}},
  		},
  		"timeoutOpts": map[string]any{
  			"milliseconds": 30000,
  			"behavior":     "return-partial",
  		},
  	}, &response)
  	if err != nil {
  		panic(err)
  	}
  	fmt.Println(response["json_content"], response["sources"], response["partial"])
  }
  ```

  ```php PHP theme={null}
  <?php
  require __DIR__.'/vendor/autoload.php';

  use ContextDev\Client;

  $client = new Client(apiKey: getenv('CONTEXT_DEV_API_KEY'));

  $raw = $client->request(
      method: 'post',
      path: 'web/answers',
      body: [
          "mode" => "fast",
          "task" => "Find the pricing page URL and plan names for context.dev.",
          "json_format" => [
              "pricing_page_url" => "",
              "plans" => [[
                      "name" => "",
                  ]],
          ],
          "timeoutOpts" => [
              "milliseconds" => 30000,
              "behavior" => "return-partial",
          ],
      ],
  );

  $response = json_decode((string) $raw->getBody(), true, flags: JSON_THROW_ON_ERROR);
  print_r($response['json_content']);
  print_r($response['sources']);
  var_dump($response['partial'] ?? false);
  ```
</CodeGroup>

An illustrative response is:

```json theme={null}
{
  "json_content": {
    "pricing_page_url": "https://www.context.dev/pricing",
    "plans": [{ "name": "Developer" }, { "name": "Pro" }, { "name": "Scale" }]
  },
  "sources": ["https://www.context.dev/pricing"]
}
```

The example illustrates the shape; plan names and source content can change.

## Shape and check the answer

`task` is required, trimmed, and limited to 2,000 characters. `json_format` is an example object whose keys and placeholder values describe the desired output. Omit it for the default `{"result": ""}` shape.

* Nonempty objects preserve their keys; strings, numbers, and booleans preserve their types. Unknown values can be `null`.
* An example array describes its items; the answer can contain any number of matching items.
* Empty objects permit arbitrary fields, empty arrays permit any JSON items, and a `null` placeholder permits any JSON value.
* Examples support at most eight levels, 500 values, and 16,000 serialized characters.

For extraction from known URLs with an explicit JSON Schema and controlled crawl scope, use [Extract structured data](/guides/extract-structured-data-from-websites). Answers uses an example shape and chooses its own research steps.

## Read sources and partial results

`sources` lists contributing search results or readable pages, deduplicated in first-seen order. A URL may have contributed a search snippet without its full page being read. Sources do not map individual answer fields to citations. Check important claims against the source before using them in a decision.

Page reads request fresh content; search snippets can still reflect indexed material. With `timeoutOpts.behavior: "return-partial"`, research can stop early enough to produce a valid answer from collected evidence. A partial answer includes `partial: true` and costs the selected mode's price. Preserve that marker when storing or displaying the result.

`timeoutOpts.milliseconds` accepts 1,000–300,000 and can shorten the mode's research budget. It cannot extend the 30-second Fast or 50-second Ultra limit. See [Timeouts and partial results](/optimization/timeouts).

## Handle failures

| Status | Meaning                                                  | Recovery                                                         |
| ------ | -------------------------------------------------------- | ---------------------------------------------------------------- |
| `400`  | Invalid task/example shape, or `ZDR_NOT_SUPPORTED`.      | Correct the input. Answers does not support Zero Data Retention. |
| `403`  | Key permissions or another access prerequisite.          | Inspect `error_code` and the key's `data:execute` grant.         |
| `408`  | Caller deadline expired without an acceptable result.    | Allow a larger budget or use partial mode.                       |
| `502`  | No usable evidence or no valid answer could be produced. | Refine the task or provide a more relevant starting URL.         |
| `504`  | Research/model time limit expired.                       | Narrow the question and retry with a bounded attempt count.      |

Standard authentication, credits, and rate limits also apply. Follow [Troubleshooting](/optimization/troubleshooting) for shared errors.
