---
title: "List participants"
method: GET
path: "/v1/participants"
tags: ["Participants"]
---

# List participants

`GET /v1/participants`

## Request

- Base URL: `https://api.peppolstatus.com`
- URL: `https://api.peppolstatus.com/v1/participants`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`

The participant set, keyset-paginated. Default sort is first-seen newest-first. Comma-array filters (`country`, `scheme`, `smp`, `ap`, `doctype`, `transport_profile`, `host`, `provenance`, and the company-register cuts `entity_type`, `sector`, `size`, `region`, `postcode`), the single-valued `sub_provider` cut, `registered` + `vat_liable` booleans, and a smart `q` (a full Peppol ID or a bare identifier number matches the ID; other text is a name search on the business-card name or the company-register name — see `q`). First-page `meta` carries estimated totals and rollup facets; `meta.filter_count` is a bounded exact count that degrades to null (never an error) if it exceeds the query timeout. A name search that exceeds the query timeout returns an empty first page with `meta.search_degraded`, and a 503 on a later page. Discovered participants carry no name/card fields (privacy).

## Query parameters

- `sort` 'first_seen.desc' | 'first_seen.asc' | 'name.asc' | 'name.desc' | 'country.asc' | 'country.desc' | 'registered.asc' | 'registered.desc' | 'entity_type.asc' | 'entity_type.desc' | 'sector.asc' | 'sector.desc'
- `country` string[]
- `scheme` string[]
- `smp` string[]
- `ap` string[]
- `doctype` string[]
- `transport_profile` string[]
- `host` string[]
- `sub_provider` string
- `registered` boolean
- `provenance` string[]
- `entity_type` string[]
- `sector` string[]
- `size` string[]
- `region` string[]
- `postcode` string[]
- `vat_liable` boolean
- `not_country` string[]
- `not_smp` string[]
- `not_entity_type` string[]
- `not_sector` string[]
- `not_size` string[]
- `not_region` string[]
- `q` string
- `limit` integer
- `cursor` string

## Response `200`

A page of participants.

- ParticipantListPage: A keyset page of participants with a prev cursor and first-page meta.
  - `items` ParticipantListItem[], required
    - `id` string, required: Canonical `scheme::value`.
    - `scheme` string, required
    - `value` string, required
    - `name` string, nullable, required: Current card name; null for discovered participants.
    - `company_name` string, nullable, required: Company-register legal name (KBO/SIRENE via participant_company_link), a display fallback when `name` (the business card) is null. Withheld (null) for natural persons per the §10 name gate; not sortable/searchable.
    - `country` string, nullable, required: Current card country; null for discovered participants.
    - `registered` boolean, required: Currently registered in the SML.
    - `smp` string, nullable, required: Current SMP hostname, or null.
    - `ap_seat_id` string, nullable, required: Serving Access Point SeatID, or null before the deep SMP fetch.
    - `ap_provider` string, nullable, required: Curated provider name behind that Seat, or null when unmapped.
    - `provenance` 'directory' | 'discovered', required
    - `first_seen_at` string, date-time, required
    - `company_entity_type` string, nullable, required: Company legal-form family (company|natural_person|association|public), or null when unmatched.
    - `company_sector` string, nullable, required: Company NACE Rev. 2.1 division (2-digit, one of 87; never 45), or null. Derived from the register code by its nomenclature: a Rev. 1-era code (e.g. NAF 1993, NACE-BEL 2003) gives null.
    - `company_size` string, nullable, required: Company size band code, or null. Stored codes: the INSEE trancheEffectifs codes for FR (e.g. `21`; `NN` = unknown), and for NO the same code set plus `1-4`. No other register has a size.
    - `company_region` string, nullable, required: Company seat region code, or null. A bare INSEE région code for FR (e.g. `84`); ISO 3166-2 for BE, NO and SK (e.g. `BE-VLG`). No other register has a region.
    - `company_size_label` string, nullable, required: English size band label of company_size (e.g. 21 → "50–99 employees", NN → "Size unknown"). Equal to the code when the code is unknown; null when company_size is null.
    - `company_region_label` string, nullable, required: Region name of company_region in the local language (e.g. 84 → "Auvergne-Rhône-Alpes", BE-VLG → "Flanders"). Equal to the code when the code is unknown; null when company_region is null.
    - `company_postcode` string, nullable, required: Company seat postcode, or null.
    - `company_vat_liable` boolean, nullable, required: Company VAT-liable / mandate-scope flag, or null.
  - `next_cursor` string, nullable, required
  - `prev_cursor` string, nullable, required
  - `meta` ListMeta: First-page list metadata: estimated totals and rollup facets.
    - `total_count` integer, required: GLOBAL estimated participant total (pg_class.reltuples) — the whole directory, NEVER the filtered match count. Use filter_count for that.
    - `total_count_estimated` boolean, required: Always true: total_count is a table estimate, not an exact count.
    - `filter_count` integer, nullable, required: Exact count of the rows the active filter/search matches, else null when no filter is active or no count could be produced. A count query is capped at 10000; when the match set exceeds the cap this is that cap and filter_count_capped is true. See filter_count_source.
    - `filter_count_capped` boolean: True when filter_count is the cap (a floor), not an exact total.
    - `filter_count_source` 'exact' | 'facet' | 'bounded' | 'null', nullable: How filter_count was produced: 'exact' (an exact lookup or a direct count of the match set), 'facet' (read off the rollup facets for a single-dimension filter — exact and never capped), 'bounded' (the capped count query), or null when no count was produced.
    - `search_degraded` boolean: True when a name search matched too many rows to rank inside the query budget: the first page was returned empty (never a 500) and the caller should retry with a narrower term. It does not mean 'no match'. filter_count is null in this case. Only a first page carries it; the same timeout on a later page is a 503.
    - `facets` object, required

## Other responses

- `400`: An invalid `sort`, `registered`, `vat_liable`, `provenance`, `limit` or `cursor`, or a `q` with no word of 3 or more characters.
- `503`: The query exceeded the database statement timeout. A name search returns this only on a page after the first; narrow the query and retry.

---

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