Skip to main content
POST /secrets stores a reusable hosted secret, such as a model API key or an environment variable a task requires. This is the API equivalent of adding secrets through the Web UI. The examples below use $BASE and $KEY. Get a key from Harbor Hub API Key.
scope is user by default. Use job instead to scope a secret to a single job, which then requires a job_id; job_id is rejected when the scope is user. You can pass an org_id to place the secret in a specific organization, and an optional provider label of up to 64 characters. The response returns metadata only, never the value:

Replacing a Secret

Storing a secret whose env_var already has an active secret does not silently overwrite it. The request comes back as 409 replacement_required along with the record you are about to replace, so you can see exactly what is being replaced:
Send the same request again with "supersede_credential_id": "<existing.id>" to confirm. If that ID no longer matches the active secret, because something changed in between, you get 409 replacement_stale instead and should re-read before retrying. Superseding requires organization owner rights. The same pattern applies to registry secrets below.

Listing and Revoking Secrets

GET /secrets lists your secrets as metadata only. Filter with scope, job_id, and status, where status accepts active (the default), revoked, or all.
DELETE /secrets revokes a secret by environment variable name. Set purge to true only when the stored record should be permanently deleted rather than marked revoked.

Checking Secrets Before Launching

POST /secrets/preflight is an advisory check that reports whether each agent in a config will actually receive a credential its model can authenticate with. It never blocks a launch on its own.
Because secrets are scoped per agent, the check is run against each agent’s own selection rather than everything the organization stores: a name counts only when that agent’s secrets lists it and it resolves, either to an active secret in the owning organization or to a name in declared_env_vars. Send declared_env_vars for the one-off keys you plan to pass as job_secrets, since preflight never sees their values. The response reports an overall ok, per-provider results under providers, per-agent detail under agent_requirements — each with its model, provider, missing_env_vars, and configured — and task_requirements listing the environment variables the resolved tasks hard-require. The older agents field is still returned for existing clients. A task requirement counts as met only when the secret is configured and supplyable. Reserved infrastructure names — PATH, LD_PRELOAD, anything starting with MODAL_, SUPABASE_, HOSTED_HARBOR_, or GCP_, and anything ending in _PROXY — are never exported into a trial’s environment, so a task requiring one cannot be satisfied by supplying your own key.