---
title: "Create a secret"
method: POST
path: "/api/secrets"
---

# Create a secret

`POST /api/secrets`

## Request

- Base URL: `https://api.hyperbrowser.ai`
- URL: `https://api.hyperbrowser.ai/api/secrets`
- Auth: API key in header `x-api-key`
- TypeScript: <https://skmtc.dev/hyperbrowser/apis/hyperbrowser-api/docs/api/secrets/post.ts> (a function with typed inputs; its response is checked against the schema)

Creates a secret without a value. Then upload its value with POST /api/secrets/{id}/versions, encrypted with the `encryptionContext` this returns. A team can have at most 100 secrets. Secrets are enabled for teams on request; please contact support to enable them (otherwise 403 SECRETS_FEATURE_DISABLED). Restricted API keys need the secrets.manage scope. When you're signed in rather than using an API key, you must be a team owner or admin (otherwise 403 SECRETS_ADMIN_REQUIRED).

## Request body

- CreateSecretParams
  - `name` string, required: 1-128 letters, digits, `_` or `-`, starting with a letter or digit. Unique within your team.
  - `description` string: Trimmed before it's stored.
  - `type` 'secret' | 'totp' | 'op_token': What the value is. Fixed at creation. `secret`: any string, set as an environment variable and, once it has allowed origins, typed into browser pages. `totp`: an authenticator seed (base32, or an `otpauth://totp/` URI); environment variables get the code current when the process starts, and fills type the code current at fill time. `op_token`: a 1Password service account token, used only to read the `onePassword` fields of a sandbox create, process start or browser credential fill; it's never an environment variable, a vault entry or a value typed into a page. Treat types you don't recognize as opaque: more may be added.
  - `metadata` SecretMetadata: Settings that aren't secret, returned by the API and editable without uploading a new value. A `secret` or `totp` secret can't be filled into browser pages until `browser.allowedOrigins` is set. An `op_token` secret accepts only `{}` (otherwise 400 SECRET_METADATA_INVALID).
    - `browser` SecretBrowserMetadata: Where the secret may be typed into browser pages. Allowed for `secret` and `totp`.
      - `allowedOrigins` string[], required: Origins a page or frame must be on before anything is typed, as `scheme://host[:port]` with no path, such as `https://github.com`. A leading `*.` matches any subdomain but not the domain itself, and must name at least two labels (`*.example.com`); you can't use a wildcard with an IP address. Origins must use https, except `http://localhost`, `http://127.0.0.1` and `http://[::1]`. Hyperbrowser lowercases origins, drops default ports and removes duplicates. An invalid entry returns 400 SECRET_METADATA_INVALID naming it.
  - `protection` 'platform' | 'customer': `platform` (the default): the value is encrypted to the platform key. `customer`: each version is also wrapped with your own key, and each use passes the envelope you unwrapped. See [Customer-protected secrets](/sandboxes/customer-keys).

## Response `200`

Success

- Secret: A secret. The API never returns its value.
  - `id` string, uuid, required
  - `name` string, required: 1-128 letters, digits, `_` or `-`, starting with a letter or digit. Unique within your team.
  - `description` string, required
  - `type` 'secret' | 'totp' | 'op_token', required: What the value is. Fixed at creation. `secret`: any string, set as an environment variable and, once it has allowed origins, typed into browser pages. `totp`: an authenticator seed (base32, or an `otpauth://totp/` URI); environment variables get the code current when the process starts, and fills type the code current at fill time. `op_token`: a 1Password service account token, used only to read the `onePassword` fields of a sandbox create, process start or browser credential fill; it's never an environment variable, a vault entry or a value typed into a page. Treat types you don't recognize as opaque: more may be added.
  - `metadata` SecretMetadata, required: Settings that aren't secret, returned by the API and editable without uploading a new value. A `secret` or `totp` secret can't be filled into browser pages until `browser.allowedOrigins` is set. An `op_token` secret accepts only `{}` (otherwise 400 SECRET_METADATA_INVALID).
    - `browser` SecretBrowserMetadata: Where the secret may be typed into browser pages. Allowed for `secret` and `totp`.
      - `allowedOrigins` string[], required: Origins a page or frame must be on before anything is typed, as `scheme://host[:port]` with no path, such as `https://github.com`. A leading `*.` matches any subdomain but not the domain itself, and must name at least two labels (`*.example.com`); you can't use a wildcard with an IP address. Origins must use https, except `http://localhost`, `http://127.0.0.1` and `http://[::1]`. Hyperbrowser lowercases origins, drops default ports and removes duplicates. An invalid entry returns 400 SECRET_METADATA_INVALID naming it.
  - `encryptionContext` string, required: Copy this verbatim into the `ctx` header of every envelope you upload for this secret. Don't build it yourself: it includes the secret's type for types other than `secret`, and an envelope sealed with another context returns 400 SECRET_ENVELOPE_INVALID.
  - `latestVersion` integer, nullable, required: The newest version number, or null until a value is uploaded.
  - `createdAt` string, date-time, required
  - `updatedAt` string, date-time, required
  - `protection` 'platform' | 'customer': `platform` (the default): the value is encrypted to the platform key. `customer`: each version is also wrapped with your own key, and each use passes the envelope you unwrapped. See [Customer-protected secrets](/sandboxes/customer-keys).

## Other responses

- `400`: Invalid request body, or SECRET_METADATA_INVALID.
- `401`: Authentication required.
- `403`: API_KEY_SCOPE_DENIED (the API key lacks a required scope), SECRETS_FEATURE_DISABLED, or SECRETS_ADMIN_REQUIRED.
- `409`: SECRET_NAME_TAKEN: a secret with this name exists. SECRET_LIMIT_REACHED: your team has 100 secrets.
- `500`: Internal server error.

## Changes

- **2026-11-10** `94dc06948680`: 2 info
  - added the new optional request property `protection`
  - added the optional property `protection` to the response with the `200` status
- **2026-10-15** `6ca0b00ee564`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/hyperbrowser/apis/hyperbrowser-api/changes/api/secrets/post.md)

---

[API](https://skmtc.dev/hyperbrowser/apis/hyperbrowser-api.md) - [All operations](https://skmtc.dev/hyperbrowser/apis/hyperbrowser-api/llms.txt) - [OpenAPI document](https://skmtc.dev/hyperbrowser/apis/hyperbrowser-api/revisions/ef089024c533?raw)
