API Reference
Authentication
LinkedIn Automation
Voice Cloning
Lead Management
Enrichment & Prospecting
Get User Jobs
Get job status, counts, and statistics for the authenticated user
curl --request GET \
--url https://api.buena.ai/api/v2/users/jobs \
--header 'x-api-key: <api-key>'
{
"userId": "65e0a32640a597f6a7f897ea",
"success": true,
"data": {
"jobs": [
{
"id": "job_123abc",
"type": "linkedin_action",
"status": "completed",
"createdAt": "2024-01-20T10:00:00Z",
"completedAt": "2024-01-20T10:02:00Z",
"message": "Connection request sent successfully",
"progress": 100,
"metadata": {
"actionType": "sendConnectionRequest",
"profileUrl": "https://linkedin.com/in/johndoe",
"delay": 75000
}
},
{
"id": "job_456def",
"type": "data_enrichment",
"status": "running",
"createdAt": "2024-01-20T11:00:00Z",
"completedAt": null,
"message": "Processing lead enrichment batch",
"progress": 60,
"metadata": {
"batchSize": 50,
"processed": 30
}
}
],
"statistics": {
"total": 25,
"pending": 3,
"running": 2,
"completed": 18,
"failed": 2,
"successRate": 85.7
}
}
}
Get User Jobs
Retrieve job status information, counts, and statistics for the authenticated user. This simplified endpoint automatically detects the user from the API key, eliminating the need for user IDs in the URL.
Requires a user-specific API key with users:read
permission. Global API
keys should use the legacy routes.
Request
Your user-specific API key with users:read
permission (format:
bna_hexstring
)
Query Parameters
Unix timestamp for filtering jobs from this date
Unix timestamp for filtering jobs until this date
Filter jobs by status (e.g., “completed”, “pending”, “failed”)
Filter jobs by type (e.g., “linkedin_action”, “data_enrichment”)
Examples
Get All Jobs
curl -X GET "https://api.buena.ai/api/v2/users/jobs" \
-H "x-api-key: bna_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Get Jobs with Date Range
curl -X GET "https://api.buena.ai/api/v2/users/jobs?startDate=1640995200&endDate=1703980800" \
-H "x-api-key: bna_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Get Jobs by Status
curl -X GET "https://api.buena.ai/api/v2/users/jobs?status=completed" \
-H "x-api-key: bna_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Response
The authenticated user’s ID
Always true
for successful requests
Job information and statistics
Show Data Object
Show Data Object
Array of job objects for the user
Show Job Object
Show Job Object
Unique job identifier
Type of job (e.g., “linkedin_action”, “data_enrichment”)
Current status (“pending”, “running”, “completed”, “failed”)
ISO 8601 timestamp when job was created
ISO 8601 timestamp when job completed (null if not completed)
Job description or error message
Completion percentage (0-100)
Additional job-specific information
{
"userId": "65e0a32640a597f6a7f897ea",
"success": true,
"data": {
"jobs": [
{
"id": "job_123abc",
"type": "linkedin_action",
"status": "completed",
"createdAt": "2024-01-20T10:00:00Z",
"completedAt": "2024-01-20T10:02:00Z",
"message": "Connection request sent successfully",
"progress": 100,
"metadata": {
"actionType": "sendConnectionRequest",
"profileUrl": "https://linkedin.com/in/johndoe",
"delay": 75000
}
},
{
"id": "job_456def",
"type": "data_enrichment",
"status": "running",
"createdAt": "2024-01-20T11:00:00Z",
"completedAt": null,
"message": "Processing lead enrichment batch",
"progress": 60,
"metadata": {
"batchSize": 50,
"processed": 30
}
}
],
"statistics": {
"total": 25,
"pending": 3,
"running": 2,
"completed": 18,
"failed": 2,
"successRate": 85.7
}
}
}
Advanced Use Cases
1. Job Status Monitoring Dashboard
async function createJobsDashboard() {
try {
const response = await fetch("https://api.buena.ai/api/v2/users/jobs", {
headers: {
"x-api-key": process.env.BUENA_USER_API_KEY,
},
});
const data = await response.json();
// Display job statistics
const stats = data.data.statistics;
console.log(`📊 Job Statistics:`);
console.log(`Total: ${stats.total}`);
console.log(`✅ Completed: ${stats.completed}`);
console.log(`⏳ Running: ${stats.running}`);
console.log(`📋 Pending: ${stats.pending}`);
console.log(`❌ Failed: ${stats.failed}`);
console.log(`📈 Success Rate: ${stats.successRate}%`);
// Show recent jobs
const recentJobs = data.data.jobs
.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
.slice(0, 5);
console.log(`\n🕐 Recent Jobs:`);
recentJobs.forEach((job) => {
const status = getStatusEmoji(job.status);
console.log(`${status} ${job.type} - ${job.message} (${job.progress}%)`);
});
} catch (error) {
console.error("Failed to fetch job data:", error);
}
}
function getStatusEmoji(status) {
const statusMap = {
completed: "✅",
running: "⏳",
pending: "📋",
failed: "❌",
};
return statusMap[status] || "❓";
}
// Update dashboard every 30 seconds
setInterval(createJobsDashboard, 30000);
2. Job Progress Tracking
import requests
import time
from datetime import datetime
class JobTracker:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = 'https://api.buena.ai/api/v2'
def get_jobs(self, status=None, job_type=None):
"""Get jobs with optional filtering"""
params = {}
if status:
params['status'] = status
if job_type:
params['type'] = job_type
response = requests.get(
f'{self.base_url}/users/jobs',
headers={'x-api-key': self.api_key},
params=params
)
return response.json()
def wait_for_completion(self, job_id, timeout=300):
"""Wait for a specific job to complete"""
start_time = time.time()
while time.time() - start_time < timeout:
jobs_data = self.get_jobs()
job = next((j for j in jobs_data['data']['jobs'] if j['id'] == job_id), None)
if not job:
print(f"❌ Job {job_id} not found")
return False
if job['status'] == 'completed':
print(f"✅ Job {job_id} completed successfully")
return True
elif job['status'] == 'failed':
print(f"❌ Job {job_id} failed: {job['message']}")
return False
else:
print(f"⏳ Job {job_id} progress: {job['progress']}% ({job['status']})")
time.sleep(10)
print(f"⏰ Timeout waiting for job {job_id}")
return False
def get_daily_summary(self):
"""Get today's job summary"""
today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
start_timestamp = int(today.timestamp())
response = requests.get(
f'{self.base_url}/users/jobs',
headers={'x-api-key': self.api_key},
params={'startDate': start_timestamp}
)
data = response.json()
return {
'date': today.strftime('%Y-%m-%d'),
'statistics': data['data']['statistics'],
'recent_jobs': data['data']['jobs'][:10]
}
# Usage
tracker = JobTracker(os.getenv('BUENA_USER_API_KEY'))
# Monitor running jobs
running_jobs = tracker.get_jobs(status='running')
print(f"Currently running {len(running_jobs['data']['jobs'])} jobs")
# Get daily summary
summary = tracker.get_daily_summary()
print(f"Today's summary: {summary['statistics']}")
3. Automated Job Cleanup
async function cleanupFailedJobs() {
const response = await fetch(
"https://api.buena.ai/api/v2/users/jobs?status=failed",
{
headers: {
"x-api-key": process.env.BUENA_USER_API_KEY,
},
}
);
const data = await response.json();
const failedJobs = data.data.jobs;
// Group failed jobs by type
const failuresByType = failedJobs.reduce((acc, job) => {
if (!acc[job.type]) acc[job.type] = [];
acc[job.type].push(job);
return acc;
}, {});
console.log("Failed Jobs Analysis:");
Object.entries(failuresByType).forEach(([type, jobs]) => {
console.log(`\n${type}: ${jobs.length} failures`);
// Find common error patterns
const errorMessages = jobs.map((j) => j.message);
const uniqueErrors = [...new Set(errorMessages)];
uniqueErrors.forEach((error) => {
const count = errorMessages.filter((msg) => msg === error).length;
console.log(` - "${error}": ${count} occurrences`);
});
});
// Identify jobs that might need retry
const retryableJobs = failedJobs.filter(
(job) =>
job.message.includes("rate limit") ||
job.message.includes("timeout") ||
job.message.includes("network")
);
if (retryableJobs.length > 0) {
console.log(`\n🔄 ${retryableJobs.length} jobs might be retryable`);
}
}
// Run cleanup analysis daily
cleanupFailedJobs();
Legacy Routes
For backward compatibility, these legacy routes are still supported but require explicit user IDs:
GET /api/v2/users/jobs/userJobStatus/:userId
- Get user job statusGET /api/v2/users/jobs/jobStatus
- Get all jobs (requiresjobs:read
permission)GET /api/v2/users/jobs/jobCounts
- Get job counts onlyPUT /api/v2/users/jobs/editJobMessage/:jobId
- Edit job message (requiresjobs:update
)
Error Responses
Global API Key Used (400)
{
"error": "When using global API key, please use the specific route: /api/v2/users/jobs/userJobStatus/:userId",
"availableRoute": "/api/v2/users/jobs/userJobStatus/:userId"
}
Invalid Permission (403)
{
"error": true,
"code": "PERMISSION_DENIED",
"message": "Insufficient permissions for user job access",
"version": "2.0",
"timestamp": "2024-01-20T15:30:00Z",
"permissionHelp": {
"required": "users:read",
"available": ["linkedin:schedule"],
"documentation": "https://docs.buena.ai/authentication"
}
}
Next Steps
curl --request GET \
--url https://api.buena.ai/api/v2/users/jobs \
--header 'x-api-key: <api-key>'
{
"userId": "65e0a32640a597f6a7f897ea",
"success": true,
"data": {
"jobs": [
{
"id": "job_123abc",
"type": "linkedin_action",
"status": "completed",
"createdAt": "2024-01-20T10:00:00Z",
"completedAt": "2024-01-20T10:02:00Z",
"message": "Connection request sent successfully",
"progress": 100,
"metadata": {
"actionType": "sendConnectionRequest",
"profileUrl": "https://linkedin.com/in/johndoe",
"delay": 75000
}
},
{
"id": "job_456def",
"type": "data_enrichment",
"status": "running",
"createdAt": "2024-01-20T11:00:00Z",
"completedAt": null,
"message": "Processing lead enrichment batch",
"progress": 60,
"metadata": {
"batchSize": 50,
"processed": 30
}
}
],
"statistics": {
"total": 25,
"pending": 3,
"running": 2,
"completed": 18,
"failed": 2,
"successRate": 85.7
}
}
}