Claude API: Admin, Workspaces, Webhooks — Function Reference
Source files:
admin/api-keys.js(839 LOC) — API key CRUD + validation + rotation + auditadmin/workspaces.js(725 LOC) — admin workspace managementadmin/organization.js— organization managementworkspaces/manager.js(710 LOC) — workspace lifecycleworkspaces/collaboration.js(818 LOC) — workspace members + invitationsworkspaces/projects.js(732 LOC) — projects within workspaceswebhooks/manager.js(659 LOC) — webhook registration + lifecyclewebhooks/delivery.js(669 LOC) — webhook delivery with retrywebhooks/signature.js— HMAC signature generation/verificationwebhooks/events.js— event type definitions + emitter
Exported Functions — admin/api-keys.js
createApiKey(options): Promise<ApiKey>
Purpose: Generate a new API key, hash it for storage, store in DB. Plaintext key returned ONLY on creation. Parameters:
name(string): Key display nameorg_id(string): Organization ID-
workspace_id(stringnull): Scope to workspace user_id(string): Owner user IDpermissions(string[]): Permission stringsscopes(string[]): Access scopes (default:["read", "write"])rate_limit(object): Custom limits override-
expires_at(stringnull): ISO expiry date created_by(string): Creator user IDmetadata(object)
Returns: ApiKey instance with .plaintext_key attached (only on creation).
Notes for rewrite: Key format: ams_{64-char hex}. Stored as SHA-256 hash. Default rate limits: 100 req/min, 1000 req/hr, 10000 req/day.
getApiKeyById(id): Promise<ApiKey|null>
getApiKeyByHash(keyHash): Promise<ApiKey|null>
Purpose: Look up active key by SHA-256 hash (used for authentication).
validateApiKey(plaintextKey): Promise<ValidationResult>
Purpose: Authenticate a plaintext API key — hash it, find in DB, check expiry and revocation status.
Returns: { valid: true, apiKey } or { valid: false, reason: string }
listApiKeys(options): Promise<ApiKey[]>
Purpose: List keys with optional filters.
Parameters: { org_id?, workspace_id?, user_id?, status?, limit?, offset? }
updateApiKey(id, updates): Promise<ApiKey|null>
Purpose: Update allowed fields: name, permissions, scopes, rate_limit, status, metadata.
revokeApiKey(id, revokedBy): Promise<ApiKey>
Purpose: Set key status to “revoked” and log the action.
rotateApiKey(id, options): Promise<{oldKey, newKey}>
Purpose: Create a new key with same settings, revoke old key, set rotated_from link.
Parameters:
rotatedBy(string): User performing rotationgracePeriodMs(number): Overlap window where old key still works
Returns: { oldKey: ApiKey, newKey: ApiKey (with plaintext) }
checkRateLimit(apiKeyId): Promise<RateLimitResult>
Purpose: Check and increment rate limit counters.
Returns: { allowed: boolean, remaining: {perMinute, perHour, perDay}, resetAt }
getApiKeyUsage(id, options): Promise<UsageRecord[]>
Purpose: Get usage history from audit log.
getApiKeyAuditLog(id, options): Promise<AuditRecord[]>
Purpose: Get all audit log entries for a key.
class ApiKey
Fields: id, name, key_hash, key_preview, org_id, workspace_id, user_id, permissions, scopes, rate_limit, usage, status (active|revoked|expired), expires_at, last_used_at, created_at, updated_at, created_by, rotated_from, metadata
Method: toJSON(includeSensitive) — omits hash unless includeSensitive: true
Exported Functions — workspaces/manager.js
createWorkspace(options): Promise<Workspace>
Purpose: Create workspace with resource limits and ownership. Parameters:
name(string, required, max 255 chars)description(string)owner_id(string)-
org_id(stringnull) settings(object)resource_limits(object): Overrides default limits (max_projects: 100, max_members: 50, storage_gb: 100, api_calls_per_day: 10000, max_conversations: 1000)metadata(object)
Returns: Workspace instance.
getWorkspace(id): Promise<Workspace|null>
listWorkspaces(options): Promise<Workspace[]>
Parameters: { org_id?, owner_id?, status?, limit?, offset? }
updateWorkspace(id, updates): Promise<Workspace|null>
Purpose: Update name, description, settings, metadata, status, resource_limits.
deleteWorkspace(id): Promise<DeleteResult>
Purpose: Archive workspace and all associated resources.
getWorkspaceStats(id): Promise<WorkspaceStats>
Purpose: Count projects, members, conversations within workspace.
Returns: { projectCount, memberCount, conversationCount, apiCallsToday, storageUsed }
class Workspace
Fields: id, name, description, owner_id, org_id, settings, metadata, status (active|suspended|archived), resource_limits, created_at, updated_at, created_by
Method: toJSON()
Exported Functions — workspaces/collaboration.js
addMember(workspaceId, options): Promise<MemberRecord>
Parameters: { user_id, role: owner|admin|member|viewer, invited_by, metadata? }
removeMember(workspaceId, userId): Promise<boolean>
getMember(workspaceId, userId): Promise<MemberRecord|null>
listMembers(workspaceId, options): Promise<MemberRecord[]>
updateMemberRole(workspaceId, userId, role): Promise<MemberRecord>
inviteMember(workspaceId, options): Promise<InvitationRecord>
Parameters: { email, role, invited_by, message? }
Notes for rewrite: Creates invitation record with token; actual email delivery not included.
acceptInvitation(token): Promise<AcceptResult>
revokeInvitation(invitationId): Promise<boolean>
listInvitations(workspaceId, options): Promise<InvitationRecord[]>
Exported Functions — workspaces/projects.js
createProject(workspaceId, options): Promise<Project>
getProject(projectId): Promise<Project|null>
listProjects(workspaceId, options): Promise<Project[]>
updateProject(projectId, updates): Promise<Project|null>
archiveProject(projectId): Promise<Project>
deleteProject(projectId): Promise<DeleteResult>
Exported Functions — webhooks/manager.js
validateWebhookUrl(url): ValidationResult
Purpose: Check URL protocol (http/https only) and block private IPs in production.
Returns: { valid: boolean, error?: string }
generateWebhookId(): string
Purpose: Generate timestamped unique webhook ID (wh_{timestamp}_{random}).
class WebhookManager
Central manager for all webhooks:
register(options): RegistrationResult
Purpose: Validate URL + event types, create and store Webhook instance.
Parameters:
url(string): Callback URLdescription(string)eventTypes(string[]): Empty = all events; supports wildcards (*,category.*)secret(string, optional): Auto-generated if not providedconfig(object):{ maxRetries, timeout, rateLimitPerSecond, rateLimitPerMinute }metadata(object)
Returns: { success, webhook: {id, url, secret} }
unregister(webhookId): boolean
pause(webhookId): boolean
resume(webhookId): boolean
getWebhook(webhookId): Webhook|undefined
listWebhooks(filters): Webhook[]
Parameters: { status?, eventType?, limit?, offset? }
updateWebhook(webhookId, updates): UpdateResult
testWebhook(webhookId): Promise<TestResult>
Purpose: Send test ping event to webhook URL.
triggerEvent(eventType, payload): Promise<TriggerResult>
Purpose: Fire event to all subscribed webhooks.
Returns: { triggered, delivered, failed }
getStats(): WebhookStats
class Webhook
Fields: id, url, description, eventTypes, secret, status (active|paused|disabled|error), config, metadata, createdAt, updatedAt, stats
Methods:
isSubscribedTo(eventType): Check subscription including wildcardsupdateStats(success): Increment delivery counterssetStatus(newStatus): Change statusrotateSecret(newSecret?): Generate new HMAC secretsetEventTypes(eventTypes): Update subscriptions with validationtoJSON(): Safe output without secret; setshasSecret: truestatic fromJSON(data): Deserialize
Exported Functions — webhooks/delivery.js
class WebhookDeliveryManager
deliver(webhook, event): Promise<DeliveryResult>
Purpose: Send event payload to webhook URL with HMAC signature. Implements exponential backoff retry.
Returns: { success, statusCode, attempts, duration }
getDeliveryHistory(webhookId, options): DeliveryRecord[]
getDeliveryStats(): DeliveryStats
Returns: { totalDeliveries, successRate, averageResponseTime, failuresByWebhook }
Exported Functions — webhooks/signature.js
generateSecret(): string
Purpose: Generate a cryptographically random webhook secret.
class SignatureManager
sign(payload, secret): string
Purpose: Generate HMAC-SHA256 signature of payload.
Returns: sha256={hex_digest}
verify(payload, signature, secret): boolean
Purpose: Constant-time compare of computed vs provided signature.
getGlobalDeliveryManager(): WebhookDeliveryManager
Purpose: Singleton delivery manager.
webhooks/events.js — Key Exports
WebhookEventTypes
| Category | Events | |———-|——–| | message | message.created, message.completed, message.failed | | batch | batch.created, batch.completed, batch.failed | | usage | usage.threshold_exceeded, usage.daily_reset | | api_key | api_key.created, api_key.rotated, api_key.revoked | | workspace | workspace.created, workspace.updated, workspace.deleted | | member | member.added, member.removed, member.role_changed |
isValidEventType(eventType): boolean
getGlobalEmitter(): EventEmitter
Key Data Structures
| Structure | Fields | Purpose |
|---|---|---|
| ApiKey | id, name, key_hash, key_preview, org_id, scopes, rate_limit, status, expires_at | API key entity |
| Workspace | id, name, owner_id, org_id, status, resource_limits | Workspace entity |
| MemberRecord | workspace_id, user_id, role, joined_at, invited_by | Membership |
| Webhook | id, url, eventTypes, secret, status, config, stats | Webhook registration |
| DeliveryRecord | webhookId, eventType, payload, statusCode, attempts, duration, createdAt | Delivery log |
DB Tables Used
api_keysapi_key_audit_logworkspacesworkspace_membersworkspace_invitationsworkspace_projects- Webhooks: in-memory (Map) — not persisted to DB
External Dependencies
../../db/index.js—getDb()crypto(Node.js built-in):randomUUID,createHash,randomBytes,timingSafeEqualurl(Node.js built-in):URLfor webhook URL validation
Notes for Rewrite
- Webhook registrations are in-memory only (no DB persistence). Add a
webhookstable for production. rotateApiKeywithgracePeriodMscurrently only setsrotated_fromlink — grace period enforcement is not implemented.- Rate limiting counters use JSON-serialized usage field in
api_keystable — not atomic under concurrent load. inviteMembercreates invitation record but does NOT send email. Caller must handle email delivery.- Webhook wildcards (
category.*) are correctly handled inWebhook.isSubscribedTo(). SignatureManager.verify()usescrypto.timingSafeEqual— safe against timing attacks.