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

# Get Companies (Batch)

> Fetch up to 50 companies in one call, billed only for the companies found

## Endpoint

```
POST /api/v1/company/batch
```

[Get Company](/api-reference/endpoint/get-company), once per entry, in a single
request: send up to 50 companies and get the same company object back for each
one that was found, with a per-entry error for the others.

<Note>
  The request is a JSON **body**, not query parameters, and the response is
  `200` even when some entries — or all of them — could not be fetched. Read
  `found`, or each entry's `error`, rather than the HTTP status.
</Note>

## Authentication

Include your API key in the request header:

```bash theme={null}
X-API-Key: your-api-key-here
```

## Billing

<Warning>
  **1 credit per company returned.**

  * An entry that is not found, fails, or cannot be used costs nothing: only
    entries that come back with a `company` are billed. A batch that finds
    nothing costs 0.
  * The balance is checked for the **whole batch before any work**: a batch of
    N distinct entries needs N credits available, otherwise it is refused with
    `402` `QUOTA_EXHAUSTED` and nothing is fetched.
  * Validation errors (`400`) are free.
  * Duplicates are fetched and billed once — see `companies` below.
</Warning>

## Rate limit

A batch uses your plan's per-second rate limit, not a separate allowance. The
request itself takes one unit like any call, and **each company after the first
consumes one more unit** from the same budget, waiting for it when the window is
full. A 50-company batch on a 5 req/s plan therefore takes about **10 seconds** —
the same as 50 separate calls — and any other traffic you send at the same time
draws on the same budget.

Entries that could not be fetched within **90 seconds** come back with an error
`RATE_LIMITED` (`status: 429`) and are not billed. Send those again, in a smaller
batch. Plan a client timeout of at least 120 seconds.

See [Rate Limits](/concepts/rate-limits).

## Request body

<ParamField body="companies" type="string[]" required>
  1 to 50 companies. Each entry is any input
  [Get Company](/api-reference/endpoint/get-company) accepts:

  * **Company page URL**. Example: `https://www.linkedin.com/company/microsoft`
  * **Public identifier** (universal name). Example: `microsoft`
  * **Company URN**. Example: `urn:li:fsd_company:1035`

  Duplicates (the same text, case-insensitive) are fetched, billed and returned
  **once**, at their first position.

  Validation, all `400 INVALID_PARAMETER` and free:

  * missing, empty or not an array — `'companies' must be an array of 1 to 50 company URLs, public identifiers or URNs.`
  * more than 50 entries — `'companies' accepts at most 50 entries (received 51).`
  * an entry that is not a non-empty string — `'companies[3]' must be a non-empty string.`
</ParamField>

## Response

<ResponseField name="results" type="array">
  One entry per distinct input, **in input order**. Each entry has `input` and
  exactly one of `company` or `error`.

  <Expandable title="Result entry">
    <ResponseField name="input" type="string">
      The entry as you sent it (trimmed).
    </ResponseField>

    <ResponseField name="company" type="object">
      Present when the company was found: the **same object as
      [Get Company](/api-reference/endpoint/get-company)** returns (`id`,
      `companyId`, `name`, `publicIdentifier`, `url`, `industry`,
      `employeeCount`, …). Billed 1 credit.
    </ResponseField>

    <ResponseField name="error" type="object">
      Present when the company was not returned. Not billed.

      <Expandable title="Error object">
        <ResponseField name="code" type="string">
          The same codes as a single call — `COMPANY_NOT_FOUND` when the company
          does not exist, `RATE_LIMITED` when the batch ran out of time waiting
          for your rate limit, `INVALID_PARAMETER` / `INVALID_URN` for an entry
          that is not a usable company input, `SERVICE_UNAVAILABLE` or
          `INTERNAL_ERROR` on our side.
        </ResponseField>

        <ResponseField name="message" type="string">
          Human-readable description. Do not branch on it.
        </ResponseField>

        <ResponseField name="status" type="integer">
          The HTTP status a single [Get Company](/api-reference/endpoint/get-company)
          call would have returned for this entry: `404`, `429`, `400`, `503`, …
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="found" type="integer">
  Entries returned with a `company` — the number of credits billed.
</ResponseField>

<ResponseField name="notFound" type="integer">
  Entries whose error has `status: 404`.
</ResponseField>

<ResponseField name="failed" type="integer">
  Every other error (rate limit, invalid entry, failure on our side). Worth
  retrying, except an invalid entry.
</ResponseField>

