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:
GET /api/v6/utilities/ping HTTP/1.1
Host: developers.hablame.co
Authorization: Bearer hk_TU_API_KEYThe header is the only accepted place. A token sent in the URL (?) 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:
^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 answers401 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/ignore that list: they are universal.api/ v6/ utilities/ - 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) anddirectory(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.
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:
- 01Create the new key
In Cloud, with the same permissions as the previous one.
- 02Deploy
Ship your application with the new key and verify it returns 200.
- 03Delete 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:
- The token is present and preceded by
Bearer; otherwise,401 AUTH_REQUIRED. - The token fingerprint matches a key that exists, was not deleted and has not expired; otherwise,
401 AUTH_INVALID_KEY. - The key’s organization is active; otherwise,
403 ACCOUNT_NOT_ACTIVE. - 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 inmeta..clientIp - If the endpoint requires a service, the key has it (and the organization did not turn it off); otherwise,
403 AUTH_SERVICE_NOT_ALLOWED. - If the endpoint requires an account capability (
accountordirectory), 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
. env files with real keys to version control.hk_***).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):
- Delete it immediately in Cloud. It stops working within 30 seconds at most; if you need it to be instant, tell support.
- Create a replacement key and deploy.
- 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.of every response) or unusual volumes.clientIp - Quote the
requestIdvalues of the suspicious calls in your message to support so we can correlate them.
To check your new key a single call to https: is enough.