---
title: "List the custom fields of a company"
method: GET
path: "/v1/companies/{company_id}/custom-fields"
tags: ["CompanyCustomFields"]
---

# List the custom fields of a company

`GET /v1/companies/{company_id}/custom-fields`

## Request

- Base URL: `https://app.beel.es/api`
- URL: `https://app.beel.es/api/v1/companies/{company_id}/custom-fields`
- Auth: HTTP bearer

Returns the invoice custom fields of this company, each one with the options that apply
to the query, ordered by `key`. A field with `suggest_values: false` carries no options.

- **Options per customer:** with `customer_id`, each field carries the common options and
  those of that customer, which is what an invoice for that customer can offer. Without
  it, only the common options. To page through every option of a field, use
  `GET /v1/companies/{company_id}/custom-fields/{key}/options`.
- **Archived:** archived fields and options are left out unless `include_archived=true`.

**Closed catalogue.** A company defines a small set of fields: this collection carries no
`pagination`, takes no `page`/`limit`, and every response holds the whole set.

## Query parameters

- `customer_id` string, uuid
- `include_archived` boolean

## Response `200`

Custom fields of the company.

- CustomFieldListResponse: The envelope every successful JSON response of the BeeL. API is wrapped in. There are no bare resources in v1 and none are planned: the payload always hangs off `data`. - A **single resource** is an object in `data`. - A **collection** hangs off a named key inside `data`, together with its `pagination`, also inside `data` — `data: {invoices: [...], pagination: {...}}`. - A collection carries `pagination` unless its operation declares itself a **closed catalogue**: a fixed, bounded list with nothing to page through. The declaration is explicit in the operation; a missing `pagination` is never something to infer. - `GET /v1/accounts` pages by cursor (`data: {accounts: [...], next_cursor}`). It is a documented variant of pagination, not another envelope. Putting the array straight into `data` with `pagination` as its sibling is the shape a v2 would adopt; v1 is not being flipped to it.
  - `success` boolean, required
  - `data` object, required: The payload. An object for a single resource; an object holding the named collection (and its `pagination`) for a listing. Never a bare array at this level in v1.
    - `custom_fields` CustomField[], required
      - `id` string, uuid, required: Unique identifier of the custom field.
      - `key` string, required: Identifier of the custom field within the company, chosen when the field is created: lowercase letters, digits and `_`, up to 64 characters. It never changes. BeeL. gives it no meaning of its own.
      - `label` string, required: Name people see next to the value, on screen and, if `show_on_pdf`, on the PDF.
      - `show_on_pdf` boolean, required: Whether the PDF of the invoice prints this field, in a block of its own under the notes. It applies to invoices saved from then on: an invoice keeps the setting it was saved with.
      - `suggest_values` boolean, required: Whether the field offers the values already used as options. With `true`, saving an invoice reuses an equivalent option or adds the value as a new one. With `false`, for a value that changes on every invoice such as an order number, the invoice stores the text as sent (without leading and trailing spaces), no option is created, and `options` comes back empty. Turning it off deletes no option: the existing ones are kept, can still be listed and managed under `GET /v1/companies/{company_id}/custom-fields/{key}/options`, and are offered again when it is turned back on.
      - `is_archived` boolean, required: An archived field cannot be added to new invoices and is left out of listings unless `include_archived=true`. Invoices that already carry it keep it.
      - `options` CustomFieldOption[], required: The options of this field that apply to the query: the common ones plus, when the query names a `customer_id`, the ones of that customer. Archived options appear only with `include_archived=true`. Always empty when `suggest_values` is `false`. To page through every option of the field, of every customer, use `GET /v1/companies/{company_id}/custom-fields/{key}/options`.
        - `id` string, uuid, required: Unique identifier of the option.
        - `value` string, required: Text of the option, exactly as it is shown and copied onto an invoice.
        - `customer_id` string, uuid, nullable, required: Customer the option belongs to, or `null` for an option common to every customer. It is set when the option is created and never changes.
        - `is_archived` boolean, required: An archived option is no longer offered and is left out of listings unless `include_archived=true`. Invoices that already carry its text keep it.
  - `meta` ResponseMeta
    - `timestamp` string, date-time
    - `request_id` string

## Other responses

- `400`: The request target could not be read as declared, so nothing was looked up. Three causes, all named in `error.details`: a path or query parameter whose value does not parse as its type (`VALIDATION_ERROR` — a UUID that is not a UUID, an unknown enum value, an empty element in a list such as `status=ISSUED,`), a required parameter that was not sent (`MISSING_PARAMETER`), or a header that is meant to carry an identifier and does not (`ACTIVE_COMPANY_HEADER_INVALID`). A list parameter sent entirely empty (`status=`) is not an error: it is the same as omitting it. The fault is in the target, not in the content — which is what `422` is defined over.
- `401`: Missing or invalid authentication. Like every other error, `message`/`detail` is localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English when the header is missing or asks for none of those.
- `403`: Your account does not own or manage this company, or does not hold the required access over it. A company that does not exist answers the same way. That case answers `error.code` `ACTIVE_COMPANY_NOT_ACCESSIBLE`.
- `429`: Rate limit exceeded. `RATE_LIMIT_EXCEEDED` when the request rate of your credential is over its limit; `TOO_MANY_REQUESTS` when an email the operation sends is held back because too many went out to that recipient in a short time. Either way, retry after the `Retry-After` seconds. `QUOTA_EXCEEDED` is the other `429`: the operation would go over a quota of your plan for the current period (issued invoices, for instance). Retrying does not help until the quota resets or the plan changes. `error.details` carries `feature_code`, `current_usage`, `quota_limit` and `reset_date`, and `RateLimit-Reset` the seconds until the reset when it is known.
- `500`: Internal server error
- `default`: Any status code the operation does not list above. Every operation declares it, so a generated client always has a branch to fall into and never loses the cause of a failure it did not anticipate. This is where the transport-level answers land — `405`, `406`, `415` and `429` — together with any status a future version of the API starts returning. All of them carry the same error envelope as the codes listed explicitly, so `error.code` is what tells them apart: switching on the status code alone is not enough. See «Transport-level errors» in the API description for when each one is produced. A `402` carrying `SUBSCRIPTION_REQUIRED` lands here when the account has no active subscription. `error.details` says why and what to do: `current_status` (absent if it never had one), `required_permission` and `action`. A `503` carrying `SERVICE_UNAVAILABLE` lands here too, with a `Retry-After` header: a dependency of BeeL itself (the database, the email provider) was momentarily unavailable and nothing was done. Retry after those seconds. A `502` carrying `EXTERNAL_SERVICE_ERROR` also lands here: an outbound integration the operation depends on failed or did not answer in time. It is a transient condition — retry with the same `Idempotency-Key` where the operation accepts one. One exception to the envelope: a failure of the network edge that never reaches the application (`502`, `503`, `504`, `524`) is generated by Cloudflare and its body is not BeeL's — it may not even be JSON. Treat those as "no answer", and retry.

---

[API](https://skmtc.dev/beel/apis/beel-public-api.md) · [All operations](https://skmtc.dev/beel/apis/beel-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/beel/apis/beel-public-api/revisions/ffbc0ae31f79?raw)
