{
  "description": "Search Jobgether job opportunities. Intended for AI agents/assistants answering user job-search queries. Each job's `url` is its Jobgether listing page, not an external apply link. Results are capped at 25 per page.",
  "endpoint": "/api/v1/jobs",
  "endpointAliases": [
    "/astroapi/ai/jobs.json"
  ],
  "mcpEndpoint": "/mcp",
  "methods": [
    "GET",
    "POST"
  ],
  "methodNotes": "GET takes parameters as query string params. POST takes the same parameters as a JSON object body (Content-Type: application/json) — array-valued params (jobReferences, locations, industries, contractType, experience) may be given as a JSON array or a comma-separated string. Both methods accept the same parameters and return the same response shape.",
  "parameters": [
    {
      "name": "keyword",
      "type": "string",
      "required": false,
      "description": "Free-text search across job title, job function, skills, company name, contract type, and language.",
      "example": "react developer"
    },
    {
      "name": "jobReferences",
      "type": "string[] (comma-separated or repeated)",
      "required": false,
      "description": "Job function slugs (e.g. \"frontend-developer\"). Unknown values return a 400 error — there is no fixed enum, this is a large taxonomy; when unsure, omit and rely on `keyword` instead.",
      "example": "frontend-developer,backend-developer"
    },
    {
      "name": "locations",
      "type": "string[] (comma-separated or repeated)",
      "required": false,
      "description": "Location slugs — country, continent, or city (e.g. \"spain\", \"europe\", \"worldwide\"). Unknown values return a 400 error.",
      "example": "spain,france"
    },
    {
      "name": "industries",
      "type": "string[] (comma-separated or repeated)",
      "required": false,
      "description": "Industry slugs or ids.",
      "example": "fintech"
    },
    {
      "name": "contractType",
      "type": "string[] (comma-separated or repeated)",
      "required": false,
      "description": "Employment type.",
      "allowedValues": [
        "full-time",
        "part-time",
        "fixed-term",
        "freelance",
        "internships"
      ],
      "example": "full-time"
    },
    {
      "name": "experience",
      "type": "string[] (comma-separated or repeated)",
      "required": false,
      "description": "Seniority level required.",
      "allowedValues": [
        "entry-level-graduate",
        "junior-1-2-years",
        "mid-level-2-5-years",
        "senior-5-10-years",
        "expert-10-years"
      ],
      "example": "senior-5-10-years"
    },
    {
      "name": "remoteType",
      "type": "string",
      "required": false,
      "description": "Degree of remote work. All jobs on this platform are remote-friendly by default (Full Remote); use this to widen or narrow that.",
      "allowedValues": [
        "full-remote",
        "remote-first",
        "hybrid"
      ],
      "example": "full-remote"
    },
    {
      "name": "includeHybrid",
      "type": "boolean (\"true\"/\"false\")",
      "required": false,
      "description": "When \"true\", also include hybrid roles alongside remote ones.",
      "example": "true"
    },
    {
      "name": "salaryMin",
      "type": "number",
      "required": false,
      "description": "Minimum annual salary filter, in the given `currency`.",
      "example": "60000"
    },
    {
      "name": "salaryMax",
      "type": "number",
      "required": false,
      "description": "Maximum annual salary filter, in the given `currency`.",
      "example": "90000"
    },
    {
      "name": "currency",
      "type": "string",
      "required": false,
      "description": "ISO currency code for the salary filters.",
      "example": "EUR"
    },
    {
      "name": "sort",
      "type": "string",
      "required": false,
      "description": "Result ordering. Defaults to \"relevance\".",
      "allowedValues": [
        "relevance",
        "date"
      ],
      "example": "date"
    },
    {
      "name": "page",
      "type": "integer",
      "required": false,
      "description": "Page number, starting at 1. Capped at 10.",
      "example": "1"
    },
    {
      "name": "limit",
      "type": "integer",
      "required": false,
      "description": "Results per page. Defaults to 10, capped at 25.",
      "example": "10"
    }
  ],
  "errorFormat": {
    "description": "Errors are RFC 9457 problem documents served as `application/problem+json`. Branch on `code` — it is the stable machine-readable discriminator; `title` and `detail` are human-facing and may be reworded. On invalid input the offending `field` and its complete `allowedValues` are included so a caller can correct the call and retry without a lookup. The `error`, `field`, `allowedValues` and `docs` members predate the RFC 9457 adoption and are retained, so integrations written against the older shape keep working.",
    "contentType": "application/problem+json",
    "codes": {
      "invalid_parameter": "400 — a parameter is missing, malformed, or outside its allowed values.",
      "invalid_body": "400 — the POST body was not valid JSON.",
      "not_found": "404 — no endpoint at that path. The response lists the endpoints that do exist.",
      "timeout": "504 — the search exceeded its server-side budget. Retry with a narrower query.",
      "internal_error": "500 — unexpected server error."
    },
    "example": {
      "type": "/astroapi/ai/jobs/docs#invalid_parameter",
      "title": "Invalid parameter",
      "status": 400,
      "detail": "Invalid value for 'experience': \"senior\"",
      "code": "invalid_parameter",
      "field": "experience",
      "allowedValues": [
        "entry-level-graduate",
        "junior-1-2-years",
        "mid-level-2-5-years",
        "senior-5-10-years",
        "expert-10-years"
      ],
      "error": "Invalid value for 'experience': \"senior\"",
      "docs": "/astroapi/ai/jobs/docs"
    }
  },
  "versioning": {
    "description": "The REST API is versioned in the URL path; `/api/v1/jobs` is the current stable surface. Within a version only backward-compatible changes ship (new optional parameters, new response fields, new enum values). A change that would break an existing caller ships as `/api/v2/...` instead, leaving `/v1/` answering as before.",
    "deprecationPolicy": "A superseded path keeps serving and announces its retirement rather than failing: a `Deprecation` header (RFC 9745) with the date it was deprecated, a `Sunset` header (RFC 8594) with the date it stops responding — at least 30 days later — and `Link: <successor>; rel=\"successor-version\"`. JSON responses from a deprecated path also carry a `deprecation` object, so a caller reading only the body still sees it.",
    "currentlyDeprecated": [
      {
        "path": "/astroapi/ai/jobs",
        "successor": "/api/v1/jobs",
        "sunset": "2026-09-28"
      }
    ]
  },
  "exampleRequests": [
    {
      "description": "Remote frontend jobs in Spain paying over 50k EUR",
      "query": "/api/v1/jobs?keyword=frontend&locations=spain&salaryMin=50000&currency=EUR"
    },
    {
      "description": "Senior full-time roles, most recent first",
      "query": "/api/v1/jobs?experience=senior-5-10-years&contractType=full-time&sort=date"
    },
    {
      "description": "Include hybrid roles in Europe",
      "query": "/api/v1/jobs?locations=europe&includeHybrid=true&limit=5"
    },
    {
      "description": "Same as the first example, sent as a POST",
      "method": "POST",
      "query": "/api/v1/jobs",
      "body": {
        "keyword": "frontend",
        "locations": [
          "spain"
        ],
        "salaryMin": 50000,
        "currency": "EUR"
      }
    }
  ],
  "exampleResponse": {
    "jobs": [
      {
        "id": "65f1a2b3c4d5e6f7a8b9c0d1",
        "title": "Senior Frontend Developer",
        "company": "Acme Inc.",
        "url": "https://www.jobgether.com/offer/senior-frontend-developer-acme-inc",
        "location": "Spain, France",
        "remote": "Full Remote",
        "contractType": "Full time",
        "experience": "Senior (5-10 years)",
        "salaryRange": "60000-80000 EUR",
        "jobFunctions": [
          "Frontend Developer"
        ],
        "postedAt": "2026-07-01T00:00:00.000Z"
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 10,
      "hasMore": true
    },
    "browseOnSiteUrl": "https://www.jobgether.com/search-offers?keyword=frontend",
    "docs": "/astroapi/ai/jobs/docs"
  },
  "notes": [
    "Pagination is done through this API's own `page`/`limit` params — increment `page` and re-request to get the next batch of results. `pagination.hasMore` tells you whether another page exists.",
    "`browseOnSiteUrl` is NOT a paginator and does not return more/different results than this response. It is a human-facing link to the same search rendered on jobgether.com, for offering the user a place to browse interactively — not a mechanism for the agent to fetch further pages.",
    "If you are wiring this endpoint up via Anthropic's web_fetch tool, set `use_cache: false` on the tool definition itself (not as a URL query parameter). Job listings change frequently, so fetches of this endpoint should not be served from the tool's own cache."
  ]
}