Docs Guides API Keys API keys are the primary way to authenticate with the Weavz API from your backend services. Each key belongs to an organization; by default it has org-wide access, but it can be restricted to selected workspaces and optionally granted Human Gates decision permission.
All Weavz API keys use the wvz_ prefix followed by a random string:
wvz_550e8400-e29b-41d4-a716-446655440000...
This prefix makes it easy to identify Weavz keys in your codebase and allows secret scanners to detect leaked credentials.
Dashboard Code
Open Settings Navigate to Settings → API Keys in the Weavz dashboard.
Create a new key Click Create API Key and enter a descriptive name (e.g., production-backend, staging-server).
Set expiration (optional) Optionally set an expiration date for automatic key rotation.
Copy the key Click Create and copy the key immediately — it will only be shown once.
curl TypeScript SDK Python SDK TypeScript Python
curl -X POST https://api.weavz.io/api/v1/api-keys \
-H "Authorization: Bearer wvz_your_existing_key" \
-H "Content-Type: application/json" \
-d '{
"name": "production-backend",
"expiresAt": "2026-12-31T23:59:59Z"
}' Response:
{
"apiKey" : {
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"name" : "production-backend" ,
"expiresAt" : "2026-12-31T23:59:59Z" ,
"createdAt" : "2025-01-15T10:30:00Z"
},
"plainKey" : "wvz_550e8400-e29b-41d4-a716-446655440000..."
} The plainKey field contains the full API key. This is the only time it will be returned — Weavz stores a hashed version at rest.
import { WeavzClient } from '@weavz/sdk'
const client = new WeavzClient ({ apiKey: 'wvz_your_key' })
const { apiKey , plainKey } = await client.apiKeys. create ({
name: 'staging-server' ,
expiresAt: '2026-06-01T00:00:00Z' ,
})
console. log ( 'New key:' , plainKey) from weavz_sdk import WeavzClient
client = WeavzClient( api_key = "wvz_your_key" )
result = client.api_keys.create( name = "staging-server" )
print ( "New key:" , result[ "plainKey" ]) const res = await fetch ( 'https://api.weavz.io/api/v1/api-keys' , {
method: 'POST' ,
headers: {
'Authorization' : 'Bearer wvz_your_existing_key' ,
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
name: 'production-backend' ,
expiresAt: '2026-12-31T23:59:59Z' ,
}),
})
const { apiKey , plainKey } = await res. json ()
console. log ( 'New key:' , plainKey) import httpx
res = httpx.post(
"https://api.weavz.io/api/v1/api-keys" ,
headers = { "Authorization" : "Bearer wvz_your_existing_key" },
json = {
"name" : "production-backend" ,
"expiresAt" : "2026-12-31T23:59:59Z" ,
},
)
data = res.json()
print ( "New key:" , data[ "plainKey" ])
Include your API key in the Authorization header of every API request:
Authorization : Bearer wvz_your_key
curl TypeScript SDK Python SDK TypeScript Python
curl https://api.weavz.io/api/v1/api-keys \
-H "Authorization: Bearer wvz_your_key" const keys = await client.apiKeys. list () keys = client.api_keys.list() const res = await fetch ( 'https://api.weavz.io/api/v1/api-keys' , {
headers: { 'Authorization' : 'Bearer wvz_your_key' },
})
const keys = await res. json () import httpx
res = httpx.get(
"https://api.weavz.io/api/v1/api-keys" ,
headers = { "Authorization" : "Bearer wvz_your_key" },
)
keys = res.json()
curl TypeScript SDK Python SDK TypeScript Python
curl -X DELETE https://api.weavz.io/api/v1/api-keys/API_KEY_UUID \
-H "Authorization: Bearer wvz_your_key" await client.apiKeys. delete ( 'API_KEY_UUID' ) client.api_keys.delete( "API_KEY_UUID" ) const res = await fetch ( 'https://api.weavz.io/api/v1/api-keys/API_KEY_UUID' , {
method: 'DELETE' ,
headers: { 'Authorization' : 'Bearer wvz_your_key' },
}) import httpx
res = httpx.delete(
"https://api.weavz.io/api/v1/api-keys/API_KEY_UUID" ,
headers = { "Authorization" : "Bearer wvz_your_key" },
)
To rotate an API key without downtime:
Create a new key Generate a new API key via the dashboard or API.
Update your application Deploy the new key to your environment variables.
Verify the new key Confirm the new key works in production.
Delete the old key Revoke the old key once the new one is verified.
Use the create key examples to generate the replacement, deploy the new secret to your backend, verify it with a low-risk request, then use the delete key examples to revoke the old key.
By default, API keys have org-wide access. For tighter security, you can scope a key to specific workspaces — the key will only be able to access resources (connections, MCP servers, triggers, actions) within those workspaces.
curl TypeScript SDK Python SDK TypeScript Python
curl -X POST https://api.weavz.io/api/v1/api-keys \
-H "Authorization: Bearer wvz_your_existing_key" \
-H "Content-Type: application/json" \
-d '{
"name": "checkout-service",
"permissions": {
"scope": "workspace",
"workspaceIds": ["WORKSPACE_UUID_1"]
}
}' import { WeavzClient } from '@weavz/sdk'
const client = new WeavzClient ({ apiKey: 'wvz_your_key' })
const { apiKey , plainKey } = await client.apiKeys. create ({
name: 'checkout-service' ,
permissions: {
scope: 'workspace' ,
workspaceIds: [ 'WORKSPACE_UUID_1' ],
},
})
console. log ( 'Scoped key:' , plainKey) from weavz_sdk import WeavzClient
client = WeavzClient( api_key = "wvz_your_key" )
result = client.api_keys.create(
name = "checkout-service" ,
permissions = {
"scope" : "workspace" ,
"workspaceIds" : [ "WORKSPACE_UUID_1" ],
},
)
print ( "Scoped key:" , result[ "plainKey" ]) const res = await fetch ( 'https://api.weavz.io/api/v1/api-keys' , {
method: 'POST' ,
headers: {
'Authorization' : 'Bearer wvz_your_existing_key' ,
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
name: 'checkout-service' ,
permissions: {
scope: 'workspace' ,
workspaceIds: [ 'WORKSPACE_UUID_1' ],
},
}),
})
const { apiKey , plainKey } = await res. json ()
console. log ( 'Scoped key:' , plainKey) import httpx
res = httpx.post(
"https://api.weavz.io/api/v1/api-keys" ,
headers = { "Authorization" : "Bearer wvz_your_existing_key" },
json = {
"name" : "checkout-service" ,
"permissions" : {
"scope" : "workspace" ,
"workspaceIds" : [ "WORKSPACE_UUID_1" ],
},
},
)
data = res.json()
print ( "Scoped key:" , data[ "plainKey" ])
If a workspace-scoped key tries to access a resource outside its allowed workspaces, the API returns 403 with code SCOPE_DENIED. API key management requires an org-wide key.
When sending connectionExternalId/externalId for action execution or connection resolution, include the correct workspaceId (and endUserId when applicable). Explicit connection IDs are still validated against that context and are rejected on scope mismatch.
Human Gates decisions require an API key with approvals.decide. Enable it on the same backend key when your product should both create and resolve gated work, or keep it on a separate backend API key when you want operational separation.
curl TypeScript SDK Python SDK TypeScript Python
curl -X POST https://api.weavz.io/api/v1/api-keys \
-H "Authorization: Bearer wvz_your_existing_key" \
-H "Content-Type: application/json" \
-d '{
"name": "approval-reviewer",
"permissions": {
"scope": "workspace",
"workspaceIds": ["WORKSPACE_UUID_1"],
"approvals": { "decide": true }
}
}' const { plainKey } = await client.apiKeys. create ({
name: 'approval-reviewer' ,
permissions: {
scope: 'workspace' ,
workspaceIds: [ 'WORKSPACE_UUID_1' ],
approvals: { decide: true },
},
}) result = client.api_keys.create(
name = "approval-reviewer" ,
permissions = {
"scope" : "workspace" ,
"workspaceIds" : [ "WORKSPACE_UUID_1" ],
"approvals" : { "decide" : True },
},
)
plain_key = result[ "plainKey" ] const res = await fetch ( 'https://api.weavz.io/api/v1/api-keys' , {
method: 'POST' ,
headers: {
'Authorization' : 'Bearer wvz_your_existing_key' ,
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
name: 'approval-reviewer' ,
permissions: {
scope: 'workspace' ,
workspaceIds: [ 'WORKSPACE_UUID_1' ],
approvals: { decide: true },
},
}),
})
const { plainKey } = await res. json () import httpx
res = httpx.post(
"https://api.weavz.io/api/v1/api-keys" ,
headers = { "Authorization" : "Bearer wvz_your_existing_key" },
json = {
"name" : "approval-reviewer" ,
"permissions" : {
"scope" : "workspace" ,
"workspaceIds" : [ "WORKSPACE_UUID_1" ],
"approvals" : { "decide" : True },
},
},
)
plain_key = res.json()[ "plainKey" ]
The permission is still scoped. Workspace keys can only decide Human Gates requests in their allowed workspaces, while organization keys can decide organization-wide requests.
Use workspace-scoped keys for least-privilege access — each service should only access the workspaces it needs
Use environment variables — never hardcode API keys in source code
Separate keys per environment — use different keys for development, staging, and production
Set expiration dates — rotate keys periodically for better security
Never expose keys in client-side code — API keys should only be used in server-side applications
Monitor usage — check the Activity page to track API key usage
Revoke compromised keys immediately — if a key is leaked, delete it and create a new one
PreviousSetup Templates Next Setting Up Connections