Secrets
Secrets are named, encrypted credentials that tools can reference from argument_override via {"$ref": "<scope>.secrets.<name>"}. The value is substituted at tool-execution time and masked everywhere it is read back — in API responses, session events, and tool-input streams.
There are two scopes, picked by who owns the credential:
| Scope | $ref grammar | Lifetime | Typical use |
|---|---|---|---|
| Agent | agent.secrets.<name> | Belongs to the agent definition. Set once by the agent's administrator; shared across every session and every caller. | Tokens the agent itself uses regardless of who is talking to it (a generic Jira service account, a Slack bot webhook). |
| Session | session.secrets.<name> | Belongs to a single chat session. Set at session creation (or via session update) and lives until the session is deleted. | Short-lived credentials bound to one conversation (an OAuth access token the user pasted, an ephemeral API token tied to a workflow). |
Both scopes share the same threat model: encrypted at rest, masked on read, masked in events. The tool always receives the real plaintext; everything observed from outside the tool sees "****".
Use secrets for credentials a tool needs to call out. Keep agent.metadata and argument_override for non-sensitive configuration — both of those are returned verbatim by GET /v2/agents/{agent_key}; secrets are not.
Agent secrets
An agent secret is a named, encrypted credential stored on a specific agent. Tools reach it from argument_override via {"$ref": "agent.secrets.<name>"}, the value is passed to the tool at execution time, and it is masked everywhere the agent or its session events are read back.
Use agent secrets for the credentials a tool needs to call out: a Jira API token, a Slack webhook URL, a database password the agent reaches through web_get. Keep agent.metadata and argument_override for non-sensitive configuration. Both of those are returned verbatim by GET /v2/agents/{agent_key}; secrets are not.
Why not put credentials in metadata or argument_override?
agent.metadata is a free-form map intended for organizing agents and for use as $ref values inside tool configurations. It is returned in plaintext by GET /v2/agents/{agent_key}, and the response is visible to anyone with read access on the agent. The same applies to literal values written into argument_override — the agent definition stores them, and reads return them.
Secrets fix both problems. They live on a separate resource (/v2/agents/{agent_key}/secrets), are encrypted at rest with the agent's encryption key, are never returned in plaintext on read, and are masked in the tool_input events of every session that uses them.
Endpoints
All three endpoints require owner, administrator, or agent_administrator (API role), or agent_administrator (agent role).
| Method | Path | Effect |
|---|---|---|
GET | /v2/agents/{agent_key}/secrets | Returns the agent's secrets with values masked as "****". |
PUT | /v2/agents/{agent_key}/secrets | Replaces the whole set. Names not in the request are removed. |
PATCH | /v2/agents/{agent_key}/secrets | Partial update. Names mapped to a value are added or replaced. Names mapped to null are removed. Names absent from the map are left alone. |
The response from every endpoint is the same AgentSecrets shape with masked values. Plaintext is never on the wire after a write completes.
Set secrets
Use PUT to write the full set in one call. This is the right verb for first-time setup and for any flow that owns the entire secrets list.
REPLACE THE SECRETS SET
Code example with multiple language options.1
Use PATCH to add, rotate, or remove individual secrets without resending the rest. A name mapped to null removes it; a name absent from the map is left as it was.
ROTATE ONE SECRET, REMOVE ANOTHER, LEAVE THE REST ALONE
Code example with bash syntax.1
Per-value size cap is 4096 bytes. Secret names are arbitrary map keys; pick something stable, because tool configurations reference them by name.
Reference a secret from a tool
Inside argument_override, replace the literal credential with a $ref to the secret you just wrote. The platform substitutes the plaintext value when the tool runs. The tool receives the real credential; everything observed from outside the tool sees the mask.
A WEB_GET TOOL WRAPPING JIRA, WITH THE API TOKEN REFERENCED FROM SECRETS
Code example with json syntax.1
$ref accepts the same path grammar everywhere secrets are valid: top-level string fields, nested headers, body fields, array elements. The substitution happens once per tool invocation.
If a tool references agent.secrets.<name> and that name is not currently set, the reference fails at execution time and surfaces as an error event on the session. There is no validation at PUT or PATCH time that every existing reference resolves — the rule is checked when the tool runs.
How values are protected
Three layers, each closing a different hole.
- At rest. Secrets are stored encrypted, using the same agent encryption key that protects service-account credentials and connector tokens.
- On read.
GET /v2/agents/{agent_key}/secretsand the response fromPUT/PATCHalways return"****"in place of every value. The plaintext leaves the platform only when a tool that references the secret is executed. - In session events. The platform emits a
tool_inputevent for every tool call so that session viewers and clients can see what the agent did. Fields populated fromagent.secrets.<name>are replaced with"****"in that event. The same call's tool receives the real value; the event records the mask.
The threat model is database compromise and accidental exposure through API responses or the session-event stream. Secrets are not protected from a custom tool that chooses to log its own arguments — once the tool receives the plaintext, what it does with it is the tool's responsibility.
List secret names
GET returns the keys without revealing the values, so it doubles as a way to audit what is configured without leaking anything.
LIST THE SECRET NAMES ON AN AGENT
Code example with multiple language options.1
Remove secrets
To remove a single secret, PATCH with the name mapped to null. To clear every secret on the agent, PUT an empty map.
CLEAR ALL SECRETS
Code example with bash syntax.1
Removing a secret that a tool's argument_override still references does not delete the reference. The next tool call that tries to resolve it produces an error event on the session, so plan rotations either as PATCH overwrites (write the new value under the same name) or by updating the tool configuration first.
Migrating from metadata or argument_override
Existing agents that store credentials in agent.metadata or as literal values in argument_override keep working. To move them onto secrets:
PUTthe credential to/v2/agents/{agent_key}/secretsunder a stable name (jira_api_token,slack_webhook).PATCHthe agent in a single request: replace the literal in the tool'sargument_overridewith{"$ref": "agent.secrets.jira_api_token"}, and remove the credential frommetadata. After thisPATCH,GET /v2/agents/{agent_key}no longer returns the plaintext.
Session secrets
A session secret belongs to a single chat session. It is set on the same POST /v2/agents/{agent_key}/sessions call that creates the session, and rotated or removed afterwards with the same PATCH /v2/agents/{agent_key}/sessions/{session_key} call you would use to change any other session field — there is no separate secrets endpoint.
Use session secrets when the credential is bound to one conversation: an OAuth access token the user pasted at session start, an ephemeral API token tied to a single workflow run, anything that should not survive the session.
Reach the plaintext from a tool with {"$ref": "session.secrets.<name>"}. The substitution and masking work exactly the same way as agent secrets.
CREATE A SESSION WITH SECRETS
Code example with bash syntax.1
The names (with values masked as "****") are returned on every session read — GET /v2/agents/{agent_key}/sessions/{session_key} and the list endpoint both surface them on AgentSession.secrets.
To rotate one secret or remove another, PATCH the session with a partial secrets map: names with a value are added or replaced, names mapped to null are removed, and names absent from the map are left alone. Omit secrets entirely from the request to leave the stored secrets untouched.
ROTATE ONE SESSION SECRET, REMOVE ANOTHER
Code example with bash syntax.1
Session secrets are stored encrypted at rest and always returned with values masked as "****" — plaintext is never exposed on read.