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

# Get Job Visitors

> Retrieve visitor counts for specific job postings over a specified time period

## Authentication

This endpoint requires API key authentication. Include your API key in the request header:

```bash theme={null}
x-api-key: your-api-key-here
```

<Info>
  You can generate API keys from your organization settings in the Kardow dashboard under **Settings > API Keys**.
</Info>

## Query Parameters

<ParamField query="jobIds" type="string" required>
  Comma-separated list of job UUIDs to fetch visitor counts for. Maximum 100 job IDs per request.

  Example: `123e4567-e89b-12d3-a456-426614174000,123e4567-e89b-12d3-a456-426614174001`
</ParamField>

<ParamField query="period" type="string" default="30d">
  Time period for analytics data. Must be one of:

  * `7d` - Last 7 days
  * `30d` - Last 30 days
  * `6mo` - Last 6 months
  * `12mo` - Last 12 months
</ParamField>

## Response

<ResponseField name="data" type="object">
  The analytics data for the requested jobs

  <Expandable title="data properties">
    <ResponseField name="visitors" type="object">
      Map of job IDs to their visitor counts

      ```json theme={null}
      {
        "123e4567-e89b-12d3-a456-426614174000": 150,
        "123e4567-e89b-12d3-a456-426614174001": 320
      }
      ```
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="meta" type="object">
  Metadata about the request

  <Expandable title="meta properties">
    <ResponseField name="period" type="string">
      The time period used for the analytics query
    </ResponseField>

    <ResponseField name="total_jobs" type="number">
      Total number of jobs included in the query
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X GET \
    "https://api.kardow.com/analytics/jobs?jobIds=123e4567-e89b-12d3-a456-426614174000,123e4567-e89b-12d3-a456-426614174001&period=30d" \
    -H "x-api-key: your-api-key-here"
  ```

  ```javascript JavaScript theme={null}
  const apiKey = process.env.KARDOW_API_KEY;
  const jobIds = [
    '123e4567-e89b-12d3-a456-426614174000',
    '123e4567-e89b-12d3-a456-426614174001'
  ];

  const response = await fetch(
    `https://api.kardow.com/analytics/jobs?jobIds=${jobIds.join(',')}&period=30d`,
    {
      headers: {
        'x-api-key': apiKey
      }
    }
  );

  const data = await response.json();
  console.log('Visitor data:', data.data.visitors);
  ```

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

  api_key = os.environ.get('KARDOW_API_KEY')
  job_ids = [
      '123e4567-e89b-12d3-a456-426614174000',
      '123e4567-e89b-12d3-a456-426614174001'
  ]

  url = 'https://api.kardow.com/analytics/jobs'
  params = {
      'jobIds': ','.join(job_ids),
      'period': '30d'
  }
  headers = {
      'x-api-key': api_key
  }

  response = requests.get(url, params=params, headers=headers)
  data = response.json()
  print('Visitor data:', data['data']['visitors'])
  ```

  ```php PHP theme={null}
  <?php
  $apiKey = getenv('KARDOW_API_KEY');
  $jobIds = [
      '123e4567-e89b-12d3-a456-426614174000',
      '123e4567-e89b-12d3-a456-426614174001'
  ];

  $url = 'https://api.kardow.com/analytics/jobs';
  $queryParams = http_build_query([
      'jobIds' => implode(',', $jobIds),
      'period' => '30d'
  ]);

  $ch = curl_init("$url?$queryParams");
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
      "x-api-key: $apiKey"
  ]);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

  $response = curl_exec($ch);
  $data = json_decode($response, true);
  curl_close($ch);

  print_r($data['data']['visitors']);
  ?>
  ```
</RequestExample>

