API
Call the same data from your own code.
On this page
Getting started with the API
Everything the StackScan dashboard shows is available over a plain REST API: the technology stack behind any domain, the websites running a given technology, and the company behind a website.
Three minutes to your first call
- Create a token. In your dashboard, open My Account → API Tokens. Your workspace UUID is on the same page. The token is shown once.
- Send both on every request. The token as a bearer header, the workspace UUID as
X-Tenant-Id. - Call it. The base URL is
https://api.stackscan.com.
One domain
curl https://api.stackscan.com/v1/tech-lookup/domains/lookup?domain=example.com \
-H "Authorization: Bearer $STACKSCAN_TOKEN" \
-H "X-Tenant-Id: $STACKSCAN_WORKSPACE"
A hundred at once
curl -X POST https://api.stackscan.com/v1/tech-lookup/companies/batch \
-H "Authorization: Bearer $STACKSCAN_TOKEN" \
-H "X-Tenant-Id: $STACKSCAN_WORKSPACE" \
-H "Content-Type: application/json" \
-d '{"domains":["shopify.com","stripe.com"]}'
The full API reference documents every parameter, with code samples in around twenty languages and a test console for each endpoint.
What you can call
Six endpoints. Every one returns JSON, and every one costs a single credit when it finds something.
Domain to technologies
Every technology detected on a domain, with its category and how many sites run it.
GET /v1/tech-lookup/domains/lookup
Technology to websites
Who runs a given technology, with totals and a country breakdown.
GET /v1/tech-lookup/technologies/lookup
Domain to company
The firmographics behind a website: name, industry, location, LinkedIn.
GET /v1/tech-lookup/companies/lookup
Companies, up to 100 at once
Resolve a whole page of companies in one request instead of one at a time. A 10,000-company CRM takes minutes, not hours.
POST /v1/tech-lookup/companies/batch
Technologies, up to 100 domains at once
Each domain's technology list in a single request, with an optional category filter.
POST /v1/tech-lookup/domains/batch
Check your balance
Remaining credits and this month's allocation. Free to call.
GET /v1/tech-lookup/credits
Other formats
Both batch endpoints also return CSV for spreadsheet workflows: add ?format=csv or send Accept: text/csv.
Building against this from an AI agent? There is a plain-text summary at llms.txt and a full field-level reference at llms-full.txt.
API credits and rate limits
The API draws on the same Bulk Lookup Credits as the dashboard, so there is nothing separate to buy.
One credit per hit
A lookup that finds nothing is not charged, and neither is checking your balance. In a batch you pay for the domains that resolved, not the ones you sent.
Rate limits
- 120 requests a minute per token for single lookups.
- 30 requests a minute for the batch endpoints, which is up to 3,000 domains a minute.
Reading your usage from the response
Every authenticated response carries headers you can read instead of guessing:
X-Credits-Used,X-Credits-Remaining,X-Credits-CostX-RateLimit-Limit,X-RateLimit-Remaining,Retry-After
Browser clients can read these too - they are listed in the API's CORS exposed headers.
Included in every plan
Any plan with Bulk Lookup Credits can use the API. See pricing for what each plan includes.
Technology lists (whole-technology exports)
A technology list is every website we know of running one technology. It is the same export the dashboard's Tech Lookup produces, requested over HTTP. It arrives as a file, and it lands in your Reports page exactly as if you had clicked the button yourself.
It costs one credit, whatever the size
A list of four million websites costs 1 credit. Not one per row, not one per domain. One.
Two things about that credit are worth knowing:
- It comes out of your standard credits, not your bulk-lookup credits. These are separate balances. A full bulk-lookup balance will not pay for a list, and
GET /v1/mereports both so you can check which is which. - Asking for the same technology again inside the same billing period is free. One credit buys that technology for the period, so a nightly refresh costs one credit a month rather than thirty.
Nothing is charged when a request is refused. An unknown technology, or filters that match no websites, both come back as an error with your balance untouched.
It is asynchronous, and it has to be
Building a list can take minutes, so there is nothing useful to return straight away. You start it, poll, then download.
1. Start it
curl -X POST https://api.stackscan.com/v1/tech-lookup/lists \
-H "Authorization: Bearer $STACKSCAN_TOKEN" \
-H "X-Tenant-Id: $STACKSCAN_WORKSPACE" \
-H "Content-Type: application/json" \
-d '{"technology": "Shopify"}'
{
"success": true,
"report_id": 241,
"status": "queued",
"technology": "Shopify",
"credits_charged": 1,
"credit_type": "standard",
"reused_billing_period": false,
"estimated_rows": 4210338,
"status_url": "https://api.stackscan.com/v1/tech-lookup/lists/241"
}
reused_billing_period: true means you had already bought this technology this period and were not charged again.
2. Poll until it is ready
curl https://api.stackscan.com/v1/tech-lookup/lists/241 \
-H "Authorization: Bearer $STACKSCAN_TOKEN" \
-H "X-Tenant-Id: $STACKSCAN_WORKSPACE"
status is queued, ready or failed. Polling is free, so check every few seconds at first and back off. A failed list has already had its credit refunded automatically, so you do not need to ask.
3. Download
curl -L -o shopify.csv \
https://api.stackscan.com/v1/tech-lookup/lists/241/download \
-H "Authorization: Bearer $STACKSCAN_TOKEN" \
-H "X-Tenant-Id: $STACKSCAN_WORKSPACE"
Large lists come back as CSV, small ones as XLSX. Downloading while the list is still building returns 409, so poll first.
Download limits
These files are big, so downloads are limited in two ways. Neither costs credits.
A rate limit of a few downloads a minute. Generous enough to retry a failed transfer, tight enough that a runaway script cannot pull terabytes. Exceeding it returns 429 with a retry_after, and waiting fixes it.
A ceiling of 30 downloads per list. The status response reports download_count, download_limit and downloads_remaining so you can see it coming. Past the ceiling you get 403 with error_code: download_limit_reached. Not a 429, because retrying will not help. Contact us if you need it lifted, or start a fresh list.
Two details worth knowing:
- Attempts are counted, not completed downloads. A transfer that drops halfway still spends one. We hand the file to the web server and return immediately, so we genuinely cannot tell a completed download from an abandoned one. The ceiling is 30 rather than something smaller precisely because of that.
- An expired file does not count. If retention has removed the file you get
410and your remaining downloads are untouched.
If you find yourself near the ceiling regularly, you probably want to fetch once and cache it your side rather than re-downloading. The data only changes when we recrawl.
Check truncated before you treat a list as complete
Plans cap how many rows an export may contain, and there is a ceiling of 1,000,000 rows even on unlimited plans. Popular technologies exceed that.
The status response tells you exactly where you stand:
| Field | Meaning |
|---|---|
result_count |
how many websites matched |
exported_rows |
how many are actually in the file |
truncated |
true when the cap cut the list short |
withheld_rows |
the difference between the two |
If truncated is true, the file is the top slice of a larger population, not the whole of it. Narrowing with filters is usually more useful than a truncated list of everything.
Narrowing the list
{
"technology": "Shopify",
"tld": [".co.uk"],
"only_with_company_info": true
}
technology: the name. Usestack_idinstead if you want to be exact.country/country_condition: country IDs,includeorexclude.tld/tld_condition: domain endings,includeorexclude.company_size: restrict to company size bands.only_with_company_info: skip websites we hold no company record for. Smaller list, far more useful for outreach.
Your list history
curl https://api.stackscan.com/v1/tech-lookup/lists \
-H "Authorization: Bearer $STACKSCAN_TOKEN" \
-H "X-Tenant-Id: $STACKSCAN_WORKSPACE"
Every list your workspace has requested, newest first. These are the same rows the dashboard shows under Reports. Lists belong to the workspace that paid for them, so any member can fetch one.
How long files are kept
Generated files are retained for a period and then removed; the report row stays. A download of an expired list returns 410 Gone, which is deliberately different from 404 so you can tell "this expired" from "this never existed". Request it again to rebuild it.