Skip to content

Authentication

Every request to the public API authenticates with an API key passed in the Authorization header. Keys are scoped (catalog vs knowledge, read vs write) and bound to a single company. There are no OAuth flows, no JWTs, no signed requests, just one bearer token per call.

Admin only

Only users with the admin role on a company can create or manage API keys. If the Developer Credentials page is read-only in your dashboard, ask the company owner to grant you admin access first.

Generate a key

  1. Open your dashboard at app.thehumind.com.
  2. Go to Settings → Developer → Credentials.
  3. Click Create API key.
  4. Pick:
    • A label (max 64 characters): e.g. "production push", "CI test runner", "staging backfill". The label is what you'll see in the list later; pick something descriptive.
    • The environment: live or test. See Test mode.
    • The scopes you need.
  5. Click Create.
  6. Copy the secret immediately. It's shown once and never displayed again.

One-time reveal

The full key is only displayed in the dialog right after creation. Once you close that dialog, the dashboard only stores the key's prefix (hmd_live_xxxxx_…) and the metadata. There is no "show key" button. If you lose it, you must regenerate.

After creation, the new key appears in the list with its prefix, label, scopes, environment, and creation date. You can revoke it from there at any time.

Use the key

Send the key in the Authorization header on every request:

bash
curl https://api.thehumind.com/public/v1/products \
  -H "Authorization: Bearer hmd_live_aB3xK9qLm2pR7sT5wY8zN1_4f7c2e9a"

That's the entire auth contract. No timestamp, no signature, no nonce. The connection is HTTPS-only. Requests over plain HTTP are rejected before reaching the API.

Treat the key like a password

Never commit the key to a repo, paste it in a screenshot, log it, or send it in a query string. Keep it in your platform's secret store (GitHub Actions secrets, Vercel env, AWS Secrets Manager, etc.).

Key format

A Humind API key looks like:

hmd_live_aB3xK9qLm2pR7sT5wY8zN1_4f7c2e9a
└─┬─┘ └┬─┘ └────────┬────────┘ └───┬───┘
  │    │            │              └──── 8-char CRC32 checksum (lowercase hex)
  │    │            └─────────────────── 22-char base62 secret
  │    └──────────────────────────────── environment: `live` or `test`
  └───────────────────────────────────── Humind prefix (constant)
SegmentWhat it is
hmd_Constant Humind prefix. Lets secret-scanning tools (GitHub, GitGuardian, etc.) detect leaked keys at a glance.
live or testEnvironment. Must match the environment you selected at creation. See Test mode.
22-char base62 secretThe actual entropy (~131 bits). Generated server-side.
8-char CRC32 checksumValidates the rest of the token client-side and on the API edge. A typo in the secret part is rejected as invalid_checksum before any database lookup.

The full token format is hmd_(live|test)_[A-Za-z0-9]{22}_[a-f0-9]{8}.

Why a checksum?

The checksum lets us reject malformed keys instantly without a database lookup. It also means a copy-paste error (a missing character, a swapped letter) fails fast with a precise invalid_checksum instead of a generic 401.

Test mode

Test mode is currently disabled for new keys; existing test keys still authenticate. Requests to POST /companies/api-keys with environment: "test" are rejected with 400 test_mode_unavailable, and the dashboard no longer offers a live/test choice on creation, so all new keys are live. The table below describes the test-mode model used by test keys minted before the freeze and the expected behaviour when test-key creation is re-enabled.

API keys come in two flavours: live and test. The mode is baked into the key prefix and cannot be changed after creation.

ModePrefixWhat it touches
livehmd_live_…Your real, customer-facing catalog. The assistant uses these products when answering shoppers.
testhmd_test_…An isolated test surface. Resources created with a test key are isolated from the live catalog.

Use test for CI pipelines, scripted regression checks, exploratory work, and anything you don't want shoppers to see. Test resources never contaminate the live catalog: a live key can't read or modify test resources and vice versa.

