---
updatedAt: 2026-05-14T15:55:52.000Z
agentTools:
  projectIndex: https://docs.cardda.com/llms.txt
---

# The company-id header 🏢

Almost every endpoint in the Cardda API operates on data that belongs to a company. Cardda is multi-tenant: a single user (and a single API key) can have access to several companies, so every request that touches company-scoped data must say which company it is for. That is what the `company-id` header is for.

Think of it as the equivalent of the `Stripe-Account` header for Stripe Connect, or the workspace selector you see in any modern dashboard. It is mandatory for **159 of our 168 public endpoints**.

## What it looks like

The `company-id` header is a UUID. It must match the `id` of one of the companies your user (the owner of the API key) has access to.

```bash
curl https://api.cardda.com/v1/banking/bank_transactions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "company-id: 550e8400-e29b-41d4-a716-446655440000"
```

Both `company-id` and `company_id` are accepted, but **`company-id` (with hyphen) is canonical**. Use it everywhere.

## How to obtain a `company-id`

The only endpoint that lists the companies your user has access to is:

```
GET /v1/companies
```

This endpoint does **not** require the `company-id` header (otherwise you would have a chicken-and-egg problem). Call it once on integration startup and cache the result.

```bash
curl https://api.cardda.com/v1/companies \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Sample response (truncated):

```json
{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Acme Holdings",
      "legal_name": "Acme Holdings SpA",
      "country": "CL",
      "tax_id": "76123456-7",
      "created_at": "2024-01-15T12:00:00Z"
    },
    {
      "id": "7c1bf5d2-4e2a-4f7e-8c7d-2a3b4c5d6e7f",
      "name": "Acme Mexico",
      "legal_name": "Acme Mexico SA de CV",
      "country": "MX",
      "tax_id": "ACM240115AB1",
      "created_at": "2024-03-20T09:30:00Z"
    }
  ],
  "total": 2
}
```

## When the header is required

| Endpoint family                                                                                                                                    | `company-id` required?                           |
| -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| `GET /v1/companies`                                                                                                                                | No (this is how you discover the IDs)            |
| `POST /v1/api_keys`, `GET /v1/api_keys`                                                                                                            | No (api keys belong to the user, not a company)  |
| `GET /v1/users/{id}` (your own user)                                                                                                               | No                                               |
| `GET /v1/permissions`                                                                                                                              | No (lists permissions across all your companies) |
| `GET /v1/banking/banks` (reference data)                                                                                                           | No                                               |
| **Everything else** (banking, cards, charges, transactions, fiscal invoices, bills, payables, purchase orders, KYC, allocations, statements, etc.) | **Yes**                                          |

Each endpoint page in the API Reference declares `company-id` as a required header parameter when it applies.

## Errors

| Situation                                                      | Status             | Body                                                                 |
| -------------------------------------------------------------- | ------------------ | -------------------------------------------------------------------- |
| Header is omitted on an endpoint that requires it              | `401 Unauthorized` | *(empty body — see [Errors](errors) for why)*                        |
| Header is present but the user is not a member of that company | `404 Not Found`    | `{"error": "not_found"}` (we do not leak whether the company exists) |
| Header is malformed (not a UUID)                               | `400 Bad Request`  | `{"error": "bad_request", "message": "company-id must be a UUID"}`   |
| Header references a deleted company                            | `404 Not Found`    | `{"error": "not_found"}`                                             |

> Branch your client on the status code, not the body. The 401 case returns an empty body today; treat any `JSON.parse` attempt on it as a parse error.

## Caching pattern

For most integrations, the list of companies a user has access to changes rarely (typically only when a person is invited to a new workspace). A reasonable pattern is:

1. Call `GET /v1/companies` once on startup or on session boot.
2. Cache the result in memory (or your usual cache layer) for 1–6 hours.
3. Refresh on a 401 or 403 from a downstream endpoint.

```javascript
// Node.js example
let companiesCache = null;
let companiesCachedAt = 0;
const CACHE_TTL = 60 * 60 * 1000; // 1 hour

async function listCompanies(apiKey) {
  if (companiesCache && Date.now() - companiesCachedAt < CACHE_TTL) {
    return companiesCache;
  }
  const res = await fetch("https://api.cardda.com/v1/companies", {
    headers: { Authorization: `Bearer ${apiKey}` }
  });
  if (!res.ok) throw new Error(`Cardda /v1/companies failed: ${res.status}`);
  const json = await res.json();
  companiesCache = json.data;
  companiesCachedAt = Date.now();
  return companiesCache;
}
```

```python
# Python example
import time, requests

_cache = {"data": None, "ts": 0}
TTL = 60 * 60  # seconds

def list_companies(api_key: str):
    if _cache["data"] and time.time() - _cache["ts"] < TTL:
        return _cache["data"]
    r = requests.get(
        "https://api.cardda.com/v1/companies",
        headers={"Authorization": f"Bearer {api_key}"},
        timeout=10,
    )
    r.raise_for_status()
    _cache["data"] = r.json()["data"]
    _cache["ts"] = time.time()
    return _cache["data"]
```

## Setting it once per request: a small client wrapper

Most SDKs add the header at construction time so you do not forget it on every call:

```javascript
class CarddaClient {
  constructor({ apiKey, companyId }) {
    this.apiKey = apiKey;
    this.companyId = companyId;
  }

  async request(path, init = {}) {
    return fetch(`https://api.cardda.com${path}`, {
      ...init,
      headers: {
        ...init.headers,
        "Authorization": `Bearer ${this.apiKey}`,
        "company-id": this.companyId,
        "Content-Type": "application/json",
      },
    });
  }
}

const cardda = new CarddaClient({ apiKey: API_KEY, companyId: COMPANY_ID });
const tx = await cardda.request("/v1/banking/bank_transactions");
```

## Switching between companies

If your integration manages multiple companies (e.g. an accounting tool with one Cardda account per client), you do **not** need to re-authenticate. Just change the `company-id` header on each request:

```bash
# Request against Acme Holdings
curl ... -H "company-id: 550e8400-e29b-41d4-a716-446655440000"

# Same key, different company
curl ... -H "company-id: 7c1bf5d2-4e2a-4f7e-8c7d-2a3b4c5d6e7f"
```

The API key authenticates the user; the `company-id` header scopes the request.

## Common mistakes

* **Sending `company-id` to `GET /v1/companies`** — harmless, but pointless. The header is ignored on that endpoint.
* **Putting it in the request body** — the API only reads the header (or, deprecated, a `company_id` query param).
* **Hardcoding a UUID from another customer's tenant** — you will get a `404`. Always pull the list from `GET /v1/companies`.
* **Confusing `company-id` with the company `tax_id` (RUT)** — `company-id` is always a UUID, never a tax id.

## Related

* [Authentication & API keys](api-keys) — how to generate the key referenced above.
* [Getting Started](getting-started) — full quickstart that puts API keys + `company-id` together.
* [Errors](errors) — the full error catalog.