> ## Documentation Index
> Fetch the complete documentation index at: https://docs.buena.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Get User Jobs

> Get job status, counts, and statistics for the authenticated user

# 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.

<Note>
  Requires a **user-specific API key** with `users:read` permission. Global API
  keys should use the legacy routes.
</Note>

## Request

<ParamField header="x-api-key" type="string" required>
  Your user-specific API key with `users:read` permission (format:
  `bna_hexstring`)
</ParamField>

### Query Parameters

<ParamField query="startDate" type="number">
  Unix timestamp for filtering jobs from this date
</ParamField>

<ParamField query="endDate" type="number">
  Unix timestamp for filtering jobs until this date
</ParamField>

<ParamField query="status" type="string">
  Filter jobs by status (e.g., "completed", "pending", "failed")
</ParamField>

<ParamField query="type" type="string">
  Filter jobs by type (e.g., "linkedin\_action", "data\_enrichment")
</ParamField>

## Examples

### Get All Jobs

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.buena.ai/api/v2/users/jobs" \
    -H "x-api-key: bna_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.buena.ai/api/v2/users/jobs", {
    method: "GET",
    headers: {
      "x-api-key":
        "bna_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    },
  });

  const data = await response.json();
  console.log(data);
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      'https://api.buena.ai/api/v2/users/jobs',
      headers={
          'x-api-key': 'bna_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
      }
  )

  print(response.json())
  ```
</CodeGroup>

### Get Jobs with Date Range

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.buena.ai/api/v2/users/jobs?startDate=1640995200&endDate=1703980800" \
    -H "x-api-key: bna_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  ```

  ```javascript JavaScript theme={null}
  const startDate = Math.floor(new Date("2022-01-01").getTime() / 1000);
  const endDate = Math.floor(new Date("2023-12-31").getTime() / 1000);

  const response = await fetch(
    `https://api.buena.ai/api/v2/users/jobs?startDate=${startDate}&endDate=${endDate}`,
    {
      method: "GET",
      headers: {
        "x-api-key":
          "bna_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      },
    }
  );

  const data = await response.json();
  console.log(data);
  ```
</CodeGroup>

### Get Jobs by Status

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.buena.ai/api/v2/users/jobs?status=completed" \
    -H "x-api-key: bna_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    "https://api.buena.ai/api/v2/users/jobs?status=completed",
    {
      method: "GET",
      headers: {
        "x-api-key":
          "bna_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      },
    }
  );

  const data = await response.json();
  console.log(data);
  ```
</CodeGroup>

## Response

<ResponseField name="userId" type="string">
  The authenticated user's ID
</ResponseField>

<ResponseField name="success" type="boolean">
  Always `true` for successful requests
</ResponseField>

<ResponseField name="data" type="object">
  Job information and statistics

  <Expandable title="Data Object">
    <ResponseField name="jobs" type="array">
      Array of job objects for the user

      <Expandable title="Job Object">
        <ResponseField name="id" type="string">
          Unique job identifier
        </ResponseField>

        <ResponseField name="type" type="string">
          Type of job (e.g., "linkedin\_action", "data\_enrichment")
        </ResponseField>

        <ResponseField name="status" type="string">
          Current status ("pending", "running", "completed", "failed")
        </ResponseField>

        <ResponseField name="createdAt" type="string">
          ISO 8601 timestamp when job was created
        </ResponseField>

        <ResponseField name="completedAt" type="string">
          ISO 8601 timestamp when job completed (null if not completed)
        </ResponseField>

        <ResponseField name="message" type="string">
          Job description or error message
        </ResponseField>

        <ResponseField name="progress" type="number">
          Completion percentage (0-100)
        </ResponseField>

        <ResponseField name="metadata" type="object">
          Additional job-specific information
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="statistics" type="object">
      Job statistics summary

      <Expandable title="Statistics Object">
        <ResponseField name="total" type="number">
          Total number of jobs
        </ResponseField>

        <ResponseField name="pending" type="number">
          Number of pending jobs
        </ResponseField>

        <ResponseField name="running" type="number">
          Number of currently running jobs
        </ResponseField>

        <ResponseField name="completed" type="number">
          Number of completed jobs
        </ResponseField>

        <ResponseField name="failed" type="number">
          Number of failed jobs
        </ResponseField>

        <ResponseField name="successRate" type="number">
          Success rate as a percentage
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseExample>
  ```json Response theme={null}
  {
    "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
      }
    }
  }
  ```
</ResponseExample>

## Advanced Use Cases

### 1. Job Status Monitoring Dashboard

```javascript theme={null}
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

```python theme={null}
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

```javascript theme={null}
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

<Info>
  For backward compatibility, these legacy routes are still supported but
  require explicit user IDs:
</Info>

* `GET /api/v2/users/jobs/userJobStatus/:userId` - Get user job status
* `GET /api/v2/users/jobs/jobStatus` - Get all jobs (requires `jobs:read` permission)
* `GET /api/v2/users/jobs/jobCounts` - Get job counts only
* `PUT /api/v2/users/jobs/editJobMessage/:jobId` - Edit job message (requires `jobs:update`)

## Error Responses

### Global API Key Used (400)

```json theme={null}
{
  "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)

```json theme={null}
{
  "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

<CardGroup cols={2}>
  <Card title="LinkedIn Integration" icon="linkedin" href="/api-reference/users/linkedin">
    Check LinkedIn integration status
  </Card>

  <Card title="User Integrations" icon="plug" href="/api-reference/users/integrations">
    Manage user integrations
  </Card>

  <Card title="Schedule Actions" icon="calendar" href="/api-reference/linkedin/schedule-action">
    Schedule LinkedIn actions
  </Card>

  <Card title="User Guide" icon="book" href="/guides/user-management">
    Learn user management best practices
  </Card>
</CardGroup>
