Every request to the public API carries an API key in the X-Api-Key
header. There are no sessions, no cookies, no OAuth flow and no
Authorization: Bearer form: the key is the credential, and X-Api-Key is
the only header the API reads it from.
curl -H "X-Api-Key: mvk_…" https://dev-api-muvia.oncode.it/api/public/v1/company
mvk_<key_id>_<secret>
mvk — a fixed prefix, so a leaked key is recognisable in a log line or to
a secret scanner.key_id — 16 hex characters, the key's public handle. The API keys console
shows a key as mvk_<key_id>_••••••••. It is not a secret.secret — 64 hex characters (32 random bytes). Muvia keeps only a digest of
it, which is why the full key is shown once, when it is issued, and can
never be shown again.A company administrator issues keys in Muvia, under Settings → Company → API keys, choosing a name, a lifetime and the scopes. An administrator can grant a key only scopes they hold themselves.
A key belongs to the company, not to the person who issued it. It keeps working when that person leaves the company, changes password or loses a role; it stops only when it is revoked or when it expires.
Every key expires; there is no "never". The lifetime is chosen when the key is issued: 90 days by default, at most 3650 days. From its expiry on, every request with the key answers 401.
The console shows each key's expiry date. An administrator can renew a key there before it lapses; the key's value does not change, so the integration needs no update. Put the date in your own calendar: an integration that forgets it finds out by breaking.
Revoking a key takes effect immediately and is permanent: a revoked key never works again and cannot be re-enabled. Issue a new key instead. When someone leaves, an administrator can also revoke, in one gesture, every live key that person issued.
One integration, one key: a revocation then stops exactly one integration.
Every credential failure answers the same 401: a missing header, a
malformed key, an unknown key_id, a wrong secret, a revoked key, an expired
key. The response does not say which, so it reveals nothing about which keys
exist.
{
"error": {
"code": "unauthorized",
"message": "Invalid or missing API key",
"status": 401
}
}
A 403 is different: the key is valid, but it does not hold the scope the endpoint requires. See Scopes.
key_id part only.