Making Your First API Request
The Karbon API uses two required headers on every request. Once you have them, you’re ready to go.
Prerequisites
- A Karbon account with API access
Required Headers
Every request must include both of the following headers:
| Header | Format | Where to find it |
|---|---|---|
Authorization | Bearer {token} | Issued when you register for API access |
AccessKey | JWT (starts with eyJ...) | Karbon UI → Settings → Connected Apps → your application |
The Authorization token is a 36 character long GUID. The AccessKey is a JWT with three
Base64URL-encoded segments separated by dots. These two values are not interchangeable — swapping them results in a 401.
This guide contains example values for Authorization and AccessKey, you’ll need to substitute in your own values in order to make a successful API request.
Base URL
https://api.karbonhq.com
All endpoints are versioned under /v3/.
Making a Request
The following examples all call GET /v3/TenantSettings — a good smoke test that returns your
account configuration with no side effects.
Postman / Bruno
Postman and Bruno are desktop API clients that let you make HTTP requests without writing any code — useful for exploring the API and testing requests interactively. Bruno is open-source and stores collections as local files; Postman is cloud-based with a generous free tier.
- Create a new GET request to
https://api.karbonhq.com/v3/TenantSettings - Open the Headers tab and add:
- Key:
Authorization— Value:Bearer 550e8400-e29b-41d4-a716-446655440000 - Key:
AccessKey— Value:<your-access-key>
- Send the request
Tip: Store your credentials in an environment and reference them as variables (e.g.
{{authToken}} and {{accessKey}}) so you don’t need to repeat them on every request.
curl
curl https://api.karbonhq.com/v3/TenantSettings \
-H "Authorization: Bearer 550e8400-e29b-41d4-a716-446655440000" \
-H "AccessKey: <your-access-key>"
JavaScript (fetch)
const TOKEN = process.env.KARBON_TOKEN;
const ACCESS_KEY = process.env.KARBON_ACCESS_KEY;
const response = await fetch("https://api.karbonhq.com/v3/TenantSettings", {
headers: {
"Authorization": `Bearer ${TOKEN}`,
"AccessKey": ACCESS_KEY,
},
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
console.log(data);
JavaScript (axios)
import axios from "axios";
const client = axios.create({
baseURL: "https://api.karbonhq.com/v3",
headers: {
"Authorization": `Bearer ${process.env.KARBON_TOKEN}`,
"AccessKey": process.env.KARBON_ACCESS_KEY,
},
});
const {data} = await client.get("/TenantSettings");
console.log(data);
Python (requests)
import os
import requests
headers = {
"Authorization": f"Bearer {os.environ['KARBON_TOKEN']}",
"AccessKey": os.environ["KARBON_ACCESS_KEY"],
}
response = requests.get(
"https://api.karbonhq.com/v3/TenantSettings",
headers=headers,
)
response.raise_for_status()
print(response.json())
Tip: Create a reusable session so headers are sent on every request automatically:
session = requests.Session()
session.headers.update(headers)
tenant = session.get("https://api.karbonhq.com/v3/TenantSettings").json()
contacts = session.get("https://api.karbonhq.com/v3/Contacts").json()
C# (.NET)
using System.Net.Http;
using System.Net.Http.Headers;
var token = Environment.GetEnvironmentVariable("KARBON_TOKEN");
var accessKey = Environment.GetEnvironmentVariable("KARBON_ACCESS_KEY");
using var client = new HttpClient { BaseAddress = new Uri("https://api.karbonhq.com/v3/") };
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
client.DefaultRequestHeaders.Add("AccessKey", accessKey);
var response = await client.GetAsync("TenantSettings");
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
Tip: Register HttpClient as a singleton (e.g., via IHttpClientFactory in ASP.NET Core) so
headers are configured once and reused across requests.
Ruby (net/http)
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://api.karbonhq.com/v3/TenantSettings')
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
request = Net::HTTP::Get.new(uri)
request['Authorization'] = "Bearer #{ENV['KARBON_TOKEN']}"
request['AccessKey'] = ENV['KARBON_ACCESS_KEY']
http.request(request)
end
puts JSON.parse(response.body)
Or with the faraday gem for a cleaner interface:
require 'faraday'
require 'json'
conn = Faraday.new(url: 'https://api.karbonhq.com/v3') do |f|
f.headers['Authorization'] = "Bearer #{ENV['KARBON_TOKEN']}"
f.headers['AccessKey'] = ENV['KARBON_ACCESS_KEY']
f.response :raise_error
end
response = conn.get('/TenantSettings')
puts JSON.parse(response.body)
Verifying Your Setup
A successful GET /v3/TenantSettings returns your tenant’s configuration:
{
"ContactTypes": [
"Individual",
"Business"
],
"WorkTypes": [
...
],
"WorkStatuses": [
...
],
"ClientAccessActivated": false
}
Cache this response — you’ll need WorkTypes, ContactTypes, and WorkStatuses throughout your
integration.
Account-Level Access
The Karbon API operates at the account level, not the user level. When you authenticate, you are acting on behalf of the entire Karbon account — not as any individual user within it.
This means:
- Actions taken via the API (creating work, updating contacts, recording payments) are not attributed to a specific Karbon user
- The
AccessKeyis tied to your API application and the account it’s connected to, not to any individual’s login - All data visible within that account is accessible regardless of which user would normally see it in the Karbon UI
If your integration needs to attribute actions to a specific person (e.g., setting an assignee on a work item), you pass that user’s email address explicitly in the request body — it is not inferred from the credentials.
Common Authentication Errors
| Status | Meaning |
|---|---|
401 Unauthorized | Missing or invalid Authorization header or AccessKey |
Security Note
Never hard-code credentials in source code. Use environment variables or a secrets manager.