Skip to content

Authentication

Every request carries a bearer access token, obtained by exchanging a client credential at POST /oauth/token.

The credential identifies your company. It is not tied to a person, a login, a team or a selected workspace, and it does not inherit anybody’s permissions. Everything the token can read is scoped to the company it was issued for, and no parameter widens that.

This is why there is no user login flow: there is no user.

Terminal window
curl -X POST https://api.salesbud.com.br/oauth/token \
-d 'grant_type=client_credentials' \
-d "client_id=$SALESBUD_CLIENT_ID" \
-d "client_secret=$SALESBUD_CLIENT_SECRET"

The endpoint accepts only application/x-www-form-urlencoded. Credentials may also be sent with HTTP Basic instead of in the body.

200 OK
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "meetings.read calls.read transcriptions.read"
}

Tokens are signed RS256 and carry the company, the granted scopes and the credential version.

ScopeGrants
meetings.readList and retrieve meetings, their template answers and their overall evaluations.
calls.readList and retrieve calls, their template answers and their overall evaluations.
transcriptions.readRead transcripts, alongside the scope of the collection the transcript belongs to. Requested separately because a transcript is the most sensitive payload the API serves.

A transcript therefore needs two scopes: meetings.read and transcriptions.read for a meeting transcript, calls.read and transcriptions.read for a call transcript. transcriptions.read on its own reads nothing.

A token receives the scopes attached to its credential. Requesting a route outside them returns 403 INSUFFICIENT_SCOPE — that is the gate working, not a missing route.

Call GET /v1/context to see the scopes a token actually carries.

Tokens expire after expires_in seconds (3600 by default).

There is no refresh token, by design. Client credentials is a machine-to-machine grant with no user to re-consent, so RFC 6749 §4.4.3 says not to issue one — a refresh token would be a second long-lived secret with the same power as the first. Renewal is calling /oauth/token again.

Cache the token slightly under expires_in, and also re-issue when a request returns 401 INVALID_ACCESS_TOKEN. A credential can be revoked before the clock runs out; a timer alone will not notice.

Rotation issues a new secret while the previous one keeps working for seven days, so you can deploy the new value without a window of failed requests.

At most two secrets are valid at once. Revoke the expiring one before starting another rotation, otherwise the second rotation is refused with 409 ROTATION_IN_PROGRESS.

Revoking or disabling the whole client invalidates issued tokens immediately — that is the lever to pull on a suspected leak, not rotation.

A credential can carry an optional list of IPv4/IPv6 CIDRs. When set, it is enforced both when issuing a token and on every request that uses it, so a leaked token is useless from outside your network.