<ResponseExample>
  ```json 200 Success theme={null}
  {
    "data": {
      "visitors": {
        "123e4567-e89b-12d3-a456-426614174000": 150,
        "123e4567-e89b-12d3-a456-426614174001": 320
      }
    },
    "meta": {
      "period": "30d",
      "total_jobs": 2
    }
  }
  ```

  ```json 401 Missing API Key theme={null}
  {
    "error": {
      "message": "API key is required",
      "code": "missing_api_key",
      "details": "Please provide an API key in the x-api-key header",
      "url": "https://kardow.featurebase.app/help/articles/api-documentation"
    }
  }
  ```

  ```json 401 Invalid API Key theme={null}
  {
    "error": {
      "message": "Invalid API key",
      "code": "invalid_api_key",
      "details": "The provided API key is invalid or expired",
      "url": "https://kardow.featurebase.app/help/articles/api-documentation"
    }
  }
  ```

  ```json 400 Missing Parameters theme={null}
  {
    "error": {
      "message": "Missing required parameter",
      "code": "missing_parameter",
      "details": "jobIds parameter is required (comma-separated list of UUIDs)",
      "url": "https://kardow.com/help/api/get-job-analytics-with-the-api"
    }
  }
  ```

  ```json 403 Invalid Job IDs theme={null}
  {
    "error": {
      "message": "Invalid job IDs",
      "code": "forbidden",
      "details": "The following job IDs do not belong to your organization or do not exist: 123e4567-e89b-12d3-a456-426614174002",
      "url": "https://kardow.com/help/api/get-job-analytics-with-the-api"
    }
  }
  ```
</ResponseExample>

## Security

This endpoint implements multiple security layers:

1. **API Key Authentication** - Only valid API keys can access the endpoint
2. **Organization Scoping** - You can only access jobs belonging to your organization
3. **Job Ownership Validation** - All requested job IDs are verified to belong to your organization
4. **Domain Validation** - Analytics are fetched only from your organization's verified domain

## Rate Limits

<Warning>
  API requests are subject to rate limits:

  * **100 requests per minute** per API key
  * **10 concurrent requests** maximum
</Warning>

When you exceed the rate limit, you'll receive a `429 Too Many Requests` response.

## Best Practices

### Batch Multiple Jobs

Instead of making individual requests for each job, batch multiple job IDs in a single request:

<CodeGroup>
  ```javascript Don't - Multiple Requests theme={null}
  // Making 50 requests
  for (const jobId of jobIds) {
    await fetch(`https://api.kardow.com/analytics/jobs?jobIds=${jobId}`);
  }
  ```

  ```javascript Do - Single Batched Request theme={null}
  // Making 1 request for up to 100 jobs
  const jobIdsBatch = jobIds.slice(0, 100).join(',');
  await fetch(`https://api.kardow.com/analytics/jobs?jobIds=${jobIdsBatch}`);
  ```
</CodeGroup>

### Implement Error Handling

Always implement proper error handling with retries:

```javascript theme={null}
async function getAnalyticsWithRetry(jobIds, maxRetries = 3) {
  let lastError;

  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(
        `https://api.kardow.com/analytics/jobs?jobIds=${jobIds.join(',')}`,
        { headers: { 'x-api-key': apiKey } }
      );

      if (response.status === 429) {
        // Rate limited - wait and retry
        await new Promise(resolve => setTimeout(resolve, 2000 * (i + 1)));
        continue;
      }

      if (!response.ok) {
        const error = await response.json();
        throw new Error(error.error.message);
      }

      return await response.json();
    } catch (error) {
      lastError = error;
      if (i < maxRetries - 1) {
        await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
      }
    }
  }

  throw lastError;
}
```

### Cache Results

Cache analytics data to reduce API calls:

```javascript theme={null}
const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes

