# Startupland for agents

Startupland is a structured directory of startups, people, tags, financing rounds, investors, sources, and logo assets. Agents should prefer the read-only JSON API over parsing the visual site.

Base URL: `https://startupland.pages.dev`

Machine-readable index: `GET /api/public` (endpoint directory) and `GET /api/public/openapi.json` (OpenAPI 3.1).

## Recommended workflow

1. Use company lookup when starting from a name, alias, or domain.
2. Fetch company detail directly by exact name or UUID.
3. Use the compact company index for bulk discovery.
4. Follow each round's `sources` when evidence or attribution is required.
5. Use the logo endpoint only when an image asset is needed.

Fields may be `null`, and lists may be empty. Company IDs and tag IDs are UUIDs. All endpoints below are public, read-only `GET` endpoints.

## Company lookup

`GET /api/public/lookup?q=<name-or-domain>`

Returns up to 10 ranked matches across tracked and reference companies. Set `limit` from 1 to 25 when needed. Results include the company UUID, aliases, status, whether the record is reference-only, latest round, round count, and `headline_valuation` provenance.

```sh
curl -fsS "https://startupland.pages.dev/api/public/lookup?q=OpenAI"
```

For an exact company or alias, skip the second request and fetch full detail by name:

```sh
curl -fsS "https://startupland.pages.dev/api/public/company?name=OpenAI"
```

## Company index

`GET /api/public/companies`

Returns a JSON array of non-reference companies. The response is optimized for discovery and includes:

- identity: `id`, `company`, `description`, `status`, `founded`
- location: `hq`, `hq_city`, `hq_region`, `hq_metro`, `jurisdiction`
- links: `url`, `linkedin`, `twitter`, `wikipedia`
- classification: `tags[]` with `id`, `name`, and `parent_id`
- people search: `search_people[]` with `name` and `roles`
- latest financing summary: `last_round_at` and `latest_round`
- headline financing fields: `last_known_valuation`, `last_known_round`, `lead_investors`, and `headline_valuation`
- logo metadata: `assets[]` with `kind`, `mime`, and `updated_at`
- map coordinates: `x2`, `y2`, `x3`, `y3`, `z3`, and `cluster`

The endpoint is not paginated, excludes reference-only records, and is cached for 120 seconds. Use company lookup when a company is absent from this discovery feed.

```sh
curl -fsS https://startupland.pages.dev/api/public/companies
```

### Filtering the index

The index accepts optional, case-insensitive filters. They combine with `AND`, and
selecting a **parent** tag includes all of its descendants (so `category=Model Inference`
returns every inference sub-type). Tag filters accept the **human name or its slug** —
`category=Model%20Inference` and `category=model-inference` are equivalent.

- `q=<text>` — match company name or description
- `category=<name|slug>` — Category-facet tag, e.g. `Model Inference` / `model-inference`, `Payments`, `Legal Operations`
- `layer=<Apps|Infra>`
- `vertical=<name|slug>` — e.g. `Financial Services`, `Healthcare Delivery`
- `tag=<name|slug>` — any tag, regardless of facet
- `status=<active|acquired|public|defunct|pivoted|all>` — comma-separated; **default is `all`** (the visual explorer defaults to `active` only, so pass `status=active` to match what the site shows)
- `limit=<n>` — cap results (1–2000)
- `meta=1` — wrap the response as `{ query, counts, companies }`, where `counts` is the per-status breakdown (`active`, `acquired`, `public`, …, `total`) for the tag/text filters, ignoring `status`. The `X-Total-Count` header always carries the returned count.

```sh
# every AI-inference company, in one call (any status)
curl -fsS "https://startupland.pages.dev/api/public/companies?category=model-inference"

# active-only, with status counts
curl -fsS "https://startupland.pages.dev/api/public/companies?category=model-inference&status=active&meta=1"

# infra-layer security companies
curl -fsS "https://startupland.pages.dev/api/public/companies?layer=Infra&category=Security"
```

## Taxonomy (tags)

`GET /api/public/tags`

