Skip to navigation

Authentication

Every request carries one API key. Which kind depends on where the request comes from:

KeyHeaderMade for
Secret keyX-Secret-Key: sk_…Your servers
Public keyX-Public-Key: pk_…Browsers and embedded widgets

Both are created in the dashboard; API keys explains the options each one offers.

Send one key per request. A request that carries both X-Secret-Key and X-Public-Key is rejected with 400 before it reaches any endpoint.

Secret key

A secret key authenticates a server. It belongs to one entity, the workspace you see in the dashboard, so the request needs nothing else to say where to work:

curl https://api.hams.ai/outbound-batch/batches \
-H "X-Secret-Key: $HAMS_SECRET_KEY"

A secret key has a role, WRITER or READER. Readers can list and fetch; writers can also create, update and delete batches and widget configuration. A key can be limited to an IP allowlist (single addresses or CIDR ranges), and calls from any other address get 403. Secret keys are for server-to-server traffic: the API does not answer browser CORS preflights for them, and a secret key that ends up in a page should be revoked and replaced.

Public key

A public key authenticates a browser page or a widget, where a secret cannot be hidden. It only reaches the endpoints under /v1/, which are the chat session and widget configuration calls:

curl -X POST https://api.hams.ai/v1/ai-agents/$AGENT_ID/chat/init \
-H "X-Public-Key: $HAMS_PUBLIC_KEY" \
-H "Content-Type: application/json" \
-d '{}'

Three restrictions keep a public key safe even though it is visible:

  • Domains. The request’s Origin (or Referer) must match one of the key’s allowed domains. A public key cannot be created without at least one.
  • Scopes. An optional scope list names the operations the key may call, such as chat:init or widget-config:read. A key without a list may call all of them.
  • reCAPTCHA. When a reCAPTCHA secret is configured on the key, starting a chat also requires a g-token header carrying a Google reCAPTCHA token, verified against the key’s score threshold.

Which endpoints take which key

EndpointsKey
/ai-agents/{agent_id}/chat/…, /ai-agents/{agent_id}/widget-configSecret
/outbound-batch/…Secret
/v1/ai-agents/{agent_id}/chat/…, /v1/ai-agents/{agent_id}/widget-configPublic

Errors

Statuserror_codeMeaning
400—Both keys were sent; the body carries only detail
401MISSING_API_KEY, INVALID_API_KEYNo key in the header, or a key that does not exist or was revoked
403FORBIDDENThe key’s role does not allow the operation, or the IP is outside the allowlist
403DOMAIN_NOT_ALLOWEDThe page’s origin is not in the public key’s domains
403KEY_SCOPE_NOT_ALLOWEDThe public key’s scopes do not include this operation
400RECAPTCHA_TOKEN_REQUIRED, RECAPTCHA_FAILEDreCAPTCHA is enabled on the key and the token is missing or scored too low

The voice workers that run calls use an internal credential of their own. Their endpoints are not part of this reference.