Skip to content

Authentication

The COMMITLY API uses the OAuth 2.0 client credentials flow. Your application authenticates as itself with a client ID and client secret; there is no user login and no redirect.

Base URL https://app.commitly.com/api
Token URL https://app.commitly.com/api/auth/token/
Grant type client_credentials
Client authentication Credentials in the request body
Token lifetime 5 minutes
Header Authorization: Bearer <access_token>

In COMMITLY, open Add-ons and connect the COMMITLY Public API tile. The tile shows the client ID and the client secret. Disconnect revokes the credentials; connecting again issues new ones.

Credentials belong to one company. For group-level access across all companies (Enterprise), contact support@commitly.com, see Editions and access.

POST /api/auth/token/ HTTP/1.1
Host: app.commitly.com
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET

The token endpoint also accepts JSON or multipart bodies. Credentials are read from the body only; HTTP Basic authentication is not supported.

A successful response (200) looks like this:

{
"access_token": "eyJhbGciOi…",
"token_type": "bearer",
"expires_in": 300,
"refresh_token": "…",
"refresh_expires_in": 1209600,
"scope": "all"
}

Send the access_token with every request:

GET /api/categories/ HTTP/1.1
Host: app.commitly.com
Authorization: Bearer YOUR_ACCESS_TOKEN

Access tokens expire after 5 minutes (expires_in: 300). For server-to-server integrations the simplest way is to request a new token with the client credentials when the old one has expired; you do not need the refresh_token.

A robust client caches the token, reuses it for all calls within its lifetime and fetches a new one shortly before it expires, or when a call is rejected as unauthenticated.

let cached = { token: null, expiresAt: 0 };
async function getToken() {
// Renew 30 seconds early to avoid using a token that expires mid-request.
if (cached.token && Date.now() < cached.expiresAt - 30_000) return cached.token;
const res = await fetch("https://app.commitly.com/api/auth/token/", {
method: "POST",
body: new URLSearchParams({
grant_type: "client_credentials",
client_id: process.env.COMMITLY_CLIENT_ID,
client_secret: process.env.COMMITLY_CLIENT_SECRET,
}),
});
if (!res.ok) throw new Error(`Token request failed: ${res.status}`);
const { access_token } = await res.json();
cached = { token: access_token, expiresAt: Date.now() + 5 * 60_000 };
return access_token;
}
Status When Body
400 Wrong client ID or secret at the token endpoint {"non_field_errors": ["…"]}
401 Invalid or expired access token {"detail": "Invalid token."}, header WWW-Authenticate: Bearer
403 No access token sent {"detail": "User must be authenticated to access this resource."}