## Example Request

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.fetchin.io/api/v1/company/batch" \
    -H "X-API-Key: your-api-key-here" \
    -H "Content-Type: application/json" \
    -d '{
      "companies": [
        "https://www.linkedin.com/company/doctolib",
        "microsoft",
        "urn:li:fsd_company:1441",
        "this-company-does-not-exist-123"
      ]
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.fetchin.io/api/v1/company/batch', {
    method: 'POST',
    headers: {
      'X-API-Key': 'your-api-key-here',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      companies: [
        'https://www.linkedin.com/company/doctolib',
        'microsoft',
        'urn:li:fsd_company:1441',
        'this-company-does-not-exist-123',
      ],
    }),
  });

  const batch = await response.json();
  for (const entry of batch.results) {
    if (entry.company) console.log(entry.input, entry.company.name);
    else console.log(entry.input, entry.error.code);
  }
  ```

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

  response = requests.post(
      'https://api.fetchin.io/api/v1/company/batch',
      headers={'X-API-Key': 'your-api-key-here'},
      json={
          'companies': [
              'https://www.linkedin.com/company/doctolib',
              'microsoft',
              'urn:li:fsd_company:1441',
              'this-company-does-not-exist-123',
          ],
      },
      timeout=120,
  )

  batch = response.json()
  for entry in batch['results']:
      if 'company' in entry:
          print(entry['input'], entry['company']['name'])
      else:
          print(entry['input'], entry['error']['code'])
  ```

  ```php PHP theme={null}
  <?php

  $ch = curl_init('https://api.fetchin.io/api/v1/company/batch');
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_TIMEOUT, 120);
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
      'X-API-Key: your-api-key-here',
      'Content-Type: application/json',
  ]);
  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
      'companies' => [
          'https://www.linkedin.com/company/doctolib',
          'microsoft',
          'urn:li:fsd_company:1441',
          'this-company-does-not-exist-123',
      ],
  ]));

  $batch = json_decode(curl_exec($ch), true);
  curl_close($ch);
  print_r($batch);
  ?>
  ```
</CodeGroup>

## Example Response

<ResponseExample>
  ```json 200 Success theme={null}
  {
    "results": [
      {
        "input": "https://www.linkedin.com/company/doctolib",
        "company": {
          "id": "urn:li:fsd_company:4999584",
          "companyId": "4999584",
          "name": "Doctolib",
          "publicIdentifier": "doctolib",
          "url": "https://www.linkedin.com/company/doctolib/",
          "websiteUrl": "https://careers.doctolib.com/",
          "domain": "careers.doctolib.com",
          "industry": "Software Development",
          "employeeCount": 3714,
          "employeeCountRange": { "start": 1001, "end": 5000 },
          "followerCount": 323490,
          "logoUrl": "https://media.licdn.com/dms/image/...",
          "companyType": "Privately Held",
          "companyTypeCode": "PRIVATELY_HELD"
        }
      },
      {
        "input": "microsoft",
        "company": {
          "id": "urn:li:fsd_company:1035",
          "companyId": "1035",
          "name": "Microsoft",
          "publicIdentifier": "microsoft",
          "url": "https://www.linkedin.com/company/microsoft/",
          "industry": "Software Development",
          "followerCount": 29282565,
          "logoUrl": "https://media.licdn.com/dms/image/...",
          "companyType": "Public Company",
          "companyTypeCode": "PUBLIC_COMPANY",
          "hashtags": ["microsoftlife", "microsoft"]
        }
      },
      {
        "input": "urn:li:fsd_company:1441",
        "error": {
          "code": "RATE_LIMITED",
          "message": "Not fetched: the batch ran out of time waiting for your rate limit. Send it again in a smaller batch.",
          "status": 429
        }
      },
      {
        "input": "this-company-does-not-exist-123",
        "error": {
          "code": "COMPANY_NOT_FOUND",
          "message": "Unable to find company data from slug",
          "status": 404
        }
      }
    ],
    "found": 2,
    "notFound": 1,
    "failed": 1
  }
  ```

  ```json 400 Bad Request theme={null}
  {
    "error": "'companies' accepts at most 50 entries (received 51).",
    "code": "INVALID_PARAMETER"
  }
  ```

  ```json 401 Unauthorized theme={null}
  {
    "error": "Invalid API key",
    "code": "INVALID_API_KEY"
  }
  ```

  ```json 402 Payment Required theme={null}
  {
    "error": "Quota exceeded. Upgrade your plan or wait for renewal.",
    "code": "QUOTA_EXHAUSTED",
    "details": {
      "creditsRemaining": 12,
      "subscriptionCreditsRemaining": 12,
      "paygCreditsRemaining": 0,
      "buyCreditsUrl": "https://fetchin.io/credits"
    }
  }
  ```

  ```json 429 Too Many Requests theme={null}
  {
    "error": "Rate limit exceeded. Try again later.",
    "code": "RATE_LIMITED"
  }
  ```
