# Fetch: performing API requests or fetching data&#x20;

The Inngest TypeScript SDK provides a `step.fetch()` API and a `fetch()` utility, enabling you to make requests to third-party APIs or fetch data in a durable way by offloading them to the Inngest Platform:

- `step.fetch()` is a shorthand for making HTTP requests from within an Inngest function, and it also makes it easier to start parallel HTTP requests.
- The `fetch()` utility can be passed to packages that accept a custom `fetch` implementation, such as `axios`.

![Using Fetch offloads the HTTP request to the Inngest Platform](/assets/docs-markdown/features/inngest-functions/steps-workflows/fetch/step-fetch.png)

## Using `step.fetch()`

You can use `step.fetch()` to make HTTP requests within an Inngest function.

`step.fetch()` offloads the HTTP request to the Inngest Platform, so your service does not need to be active and waiting for the response.

```ts {{ title: "src/inngest/functions.ts" }}
import { inngest } from "./client";

export const retrieveTextFile = inngest.createFunction(
  { id: "retrieveTextFile", triggers: { event: "textFile/retrieve" } },
  async ({ step }) => {
    // The fetching of the text file is offloaded to the Inngest Platform
    const response = await step.fetch(
      "https://example-files.online-convert.com/document/txt/example.txt"
    );

    // The Inngest function run is resumed when the HTTP request is complete
    await step.run("extract-text", async () => {
      const text = await response.text();
      const exampleOccurences = text.match(/example/g);
      return exampleOccurences?.length;
    });
  }
);
```

**"step.fetch() example"**: [See the complete step.fetch() example including the source code and other use cases.]("/docs-markdown/examples/fetch")

`step.fetch()` is useful:

- In serverless environments, to offload long-running HTTP requests that might trigger timeouts.
- As a shorthand for making HTTP requests within an Inngest function, making it easier to start parallel HTTP requests using `Promise.all()`.
- As a best practice to ensure that all HTTP requests are durable and can be inspected in the Inngest Platform or Dev Server.

### `step.fetch()` observability

All `step.fetch()` calls are visible in your [Inngest Traces](/docs-markdown/platform/monitor/observability-metrics), allowing you to monitor and debug your HTTP requests:

![Inngest Traces showing a step.fetch() call](/assets/blog/announcing-step-fetch/step-fetch-trace.png)

## Using the `fetch()` utility

A Fetch API-compatible function is exported, allowing you to make any HTTP requests durable if they're called within an Inngest function.

For example, a `MyProductApi` class that relies on axios can take a `fetch` parameter:

```ts {{ title: "TypeScript" }}
import { fetch } from "inngest";

const api = new MyProductApi({ fetch });

// A call outside an Inngest function will fall back to the global fetch
await api.getProduct(1);

// A call from inside an Inngest function will be made durable and offloaded to the Inngest Platform
inngest.createFunction(
  { id: "my-fn", triggers: { event: "product/activated" } },
  async () => {
    await api.getProduct(1);
  },
);
```

> **Callout:** ⚠️ fetch() and step.run()Inngest's fetch() calls should not be performed inside of step.run() blocks.
> Doing so will result in fetch() to fallback to the global fetch implementation.Why? The fetch() utility transforms the fetch calls into step.run() calls, which cannot be nested.

### Within steps

By default, using Inngest's `fetch` retains all the functionality of requests made outside of an endpoint, but ensures that those made from inside are durable.

```ts {{ title: "TypeScript" }}
import { fetch as inngestFetch } from 'inngest';
import { generateText } from 'ai';
import { createAnthropic } from '@ai-sdk/anthropic';

// The AI SDK's createAnthropic objects can be passed a custom fetch implementation
const anthropic = createAnthropic({
  fetch: inngestFetch,
});

// NOTE - Using this fetch outside of an Inngest function will fall back to the global fetch
const response = await generateText({
  model: anthropic('claude-3-5-sonnet-20240620'),
  prompt: 'Hello, world!',
});

// A call from inside an Inngest function will be made durable
inngest.createFunction(
  { id: "generate-summary", triggers: { event: "post.created" } },
  async ({ event }) => {
    // This will use step.fetch automatically!
    const response = await generateText({
      model: anthropic('claude-3-5-sonnet-20240620'),
      prompt: `Summarize the following post: ${event.data.content}`,
    });
  },
);
```

