ceruleanjobs-com · Schema
SearchResponse
One page of search results.
Luxury JobsRecruitingJob BoardFashionBeautyHospitality
Properties
| Name | Type | Description |
|---|---|---|
| results | array | The requested page, in ranked order. Empty when nothing matches. |
| total | integer | Total listings matching the query across all pages, not the length of `results`. |
| hasMore | boolean | Whether any results remain after this page. |
| limit | integer | The effective page size, after clamping. |
| offset | integer | The effective offset, after clamping. |
| indexBuiltAt | string | When the index that answered this request was built, RFC 3339 in UTC. The pipeline rebuilds roughly every four hours, so this is the precise answer to "how far behind the site is this?". Added in 2.0. |
| warnings | array | Diagnostics about the request that produced this response. Omitted entirely — not emitted as an empty array — when there is nothing to say, which is the common case. Their presence never changes the s |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://artifacts.apis.io/ceruleanjobs-com/json-schema/ceruleanjobs-com-search-response-schema.json",
"title": "SearchResponse",
"description": "One page of search results.",
"x-generated": "2026-11-03",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/ceruleanjobs-com-openapi.yaml#/components/schemas/SearchResponse",
"type": "object",
"required": [
"results",
"total",
"hasMore",
"limit",
"offset"
],
"properties": {
"results": {
"type": "array",
"description": "The requested page, in ranked order. Empty when nothing matches.",
"items": {
"$ref": "#/$defs/SearchResult"
}
},
"total": {
"type": "integer",
"format": "int64",
"minimum": 0,
"description": "Total listings matching the query across all pages, not the length of `results`."
},
"hasMore": {
"type": "boolean",
"description": "Whether any results remain after this page."
},
"limit": {
"type": "integer",
"format": "int32",
"description": "The effective page size, after clamping."
},
"offset": {
"type": "integer",
"format": "int32",
"description": "The effective offset, after clamping."
},
"indexBuiltAt": {
"type": "string",
"format": "date-time",
"description": "When the index that answered this request was built, RFC 3339 in\nUTC. The pipeline rebuilds roughly every four hours, so this is the\nprecise answer to \"how far behind the site is this?\".\n\nAdded in 2.0.0. Omitted in the rare case where the serving process\ncannot determine it.\n"
},
"warnings": {
"type": "array",
"description": "Diagnostics about the request that produced this response. Omitted\nentirely — not emitted as an empty array — when there is nothing to\nsay, which is the common case. Their presence never changes the\nstatus code and never suppresses results.\n\nThe order is fixed rather than incidental: `clamped` (`limit` then\n`offset`), `truncated` in parameter order, `unknown_enum_value` in\nparameter order, `unknown_value` (`brand`, `location`, `country`),\n`unknown_parameter` alphabetically, then `similar_not_found`.\nIdentical requests therefore produce\nbyte-identical bodies, which is what makes them safe to share a CDN\ncache entry.\n\nAdded in 2.0.0.\n",
"items": {
"$ref": "#/$defs/Warning"
}
}
},
"$defs": {
"Brand": {
"type": "object",
"description": "The hiring brand.",
"required": [
"slug",
"name",
"url"
],
"properties": {
"slug": {
"type": "string",
"description": "Brand identifier. Pass to the `brand` filter. Empty string on the rare listing that is not attached to a brand, in which case `name` and `url` are empty too and `logoUrl` is absent."
},
"name": {
"type": "string",
"description": "Display name. Empty string when the listing has no brand."
},
"url": {
"type": "string",
"description": "Absolute URL of the brand's careers page on ceruleanjobs.com, or an empty string when the listing has no brand — the careers page is built from `slug`, so there is none to point at. Added in 2.0.0."
},
"logoUrl": {
"type": "string",
"format": "uri",
"description": "Absolute URL of the brand's logo, omitted when no logo exists. Replaces the `hasLogo` boolean of 1.0.0 — its presence carries the same signal, with the URL attached."
}
}
},
"SearchResult": {
"type": "object",
"description": "A single job listing.",
"required": [
"title",
"slug",
"url",
"city",
"country",
"brand",
"region",
"employmentType",
"seniorityLevel",
"industry",
"department"
],
"properties": {
"title": {
"type": "string",
"description": "Job title. In the language `site` (or the deprecated `lang`) selects, where a translation exists; English otherwise."
},
"slug": {
"type": "string",
"description": "Stable identifier for the listing, and the document's primary key. Pass it to `slug` to fetch this record again, or to `similar` to fetch its neighbours. It is not derived from `url` — `url` is derived from it, and this field is the one to store."
},
"url": {
"type": "string",
"format": "uri",
"description": "Absolute URL of the listing on ceruleanjobs.com. Always the English\n`/jobs/{slug}/` form, in every locale, and it always resolves — it\nis what belongs in an aggregator's database.\n\nIt is usually the page's own `<link rel=\"canonical\">` too. For a\nlisting in a country with an English-language Cerulean site —\nCanada, the UK — that tag names the country site's copy of the\npage, which `site=en-ca` or `site=en-gb` returns as `localizedUrl`.\n\nChanged in 2.0.0: this was the bare path `/jobs/{slug}/` in 1.0.0,\nwith a host to prepend. There is nothing to prepend now.\n"
},
"localizedUrl": {
"type": "string",
"format": "uri",
"description": "The listing's page on a localised site, emitted only when such a\npage actually exists. Two conditions must both hold: `site` names a\nlocalised site other than `en`, and the listing's country is the one\nthat site serves.\n\nSo `site=fr-fr` yields `https://cerulean.fr/emplois/{slug}/`, and\nonly for listings in France; `site=de-ch` yields\n`https://ceruleanjobs.ch/de/stellen/{slug}/`, and only for listings\nin Switzerland. A search scoped to one site still returns jobs\nelsewhere, and those simply carry no `localizedUrl`.\n\nThe deprecated `lang` can still reach this, but only for a language\nnaming exactly one site — `es` and `it` today. `de` names two sites\nand `fr` three, so neither reaches it.\n\n`url` is unaffected either way. Added in 2.0.0.\n"
},
"description": {
"type": "string",
"maxLength": 300,
"description": "Plain-text excerpt, truncated to 300 characters — characters, not bytes, so it never splits an accented word. Omitted when the listing has no description. Truncation here is expected and is not reported in `warnings`."
},
"city": {
"type": "string",
"description": "Title-cased city. Empty string when unknown."
},
"country": {
"type": "string",
"description": "Title-cased country. Empty string when unknown."
},
"datePosted": {
"type": "string",
"format": "date-time",
"description": "When the listing was first collected, RFC 3339 in UTC. Omitted when the listing has no collection timestamp — in 1.0.0 that case was reported as the 1970 epoch."
},
"paintingUrl": {
"type": "string",
"format": "uri",
"description": "Absolute URL of the generated illustration for the listing. Omitted\nwhen there is none — in 1.0.0 that case was an empty string.\n\nThis is the full-size original, 1024 × 1024. Smaller variants are\naddressed by inserting a size segment — `256`, `512`, `768` or\n`1024` — immediately before the filename:\n\n```\nhttps://ceruleanjobs.com/images/paintings/chanel-7.webp\nhttps://ceruleanjobs.com/images/paintings/512/chanel-7.webp\n```\n\nChanged in 2.0.0: absolute rather than a path, and optional.\n"
},
"brand": {
"$ref": "#/$defs/Brand"
},
"region": {
"type": "string",
"description": "Title-cased region or state. Empty string when unknown."
},
"employmentType": {
"type": "string",
"description": "Employment type as a **filter slug**, not a display label — the\nsame value the `employment-type` parameter accepts, so it round-\ntrips: `?employment-type=full-time` returns every listing whose\n`employmentType` is `full-time`. Empty string when unclassified.\n\nCorrected in 2.0.0: 1.0.0 documented a display form (`Full-time`)\nthe API has never returned.\n"
},
"seniorityLevel": {
"type": "string",
"description": "Seniority level as a filter slug, round-tripping into `seniority-level`. Empty string when unclassified. Corrected in 2.0.0, which documented `Senior` rather than `senior`."
},
"industry": {
"type": "string",
"description": "Industry as a filter slug, round-tripping into `industry`. Empty string when unclassified. Corrected in 2.0.0, which documented `Fashion` — a value the enum has never contained."
},
"department": {
"type": "string",
"description": "Department as a filter slug, round-tripping into `department`. Empty string when unclassified. Corrected in 2.0.0, which documented `Production` — a value the enum has never contained."
}
}
},
"Warning": {
"type": "object",
"description": "One thing the endpoint could not use from the request. Warnings are advisory: the request still succeeded, the status is still 200, and any results that could be returned were. Added in 2.0.0.",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "string",
"description": "Machine-readable kind. Treat an unrecognised code as advisory — the\nlist may grow, and a new one is not a breaking change.\n\n* `clamped` — `limit` or `offset` was out of range, zero, negative\n or not a number. The value actually served is in the response's\n own `limit` / `offset` field.\n* `truncated` — a parameter value was longer than 200 characters\n and was cut before searching. The 300-character cap on a result's\n `description` is expected and never warns.\n* `unknown_enum_value` — a filter value that is not a member of its\n enum, so it matched nothing. The message names how many values\n the parameter does accept.\n* `unknown_value` — a `brand`, `location` or `country` that names\n nothing Cerulean has jobs under, so it matched nothing. Values on\n file spelled close to it, if there are any, are in `suggestions`.\n Added in 2.2.0.\n* `unknown_parameter` — a query-string key this endpoint does not\n read; it was ignored. At most 10 are reported, and each echoed\n name is itself truncated to 200 characters. On\n `https://ceruleanjobs.com` the CDN normally strips such a key\n before the service sees it, so this code is rarely observed in\n production.\n* `similar_not_found` — no embedding exists for the `similar` slug,\n so similarity ranking was skipped. A `brand` filter sent with the\n request is also applied rather than ignored, which is the one case\n where `brand` is not suppressed in similarity mode; the message\n says so only when a `brand` was actually sent.\n",
"enum": [
"clamped",
"truncated",
"unknown_enum_value",
"unknown_value",
"unknown_parameter",
"similar_not_found"
]
},
"parameter": {
"type": "string",
"description": "The query parameter the warning is about. Every code currently emitted names one, but treat it as optional."
},
"message": {
"type": "string",
"description": "Human-readable explanation of what happened and what was done instead. Written to be shown to a person or logged as-is."
},
"suggestions": {
"type": "array",
"maxItems": 5,
"description": "On an `unknown_value` warning, when there are any: up to five values the parameter accepts that are spelled close to the one sent, closest first. Each can be sent back as it is. Added in 2.2.0.",
"items": {
"type": "string"
}
}
}
}
}
}
Work with this as data
Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for schemas
4 MCP tools reach this
find_json_schemasBrowse and filter every JSON Schema in the catalog.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/ceruleanjobs-com-search-response"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.