← Back to BotVault

API-based Integration Quick Start

BotVault has two integrations. This section covers the API-based integration, where a bot calls /api/v1/credentials over HTTP with a bearer token. The other integration is MCP-based (npx @botvault/cli install) and is documented in packages/cli/README.md.

Use the API-based integration whenever a bot can't use MCP — most commonly because the bot runs somewhere other than the operator's own computer (LangChain on AWS Lambda, cloud-hosted OpenClaw, GitHub Actions, n8n, Zapier, hosted agents). The MCP-based path requires a passkey paired to physical hardware, which can't move to a cloud VM by design. Both integrations talk to the same vault, with the same per-bot permissions and audit log.

1. Create the bot and generate a token

In the dashboard at https://mybotvault.com:

  1. Sign in (signup is free).
  2. Bots → Create bot. Name it after where it will run (e.g. langchain-prod, openclaw-cloud).
  3. Bots → [your bot] → Permissions. Select the credentials this bot is allowed to read. Grant only what it needs.
  4. Bots → [your bot] → Tokens → Generate token. Pick a TTL (30d / 90d / 1y / never). Copy the token now — it's shown once.

The token is a JWT. The token alone authorizes the bot — anyone with the token can read the credentials it has permission to access, so treat it like a password.

2. Configure the agent

Set the token as an environment variable on the agent. Never commit it to source control.

# AWS Lambda / Fargate / ECS — task definition env vars
BOTVAULT_TOKEN=eyJhbGciOi...

# GitHub Actions — repo secrets
BOTVAULT_TOKEN=eyJhbGciOi...

# n8n / Zapier — credential / connection setting
BOTVAULT_TOKEN=eyJhbGciOi...

# Cloud-hosted OpenClaw — instance environment
BOTVAULT_TOKEN=eyJhbGciOi...

3. Call the API

Two endpoints. Both are rate limited to 60 req/min per token.

List credentials (metadata only — no secret values)

curl -H "Authorization: Bearer $BOTVAULT_TOKEN" \
  https://mybotvault.com/api/v1/credentials
{
  "credentials": [
    { "id": "9639b427-...", "label": "OpenAI Key", "type": "API Key", "expires_at": "2026-08-02 23:59:59" },
    { "id": "62d3c8a1-...", "label": "Vercel Token", "type": "Token", "expires_at": null }
  ]
}

Fetch a credential's value

curl -H "Authorization: Bearer $BOTVAULT_TOKEN" \
  https://mybotvault.com/api/v1/credentials/9639b427-...
{
  "id": "9639b427-...",
  "label": "OpenAI Key",
  "type": "API Key",
  "value": "sk-..."
}

4. Code examples

Node.js / TypeScript:

const token = process.env.BOTVAULT_TOKEN!;

async function getCredential(id: string): Promise<string> {
  const res = await fetch(`https://mybotvault.com/api/v1/credentials/${id}`, {
    headers: { Authorization: `Bearer ${token}` },
  });
  if (!res.ok) throw new Error(`BotVault ${res.status}: ${await res.text()}`);
  const { value } = await res.json();
  return value;
}

const openaiKey = await getCredential('9639b427-...');

Python (LangChain / AutoGPT / custom):

import os, requests

BOTVAULT_TOKEN = os.environ["BOTVAULT_TOKEN"]
BASE = "https://mybotvault.com/api/v1"

def get_credential(cred_id: str) -> str:
    r = requests.get(
        f"{BASE}/credentials/{cred_id}",
        headers={"Authorization": f"Bearer {BOTVAULT_TOKEN}"},
        timeout=10,
    )
    r.raise_for_status()
    return r.json()["value"]

openai_key = get_credential("9639b427-...")

Cloud-hosted OpenClaw — system prompt template:

A cloud-hosted OpenClaw can't use the MCP-based integration (the passkey is tied to its operator's physical device, not the cloud VM). Give it the API-based integration via its system prompt:

You have access to BotVault, a credential vault.

To list credentials: GET https://mybotvault.com/api/v1/credentials
To fetch a value:    GET https://mybotvault.com/api/v1/credentials/<id>

