Skip to main content

Every endpoint requires a credential

There is no anonymous read here. The measurements describe a customer’s own footage, so a request without a recognized credential is refused rather than answered with public data:
401

Getting a token

The API is called by your servers, unattended, so the credential is a machine one. Onboarding gives you a client id, a client secret, and the token endpoint to exchange them at. Nothing here involves a browser, a user account, or a self-service signup form — so if you do not have those three things yet, ask brandon.ong@hebbianrobotics.com rather than looking for a signup page. Exchange them with the OAuth 2.0 client-credentials grant:
Response
The access token is what you send us. The client secret never leaves your side, and we never see it. Tokens are short-lived: cache one until expires_in lapses and exchange again, rather than minting one per request.
Treat the client secret as you would a database password. It is a long-lived credential for your whole organization’s data; the access token it mints is the thing designed to be passed around. Rotation and revocation happen at the issuer and take effect without any change on our side.

Presenting it

Checking what you got

GET /api/access is the authoritative answer for a given credential, and it never errors on a missing or malformed one. Call it first rather than inferring your access from a 403.
Response
A customer credential holds exactly one capability, view_data, which is what every endpoint in this documentation requires. The other capabilities the reference enumerates exist for operator credentials and are not issuable to a customer; writes_require_admin reports that the deployment is gated, and is the same for everybody.

Scoping comes from the token

Your organization is read from a verified claim inside the access token — not from a header, and not from a table we maintain. That is what makes the boundary an assertion by the issuer rather than by our configuration, and it is why a rotated or revoked client stops working without us doing anything. Two consequences worth knowing:
  • Do not send X-Squash-Organization-Id. It is an operator-only selector and a request carrying it is refused with 403 organization_selector_forbidden, even when the id is your own.
  • A dataset id is interpreted within your scope. The same id in two scopes names two different corpora, and a dataset outside your scope is simply not there. GET /api/access echoes the scope your token actually resolved to, which is the quickest way to confirm you are reading what you think you are.

Failure modes

Distinct on purpose, so a client can branch without parsing prose. A 401 means the credential itself is the problem, and retrying with it will not help until you mint a new one. A 403 means the credential is fine and the request is not. A 404 is a fact about the corpus, not about your access — which is why an unmeasured metric and an unknown dataset share one code: both mean there is nothing there to read, and a client should branch once.