Swiss Data Atlas API
Everything the app can do is available over HTTPS: company search, contact reveals, industry monitors, digests, reference data and natural-language questions. Keys are scoped, metered and self-service.
Create a key in the app · OpenAPI schema
Authentication
Send your key as a bearer token on every request. Base URL: /api/public/v1.
curl -s https://swissdataatlas.com/api/public/v1/me \
-H "Authorization: Bearer sda_live_…"Prepaid billing, consumption and receipts
Billing calls require an organisation admin (or global admin), the indicated billing scope, and an organisationId query parameter. Existing keys do not automatically gain billing scopes. List calls support limit (1 to 100, default 50) and offset (default 0). Consumption is read from recorded credit movements, not API request counts or proof of cash payment.
GET /billing/consumption?organisationId=YOUR_ORGANISATION_UUID&limit=50&offset=0
POST /billing/topups?organisationId=YOUR_ORGANISATION_UUID
{ "amount": 100 }
GET /billing/receipts?organisationId=YOUR_ORGANISATION_UUID
GET /billing/receipts/RECEIPT_UUID?organisationId=YOUR_ORGANISATION_UUID&download=htmlA topup request returns Wise bank details and a unique payment reference. It does not move money. Setup must be completed before requests can be created. Automatic Wise confirmation is not enabled. Once a global admin has independently verified the received CHF amount and transaction in Wise, confirmation credits the organisation pool exactly once. Organisation admins allocate member allowances separately. Pending transfers have no receipt. Receipts are printable HTML downloads, not Wise-issued PDFs or consumption invoices.
POST /billing/topups/TOPUP_UUID/confirm?organisationId=YOUR_ORGANISATION_UUID
{ "wiseTransactionId": "VERIFIED_WISE_TRANSACTION", "verifiedAmount": 100, "currency": "CHF" }Confirmation requires verified seller address and UID / VAT details. Repeating the same confirmation is safe; reusing a Wise transaction for another topup is rejected. Contact sda@bi-concepts.ch for billing setup. Commercial terms are available under AGB, currently a draft for review.
Response format
Successful calls return data plus meta; failures return an error object with a stable code.
{
"data": { "companies": [ … ] },
"meta": {
"requestId": "…",
"generatedAt": "2026-01-01T12:00:00.000Z",
"rowsReturned": 42,
"quota": {
"rowsUsedThisMonth": 1042,
"rowsLimitPerMonth": 25000,
"revealsUsedThisMonth": 3,
"revealsLimitPerMonth": 25,
"maxRowsPerRequest": 250
}
}
}Every response also carries x-ratelimit-limit, x-quota-rows-limit/-used and x-quota-reveals-limit/-used.
Scopes
companies:readSearch companies and read company detailscontacts:readReveal signatory contact details (billed per lookup)monitors:readList saved monitorsmonitors:writeCreate monitors and trigger runsdigests:readRead a monitor's current digestask:writeAsk questions in natural languagereference:readRead industry (NOGA) and canton reference datacustomers:readRead your customer lists, their classification and gap analysiscustomers:writeUpload customer lists for classification and delete thembilling:readRead consumption and download paid receipts (organisation admins only)billing:writeRequest prepaid Wise topups (organisation admins only)
Endpoints
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /billing/consumption | billing:read | Paginated organisation credit movements, including purchases and confirmed topups. |
| GET / POST | /billing/topups | billing:read / billing:write | List or request prepaid CHF bank transfers to Wise. |
| GET | /billing/receipts | billing:read | List confirmed payment receipts. |
| GET | /billing/receipts/{id} | billing:read | Read a receipt; ?download=html downloads a printable receipt. |
| POST | /billing/topups/{id}/confirm | billing:write | Global admin only: confirm a payment independently verified in Wise. |
| GET | /me | reference:read | Key scopes, limits and current usage. |
| POST | /companies/search | companies:read | Search companies by industry, canton, registration window or anniversary. |
| GET | /companies/{uid} | companies:read | One company by Swiss UID (CHE-…) or registry id, with signatories. |
| POST | /contacts/reveal | contacts:read | Reveal a signatory's e-mail, phone and profiles. Billed per new lookup. |
| GET | /monitors | monitors:read | List your saved monitors. |
| POST | /monitors | monitors:write | Create a monitor. |
| POST | /monitors/{id}/run | monitors:write | Run a monitor now and mail its digest. |
| GET | /digests/{id} | digests:read | The current digest of a monitor as JSON. |
| POST | /ask | ask:write | Ask a question in plain language; returns prose, SQL and rows. |
| POST | /customers/lists | customers:write | Upload up to 5,000 customers (name, UID, town); returns the classification. |
| GET | /customers/lists | customers:read | Your customer lists and those shared in your organisation. |
| GET | /customers/lists/{id} | customers:read | Classification summary and every matched customer. |
| GET | /customers/lists/{id}/gap-analysis | customers:read | Gap analysis: untapped active companies per industry. ?cantons=customers|all |
| DELETE | /customers/lists/{id} | customers:write | Delete a list you uploaded. |
| GET | /reference/noga | reference:read | Industry tree (NOGA 2025). |
| GET | /reference/cantons | reference:read | Cantons and mutation types. |
Example: company search
curl -s https://swissdataatlas.com/api/public/v1/companies/search \
-H "Authorization: Bearer sda_live_…" \
-H "Content-Type: application/json" \
-d '{
"mode": "anniversary",
"anniversaryYears": [10, 25],
"fromMonths": 3,
"toMonths": 24,
"cantons": ["ZH", "ZG"],
"industries": [{ "level": "section", "code": "L" }],
"websiteOnly": true,
"limit": 100
}'Example: classify customers and run a gap analysis
Send your customers with a company name, a UID number (CHE-…) or both; the town helps when several companies share a name. Each row is matched against the commercial register and classified by industry (NOGA), canton, legal form and age. Rows come back as matched, ambiguous (several candidates, please check) or unmatched. Lists are shared with your organisation, just like in the app under My customers. Up to 5,000 rows per upload.
curl -s https://swissdataatlas.com/api/public/v1/customers/lists \
-H "Authorization: Bearer sda_live_…" \
-H "Content-Type: application/json" \
-d '{
"name": "Key accounts 2026",
"customers": [
{ "name": "Muster AG", "uid": "CHE-123.456.789", "town": "Zürich" },
{ "name": "Beispiel GmbH", "town": "Luzern" }
],
"includeItems": false
}'{
"data": {
"id": "8f0c…",
"name": "Key accounts 2026",
"classification": {
"total": 2, "matched": 2, "ambiguous": 0, "unmatched": 0,
"byIndustry": [{ "label": "68 Real Estate Activities", "count": 1 }, …],
"byCanton": [{ "label": "ZH", "count": 1 }, …],
"byLegalForm": [ … ],
"byAge": [{ "label": "10-19 years", "count": 1 }, …]
}
},
"meta": { … }
}Then ask where the untapped potential is. By default the comparison is limited to the cantons your customers are in; pass ?cantons=all for all of Switzerland.
curl -s "https://swissdataatlas.com/api/public/v1/customers/lists/8f0c…/gap-analysis?cantons=customers" \
-H "Authorization: Bearer sda_live_…"
{
"data": {
"cantonScope": "customers",
"cantons": ["LU", "ZH"],
"industries": [
{ "divisionCode": "68", "divisionName": "Real Estate Activities", "sectionCode": "L",
"customers": 12, "totalActiveCompanies": 4210, "untapped": 4198, "coverage": 0.0029 }
]
}
}Example: ask a question
curl -s https://swissdataatlas.com/api/public/v1/ask \
-H "Authorization: Bearer sda_live_…" \
-H "Content-Type: application/json" \
-d '{ "question": "How many companies were registered in Zug last month?" }'Limits and errors
Each key has a per-request row cap, a monthly row allowance, a monthly contact-reveal allowance, a requests-per-minute limit and optional canton or industry restrictions. Error codes you should handle: missing_key, invalid_key, insufficient_scope, canton_not_allowed, rate_limited, row_quota_exhausted, reveal_quota_exhausted, not_found.