← 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" },
    { "id": "62d3c8a1-...", "label": "Vercel Token", "type": "Token" }
  ]
}

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.

## 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.

- **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.

## 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.

### 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.