# Company Competitor Engagements API
> Find people with demonstrated engagement around a company page and return their available profile URLs with post context.
**Base URL:** `https://api.nyne.ai`
**Endpoint:** `https://api.nyne.ai/company/competitor-engagements`

---

## Overview
The Company Competitor Engagements API queues an async request for a company page and returns people with demonstrated engagement around company-related posts. Results prioritize available LinkedIn profile URLs and include post date/context, request status, and credits charged.
### What You Get
- **Person Profile URLs:** Returns the available LinkedIn profile URL for each person in the result set.- **Post Context:** Includes available post date, URL, content preview, and aggregate engagement details.- **Current Employee Exclusion:** Excludes people identified as current employees of the requested company when current organization data is available.- **Async Delivery:** Receives a request_id immediately, then supports polling or callback delivery.- **Per-Result Billing:** Charges credits only for person profile results returned.
## Authentication

All requests require header authentication:

```
X-API-Key: YOUR_API_KEY
X-API-Secret: YOUR_API_SECRET
```

## Rate Limits

| Limit | Value |
|-------|-------|
| Per Minute | 60 requests |
| Per Hour | 1000 requests |
| Monthly | Varies by plan |

### Response Headers

Responses from endpoints that perform rate-limit checks include both legacy and standard rate-limit headers:

| Header | Description |
|--------|-------------|
| `X-RateLimit-Limit` | Active per-minute or per-hour limit |
| `X-RateLimit-Remaining` | Remaining requests in the active window |
| `X-RateLimit-Reset` | Unix timestamp when the active window resets |
| `RateLimit-Limit` | Active per-minute or per-hour limit |
| `RateLimit-Remaining` | Remaining requests in the active window |
| `RateLimit-Reset` | Seconds until the active window resets |
| `Retry-After` | Seconds to wait before retrying; present on HTTP `429` rate-limit responses |

Monthly quota responses include quota-specific headers when available:

| Header | Description |
|--------|-------------|
| `X-Quota-Limit` | Monthly request or credit limit |
| `X-Quota-Used` | Amount used in the current billing cycle |
| `X-Quota-Remaining` | Amount remaining in the current billing cycle |
| `X-Quota-Reset` | Unix timestamp when the current billing cycle resets |

## Credit Usage

- **Company Competitor Engagements:** 5 credits per person result returned
> Credits are charged only for person results returned. Example: if a request returns 12 person results, the request consumes 60 credits. If it returns no person profile results, no per-result credits are charged.
---

## POST /company/competitor-engagementsQueue a company competitor engagements request.
### Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `company_url` | string | Yes | Company page URL to analyze. |
| `max_items` | integer | No | Maximum person engagement results to return. Allowed range is 1-100. (default: `100`) |
| `page_number` | integer | No | Page number for result pagination. (default: `1`) |
| `sort` | string | No | Sort order. Allowed values are recent and top. (default: `recent`) |
| `callback_url` | string | No | Public HTTP or HTTPS endpoint that receives the completed or failed payload. |

> **Required:** Supply <code>company_url</code>.
### Request Examples

**With Advanced Features:**

```json
{
  "company_url": "https://www.linkedin.com/company/nyne-ai",
  "max_items": 50,
  "page_number": 1,
  "sort": "top",
  "callback_url": "https://example.com/webhook/company-engagements"
}
```

**Basic Request:**

```json
{
  "company_url": "https://www.linkedin.com/company/nyne-ai",
  "max_items": 100,
  "page_number": 1,
  "sort": "recent"
}
```

### Code Examples

**cURL:**

```bash
curl -X POST https://api.nyne.ai/company/competitor-engagements \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "company_url": "https://www.linkedin.com/company/nyne-ai",
    "max_items": 100,
    "page_number": 1,
    "sort": "recent"
  }'
```

**Python:**

```python
import requests
import json

url = "https://api.nyne.ai/company/competitor-engagements"
headers = {
    "X-API-Key": "YOUR_API_KEY",
    "X-API-Secret": "YOUR_API_SECRET",
    "Content-Type": "application/json"
}
data = {
    "company_url": "https://www.linkedin.com/company/nyne-ai",
    "max_items": 100,
    "page_number": 1,
    "sort": "recent"
}

response = requests.post(url, headers=headers, json=data)
print(json.dumps(response.json(), indent=2))
```

