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

Scope required: read:secrets

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_..."
}
}

Scope required: write:secrets

Full replacement

The API replaces all secrets in the environment. Secrets not in the payload are moved to trash.

The CLI handles this differently: without --prune, it merges vault secrets into the payload before sending, so nothing is deleted. Use the CLI for additive pushes.

Pull secrets​

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

Scope required: read:secrets

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)