Manage API keys

An API key is a bearer token bound to one workspace and carrying one scope. The secret is shown once, at creation; everything after that works with the key id and a display prefix.

Scopes#

ScopePrefixSendsReads
livehookchat_live_Go to Meta and reach real people.See live rows.
testhookchat_test_Route through a mock connection and never leave HookChat.Write rows that other reads only show with include_test.

A key inherits the caller's scope unless you pass one, and a test key can never create a live key (that is a 403 forbidden). Events produced under a test key stay inside HookChat and never reach your endpoints, so a colleague's sandbox traffic never reaches production.

Create a key#

The response carries id, prefix, scope, label, created_at and, once only, secret. Store the secret immediately; no read path returns it again.

TypeScript
import { HookChat } from '@hookchat/node'

const client = new HookChat({ apiKey: process.env.HOOKCHAT_API_KEY!, baseUrl: process.env.HOOKCHAT_BASE_URL! })

const created = await client.keys.create({ scope: 'test', label: 'docs' })
console.log('id', created.id)
console.log('prefix', created.prefix, 'scope', created.scope)
// created.secret is the plaintext key. Store it now and never log it.

List keys#

Listing returns every key in the workspace, newest first, with its prefix, scope, label, status and creation time. Revoked keys stay in the list with status revoked. The list is not paginated. The list also shows when each key was last used, to the nearest five minutes, so a key nobody has used for months is easy to spot and revoke.

TypeScript
import { HookChat } from '@hookchat/node'

const client = new HookChat({ apiKey: process.env.HOOKCHAT_API_KEY!, baseUrl: process.env.HOOKCHAT_BASE_URL! })

const keys = await client.keys.list()
for (const key of keys) console.log(key.id, key.prefix, key.scope, key.status, key.label)
console.log(keys.length, 'keys')

Revoke a key#

A revoked key stops working within a minute: the gateway keeps a key lookup for up to 60 seconds. Revoking is safe to repeat: revoking an already revoked key still succeeds. An unknown id, or an id from another workspace, is a 404 key_not_found, never a 403, so ids do not leak across workspaces. The sample creates a throwaway key and revokes it.

TypeScript
import { HookChat } from '@hookchat/node'

const client = new HookChat({ apiKey: process.env.HOOKCHAT_API_KEY!, baseUrl: process.env.HOOKCHAT_BASE_URL! })

const temp = await client.keys.create({ scope: 'test', label: 'docs-temp' })
const { revoked } = await client.keys.revoke(temp.id)
console.log('revoked', revoked, temp.id)

Operator keys and workspaces#

A key created in the console or through the API is bound to one workspace and needs no tenant parameter. An operator key serves several workspaces, so it must name one on every call. Pass it as ?tenant= on the API, the tenant client option or per-call parameter in the SDKs, or --tenant or HOOKCHAT_TENANT in the CLI.

Omitting it is a 400 tenant_required; naming a workspace the key is not allowed on is a 403 forbidden. The send routes take no workspace at all: the conversation id already scopes the send.

Where to keep the secret#

Treat a key like a password. Keep it in a secret manager or an environment variable. Give each worker its own labelled key, so you can revoke one without touching the rest. Never ship a key in a browser bundle: the API allows browser calls only from the console's own origin.

Every key action (create, revoke) is written to the audit trail with the actor that performed it. hookchat audit list or client.audit.list() shows it.

Next#