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.
Bots → Create bot. Name it after where it will run (e.g. langchain-prod, openclaw-cloud).
Bots → [your bot] → Permissions. Select the credentials this bot is allowed to read. Grant only what it needs.
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.
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.
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.