CAPABILITY · VAULT
Store a secret once, reference it by name, never by value
A write-only per-tenant vault: a stored secret is referenced in a goal as {{secret:NAME}}, resolved inside the browser at fill time, and redacted from every step, frame and log.
POST /api/v1/secrets · {{secret:NAME}}Capability
Inside credential vault
Agents need credentials to do authorized work, and credentials must never reach a model or a shared skill. The vault is write-only by construction: you can list the NAMES you have stored, never the values. A goal or a compiled path references a secret by token, and the value is resolved inside the isolated browser session at the moment a field is filled — after the planner has already decided what to type there.
Write-only, by design
GET /api/v1/secrets returns names and creation dates. There is no endpoint that returns a value, which means a compromised read cannot exfiltrate one.
Referenced, not passed
A secret appears in a prompt or a stored path as {{secret:NAME}}. The token is what the model sees and what the skill stores; the value is substituted at fill time inside the browser.
Redacted everywhere else
Secret values are stripped from the action path a run returns, from live frames, from step logs, and from anything promoted to the shared skill corpus.
Or never hold the password at all
When the credential belongs to someone whose password you should not have, mint a connect link instead: they sign in themselves and only the resulting session is captured.
How it works
The mechanism, in execution order
4 stages, in the order the runtime performs them — not a summary of them.
- 1StorePOST /api/v1/secrets with a name (1–64 chars of letters, digits, _, . and -) and a value. It is encrypted at rest and scoped to your tenant.
- 2ReferenceUse {{secret:NAME}} in a goal, or let a compile lift a literal into that token so the skill is account-independent.
- 3Resolve at fill timeThe engine substitutes the value inside the browser session at the moment the field is filled — not in the plan, not in the prompt.
- 4Strip everywhere elseThe value is redacted from the returned path, the stream, the logs, and anything eligible for the shared corpus.
In practice
A call you can paste and run
The token is what the model sees. The value never leaves the vault except into a browser field.
# Store once — free, encrypted, never returned by any read
curl -X POST https://twin-browser.com/api/v1/secrets \
-H "Authorization: Bearer $TWIN_API_KEY" \
-H "content-type: application/json" \
-d '{"name":"EXAMPLE_PASSWORD","value":"$ACME_PASSWORD"}'
# Reference it by token in the goal
curl -X POST https://twin-browser.com/api/v1/run \
-H "Authorization: Bearer $TWIN_API_KEY" \
-H "content-type: application/json" \
-d '{"url":"https://app.example.com/login",
"prompt":"sign in as ops@acme.com with {{secret:EXAMPLE_PASSWORD}} and export the invoices for this month",
"success":{"kind":"urlIncludes","value":"/invoices"}}'
# What you can read back — names only:
# GET /api/v1/secrets → { "secrets": [ { "name": "EXAMPLE_PASSWORD", "created_at": "…" } ] }- Storedone
- Referencerunning
- Resolve at fill timequeued
- Strip everywhere elsequeued
What it costs, how to switch it on
Priced from the same rate card the API serves
Every credit figure on this page is read from the rate card behind GET /api/v1/pricing — it is not typed into the copy, so it cannot drift from what you are billed.
Free
Storing, listing and deleting secrets are control-plane operations and cost nothing. You pay for the run that uses them, at that run's own price.
Turning it on
- 1Store the secretPOST /api/v1/secrets, or add it in the dashboard under Keys & Secrets.
- 2Reference itWrite {{secret:NAME}} where the value would go. Never paste the value into a prompt — the token is the whole point.
- 3Or use a per-host accountWhen you keep several logins per site, store them as labelled accounts and pass `account` on the run; the right credential and its saved session are applied automatically.
- 4Check readiness firstGET /api/v1/catalog reports which secrets a skill fills and whether the host's auth is ready — cheaper than discovering it mid-run.
At a glance
The contract, in the fewest rows that say it
| Property | Twin Browser |
|---|---|
| Store | POST /api/v1/secrets (free) |
| List | GET /api/v1/secrets — NAMES only |
| Delete | DELETE /api/v1/secrets/{name} |
| Reference | {{secret:NAME}} |
| Name rule | 1–64 chars: letters, digits, _ . - |
| Isolation | Per tenant, default-deny RLS |
Limits
Where it stops, and what it deliberately does not do
A capabilities page with no limits section is a brochure. These are the ceilings, the defaults that will surprise you, and the things this capability is not.
Limits and defaults
- Values are never returned. If you lose the original you re-store it; there is no recovery read.
- A secret name is 1–64 characters of letters, digits, underscore, dot and hyphen.
- A param value passed at call time may not contain a {{secret:…}} token — vault tokens are resolved server-side only, so a caller cannot inject one.
- A run that references a secret you have not stored returns code: "credential_missing" with the name it wanted, rather than guessing.
What it does not do
- It does not put a credential in the model context. The planner reasons over the token, not the value.
- It does not let a shared skill carry your secrets. Sanitization strips them before anything is promoted to the corpus.
- It does not generate TOTP codes or hold a second factor.
- It does not store a password captured through a connect handoff — that flow captures the SESSION and never the password.
FAQ
Questions about credential vault
Do my credentials ever reach the model?
Can I read a secret back?
What if the password is not mine to hold?
How are secrets kept apart between tenants?
Keep reading
The rest of the platform
The capabilities this one works with, the tools that expose it, the guides that use it end to end, and the vocabulary behind it.
Connected accounts & handoff
Mint a single-use link, your end user completes the sign-in in a hosted browser, and the captured session makes every later run already logged in — with no password anywhere.
Human-in-the-loop handoff
A 2FA prompt, an approval push or a CAPTCHA the agent cannot clear returns status "paused" with a live session — resolve it automatically from a connected inbox, hand back a code, or drive the page yourself.
Sub-tenants & reseller billing
One scoped call creates a sub-tenant under your account and returns its API key — billing either to its own balance or to your pool, with every charge attributed.
Tools that expose it
Guides
Related reading
Put your agent to work. Keep the decision.
Start free. Hand your agent a goal on a site you authorize, set the guardrails, and let the first successful run compile the skill every run after it replays.