</ResponseExample>

## Errors

See [Error Handling](/concepts/error-handling) for the shared envelope. These
are errors of the **whole request**; an entry that fails is reported in its own
`error` inside a `200`.

| HTTP | `code` | When | Credits |
| - | - | - | - |
| `400` | `INVALID_PARAMETER` | `companies` missing, empty, longer than 50, or holding an entry that is not a non-empty string; malformed JSON | 0 |
| `401` | `UNAUTHENTICATED` / `INVALID_API_KEY` | Missing or invalid `X-API-Key` | 0 |
| `402` | `QUOTA_EXHAUSTED` | Your balance is smaller than the number of distinct entries | 0 |
| `429` | `RATE_LIMITED` | Your per-second budget was already spent when the request arrived | 0 |
| `500` | `INTERNAL_ERROR` | An unexpected bug on our side | 0 |

## Notes

<Info>
  A `404` costs 1 credit on [Get Company](/api-reference/endpoint/get-company),
  but a not-found entry in a batch costs nothing.
</Info>

<Tip>
  Retry only what failed: collect the `input` of every entry whose `error.status`
  is `429` or `5xx` and send them again. A `404` will not change on a retry, a
  `400` entry needs fixing first, and entries returned with a `company` are
  already billed.
</Tip>


## OpenAPI

````yaml POST /api/v1/company/batch
openapi: 3.1.0
info:
  title: Fetchin API
  version: 1.0.0
  description: Public B2B data API for fetching posts and profile information
servers:
  - url: https://api.fetchin.io
    description: Production server
security:
  - ApiKeyAuth: []
