Skip to content

invalid_api_key

HTTP 401 type: authentication_error param: Authorization
{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "No API key was recognised. Send `Authorization: Bearer fh_live_…` or `Authorization: Bearer fh_test_…`.",
"param": "Authorization",
"upstream": null,
"doc_url": "https://docs.fiskhub.com/errors/invalid_api_key"
}
}

The response also carries WWW-Authenticate: Bearer.

What happened

The Authorization header was missing, malformed, or carried a key we do not recognise. The request stopped at authentication; nothing was read, written or fiscalized.

Common causes:

  • No Authorization header at all.
  • The scheme omitted — Authorization: fh_live_… instead of Authorization: Bearer fh_live_….
  • The key truncated by an environment variable that was not quoted, or by copy-paste.
  • Whitespace or a newline inside the key.
  • A key that was deleted rather than revoked, or one from a different environment.

Should you retry?

Not with the same key. Authentication is deterministic; the same key fails the same way forever.

The fix

Terminal window
curl -sS https://api.fiskhub.com/v1/invoices \
-H "Authorization: Bearer fh_live_9tK2xQ7mA4vD8nR1sB6yE3wZ0pL5cH" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{ … }'

Check, in order:

  1. The header name and scheme. Exactly Authorization: Bearer <key>, one space.
  2. The prefix. Every key starts fh_live_ or fh_test_. Anything else was not issued by us.
  3. The whole key made it. Print its length and compare — a shell variable that lost its quoting is the classic cause.
  4. It is the right environment’s key. A staging key against production, or the reverse.

Verify it against an endpoint that does nothing:

Terminal window
curl -sS -o /dev/null -w "%{http_code}\n" \
https://api.fiskhub.com/v1/companies \
-H "Authorization: Bearer $FISKHUB_API_KEY"

200 means the key is fine and the problem is elsewhere.

Lost keys are replaced, not recovered

Keys are shown once, at creation, and stored only as a SHA-256 hash. There is no way to read one back. Issue a new key in the dashboard and revoke the old one.

If the key still exists but is refused, see api_key_revoked — a revoked key returns that code, not this one.