Skip to content

API key management

API keys are the credential /api/v1 checks on every request. This page covers how to mint and revoke them, the on-disk format, and how lastUsedAt works.

UI flow

The key-management UI lives in the dashboard at Settings → API keys. It ships with FUL-13.

To mint a key:

  1. Open Settings → API keys → New key.
  2. Enter a human-readable name (e.g. ci-bot, dashboard-readonly). The name is shown in the table and in audit logs; it has no effect on authentication.
  3. Choose one or more scopes. See authentication — scopes.
  4. Click Create. The plaintext key is displayed once. Copy it immediately and store it in a secret manager.
  5. The dashboard never shows the plaintext again. If you lose it, revoke and mint a new one.

The keys table on the same page lists each key’s name, scopes, createdAt, lastUsedAt, and revokedAt, along with a Revoke action.

Key shape

A plaintext key looks like:

ts_a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f90
  • ts_ prefix marks it as a Trademark Sentinel key. Secret-scanning tools and the in-app paste detector use this prefix to flag accidental commits.
  • 32 cryptographically random bytes encoded as 64 hex characters follow the prefix (256 bits of entropy).
  • The full key is 67 characters long (ts_ + 64 hex chars).

Server-side storage

The plaintext is never persisted. On creation the server:

  1. Generates 32 cryptographically random bytes.
  2. Renders them as ts_<hex> and returns the plaintext in the create response.
  3. Computes SHA-256 over the plaintext and stores only that digest in ApiKey.hash (Prisma schema, plan §3 / §11).

On every request the server SHA-256-hashes the incoming Bearer token and looks the row up by hash. The ApiKey.hash column has a unique index, so the lookup is a single equality probe.

ApiKey columns visible to clients (over the API and in the dashboard table):

FieldTypeNotes
idstringUse this to revoke the key.
namestringUser-chosen label.
scopesstring[]See authentication — scopes.
lastUsedAtstring | nullISO-8601; updated on use (see below).
createdAtstringISO-8601.
revokedAtstring | nullISO-8601 once revoked; otherwise null.

hash is never returned over the API.

Revocation

DELETE /api/v1/api-keys/{id}

Authenticated by the dashboard session cookie (you cannot revoke a key with itself). Sets revokedAt to the current server time and from that moment forward all requests bearing that key fail with 401 unauthenticated.

Revocation is permanent and irreversible. To “un-revoke” a key, mint a new one — they are cheap, and rotating is the supported way to replace one.

Example

Terminal window
curl -sS -X DELETE \
https://api.trademarksentinel.app/api/v1/api-keys/ckxyz0000000abcdef \
-H "Cookie: session=<dashboard-session-cookie>"
{
"data": {
"id": "ckxyz0000000abcdef",
"name": "ci-bot",
"scopes": ["watches:write"],
"lastUsedAt": "2026-05-01T22:14:00.000Z",
"createdAt": "2026-04-12T08:00:00.000Z",
"revokedAt": "2026-05-02T11:32:08.123Z"
}
}

A repeat DELETE on an already-revoked key is a no-op and returns 200 with the same body. Revoking a key that does not exist (or that belongs to another user) returns 404 not_found.

lastUsedAt semantics

lastUsedAt is the timestamp of the most recent successful authentication using that key. It is intended for the dashboard’s “is this key still in use” view and for audit purposes.

  • It is updated on requests that pass authentication, even if the request later fails (e.g. validation, rate limit, scope mismatch). Authentication success is the trigger.
  • Updates are best-effort and coalesced: the server may batch writes per key over short windows (seconds, not minutes) to avoid hammering the row on every request. So the value is approximately current, not exact-to-the-millisecond.
  • A revoked key never updates lastUsedAt (the request fails authentication).
  • Newly minted, unused keys have lastUsedAt: null.

If you need stronger audit guarantees than lastUsedAt (e.g. per-request access logs), the dashboard’s Settings → API keys → Audit log view is the supported surface — it ships alongside the management UI in FUL-13.