Returns the full active tag tree as a flat array. Tags belong to one of three **facets** —
`layer` (Apps/Infra), `category` (what the product does), and `vertical` (industry served) —
and form a single-parent hierarchy within each facet. Each row includes `id`, `name`,
`parent_id`, `facet`, `path` (breadcrumb), `depth`, `layer_affinity`, plus two counts:
`primary_count` (companies whose *primary* tag this is) and `inclusive_count` (companies on
this tag **or any descendant**). Use this to discover the exact tag names accepted by the
index filters above.

```sh
curl -fsS https://startupland.pages.dev/api/public/tags
```

### Worked example: "pull me the inference companies"

1. `GET /api/public/tags` and find the category subtree under **Model Deployment**:
   `Model Inference` (with children `Generalist Inference`, `Media Inference`, `Edge Inference`, …),
   `Model Routing`, `Model Observability`.
2. `GET /api/public/companies?category=Model%20Inference` — one call returns all inference
   companies (parent match includes the sub-types). Read `company`, `description`,
   `headline_valuation`, `last_known_round`, and `tags[]` from each row.
3. For deeper detail on any hit, follow up with `GET /api/public/company?id=<uuid>`.

## Company detail

`GET /api/public/company?id=<company-uuid>`

`GET /api/public/company?name=<exact-company-or-alias>`

Returns one tracked or reference company with its full public `team[]`, `rounds[]`, and `stats`. The stats summary includes `round_count`, `latest_round_at`, `last_known_valuation`, `headline_valuation`, `latest_round`, and `latest_priced_round`.

`headline_valuation` contains:

- `value`: the curated headline figure
- `status`: `sourced`, `unsourced`, or `unknown`
- `basis`: such as `priced_round`, `secondary_transaction`, `tender_offer`, `estimate`, or `curated_record`
- `as_of`: the date represented by the value, when known
- `round_id`: the supporting financing round, when applicable
- `provenance_updated_at`: when the provenance record was last changed
- `sources[]`: supporting links; empty means the headline is not citation-safe

Use a `sourced` headline valuation or `latest_priced_round` with sources for an auditable claim. Do not present an `unsourced` headline as authoritative. Each round can include:

- `positioning`, `amount`, `valuation`, `one_liner`, `description`, `announced_at`
- `parties[]`, including lead/participant roles and associated people
- `sources[]`, including absolute `href`, stored `url`, `title`, and `source_type`

Use a UUID from the index/lookup endpoint or an exact company name. A missing identifier returns `400`; an unknown company returns `404`.

```sh
curl -fsS "https://startupland.pages.dev/api/public/company?id=<company-uuid>"
```

## Logo assets

`GET /api/public/logo?company=<company-uuid>&kind=<kind>`

`kind` must be one of:

- `brandmark`: icon or symbol only
- `wordmark`: stylized company name only
- `combinedmark`: icon and wordmark lockup

The response body is the image itself. Use the matching `mime` and `updated_at` values from the company index. Add `v=<updated_at>` for a stable, immutable cache key.

```sh
curl -fsS "https://startupland.pages.dev/api/public/logo?company=<company-uuid>&kind=combinedmark" -o logo.svg
```

## Shareable site URLs

The visual explorer at `/` accepts these query parameters:

- `q`: company, description, tag, or person search text
- `tags`: comma-separated included tag UUIDs
- `ex`: comma-separated excluded tag UUIDs
- `pub=1`: include public companies
- `acq=1`: include acquired companies
- `hq`: `m:<metro>`, `country:<country>`, or `city:<city>`
- `view`: `cards` or `map`
- `sort`: `recent`, `name`, `founded_desc`, or `founded_asc`

Open a company profile with `/#/c/<company-uuid>`. Prefer the JSON API for extraction; use site URLs when returning a human-readable view.

## Usage notes

- Do not call `/admin` or non-public `/api/*` routes; they are protected write and administration surfaces.
- Do not infer missing values. Preserve `null` and empty arrays.
- Treat round sources as the citation trail for financing claims.
- Treat `headline_valuation.status = unsourced` as a warning, not a verified valuation.
- Respect the 120-second public cache instead of repeatedly polling unchanged records.
- Descriptions are intentionally terse and are not complete company profiles.
