kiwilink

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.

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 .env files.

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 Code
claude mcp add --transport http kiwilink https://kiwilink.ai/mcp

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

Cursor · ~/.cursor/mcp.json
{
  "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.

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

Ask your agent
Move my other MCP servers into kiwilink.
  • register_mcp adds 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_tools and remove_mcp see, change, re-read and remove them.
  • start_session with mcps opens a session for one task. You confirm its scope in your agent's app.
  • list_mcp_tools and call_mcp_tool use the servers through that session, and end_mcp_session ends 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:

Ask your agent
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:

Shell
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
  }'
Response
{
  "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"
}
  • read allows GET only. write allows 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.

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

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

Node
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." }],
});
Python
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:

Shell
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:

Shell
curl https://kiwilink.ai/v1/github@work/repos/acme/web/pulls \
  -H "Authorization: Bearer $KIWILINK_SESSION_KEY"
# 401: the key was revoked

That is the whole loop. See pricing for what each plan includes, and the privacy policy for how kiwilink keeps your keys.

Pricing · Quickstart · Terms of Service · Privacy Policy