Open Api > Third-party application API access
Use the client credentials flow
Client credentials authentication for server apps
Section titled “Client credentials authentication for server apps”The OAuth 2.0 client credentials flow is for machine-to-machine sign-in. It’s built for backend services and third-party apps. They call the Tallyfy API with no user logging in.
You’ll need a Client ID and Client Secret from Tallyfy Support before you start.
How the flow works
Section titled “How the flow works”What to notice
Section titled “What to notice”- Step 1 is manual. You contact Tallyfy Support for credentials once. You can’t automate it.
- There are two token types. Application tokens are for system operations. User-specific tokens act as a particular user.
- They last for different lengths of time. Application tokens expire in 7 days (604,800 seconds). User-specific tokens expire in 3 months (7,776,000 seconds).
When to use this
Section titled “When to use this”This pattern works well when you want to:
- Put Tallyfy features inside your own software.
- Automate process management or user provisioning.
- Build system-level integrations, such as reporting or data sync.
- Give your users workflow features without separate Tallyfy logins.
1. Request client credentials
Section titled “1. Request client credentials”Contact Tallyfy Support and describe your integration. They’ll give you a Client ID and Client Secret for your organization. Keep them somewhere safe.
2. Get an application access token
Section titled “2. Get an application access token”First, your app needs its own access token. It uses this token for jobs like creating users or getting user-specific tokens.
- Endpoint:
POST https://go.tallyfy.com/oauth/token - Content-Type:
application/x-www-form-urlencoded - Parameters:
grant_type:client_credentialsclient_id: Your Client IDclient_secret: Your Client Secretscope:*(optional)
const clientId = 'YOUR_CLIENT_ID';const clientSecret = 'YOUR_CLIENT_SECRET';const tokenUrl = 'https://go.tallyfy.com/oauth/token';
const params = new URLSearchParams();params.append('grant_type', 'client_credentials');params.append('client_id', clientId);params.append('client_secret', clientSecret);params.append('scope', '*');
const response = await fetch(tokenUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params});
if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`);}
const data = await response.json();console.log('Access token:', data.access_token);// Use data.access_token for subsequent API callsimport requests
client_id = 'YOUR_CLIENT_ID'client_secret = 'YOUR_CLIENT_SECRET'token_url = 'https://go.tallyfy.com/oauth/token'
payload = { 'grant_type': 'client_credentials', 'client_id': client_id, 'client_secret': client_secret, 'scope': '*'}
response = requests.post(token_url, data=payload)
if response.status_code == 200: token_data = response.json() print("Access token:", token_data['access_token'])else: print(f"Error: {response.status_code}") print(response.text)import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;import java.net.URLEncoder;import java.nio.charset.StandardCharsets;import java.util.Map;import java.util.stream.Collectors;
public class TallyfyClientCredentials { public static void main(String[] args) throws Exception { String tokenUrl = "https://go.tallyfy.com/oauth/token";
Map<String, String> formData = Map.of( "grant_type", "client_credentials", "client_id", "YOUR_CLIENT_ID", "client_secret", "YOUR_CLIENT_SECRET", "scope", "*" );
String form = formData.entrySet().stream() .map(e -> e.getKey() + "=" + URLEncoder.encode( e.getValue(), StandardCharsets.UTF_8)) .collect(Collectors.joining("&"));
HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(tokenUrl)) .header("Content-Type", "application/x-www-form-urlencoded") .POST(HttpRequest.BodyPublishers.ofString(form)) .build();
HttpResponse<String> response = client.send( request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() == 200 ? "Success: " + response.body() : "Error " + response.statusCode() + ": " + response.body()); }}package main
import ( "fmt" "io" "net/http" "net/url" "strings")
func main() { tokenUrl := "https://go.tallyfy.com/oauth/token"
data := url.Values{} data.Set("grant_type", "client_credentials") data.Set("client_id", "YOUR_CLIENT_ID") data.Set("client_secret", "YOUR_CLIENT_SECRET") data.Set("scope", "*")
req, err := http.NewRequest("POST", tokenUrl, strings.NewReader(data.Encode())) if err != nil { fmt.Println("Error:", err) return } req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := http.DefaultClient.Do(req) if err != nil { fmt.Println("Error:", err) return } defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body) fmt.Printf("Status %d: %s\n", resp.StatusCode, string(body))}#include <iostream>#include <string>#include <cpprest/http_client.h>
using namespace web;using namespace web::http;using namespace web::http::client;
int main() { http_client client(U("https://go.tallyfy.com/oauth/token"));
uri_builder builder; builder.append_query(U("grant_type"), U("client_credentials")); builder.append_query(U("client_id"), U("YOUR_CLIENT_ID")); builder.append_query(U("client_secret"), U("YOUR_CLIENT_SECRET")); builder.append_query(U("scope"), U("*"));
http_request request(methods::POST); request.headers().set_content_type( U("application/x-www-form-urlencoded")); request.set_body(builder.query());
client.request(request) .then([](http_response response) { return response.extract_json(); }) .then([](json::value body) { std::wcout << body.serialize() << std::endl; }) .wait();
return 0;}// Requires C++ REST SDK (Casablanca)using System;using System.Collections.Generic;using System.Net.Http;using System.Threading.Tasks;
public class TallyfyAuth{ private static readonly HttpClient client = new HttpClient();
public static async Task Main() { var tokenUrl = "https://go.tallyfy.com/oauth/token";
var formContent = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>( "grant_type", "client_credentials"), new KeyValuePair<string, string>( "client_id", "YOUR_CLIENT_ID"), new KeyValuePair<string, string>( "client_secret", "YOUR_CLIENT_SECRET"), new KeyValuePair<string, string>("scope", "*") });
var response = await client.PostAsync(tokenUrl, formContent); var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(response.IsSuccessStatusCode ? $"Success: {body}" : $"Error {response.StatusCode}: {body}"); }}Response:
{ "token_type": "Bearer", "expires_in": 604800, "access_token": "eyJ0eXAiOiJKV1Q..."}3. Provision users (optional)
Section titled “3. Provision users (optional)”With your application token, you can create users in your organization:
- Endpoint:
POST https://go.tallyfy.com/api/applications/{orgID}/users - Headers:
Authorization: Bearer {your_app_access_token}Content-Type: application/jsonX-Tallyfy-Client: APIClient
- Body fields:
first_name(required): Max 32 characterslast_name(required): Max 32 charactersemail(required): Must be unique, valid domainrole(optional):admin,standard, orlighttimezone(optional): User’s timezone string
4. Get user-specific tokens (optional)
Section titled “4. Get user-specific tokens (optional)”To act as a specific user, use your application token to get a user-scoped token.
- Endpoint:
POST https://go.tallyfy.com/api/applications/{orgID}/users/{email}/token - Headers:
Authorization: Bearer {your_app_access_token}X-Tallyfy-Client: APIClient
- Note: No request body needed - the user’s email goes in the URL path.
Response:
{ "token_type": "Bearer", "expires_in": 7776000, "access_token": "eyJ0eXAiOiJKV1Q..."}5. Make API requests
Section titled “5. Make API requests”Use either token (application-level or user-specific) in your API calls. Send these required headers:
Authorization: Bearer {token}Accept: application/jsonX-Tallyfy-Client: APIClient
All API endpoints follow the pattern https://go.tallyfy.com/api/organizations/{orgID}/....
For code examples of specific API calls, see the personal access token guide. The requests look the same. Just swap in your token.
Security best practices
Section titled “Security best practices”- Keep client credentials in an encrypted secrets manager, never in source code.
- Protect both application-level and user-specific tokens.
- Rotate your secrets regularly.
- Use HTTPS for all requests.
- Get a new application token before the 7-day expiry.
Related articles
Section titled “Related articles”Code Samples > Authentication methods
Open Api > API integration guide
Was this helpful?
- 2026 Tallyfy, Inc.
- Privacy Policy
- Terms of Use
- Report Issue
- Trademarks