# Profile live

> Trigger a live fetch of a Social company profile and retrieve results via polling or webhook callback.

## Introduction

The Company Profile Live endpoint triggers a real-time fetch of a Social company profile. Instead of relying on cached data, it pulls a fresh copy and returns the result asynchronously.

Use this endpoint when you need the most up-to-date company data and can wait for the async result. Retrieve the result via [polling](https://docs.reversecontact.com/guides/polling) (recommended, no public endpoint required) or via a [webhook callback](https://docs.reversecontact.com/guides/webhooks) (advanced, push delivery).

> [!NOTE]
> **Async, not real-time.** We aim to deliver each result in under 15 seconds, but it can take tens of minutes depending on conditions. Built to update databases and feed async pipelines, not to back a synchronous request a user is waiting on. See [Polling](https://docs.reversecontact.com/guides/polling) for delivery details.

> [!IMPORTANT]
> **Not available on the free trial.** This endpoint requires an active pay-as-you-go balance or an Enterprise plan. [Add credits](https://app.reversecontact.com/settings/billing) to your workspace to unlock it, or contact sales to discuss Enterprise pricing.

## Authorization

| Name     | Type   | Required | Description                                                                                         |
| -------- | ------ | -------- | --------------------------------------------------------------------------------------------------- |
| `apikey` | string | Yes      | Your API key from the developer dashboard. Pass it via `Authorization: Bearer YOUR_API_KEY` header. |

## Request body

| Name         | Type   | Required    | Description                                                                                         |
| ------------ | ------ | ----------- | --------------------------------------------------------------------------------------------------- |
| `url`        | string | Conditional | Public Social company URL (e.g. `https://social.com/company/acme-corp`). Provide exactly one of `url` or `id`. |
| `id`         | string | Conditional | ReverseContact company id (`com_…`). The gateway resolves it to the current Social public slug before starting the scrape. |
| `webhookUrl` | string | Optional | HTTPS push URL for webhook delivery. Omit this field to retrieve the result via [polling](https://docs.reversecontact.com/guides/polling) (recommended). See the [Webhooks guide](https://docs.reversecontact.com/guides/webhooks) when you need push delivery. |

## Response structure

This endpoint replies immediately with a `webhookId`. You then have two ways to retrieve the actual result:

1. **Polling (recommended).** Call `GET /v2/webhooks/:webhookId` until the status is `succeeded`. No webhook URL needed. See the [Polling guide](https://docs.reversecontact.com/guides/polling).
2. **Webhook callback (advanced).** If you provided a `webhookUrl` (or a workspace default is configured), the gateway POSTs the company data to that URL once the fetch completes. See [Webhook callback payload (advanced)](#webhook-callback-payload-advanced) below.

| Field     | Type    | Description                                |
| --------- | ------- | ------------------------------------------ |
| `success` | boolean | `true` if the job was created successfully |

**data** (JobAck): Initial job acknowledgement. Save the `webhookId` to retrieve the result via polling (`GET /v2/webhooks/:webhookId`) or to correlate an upcoming webhook callback (`null` on error responses).

| Field       | Type   | Description                                                                                                                            |
| ----------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| `status`    | string | Job status, always `"created"` for the initial response                                                                                |
| `webhookId` | string | Unique identifier (UUID). **Save it.** Use it to poll the result at `GET /v2/webhooks/:webhookId`, or to correlate an incoming webhook callback. |
| `pollUrl`   | string | Convenience hint pointing to the polling endpoint for this job (e.g. `/v2/webhooks/{webhookId}`).                                      |

| Field   | Type   | Description              |
| ------- | ------ | ------------------------ |
| `error` | `null` | Always `null` on success |

**quotas** (V2QuotaInfo): Credits and rate limit usage after this request

| Field             | Type   | Description                      |
| ----------------- | ------ | -------------------------------- |
| `creditsConsumed` | number | Credits consumed by this request |

**workspace** (Workspace): Workspace-level limits

| Field                 | Type    | Description                                    |
| --------------------- | ------- | ---------------------------------------------- |
| `id`                  | string  | Your workspace identifier                      |
| `hasUnlimitedCredits` | boolean | Whether workspace credits are unlimited        |
| `allowDailyOvercost`  | boolean | Whether the workspace may exceed its daily cap |

**credits** (Credits): Credit balance

| Field   | Type   | Description                |
| ------- | ------ | -------------------------- |
| `total` | number | Total credits in your plan |
| `used`  | number | Credits consumed so far    |
| `left`  | number | Remaining credits          |

**dailyLimit** (DailyLimit): Daily request limit (`null` if not configured)

| Field       | Type   | Description                             |
| ----------- | ------ | --------------------------------------- |
| `limit`     | number | Maximum requests per day                |
| `used`      | number | Requests made today                     |
| `left`      | number | Remaining requests today                |
| `nextReset` | string | When the daily window resets (ISO 8601) |

**minuteRateLimit** (MinuteRateLimit): Per-minute rate limit

| Field       | Type   | Description                              |
| ----------- | ------ | ---------------------------------------- |
| `limit`     | number | Maximum requests per minute              |
| `used`      | number | Requests made in the current minute      |
| `left`      | number | Remaining requests in the current minute |
| `nextReset` | string | When the minute window resets (ISO 8601) |

**key** (ApiKey): API key-level limits (`null` when request is from dashboard)

| Field | Type   | Description        |
| ----- | ------ | ------------------ |
| `id`  | string | API key identifier |

**dailyLimit** (KeyDailyLimit): Daily limit for this key (`null` if not configured)

| Field       | Type   | Description                             |
| ----------- | ------ | --------------------------------------- |
| `limit`     | number | Maximum requests per day                |
| `used`      | number | Requests made today                     |
| `left`      | number | Remaining requests today                |
| `nextReset` | string | When the daily window resets (ISO 8601) |

**minuteRateLimit** (KeyMinuteRateLimit): Minute rate limit for this key

| Field       | Type   | Description                              |
| ----------- | ------ | ---------------------------------------- |
| `limit`     | number | Maximum requests per minute              |
| `used`      | number | Requests made in the current minute      |
| `left`      | number | Remaining requests in the current minute |
| `nextReset` | string | When the minute window resets (ISO 8601) |

**metadata** (V2ResponseMetadata): Request tracking information

| Field             | Type   | Description                          |
| ----------------- | ------ | ------------------------------------ |
| `requestId`       | string | Unique identifier for this request   |
| `executionTimeMs` | number | Total execution time in milliseconds |

## Webhook callback payload (advanced)

Once the live fetch completes, the gateway POSTs a JSON payload to your `webhookUrl`. Use the `webhookId` from the initial response to correlate the callback with your original request.

The payload is **not wrapped** in an envelope (no `success`, `error`, `metadata`, or `quotas` keys at the top level, unlike the synchronous response).

| Field       | Type   | Description                                                                                                                         |
| ----------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------- |
| `webhookId` | string | Always present. The same identifier returned in the initial response. Use it to correlate the callback with the original request. |

**data** (Company): Always present. On success: the enriched company profile (fields below). On failure: see [Webhook callback errors (advanced)](#webhook-callback-errors-advanced).

| Field                | Type                       | Description                                                |
| -------------------- | -------------------------- | ---------------------------------------------------------- |
| `id`                 | string                     | ReverseContact company id (`com_...`). Use it as the `id` parameter of the [Company Profile endpoint](https://docs.reversecontact.com/endpoints/fetch-company) to re-fetch this company |
| `companyName`        | string                     | Company name                                               |
| `linkedinId`         | string                     | Social company identifier                                  |
| `publicId`           | string                     | Universal name / slug (the `/company/xxx` part of the URL) |
| `linkedinUrl`        | string \| null             | Full Social company URL                                    |
| `websiteUrl`         | string \| null             | Official company website URL                               |
| `industry`           | string \| null             | Industry (e.g. `"Software Development"`)                   |
| `description`        | string \| null             | Full company description                                   |
| `tagline`            | string \| null             | Tagline / slogan                                           |
| `logoUrl`            | string \| null             | Logo image URL                                             |
| `backgroundUrl`      | string \| null             | Background / banner image URL                              |
| `employeesCount`     | number \| null             | Exact number of employees                                  |
| `employeeCountRange` | EmployeeCountRange \| null | Employee count range bracket                               |
| `followersCount`     | number \| null             | Number of Social followers                                 |
| `specialities`       | string[]                   | List of company specialties. Empty array if none           |
| `foundedOn`          | FoundedOn \| null          | Founding year wrapper                                      |
| `phone`              | string \| null             | Phone number                                               |

**headquarter** (Headquarter): Primary headquarter location (`null` if unknown)

| Field            | Type           | Description                                     |
| ---------------- | -------------- | ----------------------------------------------- |
| `street1`        | string \| null | Street address line 1                           |
| `street2`        | string \| null | Street address line 2                           |
| `postalCode`     | string \| null | Postal / ZIP code                               |
| `city`           | string \| null | City                                            |
| `geographicArea` | string \| null | State or region                                 |
| `country`        | string \| null | Country ISO 3166 code (e.g. `"US"`, `"FR"`)     |

**locations** (Location[]): All office locations registered on the profile (can be empty)

| Field        | Type           | Description                                     |
| ------------ | -------------- | ----------------------------------------------- |
| `street1`    | string \| null | Street address line 1                           |
| `street2`    | string \| null | Street address line 2                           |
| `postalCode` | string \| null | Postal / ZIP code                               |
| `city`       | string \| null | City                                            |
| `state`      | string \| null | State or region (named `state` here, not `geographicArea` as in `headquarter`) |
| `country`    | string \| null | Country ISO 3166 code (e.g. `"US"`, `"FR"`)     |

**employeeCountRange** (EmployeeCountRange): Employee count bracket (`null` if unknown). Buckets mirror LinkedIn's native `staffCountRange`: `1`, `2–10`, `11–50`, `51–200`, `201–500`, `501–1,000`, `1,001–5,000`, `5,001–10,000`, `10,001+`. For the top bucket (`10,001+`), LinkedIn has no upper bound and returns `end: 1` as a sentinel: interpret any range where `end < start` as `start+` (unbounded). Use `employeeCount` for the exact headcount when available.

| Field   | Type   | Description                                                                              |
| ------- | ------ | ---------------------------------------------------------------------------------------- |
| `start` | number | Lower bound of the range                                                                 |
| `end`   | number | Upper bound of the range. If `end < start`, the bucket is unbounded (`start+`, i.e. `10,001+`) |

> **Example (10,001+ bucket):** `{ "start": 10001, "end": 1 }`. Since `end` (1) < `start` (10001), this means the company has 10,001 or more employees. No upper bound is available for this bucket.

**foundedOn** (FoundedOn): Founding year (`null` if unknown)

| Field  | Type   | Description     |
| ------ | ------ | --------------- |
| `year` | number | Four-digit year |

## Webhook callback errors (advanced)

When the live fetch fails, `data` does **not** contain the company fields. Instead, it contains the original input echoed back together with an `errorCode` identifying the failure reason:

**Error payload**

```json [Webhook callback (error)]
{
  "webhookId": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
  "data": {
    "url": "https://www.social.com/company/acme-corp",
    "errorCode": "company-not-found"
  }
}
```

`data.errorCode` will be one of the following values:

| Code                | Billed | Description                                                         |
| ------------------- | ------ | ------------------------------------------------------------------- |
| `company-not-found` | Yes    | The company profile doesn't exist or could not be scraped           |
| `invalid-data`      | No     | The fetched data failed quality validation                          |
| `fetch-data-error`  | No     | The API failed while fetching data. Safe to retry                   |
| `result-unavailable` | No    | The enrichment completed but the result was lost on our side. Retry the job. If the request was charged, contact support to get the credit back. |

> [!NOTE]
> **Billed** means the credits consumed at request time are kept. **Not billed** means the credits are fully refunded to your workspace balance.

## Code examples

**Code Examples**

```javascript [JavaScript - Polling (recommended)]
const KEY = "YOUR_API_KEY";
const BASE = "https://api.reversecontact.com";

const trigger = await fetch("https://api.reversecontact.com/v2/fetch/companies/live", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    url: "https://social.com/company/acme-corp"
  })
});
const { data: { webhookId } } = await trigger.json();

async function pollUntilDone(id) {
  while (true) {
    const res = await fetch(`${BASE}/v2/webhooks/${id}`, {
      headers: { "Authorization": `Bearer ${KEY}` }
    });
    const { data } = await res.json();
    if (data.status === "succeeded") return data.result;
    if (data.status === "errored")  throw new Error(data.errorCode ?? "Job failed");
    await new Promise(r => setTimeout(r, 2000));
  }
}

const result = await pollUntilDone(webhookId);
console.log(result);
```
```javascript [JavaScript - Webhook]
const response = await fetch("https://api.reversecontact.com/v2/fetch/companies/live", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    url: "https://social.com/company/acme-corp",
    webhookUrl: "https://your-app.com/webhooks/reversecontact"
  })
});

const result = await response.json();
console.log(result.data.status, result.data.webhookId);
```
```bash [cURL - Polling (recommended)]
KEY="YOUR_API_KEY"
ID=$(curl -sX POST https://api.reversecontact.com/v2/fetch/companies/live \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"url":"https://social.com/company/acme-corp"}' | jq -r .data.webhookId)

while :; do
  S=$(curl -s https://api.reversecontact.com/v2/webhooks/$ID \
    -H "Authorization: Bearer $KEY" | jq -r .data.status)
  [ "$S" = "succeeded" ] && break
  [ "$S" = "errored" ] && echo "job failed" && exit 1
  sleep 2
done

curl -s https://api.reversecontact.com/v2/webhooks/$ID \
  -H "Authorization: Bearer $KEY" | jq .data.result
```
```bash [cURL - Webhook]
curl -X POST https://api.reversecontact.com/v2/fetch/companies/live \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://social.com/company/acme-corp",
    "webhookUrl": "https://your-app.com/webhooks/reversecontact"
  }'
```
```python [Python - Polling (recommended)]
import time
import requests

KEY = "YOUR_API_KEY"
BASE = "https://api.reversecontact.com"

trigger = requests.post(
    "https://api.reversecontact.com/v2/fetch/companies/live",
    headers={
        "Authorization": f"Bearer {KEY}",
        "Content-Type": "application/json"
    },
    json={
        "url": "https://social.com/company/acme-corp"
    }
)
webhook_id = trigger.json()["data"]["webhookId"]

def poll_until_done(wid):
    while True:
        res = requests.get(
            f"{BASE}/v2/webhooks/{wid}",
            headers={"Authorization": f"Bearer {KEY}"}
        )
        data = res.json()["data"]
        if data["status"] == "succeeded":
            return data["result"]
        if data["status"] == "errored":
            raise RuntimeError(data.get("errorCode") or "Job failed")
        time.sleep(2)

result = poll_until_done(webhook_id)
print(result)
```
```python [Python - Webhook]
import requests

response = requests.post(
    "https://api.reversecontact.com/v2/fetch/companies/live",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json"
    },
    json={
        "url": "https://social.com/company/acme-corp",
        "webhookUrl": "https://your-app.com/webhooks/reversecontact"
    }
)

result = response.json()
print(result["data"]["status"], result["data"]["webhookId"])
```

## Example response

**Example Response**

```json [Initial response]
{
  "success": true,
  "data": {
    "status": "created",
    "webhookId": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
    "pollUrl": "/v2/webhooks/b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e"
  },
  "error": null,
  "metadata": {
    "requestId": "req_d4e5f6a7b8c9",
    "executionTimeMs": 95
  },
  "quotas": {
    "creditsConsumed": 2,
    "workspace": {
      "id": "ws_abc123",
      "credits": {
        "total": 10000,
        "used": 4524,
        "left": 5476
      },
      "dailyLimit": null,
      "minuteRateLimit": {
        "limit": 60,
        "used": 5,
        "left": 55,
        "nextReset": "2025-01-20T14:16:00.000Z"
      },
      "hasUnlimitedCredits": false,
      "allowDailyOvercost": false
    },
    "key": {
      "id": "key_abc123",
      "dailyLimit": null,
      "minuteRateLimit": {
        "limit": 60,
        "used": 5,
        "left": 55,
        "nextReset": "2025-01-20T14:16:00.000Z"
      }
    }
  }
}
```
```json [Webhook callback (success)]
{
  "webhookId": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
  "data": {
    "id": "com_01jbd5vewyenebxgaz869ffe5t",
    "companyName": "Acme Corp",
    "linkedinId": "12345678",
    "publicId": "acme-corp",
    "linkedinUrl": "https://www.social.com/company/acme-corp",
    "employeesCount": 452,
    "followersCount": 28512,
    "employeeCountRange": {
      "start": 201,
      "end": 500
    },
    "websiteUrl": "https://www.acmecorp.com",
    "tagline": "Building the future of work",
    "description": "Acme Corp is a leading provider of innovative SaaS solutions for enterprise teams. Founded in 2015, we serve over 10,000 customers worldwide with a focus on data-driven productivity tools.",
    "industry": "Software Development",
    "phone": "+1 (415) 555-0123",
    "specialities": [
      "SaaS",
      "Enterprise Software",
      "Cloud Computing",
      "Data Analytics",
      "API Integration",
      "Workflow Automation",
      "Team Collaboration"
    ],
    "headquarter": {
      "street1": "600 Market Street",
      "street2": "Floor 12",
      "postalCode": "94105",
      "city": "San Francisco",
      "geographicArea": "California",
      "country": "US"
    },
    "logoUrl": "https://media.licdn.com/dms/image/v2/C4D0BAQ.../company-logo_400_400/logo.jpg",
    "foundedOn": {
      "year": 2015
    },
    "locations": [
      {
        "street1": "600 Market Street",
        "street2": "Floor 12",
        "postalCode": "94105",
        "city": "San Francisco",
        "state": "California",
        "country": "US"
      },
      {
        "street1": "10 rue de la Paix",
        "street2": null,
        "postalCode": "75002",
        "city": "Paris",
        "state": null,
        "country": "FR"
      },
      {
        "street1": "45 King William Street",
        "street2": "3rd Floor",
        "postalCode": "EC4N 7DG",
        "city": "London",
        "state": null,
        "country": "GB"
      }
    ],
    "backgroundUrl": "https://media.licdn.com/dms/image/v2/D5616AQ.../company-background/banner.jpg"
  }
}
```
```json [Webhook callback (error)]
{
  "webhookId": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
  "data": {
    "url": "https://www.social.com/company/acme-corp",
    "errorCode": "company-not-found"
  }
}
```
