Skip to content

Authentication

API v6 uses Bearer tokens (RFC 6750). One header, one format. No fallbacks through the URL, no OAuth flows and no signing of each request.

7 min readReviewed on

The Bearer scheme

Send the API key in the Authorization header of every request:

request
GET /api/v6/utilities/ping HTTP/1.1
Host:          developers.hablame.co
Authorization: Bearer hk_TU_API_KEY

The header is the only accepted place. A token sent in the URL (?token=...) or in the body is ignored, and the call fails with 401 AUTH_REQUIRED.

This is on purpose. Tokens in a URL end up in server logs, in browser history and in the Referer header browsers send to other domains. A Bearer header shows up in none of those places.

Key format

Every Hablame v6 key matches this expression:

regex
^hk_[a-f0-9]{32}$
  • The hk_ prefix identifies it as a Hablame v6 key.
  • 32 lowercase hexadecimal characters (16 random bytes, 128 bits).
  • Case-sensitive. With HK_ or uppercase hexadecimal, the API answers 401 AUTH_INVALID_KEY.

The full token is shown only at creation. Hablame stores just a fingerprint (sha256) of the token: if you lose the original value it cannot be recovered and you have to create a new key.

Key lifecycle

Creation

Keys are created in Cloud; the Your API key guide explains how. Each one carries:

  • A link to an organization: every call with that key operates against that organization.
  • A cost center, to which the key’s usage is attributed.
  • The user who created it. It is recorded, but the key does not depend on that user: if they leave the organization, the key keeps working until you delete it.
  • The services it can use (for example urlshortener). Utility endpoints under /api/v6/utilities/ ignore that list: they are universal.
  • An optional list of allowed networks: single IPs or CIDR ranges, IPv4 or IPv6. With a list, the key only works from those networks and from any other it answers 403 AUTH_IP_NOT_ALLOWED; without one, it works from any network. The list is set when the key is created.
  • An optional expiry date. Keys without one never expire.
  • Account capabilities, explicitly granted: account (financial data) and directory (personal data). They are the only ones: within a service there are no partial permissions. Having access to all services does not include them. Like the rest of the scope, they are set when the key is created and cannot be added later.

Each service is granted in full

A key’s permission over a service is all or nothing. With urlshortener, the key lists and reads links, and also creates them (each creation is charged), edits, deletes and restores them. With storage, it sees the summary, the usage, the files and their downloads. If an integration must not create or delete links, such as a visits dashboard, do not give it the URL shortener service.

Only the owner of the organization creates API keys. A key can be deleted by whoever created it, the owner or an administrator.

a key without the URL shortener service tries to create a link
HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8

{
  "success": false,
  "error": {
    "code": "AUTH_SERVICE_NOT_ALLOWED",
    "type": "https://developers.hablame.co/docs/v6/errors/auth-service-not-allowed",
    "message": "This API key is not authorized to use the requested service.",
    "details": []
  },
  "meta": {
    "requestId": "8f0c0e2a4b1d4c8f",
    "clientIp": "203.0.113.45",
    "timestamp": "2026-09-30T15:00:00+00:00",
    "responseTimeMs": 0.9
  }
}

Rotation

There is no rotation endpoint, on purpose. To rotate:

  1. 01
    Create the new key

    In Cloud, with the same permissions as the previous one.

  2. 02
    Deploy

    Ship your application with the new key and verify it returns 200.

  3. 03
    Delete the old one

    Once you confirm the new one works, delete the old one in Cloud.

A deleted key can keep authenticating for up to 30 seconds: the API keeps the verification result for a moment so it does not query the database on every request. If the token was exposed, delete it immediately and tell support.

Expiration

Keys with an expiry date answer 401 AUTH_INVALID_KEY from that moment on. The check runs on the server on every request and a key held in memory does not outlive its date, so a key about to expire fails exactly when it crosses the limit.

What happens on every request

The API runs these checks in order. Any failure short-circuits the rest:

  1. The token is present and preceded by Bearer; otherwise, 401 AUTH_REQUIRED.
  2. The token fingerprint matches a key that exists, was not deleted and has not expired; otherwise, 401 AUTH_INVALID_KEY.
  3. The key’s organization is active; otherwise, 403 ACCOUNT_NOT_ACTIVE.
  4. If the key has allowed networks, the request comes from one of them; otherwise, 403 AUTH_IP_NOT_ALLOWED. The IP we saw you calling from comes in meta.clientIp.
  5. If the endpoint requires a service, the key has it (and the organization did not turn it off); otherwise, 403 AUTH_SERVICE_NOT_ALLOWED.
  6. If the endpoint requires an account capability (account or directory), the key has it; otherwise, 403 AUTH_CAPABILITY_NOT_ALLOWED. This rejection comes before your usage limit is counted: it does not spend it.

If the service that verifies keys does not answer, the API does not let you through: it answers 503 SERVICE_UNAVAILABLE. Retry in a few seconds. The error catalog has the detail of each code.

Security best practices

Do
Don't
Store keys in a secret manager (Google Secret Manager, AWS Secrets Manager, HashiCorp Vault, 1Password CLI).
Hardcode them in source code or container images.
Read them at boot from environment variables.
Commit .env files with real keys to version control.
Keep one key per environment and per integration, and rotate them regularly.
Share a single key across all environments and the whole team.
Create a new key when someone leaves the team, and delete theirs.
Reuse keys after an off-boarding.
Mask the token in your own logs (hk_***).
Log full Authorization headers, not even when debugging.

If the token is exposed

If you suspect a key leaked (a commit to a public repository, a screenshot, a chat message):

  1. Delete it immediately in Cloud. It stops working within 30 seconds at most; if you need it to be instant, tell support.
  2. Create a replacement key and deploy.
  3. In Cloud check when the key was last used and compare it with your logs. Look for unknown IPs (the IP we saw you from comes in meta.clientIp of every response) or unusual volumes.
  4. Quote the requestId values of the suspicious calls in your message to support so we can correlate them.

To check your new key a single call to https://developers.hablame.co/api/v6/utilities/ping is enough.

Need help?

Was this page helpful?

See all support channels