Groundfloor Docs

Secrets API

List, reveal, upsert, and delete workspace-scoped secrets.

Base path: /v1/workspaces/{workspace_id}/secrets

Secrets are encrypted at rest, and kept per environment. Every reveal is logged in the activity log.

Every route except the comparison and promotion routes takes an optional ?environment_id= query parameter to pick the environment. Without it, the workspace-wide secrets are used. Responses include the environment_id they applied to.

Keys must start with a letter or underscore, contain only letters, digits and underscores, and be at most 256 characters. Other names return 422.

See also: Secrets

List secrets

GET /v1/workspaces/{workspace_id}/secrets

Returns keys and descriptions — values are redacted. Platform-managed keys are left out of the list.

Permission: read

curl -s -H "Authorization: Bearer $TOKEN" \
  "https://platform.groundfloor.cloud/v1/workspaces/$WORKSPACE_ID/secrets" | jq .

Response 200

{
  "secrets": [
    { "key": "STRIPE_API_KEY", "description": "Payments", "environment_id": null }
  ],
  "environment_id": null
}

Reveal secret

GET /v1/workspaces/{workspace_id}/secrets/{key}

Returns the plaintext value. Emits audit event secret.revealed.

Permission: write (M2M: secrets:read scope — see M2M callers)

curl -s -H "Authorization: Bearer $TOKEN" \
  "https://platform.groundfloor.cloud/v1/workspaces/$WORKSPACE_ID/secrets/STRIPE_API_KEY" | jq .

Response 200

{
  "key": "STRIPE_API_KEY",
  "value": "sk_live_…",
  "description": "Payments",
  "environment_id": null
}

Upsert secret

PUT /v1/workspaces/{workspace_id}/secrets/{key}

Create or update a secret. Response returns metadata only — never echoes the value.

Permission: write

curl -s -X PUT -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"value":"sk_live_…","description":"Payments"}' \
  "https://platform.groundfloor.cloud/v1/workspaces/$WORKSPACE_ID/secrets/STRIPE_API_KEY" | jq .

Request body

FieldTypeRequired
valuestringYes (up to 10,000 characters)
descriptionstringNo (up to 255 characters)

Delete secret

DELETE /v1/workspaces/{workspace_id}/secrets/{key}

Permission: delete

Returns 204 No Content.

Compare environments

GET /v1/workspaces/{workspace_id}/secrets/compare?source_environment_id=…&target_environment_id=…

Shows which keys differ between two environments. Values are never returned. Permission: read.

{
  "source_environment_id": "…",
  "target_environment_id": "…",
  "keys": [
    { "key": "STRIPE_API_KEY", "status": "both_differ" }
  ]
}

status is only_source, only_target, both_same or both_differ. The two environments must differ (otherwise 400) and both must be active (otherwise 409).

Promote secrets

POST /v1/workspaces/{workspace_id}/secrets/promote

Copies secrets from one environment to another.

FieldTypeRequiredDescription
source_environment_idstringYesEnvironment to copy from
target_environment_idstringYesEnvironment to copy to
keysstring[]NoKeys to copy. Omit to copy every non-platform-managed key
modestringNoskip_existing (default) leaves keys that already exist in the target; overwrite replaces them
dry_runboolNoReport what would be copied without writing. Default false

Returns { source_environment_id, target_environment_id, mode, dry_run, copied: [], skipped: [], failed: [{ key, error }] }. Permission: write. Logged as secret.promoted.

M2M callers

M2M tokens do not get Secrets access from their workspace grant alone:

RouteM2M with secrets:readM2M without it
List, compare, revealAllowed403
Upsert, delete, promote403403

Grant the scope on the client (Portal M2M tokens → Read secrets, or scopes on the M2M client API). Human callers are unaffected.

Platform-managed keys

Secrets that Groundfloor manages, such as the data API's key and managed database credentials, can't be changed or deleted through this API.

Errors

StatusMeaning
403Missing permission, platform-managed key mutation, or M2M caller without secrets:read / attempting a write
404Secret not found
422Key name isn't valid, or the value or description is too long
502The secret store is unavailable; retry