Both require the header `Authorization: Bearer <BOTVAULT_TOKEN>`,
where BOTVAULT_TOKEN is provided to you in the environment.

Rules:
- Always list credentials first to discover what you have access to.
- Never log credential values, never echo them to the user.
- Fetch a value only at the moment of use; don't cache long-term.
- If a request returns 401, the token is invalid or expired — stop the
  task and tell the operator to issue a new token in the BotVault
  dashboard.
- If a request returns 403 for an ID you saw in `list`, your permissions
  changed — re-list before reporting it as missing.
- If a request returns 429, wait 60 seconds and retry.

5. What to tell the AI

Your agent needs to know how and when to call the BotVault API. The cleanest way: paste BotVault's skill text into the agent's system prompt. The skill is a short set of rules the agent reads before doing anything that involves credentials.

The skill tells the agent to:

  • List credentials before assuming what's available — re-list at the start of every task that touches credentials, since permissions can change.
  • Check BotVault first before asking the operator to generate or paste a credential.
  • Fetch a credential value only at the moment of use; never cache long-term.
  • Never log credential values, echo them to the operator, or include them in conversation context.
  • Handle 401 / 403 / 429 / expired responses correctly (stop the task, surface the right operator action).
  • Use Authorization: Bearer <BOTVAULT_TOKEN> on every request, where BOTVAULT_TOKEN is the env var you set in step 2.

Copy the BotVault skill below and paste it into your agent's system prompt — once at agent setup time, never per-request. The bot token is not in the text; you've already set BOTVAULT_TOKEN as an env var separately.

The skill text is also visible below the page content.

6. Permissions, rotation, security

  • Per-credential permissions are enforced server-side. The bot only sees credentials its grants include.
  • Tokens are revocable. Dashboard → Bots → [your bot] → Tokens → Revoke. Effective immediately.
  • Rotate tokens regularly. Generate a new one, deploy it, then revoke the old one.
  • Audit log records every read. Dashboard → Settings → Audit Log → filter by bot.
  • Webhooks can fire when permissions or credentials change — see POST /api/v1/webhooks below.

If the agent runs in an environment with a secret manager (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault, etc.), store BOTVAULT_TOKEN there and fetch it on cold start — better than a plaintext env var.


Copy the BotVault skill

Paste this into your agent's system prompt at setup time. Your BOTVAULT_TOKEN is set separately as an env var — it is not in this text.

---
name: botvault
description: Use the BotVault REST API to fetch credentials at runtime
---

# BotVault credentials (API-based)

