---
title: Resolve a domain to its owning org and any matching products
description: >-
  Normalizes the input domain (lowercased, no scheme/path/www), exact-matches
  against organizations.domain (primary) and domain_aliases.domain (alias for
  either an org or a product), and returns whateve
---
# Resolve a domain to its owning org and any matching products

`GET https://api.releases.sh/v1/lookups/by-domain`

Normalizes the input domain (lowercased, no scheme/path/www), exact-matches against `organizations.domain` (primary) and `domain_aliases.domain` (alias for either an org or a product), and returns whatever it finds.

On a complete miss, when `listing-self-serve-enabled` is on, the handler may probe `https://{domain}/.well-known/releases.json` in-request and materialize a stub org (basis: declared) via the same core as the listing activate path and the domain-demand cron. Probe budget is per-domain (a few attempts per ~10 min rolling window) plus a per-IP rate limit on the outbound branch; budget exhaustion returns 404 (not 429). Misses still record `domain_demand` for the nightly sweep backstop.

Products can be populated even when `org` is null — a product alias may point at a domain its parent org doesn't claim as primary.

**Auth:** optional Bearer token.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `domain` | query | string | yes | Hostname to resolve. Server normalizes (lowercases, strips scheme/path/www). |

**Responses**

- `200` Resolved org and/or product matches (including a just-materialized stub)
- `400` Missing or invalid `domain` query parameter
- `404` Domain doesn't match any registered org or product (and JIT found no valid manifest)
- `429` Per-IP rate limit on the outbound JIT probe branch

Full request and response schemas: [OpenAPI 3.1 spec](https://api.releases.sh/v1/openapi.json).
