A segment is a set of explicit filters over every active legal entity of the registry. The
answer is the exact count, four facets that split it, and a sample of at most ten
companies, each with its sources and dates. With save: true the segment is stored, so you
can run it again later or
export every company in it as a CSV.
Served for fr only; any other country is a 404. It needs a key with the read scope,
sent from a server: a publishable fk_pub key is refused with 403 public_key_forbidden.
Each request is one call — on Free, one of the month's 1 000 lookups; on Pro and Scale it
spends nothing but the rate.
Run one
Keep the key out of your shell history:
read -rs FIRMUS_KEY && export FIRMUS_KEYComputer programming and consultancy (NAF division 62) with its head office in the Rhône
(69), 10 employees or more:
curl -s -X POST https://api.firmus.sh/v1/fr/segments \
-H "Authorization: Bearer $FIRMUS_KEY" \
-H "Content-Type: application/json" \
-d '{
"filters": { "activity": ["62"], "departement": ["69"], "workforce": { "from": "11" } },
"facet_limit": 3
}'The answer is 200. The sample below is cut to one of its ten companies; the figures are
the registry's on 1 November 2026 and move with it:
{
"segment": null,
"filters": {
"activity": [
{
"code": "62",
"level": "division",
"label": "Programmation, conseil et autres activités informatiques"
}
],
"departement": ["69"],
"workforce": { "from": { "code": "11", "label": "10 à 19 salariés" }, "to": null }
},
"count": 371,
"exportable_count": 370,
"facets": {
"departement": { "values": [{ "value": "69", "label": null, "count": 371 }], "other": 0 },
"activity_division": {
"values": [
{
"value": "62",
"label": "Programmation, conseil et autres activités informatiques",
"count": 371
}
],
"other": 0
},
"workforce": {
"values": [
{ "value": "11", "label": "10 à 19 salariés", "count": 160 },
{ "value": "12", "label": "20 à 49 salariés", "count": 134 },
{ "value": "21", "label": "50 à 99 salariés", "count": 45 }
],
"other": 32
},
"legal_form": {
"values": [
{ "value": "5710", "label": "SAS, société par actions simplifiée", "count": 319 },
{
"value": "5499",
"label": "Société à responsabilité limitée (sans autre indication)",
"count": 41
},
{ "value": "5599", "label": "SA à conseil d'administration (s.a.i.)", "count": 4 }
],
"other": 7
}
},
"sample": [
{
"registry_number": "847831690",
"name": "PROMY",
"legal_form": { "code": "5710", "label": "SAS, société par actions simplifiée" },
"registered_on": "2018-12-07",
"activity": {
"code": "62.01Z",
"scheme": "naf2008",
"label": "Programmation informatique"
},
"workforce": { "code": "11", "label": "10 à 19 salariés", "year": 2023 },
"size_category": { "code": "PME", "label": "Petite ou moyenne entreprise", "year": 2023 },
"head_office_address": {
"address": "30 AVENUE MARECHAL FOCH",
"postal_code": "69006",
"city": "LYON",
"departement": "69"
},
"sources": {
"registry": "insee_sirene",
"data_updated_at": "2025-12-06T08:51:12Z",
"head_office_data_updated_at": "2025-09-30T14:47:09Z",
"legal": null
}
}
],
"prospecting": {
"include_sole_traders": false,
"acknowledgement": null,
"lists_partially_disclosed": false,
"notice": "Built from INSEE Sirene. It does not reflect an opposition to prospecting recorded only in the RNE (diffusionCommerciale), which Firmus does not read yet. Partially disclosed companies are counted but never listed."
},
"sources": {
"registry": "insee_sirene",
"legal": null,
"index": {
"built_at": "2026-11-01T16:10:38Z",
"patched_at": null,
"fed_through": "2026-11-01T15:58:35Z"
},
"relative_to": "2026-11-01"
}
}A segment that matches nothing is still a 200, with count: 0, empty facet values and an
empty sample — never a 404.
The filters
A closed list. Values within one filter are ORed, filters are ANDed, a filter left out is
open, and "filters": {} is the whole active registry. Lists hold at most 100 values. An
unknown filter, an unknown body field or a value a filter does not accept refuses the whole
request with 400 invalid_request, and message names the filter and what it accepts — a
misspelt filter is never ignored, because the count would then answer a question you did not
ask.
| Filter | Value |
|---|---|
activity | NAF divisions ("62") and NAF codes ("62.01Z" or "6201Z"), mixed |
departement | The head office's département: "75", "2A", "974" |
commune | The head office's INSEE commune code, not its postal code: "31555" |
postal_code | The head office's postal code, five digits |
workforce | { "from": "11", "to": "22" }, INSEE workforce bands, inclusive, either bound optional |
size_category | "PME", "ETI", "GE" |
legal_form | INSEE legal forms, four digits ("5710"), and their two-digit categories ("57"), mixed |
registered_on | { "from": "2024-01-01", "to": "2024-12-31" }, YYYY-MM-DD, inclusive, either bound optional |
head_office_moved_within_days | The head office moved in the last N days, 1 to 3 650 |
workforce_up_within_days | The workforce band went up in the last N days, 1 to 3 650 |
proceeding_open | true: an insolvency proceeding is open, from the BODACC; false: none is |
The workforce bands are 00 (none), 01 (1–2), 02 (3–5), 03 (6–9), 11 (10–19),
12 (20–49), 21 (50–99), 22 (100–199), 31 (200–249), 32 (250–499), 41
(500–999), 42 (1 000–1 999), 51 (2 000–4 999), 52 (5 000–9 999) and 53 (10 000 and
more). A company whose band is not filled in, NN, never matches a workforce filter,
and that is most companies: run the segment without workforce first and read the
workforce facet, whose NN value is how many the filter would leave out.
In Paris, Lyon and Marseille the head office's commune is its arrondissement: Paris is
75101 to 75120, Lyon 69381 to 69389, Marseille 13201 to 13216. The city's own
code (75056, 69123, 13055) matches almost nothing, so send the arrondissements, or
departement.
Natural language is not read. "IT services in Lyon" is yours to turn into codes, and the
answer's filters says back how each value was read: a NAF division with level: "division", a code with level: "code", a legal-form category with level: "category",
each with its INSEE label, a workforce bound with its band's label, and a window with the
day it starts from, { "days": 182, "since": "2026-05-03" }. Show it to whoever asked, so
a misreading can be corrected. Labels are INSEE's, in French. A code the nomenclature does
not hold says label: null — a NAF rév. 1 code still found on old companies (51.1T), a
division NAF rév. 2 leaves unused (04), a retired legal form — so read label as
nullable. A division is the first two characters of the code whatever its revision, so
"51" also holds NAF rév. 1 wholesalers (51.1T) under the NAF rév. 2 label "Transports
aériens"; filter on full codes when the revision matters.
Windows count from the day the segment runs, in Paris, given as sources.relative_to. A
saved segment stores 182, not a date, so "moved in the last six months" slides with time.
The answer
countis exact: every active legal entity that matches, partially disclosed units and sole traders included.exportable_countis how many of them may be listed: what the sample is drawn from and what an export would write. It leaves out every partially disclosed unit and, unless you ask for them, every sole trader (below).facetssplitcountby département, NAF division (activity_division), workforce band and legal form: the topfacet_limitvalues by count (10 by default, 1 to 100) andother, what those values leave out. Each facet's values andotheradd up tocount. A missing value is a value like any other, sovaluecan benull.labelisnullon everydepartementvalue, on anullvalue, and on any value INSEE does not label.sampleis at most ten companies, spread across the segment rather than its oldest registrations, and the same ten until the data changes. Each carriesname,legal_form,registered_on,activity,workforce,size_categoryandhead_office_address, as enrich returns them.sources.data_updated_atis the registry's own timestamp for the company's record, andhead_office_data_updated_atthe one for its head office — not the time Firmus imported either.sourcesnames the registry, and the BODACC underlegal("bodacc") whenproceeding_openis used.index.fed_throughis the instant the data behind the count was read: a change Firmus received after it is not counted yet.built_atandpatched_atdate the last monthly rebuild and the last daily update;patched_atisnulluntil the first daily update after a rebuild.prospectingsays what the sample and an export were allowed to list. Repeatprospecting.noticewherever you show the companies.
What a listing may show
The sample, an export, and anything else that lists the companies of a segment follow three rules. Counts and facets are not a listing and follow none of them.
- A partially disclosed company is never listed — not in a sample, not in an export —
whatever its legal form: the person behind it asked for parts of the record to be
withheld from public reuse. A company whose head office is partially disclosed counts as
one: it is in
countand never inexportable_count, the sample or an export.prospecting.lists_partially_disclosedis alwaysfalse. A company that becomes partially disclosed after the segment was saved leaves it at once. See masked records. - Sole traders are not listed by default. A sole trader (legal form
1000) is a natural person, and on the whole registry they are nearly half ofcount. To list them, sendinclude_sole_traders: truewithacknowledgement: "sole-traders-2026-11-01"andsave: true(below). - The registry's opposition to prospecting is not read. Segments are built from INSEE
Sirene and do not reflect an opposition recorded only in the RNE
(
diffusionCommerciale).prospecting.noticesays so in every answer, and the first line of every export repeats it.
Including sole traders
The acknowledgement states that your organization is the controller of any prospecting of
the sole traders the segment lists: it informs each of them under article 14 of the GDPR
when it first uses their data, and honours their opposition to prospecting. Sending
include_sole_traders: true without it, or with another version, is refused rather than
answered with fewer companies, and message quotes the text and names the version:
{
"error": {
"status": 400,
"code": "invalid_request",
"message": "`include_sole_traders` lists natural persons, and needs the acknowledgement `sole-traders-2026-11-01` in `acknowledgement`: \"The customer is the controller of any prospecting of the sole traders (entrepreneurs individuels) this segment lists, who are natural persons: it informs each of them under article 14 of the GDPR when it first uses their data, and it honours their opposition to prospecting.\"",
"documentation_url": "https://docs.firmus.sh/reference/errors#invalid_request"
}
}The segment must also be saved, since the acknowledgement is stored with it — which key or
Claude connection gave it, when, and which version — and repeated as
prospecting.acknowledgement in every answer that runs it and at the top of every export.
Without save: true the request is 400 invalid_request. A new wording will be a new
version; the version is part of what you store on your side.
Save it
save: true stores the segment's name (up to 200 characters; "Untitled segment" without
one) and its filters as normalized — "6201Z" becomes "62.01Z" — and answers 201 Created, with the segment's URL in Location and the stored segment under segment:
curl -s -X POST https://api.firmus.sh/v1/fr/segments \
-H "Authorization: Bearer $FIRMUS_KEY" \
-H "Content-Type: application/json" \
-d '{"filters": {"activity": ["62"], "departement": ["69"]}, "name": "Lyon software", "save": true}'segment carries id, name, filters, include_sole_traders, acknowledgement (null,
or its version, text — the wording of that version, which is never edited —
acknowledged_at and acknowledged_by), created_at and updated_at.
A saved segment is not edited: delete it and save a new one.
Saved segments are a number your plan holds, not a monthly volume: 3 on Free, 100 on Pro,
1 000 on Scale. A save beyond it is refused with 402 quota_exceeded and saves nothing; it
carries no Retry-After, because deleting a segment frees its place, and no date does.
Running a segment without save is never refused for it.
A saved segment can also be followed from a watchlist, which is then told which companies enter it, and on request which leave it, after each daily update of the index: see follow a segment.
Errors
400 invalid_request— an unknown filter or body field, a value a filter does not accept, afacet_limitoutside 1 to 100, sole traders without the acknowledgement or withoutsave, or a body that is not JSON.messagesays which. Nothing is counted.402 quota_exceeded— a save beyond the plan's saved segments, withoutRetry-After; or, on Free, the month's lookups are spent, withRetry-After.403 public_key_forbidden— a publishablefk_pubkey holdingread; one without it gets403 insufficient_scope.404 not_found— a country other thanfr.503 segment_index_unavailable— this server cannot count segments yet. Nothing is counted; retry later.
Next
- Export a segment — every company in a saved segment, as a CSV.
- Errors — every code above, and how to tell a refusal from an outage.