Skip to main content

API Reference

Base URL: https://api.keyway.sh/v1

Authentication

Authorization: Bearer <token>
Token TypeSourceUse Case
Keyway API KeyDashboard -> API KeysCI/CD, automation (recommended)
Keyway JWTkeyway login -> ~/.config/keyway-nodejs/config.jsonCLI, scripts
GitHub PATFine-grained PATLegacy CI/CD

API Keys

Create and manage API keys from the Dashboard.

Token Format

kw_live_a1B2c3D4e5F6g7H8i9J0k1L2m3N4o5P6q7R8s9T0
└─┘ └──┘ └────────────────────────────────────────┘
│ │ │
│ │ └── 40 chars base62 (240-bit entropy)
│ └── Environment: live | test
└── Prefix

Scopes

ScopePermissions
read:secretsPull secrets, list vaults, view secret values
write:secretsPush secrets, create/update vaults and secrets
delete:secretsDelete secrets, trash operations, delete vaults
admin:api-keysCreate/revoke API keys
Least Privilege

For CI/CD pipelines that only need to pull secrets, use only read:secrets scope.

Create API Key

POST /v1/api-keys
{
"name": "CI/CD Production",
"environment": "live",
"scopes": ["read:secrets", "write:secrets"],
"expiresInDays": 365,
"allowedIps": ["192.168.1.0/24"] // Optional IP restrictions
}

Returns the full token once. Store it securely.

{
"data": {
"id": "uuid",
"name": "CI/CD Production",
"token": "kw_live_a1B2c3D4...",
"prefix": "kw_live_a1B2c3D4",
"environment": "live",
"scopes": ["read:secrets", "write:secrets"],
"expiresAt": "2026-01-01T00:00:00Z"
}
}

List API Keys

GET /v1/api-keys

Returns all keys (token is never returned after creation).

Get API Key

GET /v1/api-keys/:id

Revoke API Key

DELETE /v1/api-keys/:id

Immediate revocation. Cannot be undone.

Usage Example

# Pull secrets with API key
curl -H "Authorization: Bearer kw_live_xxx" \
"https://api.keyway.sh/v1/secrets/pull?repo=owner/repo&environment=production"

Vaults

List vaults

GET /v1/vaults?limit=25&offset=0

Create vault

POST /v1/vaults
{ "repoFullName": "owner/repo" }

Requires admin access. Returns 409 if vault exists.

Get vault

GET /v1/vaults/:owner/:repo

Delete vault

DELETE /v1/vaults/:owner/:repo

Requires admin access. Permanently deletes all secrets.

List collaborators

GET /v1/vaults/:owner/:repo/collaborators

Returns all GitHub collaborators with their roles.


Secrets

List secrets (metadata only)

GET /v1/vaults/:owner/:repo/secrets?limit=25&offset=0

Create secret

POST /v1/vaults/:owner/:repo/secrets
{
"key": "DATABASE_URL",
"value": "postgres://...",
"environment": "production"
}

Update secret

PATCH /v1/vaults/:owner/:repo/secrets/:secretId
{ "value": "new_value" }

Can also rename:

{ "name": "NEW_KEY_NAME" }

Delete secret

DELETE /v1/vaults/:owner/:repo/secrets/:secretId

Moves to trash (soft delete). See Trash to permanently delete.

Get secret value

GET /v1/vaults/:owner/:repo/secrets/:secretId/value

Returns { "value": "...", "preview": "post••••2/db" }. Rate limited (10/min).

View single secret (MCP/scripts)

GET /v1/secrets/view?repo=owner/repo&environment=local&key=DATABASE_URL

Returns single secret value. Logged in audit trail.


Secret Versions

Keyway keeps a history of secret changes (Team plan: 30 days).

List versions

GET /v1/vaults/:owner/:repo/secrets/:secretId/versions

Returns:

