---
title: Calling APIs
description: Call authenticated APIs, with the key kept in a vault.
---

A function is a good place for an API client: the exact calls your team makes to GitHub, your billing system, or your own backend, written once in code. What an API client needs, though, is a key — and a key must never be in the code, in the agent's context, or anywhere the model could repeat it.

With Subako the function holds no key at all. You store the key in a [vault](/console/vaults) as **HTTP headers** for the API's origin. When the function sends a request there, Subako adds the headers on the way out. The function's code, the model, and the session's files never see them.

This page sets that up for GitHub, with the [github example](https://github.com/subako-ai/subako-function-examples/tree/main/rust/github) package: read-only questions about repositories, with a token for private ones.

## 1. Put the token in a vault

Create a GitHub personal access token — a fine-grained token with read-only **Contents** covers questions about code. Then, in the console, open a vault and **Add credential**, choose **HTTP headers**, and give it:

- **Origin**: `https://api.github.com` — the scheme, host, and port, nothing more.
- A header **authorization** with the value `Bearer <your token>`.

![Add a credential: HTTP headers for the origin https://api.github.com, with an authorization header](/blume-assets/content/docs/_images/en/vault-add-headers.webp)

Once added, the value is never shown again, in the console or anywhere else.

## 2. Grant the package with the origin

Upload the package (see the [quickstart](/functions/quickstart) for how), then grant it in the agent's version editor. Two settings let it reach GitHub with the token:

- **Network**: **Only allowed hosts**, with `api.github.com` — and `codeload.github.com`, which GitHub redirects downloads to.
- **Credentials**: the origin `https://api.github.com`.

![A function package grant: github, allowed to reach api.github.com and codeload.github.com, with the credential for https://api.github.com](/blume-assets/content/docs/_images/en/agent-editor-github.webp)

In an [agent config](/reference/agent-config#functions), the same grant is:

```json
{
  "name": "github",
  "source": { "type": "workspace", "function_id": "<function-id>", "version": { "type": "latest" } },
  "default_policy": "allow",
  "network": { "type": "allowlist", "hosts": ["api.github.com", "codeload.github.com"] },
  "http_credentials": ["https://api.github.com"]
}
```

## 3. Start sessions with the vault

Credentials come from the vaults a session is started with — **Vaults** in the console's **New session**, or `vault_ids` over the API. The same agent version can then run with one customer's token in one session and another's in the next.

## The code sends no key

A request in the function is an ordinary request, with no authorization header:

**Rust**

```rust
use subako_function_sdk::http::{self, Request};

let response = http::request(&Request::get("https://api.github.com/repos/subako-ai/subako-function-examples"))?;
```

**TypeScript**

```ts
const response = await fetch("https://api.github.com/repos/subako-ai/subako-function-examples");
```

**Go**

```go
resp, err := http.Get("https://api.github.com/repos/subako-ai/subako-function-examples")
```

Subako checks the request against the grant's network, finds the session's credential for `https://api.github.com`, and sends the request with its headers. Without a credential for the origin, the request goes as it is — so the github package still answers questions about public repositories, within GitHub's lower rate limit for anonymous requests.

## Rules worth knowing

- A credential applies to exactly one origin, and only to requests the grant lists that origin for. A request to another host carries nothing.
- A redirect to another origin drops `authorization` and cookie headers, so a token never follows a redirect off its API.
- A function that sets one of the credential's headers itself is refused, rather than having either one silently win.
- Each vault holds one credential per origin. If more than one of a session's vaults hold one for the same origin, requests there fail rather than guess.
- Requests go over `https` only, to public addresses only.

## Without writing a function

The platform's [`http`](/functions/platform-packages#http) package follows the same rules: grant it with a network and credentials, and the agent can compose requests to your API itself, with the key still attached by Subako rather than seen by the model. A package of your own is the better fit when the calls are known — it validates its input, shapes the answer, and keeps large responses on the [Session Volume](/functions/runtime#the-session-volume).
