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

# Call from TypeScript

> Call a deployed agent from TypeScript or JavaScript with fetch: read the event stream, show its tool calls, and handle a failure mid stream.

This is the TypeScript snippet from your agent's page in the dashboard, which fills in the agent's URL for you. It uses the built in `fetch`, and there is no Onecortex SDK to install. It runs in Node.js 20 or later, Bun and Deno.

## Before you begin

* A deployed agent and its ID, from its page in the dashboard.
* An [API key](/call/api-keys) in `ONECORTEX_API_KEY`.

## Stream the reply

The browser's `EventSource` sends only `GET` requests and cannot set a header, so read the stream from `fetch`. Replace `agt_...` with your agent's ID:

```ts invoke.ts theme={null}
const response = await fetch('https://api.onecortex.io/v1/agents/agt_.../invoke', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.ONECORTEX_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ prompt: 'hello', stream: true }),
})

const reader = response.body.getReader()
const decoder = new TextDecoder()
let buffer = ''

while (true) {
  const { done, value } = await reader.read()
  if (done) break
  buffer += decoder.decode(value, { stream: true })

  // Frames are separated by a blank line. A partial frame stays buffered.
  const frames = buffer.split('\n\n')
  buffer = frames.pop() ?? ''

  for (const frame of frames) {
    const event = frame.match(/^event: (.*)$/m)?.[1]
    const data = frame.match(/^data: (.*)$/m)?.[1]
    if (!event || !data) continue

    if (event === 'text') process.stdout.write(JSON.parse(data).delta)
    if (event === 'tool_call_start') console.log(`[calling ${JSON.parse(data).name}]`)
    if (event === 'done') console.log()
    // Handle this, or a failure looks like an empty success.
    if (event === 'error') throw new Error(JSON.parse(data).message)
  }
}
```

For the [quickstart's](/quickstart) `echo` agent:

```text Output theme={null}
[calling word_count]
You said: hello
```

Run it with `npx tsx invoke.ts`, `bun invoke.ts` or `node invoke.ts` on Node.js 22.6 or later. A request that is refused before the run starts, for example with a wrong key, has no stream: check `response.ok` first if you want its message, which is in the JSON body.

<Warning>
  A stream that has started has already sent `200 OK`, and cannot change it. If the run fails after that, the failure arrives in the stream as `event: error`. Handle it: a client that reads only `text` and `done` shows a failed run as an empty success.
</Warning>

## Get one JSON response

Leave out `stream: true` to wait for the whole run and get one body:

```ts invoke-json.ts theme={null}
const response = await fetch('https://api.onecortex.io/v1/agents/agt_.../invoke', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.ONECORTEX_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ prompt: 'hello' }),
})

const body = await response.json()
// A failed run and a refused request both carry `error`.
if (!response.ok) throw new Error(body.error.message)
console.log(body.result)
```

```text Output theme={null}
You said: hello
```

Every field of the body is on [the invoke API](/call/invoke).

## Continue a conversation

Send the same `sessionId` on each call to reach the same running instance of your agent:

```ts theme={null}
body: JSON.stringify({ prompt: 'When will it arrive?', sessionId: 'user-42', stream: true }),
```

See [Sessions](/build/sessions) for what a session keeps, and what it does not.
