Skip to Content

Authenticating on the API

Prerequisites: the public API option open on your account. Without it, the Developers API entry does not appear under Configuration › Integrations. The setting must then be saved as Enabled: until it is, key generation is refused.

On this page

Authenticating on the API

Prerequisites: the public API option open on your account. Without it, the Developers API entry does not appear under Configuration › Integrations. The setting must then be saved as Enabled: until it is, key generation is refused.

The public API does not take the key directly: you exchange it for an access token, then present that token on every call. There is no static key header. The key itself is generated in Generating and managing API keys; this page assumes you have one.

Exchanging the key for a token

A POST on /v1/token, with the key in the body: { "appSecret": "your_key" }. The response carries two tokens: { "access_token": "…", "refresh_token": "…" }. This call is not authenticated, the key is the only proof of identity.

On every following call, the access token goes in the Authorization: Bearer <access_token> header.

⚠️ The Bearer prefix is mandatory, space included. Sending the bare token returns a 400, distinct from the error for an invalid token.

Lifetime and renewal

The access token lives 6 hours, the refresh token 730 hours, roughly a month. Both durations are fixed server-side and are not configurable. To renew: a POST on /v1/token/refresh with { "refreshToken": "…" }, which returns a new access token and a new refresh token.

⚠️ The refresh token is single-use. The one you just spent is consumed, and the new one is what you must store. An integration that keeps replaying the same refresh token gets a 404 on the second attempt.

⚠️ One refresh token stays alive per key. Going back through /v1/token with a given key invalidates the refresh token previously issued for that same key. Two integrations that share one key therefore log each other out, so give each integration its own key, and keep renewal for a given key in a single process.

💡 Renew with the refresh call, not with the key. Once the integration holds a refresh token, use /v1/token/refresh when the access token expires. Going back through /v1/token also works, but it discards the refresh token that key already had.

💡 Getting a token is not a test. The useful test is letting your integration run for more than six hours and confirming it crosses the renewal unattended.

What identity the token carries

The token identifies the account, never a person: it acts on behalf of no administrator and no learner, and what it writes is attributed to nobody. Reads are partitioned to that account, whether they return users, groups, capsules, tracks or categories.

What it does not do

  • No scope narrower than the account. Every key gets the same reach: there is no key limited to reading, to one group, or to one department.
  • No revocation of a token already issued. Deleting a key does not cancel the access token that came from it: it stays valid for the rest of its 6 hours.
  • No call quota. There is no rate limiting on the public API, so nothing protects you from a loop started on your side.

Base URL

Every call goes to https://api.developers.beedeez.com. The /v1/token and /v1/token/refresh entries, with their schemas, are described in the OpenAPI reference published at doc.developers.beedeez.com .

Error responses

SituationCodeMessage
Authorization header absent401No jwt token provided
Bearer prefix missing400Invalid authorization prefix, should be Bearer token_value
Expired token401jwt expired
Truncated token, or signed elsewhere401jwt malformed, invalid signature
Unknown or deleted key, on /v1/token404Credentials not found
Refresh token already consumed404Refresh Token not found

The body always carries message, kind and statusCode.

💡 Tell the 401 from the 404. A 401 is fixed by renewing. A 404 on /v1/token means the key no longer exists, and retrying will not bring it back.

Going further


Discutez avec nous