**JavaScript:**

```javascript
const url = "https://api.nyne.ai/company/competitor-engagements";
const headers = {
    "X-API-Key": "YOUR_API_KEY",
    "X-API-Secret": "YOUR_API_SECRET",
    "Content-Type": "application/json"
};
const data = {
    company_url: "https://www.linkedin.com/company/nyne-ai",
    max_items: 100,
    page_number: 1,
    sort: "recent"
};

fetch(url, {
    method: "POST",
    headers: headers,
    body: JSON.stringify(data)
})
.then(response => response.json())
.then(result => console.log(result));
```

### Response Codes

| Code | Description |
|------|-------------|
| 202 | Request queued successfully |
| 400 | Missing or invalid request parameters |
| 401 | Invalid, missing, or expired API credentials |
| 403 | IP, subscription, or credit access denied |
| 429 | Rate limit or monthly limit exceeded |
| 500 | The request could not be queued |

### Response Example

```json
{
  "success": true,
  "data": {
    "request_id": "65f6d9f92799d3c2a24123f4f13a7d7a3af6ac13f1d8d0695dce03b98a4e5220",
    "status": "queued",
    "company_url": "https://www.linkedin.com/company/nyne-ai",
    "max_items": 100,
    "page_number": 1,
    "sort": "recent",
    "message": "Company competitor engagements request queued. Poll this endpoint with GET request_id to retrieve results."
  },
  "timestamp": "2026-04-27T10:00:00Z"
}
```

---

## GET /company/competitor-engagements
Check the status of a request.

### Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `request_id` | string | Yes | The request ID returned from the POST call |

### Request Example

```
GET /company/competitor-engagements?request_id=65f6d9f92799d3c2a24123f4f13a7d7a3af6ac13f1d8d0695dce03b98a4e5220
```

### Response Codes

| Code | Description |
|------|-------------|
| 200 | Status retrieved successfully. Payload status can be pending, processing, completed, or failed. |
| 400 | request_id is missing |
| 401 | Authentication failed |
| 404 | Request ID not found or not owned by this API key |
| 500 | The request status could not be retrieved |

### Response Example

```json
{
  "success": true,
  "data": {
    "request_id": "65f6d9f92799d3c2a24123f4f13a7d7a3af6ac13f1d8d0695dce03b98a4e5220",
    "status": "completed",
    "company_url": "https://www.linkedin.com/company/nyne-ai",
    "max_items": 100,
    "page_number": 1,
    "sort": "recent",
    "completed": true,
    "results_count": 1,
    "total_results": 1,
    "credits_charged": 5,
    "results": [
      {
        "linkedin_profile_url": "https://www.linkedin.com/in/janedoe",
        "source_profile_url": "https://www.linkedin.com/in/janedoe",
        "person": {
          "linkedin_profile_url": "https://www.linkedin.com/in/janedoe",
          "profile_url": "https://www.linkedin.com/in/janedoe",
          "name": "Jane Doe",
          "display_name": "Jane Doe"
        },
        "actor": {
          "type": "profile",
          "username": "janedoe",
          "display_name": "Jane Doe",
          "name": "Jane Doe",
          "profile_url": "https://www.linkedin.com/in/janedoe"
        },
        "interaction_id": "7453487458471567360",
        "interaction_type": "company_post",
        "interaction_url": "https://www.linkedin.com/posts/example",
        "date_posted": "2026-04-24 18:58:09",
        "posted_timestamp": 1777057089,
        "post": {
          "url": "https://www.linkedin.com/posts/example",
          "date_posted": "2026-04-24 18:58:09"
        },
        "content": { "text": "Example post text" },
        "target": {
          "type": "post",
          "url": "https://www.linkedin.com/posts/example"
        },
        "replies": [],
        "engagement": { "likes": 22, "comments": 2, "shares": 5 }
      }
    ],
    "created_on": "2026-04-27T10:00:00",
    "completed_on": "2026-04-27T10:00:30"
  },
  "timestamp": "2026-04-27T10:00:35Z"
}
```

---

## Response Format

All API responses follow a consistent JSON format. All fields in enrichment results are **optional** and only included when data is available:
- The immediate POST response has status queued and includes request_id.- GET status responses return pending, processing, completed, or failed.- Completed responses include results, results_count, and credits_charged.- Each result prioritizes linkedin_profile_url and source_profile_url for the person in the result, with available current organization details and post context in post and target.- People identified as current employees of the requested company are excluded when current organization data is available.- Failed responses still use HTTP 200 when the request record exists; inspect data.status and data.error.
---

