---
title: "Look up the tech stack behind many domains"
method: POST
path: "/v1/tech-lookup/domains/batch"
tags: ["TechLookup"]
---

# Look up the tech stack behind many domains

`POST /v1/tech-lookup/domains/batch`

## Request

- Base URL: `https://api.stackscan.com/api`
- URL: `https://api.stackscan.com/api/v1/tech-lookup/domains/batch`
- Auth: HTTP bearer and API key in header `X-Tenant-Id`

Post up to 100 domains and get each one's technologies back in a single
request. This is the batch form of `GET domains/lookup` and costs the
same: **1 credit per domain that resolves**, regardless of how many
technologies come back for it. Domains with no data, and malformed
entries, are never charged.

Returns up to 10 technologies per domain by default; raise it with
`per_domain` (max 50). That ceiling is lower than the single-domain
endpoint's on purpose, because 100 domains x 50 technologies is a very
large response. Use `GET domains/lookup` when you want one domain's
complete stack. Each result carries `total_technologies` and `has_more`
so truncation is never silent.

Every resolved result also carries `premium_technologies`, the count of
paid products in the stack, and `monthly_tech_spend_usd`, the modelled
monthly cost of it. A `premium_technologies` of 0 is an answer rather
than a gap: 83.3% of domains run nothing paid that we price.

Pass `category` to return only technologies in one TOP-LEVEL group, e.g.
`"category": "E-commerce & Sales"` or `"Hosting & Infrastructure"`. It is
     * matched case-insensitively against `parent_category` ONLY. A
     * `child_category` such as `"Payment Processing"` matches nothing, returns
an empty result and charges no credits, which is indistinguishable from a
domain having no data. Note this FILTERS, whereas the `category` query
parameter on `GET domains/lookup` toggles whether the category field
appears in the response.

Each technology is shaped exactly as `GET domains/lookup` shapes it,
`techapi_id`, `name`, `website`, `parent_category`, `child_category`,
`total_sites`, so code written against one endpoint reads the other
unchanged. Until 2026-08-06 this endpoint returned the same data under
`technology`, `category` and `sub_category`; those names are gone.

`techapi_id` replaced the internal `stack_id` on 2026-08-10. The `fields`
toggle names are unchanged, so `fields=stack_id` still works and now
yields `techapi_id`.

Rate limit: 30 requests per minute, counted per API token. Going over returns 429 with `error_code: rate_limited` and a `Retry-After` header in seconds. A 429 costs no credits. Traffic is also subject to a higher shared ceiling per network address, applied before authentication.

## Request body

- object
  - `domains` string[], required
  - `per_domain` integer
  - `category` string: Return only technologies in this top-level group, e.g. "E-commerce & Sales". Matched against parent_category only. Case-insensitive. Omit to return every category.
  - `fields` string[]: Which per-technology fields to include. Omit for all of them. Use this to cut response size on large batches.
  - `fresh` boolean

## Response `200`

Technologies for many domains at once. Charges 1 Bulk Lookup Credit per domain that resolves; misses and malformed entries are free.

- object
  - `success` boolean, required
  - `requested` integer, required
  - `resolved` integer, required
  - `served` integer, required
  - `credits_charged` number, required
  - `per_domain` integer, required
  - `category` string, nullable, required
  - `results` object[], required
    - `success` boolean, required
    - `domain` string, required
    - `technologies` object[]
      - `techapi_id` string, nullable, required
      - `name` string, required
      - `website` string, nullable
      - `slug` string, nullable
      - `parent_category` string, nullable
      - `child_category` string, nullable
      - `total_sites` integer
    - `total_technologies` integer
    - `premium_technologies` integer
    - `monthly_tech_spend_usd` number
    - `has_more` boolean
    - `error` string
  - `not_found` string[], required
  - `invalid` string[], required
  - `skipped_insufficient_credits` string[], required

## Other responses

- `401`: Unauthenticated
- `402`: Insufficient Bulk Lookup Credits.
- `403`: Authorization error
- `422`: Validation error
- `429`: Rate limit exceeded. Costs no credits. Back off for the number of seconds in Retry-After.

---

[API](https://skmtc.dev/stackscan/apis/stackscan-api-reference.md) · [All operations](https://skmtc.dev/stackscan/apis/stackscan-api-reference/llms.txt) · [OpenAPI document](https://skmtc.dev/stackscan/apis/stackscan-api-reference/revisions/66531cd65f3a?raw)
