Secrets

Create a secret

Store a credential so environments can grant it to runs. THE VALUE TRAVELS IN THE REQUEST BODY and becomes visible to whatever makes the call. The response is metadata only. Creating a project-shared secret requires project admin; a personal one does not.

post/projects/{projectId}/secrets

Headers

Idempotency-Keystring

Retry-safe create key. Replaying the SAME key with the SAME body returns the original resource instead of creating a second one; reusing it with a DIFFERENT body is a 409. Worth passing: a retried create without one fails as a name conflict with the row the first attempt already made.

Request body

namestring required

Environment-variable name. Immutable — renaming is delete-and-recreate.

valuestring required

The credential. Stored encrypted; no route ever returns it. NOT trimmed — a trailing newline is meaningful in a PEM block, and rewriting what you sent would present as 'the key is wrong' with nothing to look at.

descriptionstring
delivery'brokered' | 'materialized' required

Required, with no default: a caller who has not said whether the value ends up inside the sandbox has not made the decision this field exists for. See Secret.delivery.

brokerHostsstring[]

Required for brokered, forbidden for materialized. Exact hostnames — no scheme, no port, no wildcard: the proxy matches a host, and a URL installs a rule that silently never fires.

brokerHeaderstring

Required for brokered, forbidden for materialized. e.g. Authorization.

brokerTemplatestring

Required for brokered, forbidden for materialized. The header value with {} where the secret goes, e.g. Bearer {}. A template without {} is rejected: it installs a constant header that never carries the credential.

sharing'user' | 'project'

Defaults to project. A non-admin asking for it is refused rather than downgraded to personal — a silent downgrade looks like success and then reaches nobody else's sessions.

Response

The created secret, as metadata.

idstring required
projectIdstring required
namestring required

The environment-variable name (^[A-Z_][A-Z0-9_]*$). This IS the secret's identity: what a materialized delivery exports, what a workflow references, and what stays stable across a rotation. Immutable.

descriptionstring nullable required
delivery'brokered' | 'materialized' required

brokered — the sandbox's egress proxy injects the value as a request header OUTSIDE the VM, so the box never holds it. Prevents EXTRACTION, not USE: any process in the box can call the bound host while the policy is live, and it works for HTTPS APIs only (domain rules bind on ports 80/443). materialized — a real environment variable inside the box, which is the only thing a CLI can read; EXTRACTABLE BY DESIGN.

brokerHostsstring[]

Brokered only: the exact hostnames the header is injected on.

brokerHeaderstring

Brokered only: the header name.

brokerTemplatestring

Brokered only: the header value, with {} where the secret goes.

sharing'user' | 'project' required

project — admin-managed, delivered to every member's sessions. user — personal, delivered ONLY in sessions its owner starts and silently absent from anyone else's run of the same environment. Immutable.

ownerUserIdstring

Personal secrets only. Project-shared rows have no owner.

lastDeliveredAtinteger nullable required

When this secret was last HANDED TO a run — not when it was last used. Brokered use is unobservable by construction (the proxy injects the header; the request is never seen here), so used would be a number nobody can honestly produce. null means nothing has been recorded, which is not the same as never delivered.

createdAtinteger required
updatedAtinteger required
createdByUserIdstring required
updatedByUserIdstring required

Changes