Skip to main content

Certified companies for your platform

You run a booking platform, OTA or marketplace, and want certification badges next to your listings: every company holding certification X, Y or Z, with enough detail to render the badge and stand behind it.

The standard-holders search answers that on its own. It returns who holds which certification, and — when you ask for it — your own identifier for each company alongside, so the result maps onto your listings without a second call. Run the companies search as well only when you need what it alone carries: names, websites and addresses. This walkthrough is the complete loop — submit, poll, download — plus that optional second search and a webhook variant that removes the polling.

Before you start

  • An API key — Getting started covers creating one, Authentication what it acts as.
  • The ids of the certifications you want, shared by BeCause during onboarding. No ids? "includeAllAccessibleStandards": true in the searches below returns holders of every certification your key's profile can reach.
  • The ids of the custom properties you want returned per company — above all your own identifier for it, if BeCause holds one for you. Both searches return no custom properties unless you list their ids in customPropertyIds, and that identifier is usually the only way to join an export back to your own listings, so decide this before the first request, not after. GET /api/v1/custom-properties lists your properties; the identifier-type ones carry isIdentifier: true.

The certification data comes from a bulk endpoint: the request is queued, not answered while you wait — see Asynchronous processing.

curl -X POST https://api.because.eco/api/v2/bulk/standards/holders/search \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"searchBy": {
"certifications": [
"3c7f2f64-0d3a-4b7e-9a11-2f66afa60001",
"3c7f2f64-0d3a-4b7e-9a11-2f66afa60002"
]
},
"customPropertyIds": [
"0992e704-5c3b-4b6e-8a1d-7f2e9c4b6d18"
]
}'

The request must narrow by something: certification ids, the id of a group your profile owns, or "includeAllAccessibleStandards": true, all inside searchBy. Only validated certification holdings are returned; "includeExpired": true and "includeInProgress": true widen that to lapsed and in-progress ones.

customPropertyIds is what makes this one call rather than two: it names the properties to return under each company's fields, and your own identifier for the company is the one worth asking for. It is a projection, not a filter — it changes which fields come back, never which companies do. Omit it and no fields are returned at all.

pageSize — optional, 5,000 to 100,000 companies per result page, default 100,000 — shapes the result files; at the default, results up to 100,000 companies arrive as a single file. The reference has the full list.

{
"correlationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

That correlation id is the handle for everything that follows. Queued means queued — no result exists yet.

2. Poll until a terminal state

curl https://api.because.eco/api/v2/bulk/tasks/3fa85f64-5717-4562-b3fc-2c963f66afa6 \
-H "Authorization: YOUR_API_KEY"

The status advances through Pending, Scheduled and InProgress; poll on an interval — seconds, not milliseconds — until one of the four terminal states:

  • Success — done; the result is ready.
  • PartialSuccess — done, but some items failed along the way. The result is still there; read it.
  • Error — the request failed; error.generalErrorMessages says why.
  • Cancelled — the request was cancelled before finishing.

On success, the response carries the result as a list of pages:

{
"correlationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"createdAtUtc": "2026-07-31T08:12:44.9Z",
"updatedAtUtc": "2026-07-31T08:14:52.03Z",
"status": "Success",
"requestType": "BulkGetStandardHolders",
"result": {
"pageSize": 100000,
"pageCount": 1,
"pages": [
{
"url": "https://exports.because.eco/…/page-0001.json?sv=…",
"companyCount": 6321
}
]
},
"error": null
}

pages is in page order and the last page is usually short; companyCount says how many companies each file holds. At the default page size a result of 6,321 companies is one file; a pageSize of 5,000 would have made it two.

3. Download the pages

Each url is a self-contained link — GET it directly, no Authorization header — valid for thirty days. The file is gzip-compressed JSON served as application/json with Content-Encoding: gzip, so most HTTP clients — Postman, a browser, Python requests, axios — decompress it for you and hand you plain JSON. A client that does not honour Content-Encoding (bare curl is the common case) receives the gzip bytes unchanged: decompress them yourself, whether that is gunzip on the command line, a GZipStream in .NET, or zlib anywhere else.

curl --compressed "https://exports.because.eco/…/page-0001.json?sv=…" > page-1.json

Every page is a complete document on its own — the catalogs at the top are repeated in each — so pages can be processed independently and in parallel. Standards, validators and custom properties are declared once per page and referenced by id from the rows below; fields with nothing to say are absent rather than null. The standard holders page reference lists every field.

{
"standards": [
{
"id": "3c7f2f64-0d3a-4b7e-9a11-2f66afa60001",
"name": "Green Stay Certification",
"levels": [
{ "id": "5a1c8e02-93d4-4f6b-8c7e-2b9d0f4a6e21", "name": "Silver", "level": 1 },
{ "id": "5a1c8e02-93d4-4f6b-8c7e-2b9d0f4a6e22", "name": "Gold", "level": 2 }
]
}
],
"validators": [
{ "id": "b83f0a2e-4c1d-4e9a-b7f2-9a8c7d6e5f04", "name": "Green Stay Foundation" }
],
"customProperties": [
{ "id": "0992e704-5c3b-4b6e-8a1d-7f2e9c4b6d18", "name": "Partner hotel ID" }
],
"companies": [
{
"id": "9c56d3a1-8b0f-4c7a-9e2d-5b1a7f3e0c11",
"fields": {
"0992e704-5c3b-4b6e-8a1d-7f2e9c4b6d18": ["HTL-12345"]
},
"heldStandards": [
{
"standardId": "3c7f2f64-0d3a-4b7e-9a11-2f66afa60001",
"standardHolderId": "6e9b2c40-77aa-4f0e-8f3d-1d2c3b4a5f66",
"startDateUtc": "2026-01-01T00:00:00Z",
"endDateUtc": "2027-01-01T00:00:00Z",
"levelId": "5a1c8e02-93d4-4f6b-8c7e-2b9d0f4a6e22",
"firstIssuedYear": 2024,
"certificationStatus": "Certified",
"applicationStatus": "NotInProgress",
"validations": [
{
"validatorId": "b83f0a2e-4c1d-4e9a-b7f2-9a8c7d6e5f04",
"validationState": "Valid"
}
]
}
]
}
]
}

What to build the badge from: certificationStatus is Certified or NotCertified, startDateUtc and endDateUtc bound the validity period, and validations names who validated the holding — validatorId resolves in the validators catalog. The certification's name comes from the standards catalog via standardId, and levelId picks the company's level from that standard's levels. A holding appears at all only because it is validated — presence in this export is itself the badge signal — except in-progress ones admitted by includeInProgress, which arrive without a validations entry.

fields is keyed by custom-property id and the customProperties catalog names them, so "HTL-12345" above is the listing this row belongs to — match on it and the badge is ready to render. The catalog is drawn from the whole export, so an id in one page's fields always resolves in that same page's catalog.

If you need nothing beyond the badge and the match to your own listing, you are done — the steps below are optional.

4. Optional: names, websites and addresses

The holders export identifies companies but does not describe them. For that, run the same loop against the companies search with the same searchBy:

curl -X POST https://api.because.eco/api/v2/bulk/companies/search \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"searchBy": {
"certifications": [
"3c7f2f64-0d3a-4b7e-9a11-2f66afa60001",
"3c7f2f64-0d3a-4b7e-9a11-2f66afa60002"
]
},
"includeAddresses": true,
"customPropertyIds": [
"0992e704-5c3b-4b6e-8a1d-7f2e9c4b6d18"
]
}'