{
"data": [
{
"id": "version-uuid",
"versionNumber": 3,
"createdAt": "2025-01-15T10:00:00Z",
"createdBy": "user-uuid"
},
{
"id": "version-uuid-2",
"versionNumber": 2,
"createdAt": "2025-01-10T10:00:00Z",
"createdBy": "user-uuid"
}
]
}

Get version value

GET /v1/vaults/:owner/:repo/secrets/:secretId/versions/:versionId/value

Returns the secret value at that specific version.

Restore version

POST /v1/vaults/:owner/:repo/secrets/:secretId/versions/:versionId/restore

Restores the secret to this version (creates a new version with the old value).


Trash

Deleted secrets are soft-deleted and can be recovered.

List trashed secrets

GET /v1/vaults/:owner/:repo/trash?limit=25&offset=0

Restore from trash

POST /v1/vaults/:owner/:repo/trash/:secretId/restore

Permanently delete

DELETE /v1/vaults/:owner/:repo/trash/:secretId

Warning: This cannot be undone.

Empty trash

DELETE /v1/vaults/:owner/:repo/trash

Permanently deletes all trashed secrets.


Bulk Operations (CLI)

Push secrets

POST /v1/secrets/push
{
"repoFullName": "owner/repo",
"environment": "local",
"secrets": {
"DATABASE_URL": "postgres://...",
"API_KEY": "sk_test_..."
}
}

Full sync: secrets not in payload are moved to trash.

Pull secrets

GET /v1/secrets/pull?repo=owner/repo&environment=local

Returns .env format in data.content.


Environments

List environments

GET /v1/vaults/:owner/:repo/environments

Create environment

POST /v1/vaults/:owner/:repo/environments
{ "name": "preview" }

Requires admin. Name: 2-30 chars, lowercase, letters/numbers/dashes.

Rename environment

PATCH /v1/vaults/:owner/:repo/environments/:name
{ "newName": "development" }

Delete environment

DELETE /v1/vaults/:owner/:repo/environments/:name

Deletes all secrets in the environment.


Users

Get current user

GET /v1/users/me

Get usage

GET /v1/users/me/usage
{
"data": {
"plan": "free",
"limits": { "maxPrivateRepos": 1 },
"usage": { "private": 0, "public": 2 }
}
}

Activity

List activity

GET /v1/activity?limit=50&offset=0

Returns paginated activity logs for the current user. See Security for details.


OAuth Device Flow

1. Start

POST /v1/auth/device/start
{ "repository": "owner/repo" }

2. Poll

POST /v1/auth/device/poll
{ "deviceCode": "abc123..." }

Returns status: pending, approved, expired, denied.


Response Format

Success

{
"data": { ... },
"meta": { "requestId": "550e8400-..." }
}

Paginated

{
"data": [ ... ],
"meta": {
"requestId": "550e8400-...",
"pagination": {
"limit": 25,
"offset": 0,
"total": 100,
"hasMore": true
}
}
}

Error (RFC 7807)

{
"type": "https://keyway.sh/errors/not-found",
"title": "Not Found",
"status": 404,
"detail": "Vault not found for repository owner/repo"
}

Error Codes

StatusTypeDescription
400bad-requestInvalid request
401unauthorizedAuth missing/invalid
403forbiddenInsufficient permissions
403plan-limitPlan limit exceeded (includes upgradeUrl)
404not-foundResource not found
409conflictResource already exists
422validation-errorInvalid field values
429rate-limitedToo many requests

Rate Limits

EndpointLimit
General100 req / 15 min
Device verify5 req / min
Secret value10 req / min

Headers: X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After


Validation Rules

Secret keys

  • Pattern: ^[A-Z][A-Z0-9_]{0,255}$
  • Max: 256 chars
  • Valid: DATABASE_URL, API_KEY_V2

Environment names

  • Pattern: ^[a-z][a-z0-9_-]{1,29}$
  • 2-30 chars
  • Valid: local, dev-01, staging_v2

Secret values

  • Max: 64 KB (256 KB on Team plan)