## Error Codes

| HTTP Code | Error Code | Description |
|-----------|------------|-------------|
| 400 | `missing_parameters` | <code>company_url</code> is missing |
| 400 | `invalid_company_url` | The supplied URL is not a supported company page URL, or it is a person profile URL |
| 400 | `invalid_limit` | <code>max_items</code> or <code>page_number</code> is not valid |
| 400 | `invalid_callback_url` | Callback URL is not a valid public HTTP or HTTPS URL |
| 400 | `invalid_json` | The request body could not be parsed as JSON |
| 400 | `missing_request_id` | GET status request omitted <code>request_id</code> |
| 401 | `missing_credentials` | POST request did not include API credentials |
| 401 | `invalid_credentials` | POST request credentials are invalid |
| 401 | `api_key_expired` | API key is expired |
| 401 | `authentication_failed` | GET status authentication failed |
| 403 | `ip_not_allowed` | API key is not allowed from this IP address |
| 403 | `subscription_required` | The account subscription does not include this API |
| 403 | `no_active_subscription` | The account does not have an active subscription for this API |
| 403 | `insufficient_credits` | The account does not have enough credits |
| 404 | `request_not_found` | The request ID does not exist or does not belong to the authenticated API key |
| 429 | `rate_limit_exceeded` | Per-minute or per-hour usage limits were exceeded |
| 429 | `monthly_limit_exceeded` | Monthly usage limit exceeded |
| 500 | `internal_error` | The request could not be processed. Try again later. |

---

## Callbacks

When you provide a `callback_url`, the API sends results to your endpoint via HTTP POST.

### Delivery- The API sends one HTTP POST to your callback URL when the request completes or fails- The callback body is JSON with <code>request_id</code> and <code>status</code>- Your endpoint should return HTTP 2xx for successCallback delivery is best effort. Continue to treat GET /company/competitor-engagements with the returned request_id as the source of truth if your receiver is unavailable.
### Callback Payload Example

```json
{
  "request_id": "65f6d9f92799d3c2a24123f4f13a7d7a3af6ac13f1d8d0695dce03b98a4e5220",
  "status": "completed",
  "completed": true,
  "company_url": "https://www.linkedin.com/company/nyne-ai",
  "max_items": 100,
  "page_number": 1,
  "sort": "recent",
  "results_count": 1,
  "credits_charged": 5,
  "results": [
    {
      "linkedin_profile_url": "https://www.linkedin.com/in/janedoe",
      "source_profile_url": "https://www.linkedin.com/in/janedoe",
      "person": {
        "linkedin_profile_url": "https://www.linkedin.com/in/janedoe",
        "profile_url": "https://www.linkedin.com/in/janedoe",
        "name": "Jane Doe",
        "display_name": "Jane Doe"
      },
      "actor": {
        "type": "profile",
        "username": "janedoe",
        "display_name": "Jane Doe",
        "name": "Jane Doe",
        "profile_url": "https://www.linkedin.com/in/janedoe"
      },
      "interaction_id": "7453487458471567360",
      "interaction_type": "company_post",
      "interaction_url": "https://www.linkedin.com/posts/example",
      "date_posted": "2026-04-24 18:58:09",
      "posted_timestamp": 1777057089,
      "post": {
        "url": "https://www.linkedin.com/posts/example",
        "date_posted": "2026-04-24 18:58:09"
      },
      "content": { "text": "Example post text" },
      "target": {
        "type": "post",
        "url": "https://www.linkedin.com/posts/example"
      },
      "replies": [],
      "engagement": { "likes": 22, "comments": 2, "shares": 5 }
    }
  ],
  "completed_on": "2026-04-27T10:00:30"
}
```

---

## Best Practices

Prioritize inputs in this order for best match rates:
1. **Use company pages** (Best) — Use a company page URL for this endpoint. Use <code>/person/competitor-engagements</code> for person profile URLs.2. **Start with the default** (Good) — Use <code>max_items = 100</code> unless you need a smaller response.3. **Use callbacks in production** (Good) — Callbacks reduce polling for async jobs.