Two options earn their keep here: "includeAddresses": true if you will match companies geographically, and customPropertyIds if you want your identifier repeated on these rows as well — step 1 already carried it, and the two exports join on the company id regardless. The reference has the full list. Poll the same task endpoint — this task reports "requestType": "BulkGetCompanies" — and download the pages the same way:

{
"customProperties": [
{ "id": "0992e704-5c3b-4b6e-8a1d-7f2e9c4b6d18", "name": "Partner hotel ID" }
],
"companies": [
{
"id": "9c56d3a1-8b0f-4c7a-9e2d-5b1a7f3e0c11",
"historicalIds": [],
"name": "Hotel Aurora",
"website": "https://www.hotel-aurora.example",
"fields": {
"0992e704-5c3b-4b6e-8a1d-7f2e9c4b6d18": ["HTL-12345"]
},
"address": {
"latitude": 55.67,
"longitude": 12.56,
"streetAddress": "Harbour Street 1",
"zipCode": "1000",
"city": "Copenhagen",
"countryCode": "DNK",
"countryName": "Denmark"
},
"establishmentTypes": ["Accommodation", "Hotel"]
}
]
}

The companies page reference lists every field. Join on the company id; historicalIds carries ids the company held before profile merges, so keep them in the join and old references still resolve. fields is keyed by custom-property id — the customProperties catalog names them — and holds only the properties you asked for. address and supportingAddresses appear only when the request set includeAddresses.

5. Optional: the certifications themselves

To render more than a name and a level — descriptions, logos, who stands behind a certification — run the same loop against the standards search with the same ids:

curl -X POST https://api.because.eco/api/v2/bulk/standards/search \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"searchBy": {
"certifications": [
"3c7f2f64-0d3a-4b7e-9a11-2f66afa60001"
]
}
}'

Each standard in the result carries its summary, logo and levels, and its owner as an id and name — the id joins against the company ids the companies search returns. The standards page describes the file; the reference has the request.

6. Skip the polling

Instead of polling in step 2, configure a webhook on the four terminal topics. When bulk.task.succeeded (or bulk.task.partially_succeeded) arrives, verify the signature, check data.requestTypeBulkGetStandardHolders for the holders search, BulkGetCompanies for the companies search; the webhook fires for every bulk request the profile submits, not just searches — and go straight to the task call, whose result now carries the page URLs.

Keeping it fresh

Certifications expire and new companies certify, so re-run the searches on a schedule — daily is plenty for most platforms; mind the rate limits. Result files stop being retrievable after thirty days, so download promptly rather than bookmarking page URLs.