Give the agent the jobKeep the key
Your agents keep working against your real production credentials. The keys stay in the vault. Anything that spends money or deletes data waits for one tap from you.
No card. 10,000 calls a month on the free plan, and going over it never blocks a call.
- 1agentdemo.request POST demo.sallyport.cloud/echoYour agent names an action. It holds no key, and it never asks for one.
- 2gatewayclass=write binding=demo credential=demo-token v1The recipe says POST /echo writes. Writes ask a person.
- 3youcard sent telegram, console, task in the client“POST demo.sallyport.cloud/echo · agent my-first-agent · workspace personal · key demo-token”
- 4youapproved scope: this call onlyOne tap. The call was waiting the whole time and continues on the same id.
- 5gatewayunwrap demo-token v1 header X-Demo-Token dispatchThe value is read here, for this call. No route on this platform returns it.
- 6upstream200 x-upstream: website body 214 B
- 7journalsealed prev b9f0705e this 8e2cec73The intent row was written before the call went out, in the same transaction as the decision.
This is the onboarding call from the quickstart: an echo endpoint, the demo recipe from the public catalogue, one approval. The hashes below are computed on this page, over the lines above them. Recompute them with the open verifier and they close.
Where the key is right now
Your agent already has it
You pasted the key into .env, or into an MCP config, or into a CI secret. From there it lives in the process, in the shell history and in a retry that got logged. It also lives in the context of a model you do not host. You find out what the agent did by reading the provider's dashboard the next morning.
- A key in a config file is a key for every call the agent decides to make, including the one you would have stopped.
- Rotating it means finding every agent, every laptop and every runner that holds a copy.
- The blast radius of one prompt injection is the whole key, not the one call.
In August 2026 the ChainDrop campaign put 400 packages on npm. They read agent credential files out of .claude, .cursor and .codex, and reinstalled themselves through a session hook. Those are the files sp init empties.
What changes on Monday
- Nothing left to paste
- Your agents get a token that opens nothing on its own. The keys go into the vault once and stay there. One command writes the client config. Claude Code, Cursor, Codex and the rest then point at the gateway. Each one sees every service it may use, in plain words, before it tries one.
- The calls that matter wait for you
- Reads run at once. Writes ask. Anything that deletes or spends is refused until you say otherwise. The question reaches you in Telegram, in the console, or as a task inside the agent's own client. One tap sends the call on its way.
- You can prove what happened
- Every call lands in your journal before it goes out. The rows are hash-chained per tenant and encrypted to a key the process that writes them does not have. Signed checkpoints go to you. The verifier is open source and reads your export with none of our keys.
The whole product in one drawing
Where the key is at every hop
Connects to
It works with the agent you already run
One endpoint and one token. The clients that take a static header connect in a single command. The ones that insist on OAuth get an authorization server built for their exact checklist.
Anything else that speaks MCP over streamable HTTP works too, and anything that can make an HTTP request works through the proxy.
How it holds
Three doors, one broker
The same binding, the same policy and the same journal, whichever way the call arrives. We surveyed fifteen vendors in this category. Each of them covers one of these three.
- MCP
- One endpoint your client connects to. Both live revisions of the protocol: the stateless 2026-07-28 one and the session-based 2025-11-25 one, each on its own handler.
- HTTP
- A reverse proxy with one path per binding at gw.sallyport.cloud. Point curl, a script or a CI job at it and the key goes on at our end.
- SSH
- Your agent runs a command on a host. The private key never reaches the executor, which asks the control plane to sign each challenge.
Three ways to reach you, in that order
Blocking on an HTTP request does not survive real clients. Claude Code backgrounds a tool call at about two minutes and drops an idle request at five. Gemini CLI waits ten. So waiting is a protocol feature here, not a held connection.
- A task
- When the client speaks the tasks extension, the call becomes a task the agent polls. It can wait as long as you need.
- A URL the agent opens
- The gateway answers with input_required and a link. Claude Code opens your browser and keeps the call in the foreground while the card is open.
- A held call with a ceiling
- The last resort holds the request with progress every ten seconds, then returns the approval URL and a call id. Answer it later and the agent continues the same call.
The journal is evidence
One chain per tenant, gapless by construction. Each row is hashed over the row before it and sealed to a per-tenant recipient. A signed checkpoint covers the lot and goes to you and to your SIEM. Point the open verifier at any export and it tells you whether the chain closes.
The questions people ask before they start
- I am asleep. Does my pipeline stop?
- Reads run without you. For the rest you set a policy once per binding: run this class, ask for that one, refuse the third. Approve a class for the next hour with a call budget and the agent runs clean until it expires. Rate limits and plan limits answer with a retry time and never raise a card.
- Does it slow my agent down?
- An automatic call spends one token check and one database transaction on our side, then waits for the upstream exactly as it did before. Reads never wait for a person at all.
- What happens when Sallyport is down?
- Gated calls stop, and nothing runs unapproved. Every workspace has a printable sheet: each binding, the provider that issued the key, and the URL to reissue it. You can take a key back and run direct within minutes. Pending approvals live in the database and continue on the same call id after a restart.
- Some APIs hand out secrets of their own. What then?
- Your agent does not get a secret from us. It can get one from an upstream if you allow it a path that hands one out. Those paths are known: GitHub installation tokens, GitLab CI variables, Vercel env with decrypt, Vault kv. The catalogue marks them, the class is destructive, the default is refuse, and your console lists every one of them in your own tenant.
- Am I locked in?
- Your journal exports as a file and verifies with an open tool that holds none of our keys. Your credentials stay credentials you own at Stripe, at AWS, on your own hosts, revocable in one click at the source. The bindings are a few lines of configuration you can read.
- What does it cost?
- Free for 10,000 calls a month, with unlimited people on your team. Team is 1,000,000 calls. Business has no call limit. Going over your plan starts a trial and sends you a note. It never blocks a call.
Take the keys out of the config today
Put one key in the vault, point one agent at the gateway, and watch the first call ask you for permission.
Free for 10,000 calls a month. The first call goes through the console, before you connect a single client.