### Using with AI SDK: Disable AI SDK retries

> **Callout:** Important: When using Inngest's fetch with the AI SDK, disable the AI SDK's built-in retry mechanism and let Inngest handle retries instead.

The AI SDK has built-in retry logic that can interfere with Inngest's retry handling, especially when working with long-running models or serverless platforms with timeout limits (e.g., Vercel's 15-minute max timeout).

**Why this matters:**

- When AI SDK retries are enabled alongside Inngest's retry mechanism, the combined retry duration can exceed your platform's timeout limits
- For long-running models (like OpenAI's o3), this is especially problematic
- When a timeout occurs, the error messages can be confusing: Vercel cancels the request, but it appears in Inngest as an "Internal server error" (from Inngest, not Vercel), making debugging difficult

**Recommended configuration:**

```ts {{ title: "generateText() with maxRetries: 0" }}
import { generateText } from 'ai';
import { createOpenAI } from '@ai-sdk/openai';
import { fetch as inngestFetch } from 'inngest';

const openai = createOpenAI({
  fetch: inngestFetch,
});

inngest.createFunction(
  { id: "generate-with-o3", triggers: { event: "content/generate" } },
  async ({ event }) => {
    // Disable AI SDK retries - let Inngest handle them instead
    const response = await generateText({
      model: openai('o3'),
      prompt: event.data.prompt,
      maxRetries: 0, // Critical: Set to 0 to let Inngest handle retries
    });
    
    return response;
  },
);
```

```ts {{ title: "streamText() with maxRetries: 0" }}
import { streamText } from 'ai';
import { createAnthropic } from '@ai-sdk/anthropic';
import { fetch as inngestFetch } from 'inngest';

const anthropic = createAnthropic({
  fetch: inngestFetch,
});

inngest.createFunction(
  { id: "stream-completion", triggers: { event: "completion/stream" } },
  async ({ event, step }) => {
    // Disable AI SDK retries for streaming operations
    const result = await streamText({
      model: anthropic('claude-3-5-sonnet-20240620'),
      prompt: event.data.prompt,
      maxRetries: 0, // Let Inngest handle retries
    });
    
    return result;
  },
);
```

By setting `maxRetries: 0` in your AI SDK calls, you:

- Avoid timeout issues on serverless platforms
- Get clearer error messages when failures occur
- Leverage Inngest's retry mechanism, which is designed for long-running operations
- Benefit from Inngest's observability to see exactly what happened during each retry attempt

However, the same `fetch` is also exported as `step.fetch`, allowing you to create your APIs isolated within the function instead:

```ts {{ title: "TypeScript" }}
import { createAnthropic } from '@ai-sdk/anthropic';
import { fetch as inngestFetch } from 'inngest';
import { generateText } from 'ai';

const anthropic = createAnthropic({
  fetch: inngestFetch,
});

inngest.createFunction(
  { id: "generate-summary", triggers: { event: "post.created" } },
  async ({ step }) => {
    const response = await generateText({
      model: anthropic('claude-3-5-sonnet-20240620'),
      prompt: `Summarize the following post: ${event.data.content}`,
    });
  },
);
```

### Fallbacks

By default, it will gracefully fall back to the global `fetch` if called outside of an Inngest function, though you can also set a custom fallback using the `config` method:

```ts {{ title: "TypeScript" }}
import { fetch } from "inngest";

const api = new MyProductApi({
  fetch: fetch.config({ fallback: myCustomFetch }),
});
```

You can also disable the fallback entirely:

```ts {{ title: "TypeScript" }}
import { fetch } from "inngest";

const api = new MyProductApi({
  fetch: fetch.config({ fallback: undefined }),
});
```

### How it works

Inngest's `fetch` function uses some of the basic building blocks of Inngest to allow seamless creation of optionally durable code. When it's called, it will:

- Check the context in which it's running
- If not in an Inngest function, optionally use the fallback; otherwise,
- Report the request to Inngest
- Inngest makes the request
- Inngest continues the function with the `Response` received from your request

Critically, this means that your service does not have to be active for the duration of the call; we'll continue your function when we have a result, while also keeping it durable!