Quickstart
Put each API key into kiwilink once. Your agents get session keys that reach only what a task needs, and kiwilink makes each call with the real key.
- 1. Sign up
- 2. Add your keys
- 3. Connect your agent
- 4. Put your MCP servers behind kiwilink
- 5. Start a session key
- 6. Call a tool
- 7. Watch and revoke
01Sign up
Go to kiwilink.ai and sign up with Google or a code sent to your email. Then add a passkey under Settings in your dashboard. Adding a key, and anything else that widens what an agent can reach, takes a touch of your passkey, so an agent driving your browser cannot do it.
02Add your keys
On your dashboard's Home tab, under Vendor keys, add each key once: pick the tool, give it a label and paste the key. Two GitHub tokens become github@work and github@personal. A consultant might label by client: vercel@acme and vercel@globex.
- A label is 1 to 32 lowercase letters, digits and
-, unique per tool. - kiwilink stores the key encrypted. No agent ever sees it, and it never leaves kiwilink.
- You can now take these keys out of your
.envfiles.
03Connect your agent
Connect your agent one of two ways. Either way it gets a kiwilink key, never a vendor key.
Over MCP, with one click
Add kiwilink's MCP server. Your browser opens kiwilink, you sign in, and the agent is connected to your workspace.
claude mcp add --transport http kiwilink https://kiwilink.ai/mcpThen run /mcp in Claude Code and choose kiwilink to sign in.
In Claude on the web or desktop, open Settings, then Connectors, choose Add custom connector and enter https://kiwilink.ai/mcp.
{
"mcpServers": {
"kiwilink": { "url": "https://kiwilink.ai/mcp" }
}
}Any other agent that speaks MCP over HTTP with OAuth works the same way, with the same URL.
With one kiwilink key
For scripts, CI and agents without MCP, make a kiwilink key on your dashboard's Home tab, under API keys. Making one takes your passkey. Put it in the environment in place of all your vendor keys.
export KIWILINK_API_KEY=kw_key_…04Put your MCP servers behind kiwilink
Your agent connects only kiwilink. Register the other MCP servers your team uses in kiwilink once, and each task reaches them through a session that names only the servers and tools it needs, read-only unless it has to change something. The agent never holds their tokens.
Move my other MCP servers into kiwilink.register_mcpadds a server with a label and its Streamable HTTP URL. You connect its account in kiwilink, which keeps the token and never returns it.list_mcps,update_mcp,refresh_mcp_toolsandremove_mcpsee, change, re-read and remove them.start_sessionwithmcpsopens a session for one task. You confirm its scope in your agent's app.list_mcp_toolsandcall_mcp_tooluse the servers through that session, andend_mcp_sessionends it.
Agents can read the same steps at kiwilink.ai/llms.txt.
05Start a session key
Give each task its own session key. Over MCP, your agent calls start_session itself. You can ask for one in plain words:
Start a kiwilink session for this task: read-only on github@work, write on openai@work, for two hours.Over HTTP, make one with your kiwilink key:
curl https://kiwilink.ai/v1/session-keys \
-H "Authorization: Bearer $KIWILINK_API_KEY" \
-H "content-type: application/json" \
-d '{
"name": "fix flaky checkout test",
"accounts": [
{ "account": "github@work", "access": "read", "paths": ["/repos/acme/web/"] },
{ "account": "openai@work", "access": "write" }
],
"expiresIn": "2h",
"maxCalls": 500
}'{
"id": "pr_…",
"key": "kw_sess_…",
"name": "fix flaky checkout test",
"expiresAt": "2026-11-04T18:00:00.000Z",
"maxCalls": 500,
"accounts": [
{ "account": "github@work", "access": "read", "paths": ["/repos/acme/web/"] },
{ "account": "openai@work", "access": "write" }
],
"baseUrl": "https://kiwilink.ai/v1"
}readallows GET only.writeallows every method kiwilink passes on.- A session key lasts at most 24 hours, and can only be narrower than the key that made it: no account, access, path, time or call the parent lacks.
- Making a session key needs no passkey, because it only narrows.
06Call a tool
Call the tool's own API through kiwilink at https://kiwilink.ai/v1/<tool>@<label>/ followed by the vendor's path, with the session key as a Bearer token. kiwilink checks the session's scope, then makes the call with your real key.
export KIWILINK_SESSION_KEY=kw_sess_…
curl https://kiwilink.ai/v1/github@work/repos/acme/web/pulls \
-H "Authorization: Bearer $KIWILINK_SESSION_KEY"A write on a read-only session, a call to github@personal, or any call after the session expires is refused. The refusal is kiwilink's own error, with an x-kiwi-error header and a message that says why, so your agent never mistakes it for GitHub's.
HTTP/1.1 403 Forbidden
x-kiwi-error: forbidden
{
"error": {
"source": "Kiwi",
"code": "forbidden",
"message": "This session key can only read github@work."
}
}With only one account for a tool, the label is optional: https://kiwilink.ai/v1/github/… works. With several and no label, kiwilink refuses and lists the labels rather than guessing.
With a vendor's SDK
Many SDKs take a base URL and a key. Point the base URL at kiwilink and pass the session key as the key. Calling a model is a POST, so this session needs write on openai@work.
import OpenAI from "openai";
const openai = new OpenAI({
baseURL: "https://kiwilink.ai/v1/openai@work",
apiKey: process.env.KIWILINK_SESSION_KEY,
});
const reply = await openai.chat.completions.create({
model: "gpt-5-mini",
messages: [{ role: "user", content: "Summarize the open pull requests." }],
});import os
from openai import OpenAI
client = OpenAI(
base_url="https://kiwilink.ai/v1/openai@work",
api_key=os.environ["KIWILINK_SESSION_KEY"],
)
reply = client.chat.completions.create(
model="gpt-5-mini",
messages=[{"role": "user", "content": "Summarize the open pull requests."}],
)SDKs that send their key in another header, such as Anthropic's x-api-key, work the same way: kiwilink takes the session key in the header each tool's SDK uses.
kiwilink passes on JSON up to 1 MB. File uploads are not supported yet. Payment APIs such as Stripe are read-only through kiwilink.
Tools you can call today: GitHub, Linear, Notion, Slack, Resend, Postmark, Vercel, Netlify, Cloudflare, Supabase, Neon, Sentry, PostHog, Render, Exa, Firecrawl, Tavily, OpenAI, Anthropic, Stripe (read-only), and the hosted browsers in kiwilink's catalog.
07Watch and revoke
Your dashboard's Home tab lists every live session under Live sessions: which agent, which accounts, calls used, time left, and a Revoke button. The Activity tab has every call.
An agent can end its own session too, with the id it got back:
curl -X DELETE https://kiwilink.ai/v1/session-keys/pr_… \
-H "Authorization: Bearer $KIWILINK_API_KEY"Revoking a session key, or the kiwilink key that made it, revokes every key made from it at once. The next call fails:
curl https://kiwilink.ai/v1/github@work/repos/acme/web/pulls \
-H "Authorization: Bearer $KIWILINK_SESSION_KEY"
# 401: the key was revokedThat is the whole loop. See pricing for what each plan includes, and the privacy policy for how kiwilink keeps your keys.