API Keys
Generate and manage API keys for programmatic access to your analytics
API keys provide secure, programmatic access to your Jetrack analytics data. Use them to build integrations, automate reports, or sync data with your internal tools.
What Are API Keys?
An API key is a unique identifier that authenticates your requests to the Jetrack API. Unlike session-based authentication, API keys are designed for server-to-server communication and long-running integrations.
Use cases:
- Building custom dashboards
- Automating analytics reports
- Integrating with internal tools (Slack, Discord, etc.)
- Syncing data with data warehouses
- Creating monitoring and alerting systems
API Key Format
Jetrack API keys follow a specific format for easy identification:
bj_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2- Prefix:
bj_live_(8 characters) - Key body: 64 hexadecimal characters
- Total length: 72 characters
The bj_live_ prefix makes it easy to identify Jetrack API keys in your codebase and helps prevent accidental exposure in logs.
Getting Your API Key
Step 1: Navigate to Settings
Log in to your Jetrack dashboard and click on your profile icon in the top navigation bar. Select API Keys from the dropdown menu to go to the Settings page.
Step 2: Generate Your Key
On the Settings page, you'll see the API key management interface. If you don't have an API key yet:
- Optionally enter a name for your key (e.g., "Production Server", "Analytics Dashboard")
- Click Generate API Key
Your API key will be displayed only once. Make sure to copy it immediately.
Step 3: Store It Securely
After copying your key, store it in a secure location:
- Use environment variables (recommended)
- Store in a secrets manager (AWS Secrets Manager, HashiCorp Vault, etc.)
- Never commit API keys to version control
Using Your API Key
You can authenticate API requests using either of these methods:
Method 1: X-API-Key Header (Recommended)
Include your API key in the X-API-Key header:
curl -X GET "https://analytics.brandjet.ai/api/v1/account" \
-H "X-API-Key: bj_live_your_api_key_here"Method 2: Authorization Bearer Header
Alternatively, use the standard Authorization header with a Bearer token:
curl -X GET "https://analytics.brandjet.ai/api/v1/account" \
-H "Authorization: Bearer bj_live_your_api_key_here"Both methods are equally secure. Choose whichever fits your existing codebase better.
Code Examples
cURL
# Get account info
curl -X GET "https://analytics.brandjet.ai/api/v1/account" \
-H "X-API-Key: bj_live_your_api_key_here"
# List all websites
curl -X GET "https://analytics.brandjet.ai/api/v1/websites" \
-H "X-API-Key: bj_live_your_api_key_here"
# Get analytics for a website
curl -X GET "https://analytics.brandjet.ai/api/v1/websites/{id}/stats/main?from=2025-01-01&to=2025-01-31" \
-H "X-API-Key: bj_live_your_api_key_here"JavaScript / Node.js
Using the Fetch API:
const API_KEY = process.env.JETRACK_API_KEY;
const BASE_URL = 'https://analytics.brandjet.ai/api/v1';
async function getWebsites() {
const response = await fetch(`${BASE_URL}/websites`, {
headers: {
'X-API-Key': API_KEY,
},
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return response.json();
}
async function getStats(websiteId, from, to) {
const params = new URLSearchParams({ from, to });
const response = await fetch(
`${BASE_URL}/websites/${websiteId}/stats/main?${params}`,
{
headers: {
'X-API-Key': API_KEY,
},
}
);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return response.json();
}
// Usage
const websites = await getWebsites();
console.log('My websites:', websites);
const stats = await getStats(websites[0].id, '2025-01-01', '2025-01-31');
console.log('Analytics:', stats);Using Axios:
import axios from 'axios';
const api = axios.create({
baseURL: 'https://analytics.brandjet.ai/api/v1',
headers: {
'X-API-Key': process.env.JETRACK_API_KEY,
},
});
// Get account info
const { data: account } = await api.get('/account');
// List websites
const { data: websites } = await api.get('/websites');
// Get analytics
const { data: stats } = await api.get(`/websites/${websiteId}/stats/main`, {
params: {
from: '2025-01-01',
to: '2025-01-31',
},
});Python
Using the requests library:
import os
import requests
API_KEY = os.environ.get('JETRACK_API_KEY')
BASE_URL = 'https://analytics.brandjet.ai/api/v1'
headers = {
'X-API-Key': API_KEY
}
def get_account():
"""Get account information."""
response = requests.get(f'{BASE_URL}/account', headers=headers)
response.raise_for_status()
return response.json()
def get_websites():
"""List all websites."""
response = requests.get(f'{BASE_URL}/websites', headers=headers)
response.raise_for_status()
return response.json()
def get_stats(website_id, from_date, to_date):
"""Get analytics for a website."""
params = {
'from': from_date,
'to': to_date
}
response = requests.get(
f'{BASE_URL}/websites/{website_id}/stats/main',
headers=headers,
params=params
)
response.raise_for_status()
return response.json()
# Usage
account = get_account()
print(f"Account: {account['data']['email']}")
websites = get_websites()
print(f"Found {len(websites['data'])} websites")
if websites['data']:
website_id = websites['data'][0]['id']
stats = get_stats(website_id, '2025-01-01', '2025-01-31')
print(f"Visitors: {stats['data']['uniqueVisitors']}")TypeScript
With type definitions:
interface ApiResponse<T> {
success: boolean;
data: T;
meta: {
status: number;
message?: string;
errors?: string[];
};
}
interface Website {
id: string;
name: string;
domain: string;
createdAt: string;
}
interface MainAnalytics {
uniqueVisitors: number;
totalPageviews: number;
avgSessionDuration: number;
bounceRate: number;
}
const API_KEY = process.env.JETRACK_API_KEY!;
const BASE_URL = 'https://analytics.brandjet.ai/api/v1';
async function fetchApi<T>(endpoint: string, params?: Record<string, string>): Promise<T> {
const url = new URL(`${BASE_URL}${endpoint}`);
if (params) {
Object.entries(params).forEach(([key, value]) => {
url.searchParams.append(key, value);
});
}
const response = await fetch(url.toString(), {
headers: {
'X-API-Key': API_KEY,
},
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
const json: ApiResponse<T> = await response.json();
return json.data;
}
// Usage
const websites = await fetchApi<Website[]>('/websites');
const stats = await fetchApi<MainAnalytics>(
`/websites/${websites[0].id}/stats/main`,
{ from: '2025-01-01', to: '2025-01-31' }
);Managing Your API Key
View Key Information
On the Settings page, you can see your API key's:
- Key prefix - The first 12 characters (e.g.,
bj_live_a1b2) - Name - The label you assigned (if any)
- Created date - When the key was generated
- Last used - When the key was last used for authentication
The full key is never displayed after creation for security reasons.
Regenerate Key
If your API key is compromised or you need a new one:
- Go to Settings
- Click Regenerate Key
- Confirm the action
Important: Regenerating immediately invalidates your old key. Any integrations using the old key will stop working until you update them with the new key.
Revoke Key
To permanently delete your API key:
- Go to Settings
- Click Revoke API Key in the Danger Zone
- Confirm the action
This is irreversible. You'll need to generate a new key if you want to use the API again.
Security Best Practices
Store Keys in Environment Variables
Never hardcode API keys in your source code:
# .env file (never commit this!)
JETRACK_API_KEY=bj_live_your_api_key_here// Access via environment variable
const apiKey = process.env.JETRACK_API_KEY;Keep Keys Server-Side Only
API keys should only be used in server-side code. Never expose them in:
- Browser JavaScript
- Mobile app code
- Client-side configuration files
- Public repositories
Use Secrets Management
For production environments, consider using a secrets manager:
- AWS Secrets Manager
- HashiCorp Vault
- Google Cloud Secret Manager
- Azure Key Vault
- Doppler
Rotate Keys Periodically
Even without a security incident, it's good practice to regenerate your API key periodically (e.g., every 90 days).
Monitor Usage
Check the "Last used" timestamp regularly to detect unauthorized usage. If you see unexpected activity, regenerate your key immediately.
Troubleshooting
401 Unauthorized
Possible causes:
- Missing API key header
- Invalid or revoked API key
- Typo in the key
Solution:
- Verify the header name is correct (
X-API-KeyorAuthorization: Bearer) - Check that the full key is included (72 characters)
- Ensure the key hasn't been regenerated or revoked
- Try regenerating a new key
403 Forbidden
Possible causes:
- Trying to access a resource you don't own
- Website belongs to another account
Solution:
- Verify you're using the correct website ID
- Check that the resource belongs to your account
Rate Limiting (429)
Possible causes:
- Too many requests in a short period
Solution:
- Implement exponential backoff
- Cache responses where appropriate
- Batch requests when possible
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status === 429) {
const delay = Math.pow(2, i) * 1000; // Exponential backoff
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}Next Steps
- API Overview - Base URL, response format, and quick start
- Endpoints Reference - Complete endpoint documentation