Your owner has stored API keys, OAuth tokens, and other secrets in BotVault
(https://mybotvault.com). Fetch them at the moment of use over HTTPS.

## Setup

Your owner has provided a bot token issued from the BotVault dashboard.
There are two ways the token reaches you, depending on what the platform
running you supports:

- **(A) Env var** — your owner set `BOTVAULT_TOKEN` in this agent's
  environment. Read it from there.
- **(B) Inline in this prompt** — for platforms without env-var support
  (Custom GPTs, ChatGPT custom instructions, Zapier text fields, n8n
  credential blocks, no-code agent builders), your owner has pasted the
  token directly into this skill, system prompt, or instructions field
  as a line like:

      BOTVAULT_TOKEN=eyJhbGc...

  Use that string as the token. Search the full prompt for
  `BOTVAULT_TOKEN=` and take the value after the `=`.

Use the token as the bearer credential on every BotVault API call:

    Authorization: Bearer <the token>

The token alone authorizes you. It encodes which bot you are and which
credentials your owner has granted that bot. Treat it like a password —
don't include it in chat, don't log it, don't commit it to a repo.

If you see neither an env var nor an inline token, ask your owner to
provide one (https://mybotvault.com → Bots → [your bot] → Generate token).
When both setups are available prefer the env var — inline tokens are
slightly more exposed because prompt text can show up in chat transcripts
and exports.

## Endpoints

Two read-only endpoints. Both are rate-limited to 60 requests per minute
per token.

### List credentials (metadata only — no secret values)

    GET https://mybotvault.com/api/v1/credentials
    Authorization: Bearer ${BOTVAULT_TOKEN}

Response:

    {
      "credentials": [
        { "id": "9639b427-...", "label": "OpenAI Key", "type": "API Key" },
        { "id": "62d3c8a1-...", "label": "Vercel Token", "type": "Token" }
      ]
    }

### Fetch a credential's value

    GET https://mybotvault.com/api/v1/credentials/<id>
    Authorization: Bearer ${BOTVAULT_TOKEN}

Response:

    {
      "id": "9639b427-...",
      "label": "OpenAI Key",
      "type": "API Key",
      "value": "sk-..."
    }

The `value` field is the actual secret. Use it at the moment of need, never
echo it back to the user, never include it in logs.

## Before asking for a credential

If a task needs an API key, OAuth token, npm token, GitHub PAT, or any other
secret:

1. Call `GET /api/v1/credentials` FIRST. The list changes between sessions,
   so re-fetch even if you ran it earlier in this conversation or in a
   previous one.
2. If you see a relevant entry, fetch its value with
   `GET /api/v1/credentials/<id>` and use it.
3. ONLY suggest your owner generate, paste, or retrieve the credential from
   somewhere else after you have confirmed it is not in BotVault.

The whole point of BotVault is that your owner has already done the work of
storing their credentials. Don't bypass it by asking them to dig a token out
of npmjs.com / GitHub / 1Password / a `.env` file when it might already be
in BotVault, one HTTP call away.

## Paying with a stored card

Card credentials (`type: card`) decrypt to a JSON object:

```json
{
  "cardholder_name": "MARTIN MEXIA",
  "card_number": "4242424242424242",
  "expiry_month": "09",
  "expiry_year": "2029",
  "cvv": "123",
  "billing_address": {
    "line1": "Al Wasl Rd 12", "line2": "Villa 4",
    "city": "Dubai", "state": "Dubai", "postal_code": "00000", "country": "AE"
  }
}
```

Use `billing_address` to fill the checkout's billing form; `country` is an
ISO-2 code. If `billing_address` is `null`, stop and ask your owner to add it
on the Cards page before paying. Most checkouts reject a card without one.
Never type the card number, CVV or address into chat.

## Rules

- NEVER log credential values or echo them back to the user.
- NEVER include the `BOTVAULT_TOKEN` in your responses, conversations, or
  logs — treat it like any other password.
- Fetch credentials on-demand at the moment of use, don't cache long-term.

## Error handling

- **401 Unauthorized**: `BOTVAULT_TOKEN` is invalid, expired, or the bot was
  revoked. Tell your owner to open the BotVault dashboard (Bots → [your bot]
  → Tokens → Generate token), copy the new token, and update the token on
  this agent — either by replacing the `BOTVAULT_TOKEN` env var or by
  pasting the new value over the inline `BOTVAULT_TOKEN=...` line in this
  prompt, depending on which setup is in use.

- **403 Forbidden** on a list call: the bot is deactivated. Tell your owner
  to re-activate it in the dashboard.

- **403 Forbidden** on a get call: this bot doesn't have permission for that
  credential id. Tell your owner to grant access in the dashboard.

- **200 with `approval_required: true` and `value: null`**: the credential is
  protected and your owner must OK it first. BotVault has already emailed them.
  Tell your owner to check their email for the BotVault message and tap how
  long you can use it (the `message` field has the exact words). Stop until
  they say they approved, then repeat the same GET. Never open an approval
  link yourself.

- **404 Not Found**: the credential id no longer exists, or the bot lost
  access. Re-list with `GET /api/v1/credentials` before reporting it as
  missing.

- **429 Too Many Requests**: rate limited (60 req/min per token). Wait 60
  seconds before retrying. Don't loop tightly.

- **5xx**: transient server problem. Wait 10-30 seconds and retry. If it
  persists, ask your owner to send a note via https://mybotvault.com/feedback.

## If you are running on a Grok Bot VM

Grok Bot gives every bot your owner runs the same cloud computer: one disk, one
browser profile, one set of CLI credentials. Anything you leave there is
readable by every other bot and by every later task, including tasks your owner
did not start.

- The bot token is the one secret that has to reach the VM. Keep it in the
  platform's secret store and read it from the environment at call time. Never
  write it to a file, a shell profile, a config, or a commit, and never echo it.
- Fetch each credential at the moment you use it, put the value straight into
  the outgoing request, and let it go. Nothing fetched from BotVault should
  survive on that disk.
- Never hand a credential value to another bot. Hand over the id instead. Your
  owner's other bots authenticate to the same BotVault.
- If a call returns 401 twice in a row, the token was revoked or rotated. Tell
  your owner which call failed and stop, rather than retrying in a loop.
- Before a checkout, read the card rules above. The browser on this VM is
  shared, so never leave a card saved in it.

## Always re-check before answering

Permissions change. Your owner can grant or revoke a credential to this bot
at any time from the dashboard. Your in-conversation memory of which
credentials you can access becomes stale the moment they make a change.

- ALWAYS call `GET /api/v1/credentials` at the start of any task that
  involves credentials, even if you called it earlier.
- If your owner says "I just gave you access to X" or "I revoked X", call
  `GET /api/v1/credentials` again IMMEDIATELY — do not rely on your previous
  list.
- If `GET /api/v1/credentials/<id>` returns 403 for an ID you saw before,
  the permission was revoked. Re-list, then tell your owner what changed.

## BotVault Brain — your owner's notes and second-brain

Beyond credentials, BotVault stores your owner's notes — meeting transcripts,
project files, people files, daily logs, open commitments — as a queryable
Brain. If granted `notes:read` (and optionally `notes:write`) scopes, you can
read and write through these endpoints:

### Read

    GET https://mybotvault.com/api/v1/notes/by-path/{path}
    GET https://mybotvault.com/api/v1/notes/search?q={query}&type={type}
    GET https://mybotvault.com/api/v1/notes/links/{name}

- `by-path/{path}` — fetch one note by path
  (e.g. `people/beatriz-goncalves.md`, `meetings/2026-05-09-1-on-1.md`).
  Returns `{ id, path, type, frontmatter, body, links, version, … }`.
- `search?q=…&type=…` — full-text (FTS5) search across notes you can read.
  Returns snippets with the query highlighted. Optional `type` filter:
  `daily | person | project | meeting | commitment | inbox | briefing |
  gmail-thread | note`.
- `links/{name}` — every note that contains `[[name]]`. Use to traverse
  the knowledge graph from a person, project, or topic.

### Write

    POST  https://mybotvault.com/api/v1/notes/append
          { "text": "remember to ping Sofia about the API rotation" }

    PUT   https://mybotvault.com/api/v1/notes/by-path/{path}
          If-Match: <version>
          { "body": "<full markdown>" }

    POST  https://mybotvault.com/api/v1/commitments
          { "text": "Send the partner doc to [[beatriz]] by Friday",
            "owner": "martin",
            "source": "fireflies:abc123",
            "project": "prior-integrations",
            "due": "2026-05-17",
            "agent_note": "Inferred from Yuno standup transcript",
            "references": ["meetings/2026-05-13-yuno-standup",
                           "inbox/gmail-thread-partner-doc"] }

    PATCH https://mybotvault.com/api/v1/notes/by-path/{path}
          { "patch": { "pinned": true, "agent_note": "Active this week" } }

- `/append` adds a timestamped line to today's daily note. Use this for
  quick-capture — a TODO, a thought, an observation your owner should see.
- `/by-path PUT` updates an existing note. Send `If-Match: <version>` to
  avoid clobbering concurrent edits (412 on mismatch).
- `/commitments POST` creates **one structured commitment note** at
  `commitments/<ulid>.md`. Body is a single `- [ ] <text>` checkbox — the
  checkbox character is the source of truth for status. Use this for every
  distinct commitment, not a rolled-up file. Pass `references` (an array
  of wikilink slugs without brackets) to attach every Brain note that
  supports this commitment as evidence; the body gets a `Related: [[a]]
  [[b]]` line and the owner's UI renders them as clickable chips. Returns
  `{ id, path, version, status: "open" }`. Requires `notes:write
  commitments/*`.
- `/by-path PATCH` merges the JSON `patch` into the note's YAML
  frontmatter. Body is untouched (the commitment checkbox stays where it
  is). Same URL as PUT; the verb decides — PUT replaces full body, PATCH
  merges frontmatter only. Send `If-Match: <version>` for optimistic
  concurrency. Use this for status metadata: `pinned`, `agent_note`,
  `martin_note`, etc. Do **not** flip a commitment to done via frontmatter
  — flip the checkbox in the body with a PUT instead.

### When to use the Brain

Reach for the Brain when the task is about your owner's context:

- "What did my owner discuss with X recently?" → `search?q=X`
- "What's the status of project Y?" → `by-path/projects/y.md`
- "Who's on the team?" → `search?q=X&type=person` or read `people/<name>.md`
- "What did my owner commit to?" → `search?q=…&type=commitment` (each
  commitment is a separate note at `commitments/<ulid>.md`; the response's
  `status` is `open` or `done` based on the checkbox in the body)
- "Record a new commitment my owner made" → `POST /commitments`
- "Pin this project" → `PATCH /by-path/projects/x.md { "patch": { "pinned": true } }`
- "Capture this for them" → `/append { text }`

If the answer lives in past meetings or notes, look there before asking
the owner.

### Connecting the Brain

The Brain is invite-only. If your owner's account does not have it, every
note call fails: reads and writes return Forbidden or 404, and searches return
nothing. In that case, stop and tell your owner that the Brain is not turned
on for their account. Do not retry and do not ask for a different token.

When your owner asks you to set up the Brain, take them through these steps
in order. They do steps 1 to 4. You cannot do them for them.

1. **Sign in.** They sign in at https://mybotvault.com. If "Brain" is not in
   the sidebar, the Brain is not turned on for their account. Stop here.
2. **Download the app.** BotVault Desktop runs on a Mac with Apple silicon
   (M1 or newer). They go to https://mybotvault.com/brain/desktop and click
   **Download for Mac**. They open the .dmg file and drag BotVault into
   Applications, then open BotVault from Applications.
3. **Pair the Mac.** The app opens mybotvault.com in the browser and shows a
   code. They sign in if the browser asks, type the code, name the Mac, and
   click **Trust**. The code lasts 5 minutes. If it expires, they click
   **Get a new code** in the app. The Free plan pairs one Mac.
4. **Choose what to copy.** The app shows the sources it finds on the Mac:
   WhatsApp (needs WhatsApp Desktop linked to their phone, and Full Disk
   Access for BotVault in System Settings), coding sessions (Claude Code,
   Codex, Cursor) and Obsidian vaults. They choose sources, chats, projects
   and folders. The Free plan copies one source. Keep the Mac awake for the
   first sync.
5. **Give this bot access.** On https://mybotvault.com/bots they open this
   bot and choose a **Brain access** level. WhatsApp chats and coding
   sessions are private sources: a bot reads them only if the owner adds
   them to that bot. Gmail, Slack and Calendar connect on the website, not
   from the Mac.
6. **Check it works.** Search for a word the owner knows is in their notes
   (for example a colleague's name). If you get results, the Brain is
   connected. If you get nothing, check step 5 first, then check in Brain ›
   Desktop on the website that the Mac shows as connected.

### Brain error handling

- **403 on read**: missing `notes:read` for that path. Tell your owner the
  path; they grant scopes in the dashboard.
- **403 on write/append**: missing `notes:write` for that path.
- **404**: note doesn't exist OR is outside this bot's read scope. Search
  before assuming it's missing.
- **412 on PUT**: stale version. Re-GET and retry.

## How tokens get issued and rotated

There is no automatic refresh. Your owner generates a token in the BotVault
dashboard, copies it once (it's shown only at creation time), and either
sets it as `BOTVAULT_TOKEN` on this agent's environment or pastes it inline
into your prompt (see Setup above). If the token expires or is revoked,
they need to issue a new one and replace whichever copy is in use. You
cannot generate tokens for yourself — only your owner can.

For the MCP-based integration, see the MCP-based Integration Quick Start or the @botvault/cli package on npm.

Questions or feedback? Send us a message.