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

# Fetch API

> Fetch URLs and extract clean text — no external APIs required

<Note>
  Fetch does not use credits.
</Note>

The TinyFish Fetch API fetches web pages, renders JavaScript-heavy pages when needed, and returns clean extracted text in your preferred format. Submit a URL, get back structured content.

```bash theme={null}
POST https://api.fetch.tinyfish.ai
```

`api.fetch.tinyfish.ai` is the public Fetch API endpoint.

## Before You Start

<Steps>
  <Step title="Get your API key">
    Visit [agent.tinyfish.ai/api-keys](https://agent.tinyfish.ai/api-keys) and create a key. Store it in your environment:

    ```bash theme={null}
    export TINYFISH_API_KEY="your_api_key_here"
    ```
  </Step>
</Steps>

All requests require the `X-API-Key` header. See [Authentication](/authentication) for the full setup and troubleshooting guide.

## Your First Request

<CodeGroup>
  ```python Python theme={null}
  from tinyfish import TinyFish

  client = TinyFish()
  result = client.fetch.get_contents(urls=["https://www.tinyfish.ai/"])
  print(result.results[0].title)
  print(result.results[0].text)
  ```

  ```typescript TypeScript theme={null}
  import { TinyFish } from "@tiny-fish/sdk";

  const client = new TinyFish();
  const result = await client.fetch.getContents({
    urls: ["https://www.tinyfish.ai/"],
  });
  console.log(result.results[0].title);
  console.log(result.results[0].text);
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.fetch.tinyfish.ai \
    -H "X-API-Key: $TINYFISH_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"urls": ["https://www.tinyfish.ai/"]}'
  ```
</CodeGroup>

## What Success Looks Like

```json theme={null}
{
  "results": [
    {
      "url": "https://www.tinyfish.ai/",
      "final_url": "https://www.tinyfish.ai/",
      "title": "TinyFish | Enterprise Web Agent Infrastructure",
      "description": "TinyFish provides enterprise infrastructure for AI web agents.",
      "language": "en",
      "format": "markdown",
      "text": "# TinyFish | Enterprise Web Agent Infrastructure\n\nTinyFish provides enterprise infrastructure for AI web agents...\n"
    }
  ],
  "errors": []
}
```

## When to Use Fetch vs the Other APIs

* Use **Fetch** when you already know the URL and need clean extracted page content.
* Use **Search** when you need help finding the right URLs first.
* Use **Agent** when TinyFish should perform a multi-step workflow on the site.
* Use **Browser** when you need direct browser control from your own code.

***

## Fetching Multiple URLs

Submit up to 10 URLs in a single request. Each URL is processed independently — one failure doesn't affect the others.

<CodeGroup>
  ```python Python theme={null}
  from tinyfish import TinyFish

  client = TinyFish()
  result = client.fetch.get_contents(
      urls=[
          "https://www.tinyfish.ai/",
          "https://en.wikipedia.org/wiki/Web_scraping",
          "https://docs.python.org/3/tutorial/index.html",
      ]
  )

  for page in result.results:
      print(page.url, "→", page.title)

  for error in result.errors:
      print("Failed:", error.url, "–", error.error)
  ```

  ```typescript TypeScript theme={null}
  import { TinyFish } from "@tiny-fish/sdk";

  const client = new TinyFish();
  const result = await client.fetch.getContents({
    urls: [
      "https://www.tinyfish.ai/",
      "https://en.wikipedia.org/wiki/Web_scraping",
      "https://docs.python.org/3/tutorial/index.html",
    ],
  });

  result.results.forEach((r) => console.log(r.url, "→", r.title));
  result.errors.forEach((e) => console.log("Failed:", e.url, "–", e.error));
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.fetch.tinyfish.ai \
    -H "X-API-Key: $TINYFISH_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "urls": [
        "https://www.tinyfish.ai/",
        "https://en.wikipedia.org/wiki/Web_scraping",
        "https://docs.python.org/3/tutorial/index.html"
      ]
    }'
  ```
</CodeGroup>

<Note>
  Per-URL failures (timeouts, DNS errors, anti-bot blocks) appear in `errors[]` alongside a `200` response — they do not cause the entire request to fail.
</Note>

***

## Output Formats

Control the format of the `text` field with the `format` parameter. When omitted, the default is `markdown`.

<Tabs>
  <Tab title="html">
    Semantic HTML.

    ```json theme={null}
    {
      "format": "html",
      "text": "<h1>Async Fn in Traits Are Now Available</h1>
    <p>Starting with Rust 1.75, you can use <code>async fn</code> directly inside traits.</p>
    <h2>What Changed</h2>
    <ul>
    <li>Works in all stable traits</li>
    <li>No heap allocation for simple cases</li>
    </ul>"
    }
    ```
  </Tab>

  <Tab title="markdown">
    Clean Markdown. Ideal for LLM consumption and readable storage.

    ```json theme={null}
    {
      "format": "markdown",
      "text": "# Async Fn in Traits Are Now Available

    Starting with Rust 1.75, you can use `async fn` directly inside traits.

    ## What Changed

    Previously, writing async functions in traits required the `async-trait` crate...

    - Works in all stable traits
    - No heap allocation for simple cases
    - Compatible with `Send` bounds"
    }
    ```
  </Tab>

  <Tab title="json">
    Structured document tree. Useful for programmatic content processing.

    ```json theme={null}
    {
      "format": "json",
      "text": {
        "type": "document",
        "children": [
          { "type": "heading", "level": 1, "text": "Async Fn in Traits Are Now Available" },
          { "type": "paragraph", "text": "Starting with Rust 1.75, you can use async fn directly inside traits." },
          { "type": "heading", "level": 2, "text": "What Changed" },
          { "type": "list", "ordered": false, "items": ["Works in all stable traits", "No heap allocation for simple cases"] }
        ]
      }
    }
    ```
  </Tab>
</Tabs>

***

## Cache Freshness

By default, Fetch may serve an existing cached entry for the URL when one is available. Pass `ttl` to set a freshness preference in seconds.

```json theme={null}
{
  "urls": ["https://example.com"],
  "ttl": 3600
}
```

* Omit `ttl` to accept any cached entry.
* Set `ttl` to `0` when you want a live fetch.
* Set `ttl` to a positive integer to accept cached entries younger than that many seconds.

***

## Supported Content Types

The Fetch API handles more than just HTML. See the [full content types table](/fetch-api/reference#supported-content-types) in the reference — highlights: PDF text extraction works, JSON endpoints return raw JSON, but binary files (images, video) return an error.

***

## Read Next

<CardGroup cols={2}>
  <Card title="API Reference" icon="code" href="/fetch-api/reference">
    Full request and response schema
  </Card>

  <Card title="Authentication" icon="key" href="/authentication">
    API key setup
  </Card>

  <Card title="Fetch Examples" icon="bolt" href="/fetch-api/examples">
    Common Fetch request patterns
  </Card>

  <Card title="For coding agents" icon="robot" href="/for-coding-agents">
    One page that routes an agent to the right TinyFish API
  </Card>
</CardGroup>
