- API reference
- Endpoints
Retrieve a company
Fetch one company profile by slug — the cheapest path to the full profile when a job or a company search has already handed you the slug.
https://api.hyperjobs.io/v1/companies/{slug}One company profile by slug. When you already have a slug — off a job or a
company search result — this is the
cheapest way to the full profile.
curl -H "Authorization: Bearer $HYPERJOBS_KEY" \
"https://api.hyperjobs.io/v1/companies/linear"Path parameters#
slugThe company's slug, matched exactly. No normalisation beyond
URL-decoding — no case-folding, no fuzzy matching, no lookup by name or
domain.
Slugs are LinkedIn-style: usually lower-case and hyphenated, and usually recognisable from the company name. "Usually" isn't "always" — see where slugs come from.
No query parameters. The full profile is always returned; there's nothing optional to request.
Where slugs come from#
Don't construct a slug from a company name
Slugs resemble company names often enough to be dangerous. Linear → linear
works; the next one you guess won't, and a wrong guess is an indistinguishable
404 rather than a hint.
// Wrong. Works for maybe half of companies, silently 404s for the rest.
const slug = name.toLowerCase().replace(/\s+/g, "-");Always read the slug from data you were given — and when you only have a name,
search for it: /v1/companies?q= does
substring name matching and returns the real slug.
Two reliable sources:
| Source | How |
|---|---|
| A job | job.company.slug — present on 99.9997% of postings |
| The search endpoint | /v1/companies — ?q= name search, plus industry, HQ country, and size filters |
In practice this endpoint is the second half of a jobs query: filter jobs, take
company.slug off a result, fetch the profile.
// The normal flow — the slug comes from the data, never from a string transform.
const { data } = await getJobs({ organization: "linear", limit: 1 });
const slug = data[0]?.company?.slug;
if (slug) {
const company = await getCompany(slug);
}A job's company may have no slug
When a posting doesn't resolve to a profile, job.company is a minimal
fallback with no slug — and
nothing to look up here. Guard it rather than interpolating undefined into
the path, which produces a confusing 404 on /v1/companies/undefined.
Response#
The company object itself, not wrapped:
{
"slug": "linear",
"name": "Linear",
"domain": "linear.app",
"website": "https://linear.app",
"logo": "https://media.licdn.com/dms/image/…",
"industry": "Software Development",
"type": "Privately Held",
"description": "Linear is a purpose-built tool for planning and building products…",
"slogan": "The issue tracking tool you'll enjoy using",
"specialties": ["issue tracking", "project management", "developer tools"],
"employee_count": 120,
"size_range": "51-200",
"followers": 48210,
"founded_year": 2019,
"hq": {
"country": "US",
"region": "California",
"locality": "San Francisco",
"raw": "San Francisco, California, United States"
},
"funding": {
"rounds": 4,
"last_round_type": "Series B",
"last_round_date": "2022-06-15",
"last_round_amount_usd": 35000000,
"total_investment_usd": 52000000,
"crunchbase_slug": "linear-2",
"crunchbase_categories": ["Software", "Productivity Tools"]
},
"stock": null,
"affiliated_companies": [],
"data_tier": "remco",
"jobs_count": 12,
"updated_at": "2026-07-02T09:14:33.000Z"
}This response is not wrapped in `data`
/v1/companies returns { data: [ … ] }.
This endpoint returns the company at the top level, matching
/v1/jobs/{id}. A shared response handler
that reaches for .data gets undefined here.
Every field is documented in the Company object. Three worth re-reading before you build on this payload:
hq.countryis ISO-2 ("US"), while a job'slocation.countriesare full names (["United States"]). Joining them needs a mapping table.hq,funding, andstockare null when the underlying data is absent — andstock: nullis not evidence a company is private.jobs_countis live — the company's non-duplicate, non-expired openings in the pool right now, recomputed roughly every 15 minutes.0means not currently hiring, not "no data".
The profile returned here is identical to the one embedded on a job. Fetching
it is only worth a request when you have a slug but no job in hand — if you
just got the job, you already have the whole company object.
Freshness#
updated_at is when the profile last
refreshed, which has nothing to do with job
ingestion. A job posted an hour ago
routinely carries a company profile that's months old. That's expected —
headcount and funding move on their own timescale.
Errors#
| Status | Cause |
|---|---|
401 | Missing, unknown, or revoked key. |
404 | No company with that slug. |
429 | Rate limit exceeded. |
500 | Server error. Retry with backoff. |
{ "error": "not found" }A 404 means no profile has that slug — most often a constructed or misremembered
one. It carries no detail, and retrying won't change it: treat it as "no such
company" and move on rather than as an error to back off from. To recover, search
for the name — /v1/companies?q= — or go
back to a jobs query and read the real slug off
company.slug.
Related#
Every field in the response above.
List companiesThe search endpoint — find a slug by name, industry, country, or size.
Company dataFirmographics — server-side filters and the embedded-company model.
The Job objectWhere company.slug comes from.