Recommended setup

  • One live key per production environment (one in your CI, one in your prod backend, etc.) so you can rotate them independently.
  • One test key for CI/staging that you can rotate aggressively without coordinating with anyone.

Scopes

Scopes restrict what each key can do. They are immutable after creation, to change scopes, create a new key and revoke the old one.

ScopeEndpoints requiring itWhen to grant
catalog:readGET /products, GET /products/{id}Read-only catalog access. Useful for verification scripts or back-office tools.
catalog:writePOST /products, POST /products/batch, PUT /products/{id}, PATCH /products/{id}, DELETE /products/{id}Pushing or updating your catalog from your e-commerce backend, ETL job, or migration script. Implies read-on-write (you get the response object back).
knowledge:readGET /knowledge, GET /knowledge/{id}Read FAQs, sizing guides, policies.
knowledge:writePOST /knowledge, POST /knowledge/batch, PUT /knowledge/{id}, PATCH /knowledge/{id}, DELETE /knowledge/{id}Push FAQs and other free-form content.

Pick the narrowest set that satisfies your use case. A migration script that only pushes products doesn't need knowledge:*.

Insufficient scopes return 403

If a request hits an endpoint your key doesn't have the scope for, the API responds with 403 Forbidden and the error code insufficient_scope, with details.required and details.missing listing what's needed. See Errors.

Multiple keys

You can have up to 10 active keys per company at a time. Multiple keys are encouraged:

  • One key per environment (CI, staging, prod): so you can rotate them independently.
  • One key per integration (your backend, a third-party ETL, a migration tool): so revoking one doesn't break the others.
  • One narrow-scope key for read-only health checks, separate from the catalog:write key your backend uses.

Revoked keys don't count toward the 10-active limit; they remain in the list as audit trail.

Rotating a key

When you regenerate a key from the dashboard, the old key is revoked immediately. The next request that uses the old key gets back 401 Unauthorized with code revoked — typically within milliseconds, and within at most 60 seconds in the unlikely case it had a hot positive auth-cache entry on a worker that hasn't yet processed the in-process invalidation.

For zero-downtime rotation, do not regenerate. Instead:

  1. Create a new key with the same scopes and environment. Copy its secret.
  2. Deploy the new key to your platform secret store and roll your service.
  3. Verify the service is using the new key (check the dashboard's "Last used at" column on the new key, and confirm the old key's "Last used at" stops moving).
  4. Revoke the old key from the dashboard.

This is the same pattern Stripe and GitHub use. The dashboard surfaces "last used" timestamps so you know when it's safe to revoke.

Regenerate is destructive

"Regenerate" replaces the key in place: same label, same scopes, but a brand-new secret, with the old one revoked instantly. Use it only when the old key has already leaked or stopped working, never as part of a planned rotation.

If a key leaks

Treat any leaked key as compromised, even if you only saw it in a private log or a Slack DM:

  1. Revoke it immediately from the dashboard. Revocation reaches the API edge within at most 60 seconds, after which every request with that key fails with 401 / revoked.
  2. Create a new key and update your secret store.
  3. Audit your usage logs. The dashboard records the IP and user-agent of the last request per key. If anything looks off (an IP you don't recognize, traffic outside your usual hours), flag it to support.

Common leak vectors to watch for:

  • Committed to a public or private repo.
  • Pasted in a Notion / Linear / GitHub issue.
  • Logged by an HTTP client that prints headers on errors.
  • Sent in a query string (don't do this; query strings end up in CDN access logs and browser history).

GitHub secret scanning

GitHub's automated secret scanning recognizes the hmd_live_ and hmd_test_ prefixes and notifies us when a key is committed to a public GitHub repo. The notification reaches our security team within minutes and we'll contact you to coordinate.

Next

  • Conventions: request format, identifiers, idempotency.
  • Errors: auth-related error codes (missing_credentials, invalid_checksum, revoked, insufficient_scope, …).
  • Products: push your first product.

Released under the proprietary Humind license.