paths:
  /api/v1/company/batch:
    post:
      summary: Get companies in batch
      description: >-
        Fetch up to 50 companies in one call: `GET /api/v1/company` once per
        entry, with the same company object for each one found and a per-entry
        error for the others, in input order. The response is 200 even when some
        or all entries failed - read `found` or each entry's `error`. Billing: 1
        credit per company returned; not-found and failed entries are free. The
        balance is checked for the whole batch (one credit per distinct entry)
        before any work, otherwise 402 QUOTA_EXHAUSTED. Validation errors are
        400 and free. Rate limit: the batch uses your plan's per-second limit -
        the request takes one unit and each company after the first consumes one
        more from the same budget, waiting for it when the window is full, so a
        50-company batch on a 5 req/s plan takes about 10 seconds. Entries that
        could not be fetched within 90 seconds come back with an error
        `RATE_LIMITED` (status 429) and are not billed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - companies
              properties:
                companies:
                  type: array
                  minItems: 1
                  maxItems: 50
                  description: >-
                    1 to 50 companies, each a company page URL, a public
                    identifier (universal name, e.g. `microsoft`) or a URN
                    (`urn:li:fsd_company:1035`). Duplicates (same text,
                    case-insensitive) are fetched, billed and returned once.
                    Refused with a free 400: not an array or empty (`'companies'
                    must be an array of 1 to 50 company URLs, public identifiers
                    or URNs.`), more than 50 entries (`'companies' accepts at
                    most 50 entries (received N).`), an entry that is not a
                    non-empty string (`'companies[i]' must be a non-empty
                    string.`).
                  items:
                    type: string
                  example:
                    - https://www.linkedin.com/company/doctolib
                    - microsoft
                    - urn:li:fsd_company:1441
      responses:
        '200':
          description: >-
            One result per distinct input, in input order. Billed 1 credit per
            entry returned with a `company`.
          content:
            application/json:
              schema:
                type: object
                required:
                  - results
                  - found
                  - notFound
                  - failed
                properties:
                  results:
                    type: array
                    items:
                      type: object
                      required:
                        - input
                      description: Exactly one of `company` or `error` is present.
                      properties:
                        input:
                          type: string
                          description: The entry as sent (trimmed).
                        company:
                          type: object
                          description: >-
                            The same object as GET /api/v1/company returns.
                            Billed 1 credit.
                          properties:
                            id:
                              type: string
                              description: Company URN (unique identifier)
                              example: urn:li:fsd_company:4999584
                            companyId:
                              type: string
                              description: Numeric company id as a string
                              example: '4999584'
                            name:
                              type: string
                              example: Doctolib
                            publicIdentifier:
                              type: string
                              description: Public identifier (slug)
                              example: doctolib
                            url:
                              type: string
                              description: Canonical company page URL
                              example: https://www.linkedin.com/company/doctolib/
                            websiteUrl:
                              type: string
                              description: The company's own website
                            domain:
                              type: string
                              description: Website domain, minus a leading www.
                              example: doctolib.com
                            industry:
                              type: string
                              description: >-
                                Primary industry in the current taxonomy,
                                matching the label shown on the company's public
                                page
                              example: Software Development
                            industryV1:
                              type: string
                              description: >-
                                The same company's industry in the legacy
                                taxonomy, for integrations that pinned the older
                                labels. Not a renaming of `industry`: a company
                                can sit under two unrelated entries in the two
                                taxonomies, so this must not be used as a
                                translation table. Prefer `industry`.
                              example: Computer Software
                            employeeCount:
                              type: number
                              description: Number of employees on the platform
                            employeeCountRange:
                              type: object
                              properties:
                                start:
                                  type: number
                                end:
                                  type: number
                                  description: Absent for open-ended brackets
                            foundedOn:
                              type: object
                              properties:
                                year:
                                  type: number
                                month:
                                  type: number
                                day:
                                  type: number
                            headquarter:
                              type: object
                              properties:
                                line1:
                                  type: string
                                line2:
                                  type: string
                                city:
                                  type: string
                                  example: Levallois-Perret
                                geographicArea:
                                  type: string
                                  description: State / region
                                  example: Île-de-France
                                postalCode:
                                  type: string
                                country:
                                  type: string
                                  description: ISO country code
                                  example: FR
                                description:
                                  type: string
                                  description: Office label, e.g. "Headquarters"
                                headquarter:
                                  type: boolean
                                  description: true for the headquarters entry
                            locations:
                              type: array
                              items:
                                type: object
                                properties:
                                  line1:
                                    type: string
                                  line2:
                                    type: string
                                  city:
                                    type: string
                                    example: Levallois-Perret
                                  geographicArea:
                                    type: string
                                    description: State / region
                                    example: Île-de-France
                                  postalCode:
                                    type: string
                                  country:
                                    type: string
                                    description: ISO country code
                                    example: FR
                                  description:
                                    type: string
                                    description: Office label, e.g. "Headquarters"
                                  headquarter:
                                    type: boolean
                                    description: true for the headquarters entry
                            followerCount:
                              type: number
                            logoUrl:
                              type: string
                            coverImageUrl:
                              type: string
                              description: Cover/background image URL
                            description:
                              type: string
                            specialities:
                              type: array
                              items:
                                type: string
                            phone:
                              type: string
                            tagline:
                              type: string
                            companyType:
                              type: string
                              description: >-
                                The company's legal type as an English label,
                                e.g. "Public Company", "Privately Held",
                                "Self-Employed", "Sole Proprietorship",
                                "Partnership", "Government Agency", "Nonprofit",
                                "Educational".
                              example: Privately Held
                            companyTypeCode:
                              type: string
                              description: >-
                                The same type as a stable code, e.g.
                                "PUBLIC_COMPANY", "PRIVATELY_HELD". Branch on
                                this rather than on the label.
                              example: PRIVATELY_HELD
                            hashtags:
                              type: array
                              description: >-
                                Hashtags the page lists on its profile, in its
                                order, without the `#`.
                              items:
                                type: string
                              example:
                                - microsoftlife
                                - microsoft
                        error:
                          type: object
                          description: Why this entry was not returned. Not billed.
                          required:
                            - code
                            - message
                            - status
                          properties:
                            code:
                              type: string
                              description: >-
                                Same codes as a single call:
                                `COMPANY_NOT_FOUND`, `RATE_LIMITED` (the batch
                                ran out of time waiting for your rate limit),
                                `INVALID_PARAMETER` / `INVALID_URN` (not a
                                usable company input), `SERVICE_UNAVAILABLE`,
                                `INTERNAL_ERROR`.
                              example: COMPANY_NOT_FOUND
                            message:
                              type: string
                              description: Human-readable description. Do not branch on it.
                            status:
                              type: integer
                              description: >-
                                The HTTP status a single GET /api/v1/company
                                call would have returned for this entry.
                              example: 404
                  found:
                    type: integer
                    description: Entries returned with a `company` - the credits billed.
                  notFound:
                    type: integer
                    description: Entries whose error has status 404.
                  failed:
                    type: integer
                    description: >-
                      Every other error: rate limit, invalid entry, failure on
                      our side.
              example:
                results:
                  - input: https://www.linkedin.com/company/doctolib
                    company:
                      id: urn:li:fsd_company:4999584
                      companyId: '4999584'
                      name: Doctolib
                      publicIdentifier: doctolib
                      url: https://www.linkedin.com/company/doctolib/
                      industry: Software Development
                      employeeCount: 3714
                      followerCount: 323490
                      companyType: Privately Held
                      companyTypeCode: PRIVATELY_HELD
                  - input: this-company-does-not-exist-123
                    error:
                      code: COMPANY_NOT_FOUND
                      message: Unable to find company data from slug
                      status: 404
                found: 1
                notFound: 1
                failed: 0
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  responses:
    BadRequest:
      description: Bad request - a required parameter is missing or a value is invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            missingParameter:
              value:
                error: Missing profileUrlOrUrn parameter
                code: MISSING_PARAMETER
            invalidParameter:
              value:
                error: limit must be a number between 1 and 100
                code: INVALID_PARAMETER
            invalidUrn:
              value:
                error: 'Invalid URN format: urn:li:member:123456789'
                code: INVALID_URN
    Unauthorized:
      description: Unauthorized - the X-API-Key header is missing or invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            missingApiKey:
              value:
                error: Missing API key. Include X-API-Key header.
                code: UNAUTHENTICATED
            invalidApiKey:
              value:
                error: Invalid API key
                code: INVALID_API_KEY
    PaymentRequired:
      description: >-
        Payment required - you are out of credits (QUOTA_EXHAUSTED): the plan
        allowance for the current period is spent AND no pay-as-you-go credits
        are left. Buy pay-as-you-go credits (self-serve,
        https://fetchin.io/credits), upgrade your plan, or wait for renewal;
        retrying will not help and no Retry-After is sent. Distinct from the
        per-second rate limit, which is a 429 (RATE_LIMITED).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            quotaExhausted:
              value:
                error: Quota exceeded. Upgrade your plan or wait for renewal.
                code: QUOTA_EXHAUSTED
                details:
                  creditsRemaining: 0
                  subscriptionCreditsRemaining: 0
                  paygCreditsRemaining: 0
                  buyCreditsUrl: https://fetchin.io/credits
    TooManyRequests:
      description: >-
        Too many requests - your per-second rate limit (RATE_LIMITED) was
        exceeded. Back off and retry, honoring the Retry-After header. (Running
        out of credits is a separate 402 PaymentRequired / QUOTA_EXHAUSTED, and
        buying credits never raises this per-second limit.)
      headers:
        Retry-After:
          description: Number of seconds to wait before retrying the request.
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            rateLimited:
              value:
                error: Rate limit exceeded. Try again later.
                code: RATE_LIMITED
    InternalError:
      description: >-
        Internal server error - an unexpected error occurred in our API. Safe to
        retry; contact support if it persists.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            internalError:
              value:
                error: Internal server error
                code: INTERNAL_ERROR
  schemas:
    Error:
      type: object
      required:
        - error
        - code
      properties:
        error:
          type: string
          description: >-
            Human-readable description of what went wrong. For display/logging;
            do not branch on this string.
        code:
          type: string
          enum:
            - MISSING_PARAMETER
            - INVALID_PARAMETER
            - INVALID_URN
            - UNAUTHENTICATED
            - INVALID_API_KEY
            - FORBIDDEN
            - NOT_FOUND
            - PROFILE_NOT_FOUND
            - POST_NOT_FOUND
            - COMPANY_NOT_FOUND
            - ENDPOINT_REMOVED
            - RATE_LIMITED
            - QUOTA_EXHAUSTED
            - INTERNAL_ERROR
            - UPSTREAM_ERROR
            - SERVICE_UNAVAILABLE
            - UPSTREAM_TIMEOUT
          description: >-
            Stable, machine-readable error code. Branch your integration on this
            value, not on the HTTP status alone or the message text.
        details:
          type: object
          additionalProperties: true
          description: >-
            Optional structured context. On QUOTA_EXHAUSTED it carries the
            balance breakdown at the moment of the rejection - creditsRemaining,
            subscriptionCreditsRemaining, paygCreditsRemaining - plus
            buyCreditsUrl, the self-serve page for buying more credits. Always
            additive and never guaranteed: read it for diagnostics and logs, but
            branch on `code` and do not require any field of it.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.