async function getCachedAnalytics(jobIds) {
  const cacheKey = jobIds.sort().join(',');
  const cached = cache.get(cacheKey);

  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return cached.data;
  }

  const data = await getJobAnalytics(jobIds);
  cache.set(cacheKey, { data, timestamp: Date.now() });
  return data;
}
```

## Common Use Cases

### Dashboard Integration

Display visitor analytics in your custom dashboard:

```javascript theme={null}
async function buildJobDashboard(jobIds) {
  const analytics = await getJobAnalytics(jobIds);

  return jobIds.map(jobId => ({
    jobId,
    visitors: analytics.data.visitors[jobId] || 0,
    // Add other job data
  }));
}
```

### Weekly Performance Reports

Generate automated reports of job performance:

```javascript theme={null}
async function generateWeeklyReport() {
  const jobs = await getAllActiveJobs();
  const jobIds = jobs.map(j => j.id);

  const analytics = await getJobAnalytics(jobIds);

  const report = {
    period: analytics.meta.period,
    totalVisitors: Object.values(analytics.data.visitors)
      .reduce((a, b) => a + b, 0),
    topJobs: Object.entries(analytics.data.visitors)
      .sort(([, a], [, b]) => b - a)
      .slice(0, 10)
      .map(([jobId, visitors]) => ({
        job: jobs.find(j => j.id === jobId),
        visitors
      }))
  };

  return report;
}
```

### Comparative Analysis

Compare performance across different time periods:

```javascript theme={null}
async function comparePerformance(jobIds) {
  const [last7Days, last30Days] = await Promise.all([
    getJobAnalytics(jobIds, '7d'),
    getJobAnalytics(jobIds, '30d')
  ]);

  return jobIds.map(jobId => ({
    jobId,
    last7Days: last7Days.data.visitors[jobId] || 0,
    last30Days: last30Days.data.visitors[jobId] || 0,
    averageDaily: (last30Days.data.visitors[jobId] || 0) / 30
  }));
}
```

## Related Endpoints

<CardGroup cols={2}>
  <Card title="Site Analytics" icon="chart-mixed" href="/docs/api-reference/analytics/analytics">
    Get comprehensive analytics with filtering options
  </Card>

  <Card title="List Jobs" icon="briefcase" href="/docs/api-reference/jobs/list">
    Retrieve your job listings
  </Card>
</CardGroup>


## OpenAPI

````yaml GET /analytics/job-visitors
openapi: 3.1.0
info:
  title: Kardow Analytics API
  description: >-
    Access comprehensive analytics data for your job board with powerful
    filtering and comparison capabilities
  version: 1.0.0
  contact:
    name: Kardow Support
    email: support@kardow.com
    url: https://kardow.com
servers:
  - url: https://api.kardow.com
    description: Production API
security:
  - ApiKeyAuth: []
tags:
  - name: Analytics
    description: Analytics endpoints for accessing visitor data and performance metrics
paths:
  /analytics/job-visitors:
    get:
      tags:
        - Analytics
      summary: Get Job Visitors
      description: >-
        Retrieve visitor counts for specific job postings. Use this endpoint
        when you need simple visitor metrics for individual jobs (up to 100 at a
        time).
      operationId: getJobVisitors
      parameters:
        - name: jobIds
          in: query
          required: true
          description: Comma-separated list of job UUIDs (max 100)
          schema:
            type: string
            example: >-
              123e4567-e89b-12d3-a456-426614174000,123e4567-e89b-12d3-a456-426614174001
        - name: period
          in: query
          required: false
          description: Time period for analytics
          schema:
            type: string
            enum:
              - 7d
              - 30d
              - 6mo
              - 12mo
            default: 30d
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JobAnalyticsResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '403':
          $ref: '#/components/responses/ForbiddenError'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - ApiKeyAuth: []
components:
  schemas:
    JobAnalyticsResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            visitors:
              type: object
              additionalProperties:
                type: integer
              description: Map of job IDs to visitor counts
        meta:
          type: object
          properties:
            period:
              type: string
            total_jobs:
              type: integer
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            message:
              type: string
            code:
              type: string
            details:
              oneOf:
                - type: string
                - type: array
            url:
              type: string
              format: uri
  responses:
    ValidationError:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    UnauthorizedError:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            missingKey:
              summary: Missing API key
              value:
                error:
                  message: API key is required
                  code: missing_api_key
                  details: Please provide an API key in the x-api-key header
                  url: >-
                    https://kardow.featurebase.app/help/articles/api-documentation
            invalidKey:
              summary: Invalid API key
              value:
                error:
                  message: Invalid API key
                  code: invalid_api_key
                  details: The provided API key is invalid or expired
                  url: >-
                    https://kardow.featurebase.app/help/articles/api-documentation
    ForbiddenError:
      description: Access denied to requested resource
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        API key for authentication. Get yours from Settings > API Keys in the
        Kardow dashboard.

````