{
  "openapi": "3.1.0",
  "info": {
    "title": "Tarve public data API",
    "version": "1.0.0",
    "summary": "UK visa sponsorship data: licensed sponsors, SOC going rates, live sponsored jobs, register changes.",
    "description": "Read-only, anonymous, rate-limited (300 requests a minute per IP). Every response carries a `source` object: cite the page URL and the attribution line. Contains public sector information licensed under the Open Government Licence v3.0.",
    "contact": { "name": "Tarve", "url": "https://tarve.co.uk/developers" },
    "license": { "name": "Open Government Licence v3.0", "url": "https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/" }
  },
  "servers": [{ "url": "https://api.tarve.co.uk" }],
  "paths": {
    "/api/public/sponsors/check": { "get": { "operationId": "checkSponsor", "summary": "Is this organisation a licensed sponsor?", "parameters": [{ "name": "name", "in": "query", "required": true, "schema": { "type": "string", "maxLength": 120 } }], "responses": { "200": { "description": "Best match (null when nothing resembles the name) and up to 5 alternatives.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SponsorCheck" } } } } } } },
    "/api/public/sponsors/{slug}": { "get": { "operationId": "getSponsor", "summary": "One sponsor by its tarve.co.uk company page slug.", "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "The sponsor.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SponsorCheck" } } } }, "404": { "description": "Unknown slug." } } } },
    "/api/public/sponsors": { "get": { "operationId": "searchSponsors", "summary": "Search the register.", "parameters": [
          { "name": "q", "in": "query", "schema": { "type": "string", "maxLength": 120 } },
          { "name": "town", "in": "query", "schema": { "type": "string", "maxLength": 80 } },
          { "name": "route", "in": "query", "schema": { "type": "string", "maxLength": 80 } },
          { "name": "rating", "in": "query", "schema": { "type": "string", "maxLength": 40 } },
          { "name": "has_jobs", "in": "query", "schema": { "type": "boolean" } },
          { "name": "page", "in": "query", "schema": { "type": "integer", "minimum": 1, "default": 1 } },
          { "name": "per_page", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 } } ],
        "responses": { "200": { "description": "A page of sponsors.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SponsorList" } } } } } } },
    "/api/public/soc/{code}": { "get": { "operationId": "getSocCode", "summary": "Going rate, thresholds, skill level and ISL/TSL status for one SOC 2020 code.", "parameters": [{ "name": "code", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^[0-9]{4}$" } }], "responses": { "200": { "description": "The code.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Soc" } } } }, "404": { "description": "Not a code in the gov.uk table." } } } },
    "/api/public/soc": { "get": { "operationId": "searchSocCodes", "summary": "Find SOC codes by occupation text.", "parameters": [{ "name": "q", "in": "query", "required": true, "schema": { "type": "string", "maxLength": 80 } }], "responses": { "200": { "description": "Up to 10 codes.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SocList" } } } } } } },
    "/api/public/jobs": { "get": { "operationId": "listJobs", "summary": "Live sponsored jobs (the /jobs listing as JSON).", "parameters": [
          { "name": "q", "in": "query", "schema": { "type": "string", "maxLength": 80 } },
          { "name": "city", "in": "query", "schema": { "type": "string", "maxLength": 100 } },
          { "name": "soc", "in": "query", "schema": { "type": "string", "pattern": "^[0-9]{4}$" } },
          { "name": "company", "in": "query", "schema": { "type": "string", "maxLength": 100 } },
          { "name": "min_salary", "in": "query", "schema": { "type": "integer", "minimum": 0 } },
          { "name": "page", "in": "query", "schema": { "type": "integer", "minimum": 1, "default": 1 } },
          { "name": "per_page", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 50, "default": 20 } } ],
        "responses": { "200": { "description": "A page of jobs.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JobsList" } } } } } } },
    "/api/public/register/changes": { "get": { "operationId": "registerChanges", "summary": "Organisations added to and removed from the register in a period (at most 93 days).", "parameters": [
          { "name": "from", "in": "query", "required": true, "schema": { "type": "string", "format": "date" } },
          { "name": "to", "in": "query", "required": true, "schema": { "type": "string", "format": "date" } } ],
        "responses": { "200": { "description": "Counts and the first 500 rows each.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RegisterChanges" } } } }, "400": { "description": "Bad dates or a range over 93 days." } } } },
    "/api/public/stats/summary": { "get": { "operationId": "statsSummary", "summary": "Live job and employer counts.", "responses": { "200": { "description": "Counts." } } } },
    "/api/public/stats/soc": { "get": { "operationId": "statsSoc", "summary": "Live public jobs per SOC code.", "responses": { "200": { "description": "Counts by code." } } } },
    "/api/public/jobs/{slug}": { "get": { "operationId": "getJob", "summary": "One job as JSON.", "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "The job." }, "404": { "description": "Unknown." }, "410": { "description": "No longer live." } } } }
  },
  "components": { "schemas": {
      "Source": { "type": "object", "properties": { "name": { "type": "string" }, "url": { "type": "string", "format": "uri" }, "attribution": { "type": "string" }, "register_checked_at": { "type": ["string", "null"], "format": "date-time" }, "licence": { "type": "string" } } },
      "Sponsor": { "type": "object", "properties": { "slug": { "type": ["string", "null"] }, "organisation_name": { "type": "string" }, "town": { "type": ["string", "null"] }, "county": { "type": ["string", "null"] }, "is_licensed": { "type": "boolean" }, "rating": { "type": ["string", "null"] }, "routes": { "type": "array", "items": { "type": "string" } }, "first_seen_on_register": { "type": ["string", "null"], "format": "date-time" }, "last_seen_on_register": { "type": ["string", "null"], "format": "date-time" }, "removed_from_register_at": { "type": ["string", "null"], "format": "date-time" }, "companies_house_number": { "type": ["string", "null"] }, "live_jobs": { "type": "integer" }, "live_jobs_url": { "type": ["string", "null"] }, "page_url": { "type": "string" }, "soc_codes_hiring": { "type": ["array", "null"], "items": { "type": "string" } } } },
      "SponsorCheck": { "type": "object", "properties": { "query": { "type": "string" }, "match": { "oneOf": [{ "$ref": "#/components/schemas/Sponsor" }, { "type": "null" }] }, "alternatives": { "type": "array", "items": { "type": "object", "properties": { "slug": { "type": ["string", "null"] }, "organisation_name": { "type": "string" }, "town": { "type": ["string", "null"] }, "is_licensed": { "type": "boolean" } } } }, "source": { "$ref": "#/components/schemas/Source" } } },
      "SponsorList": { "type": "object", "properties": { "total": { "type": "integer" }, "page": { "type": "integer" }, "per_page": { "type": "integer" }, "sponsors": { "type": "array", "items": { "$ref": "#/components/schemas/Sponsor" } }, "source": { "$ref": "#/components/schemas/Source" } } },
      "Soc": { "type": "object", "properties": { "code": { "type": "string" }, "title": { "type": "string" }, "going_rate_annual": { "type": ["number", "null"] }, "going_rate_hourly": { "type": ["number", "null"] }, "national_pay_scale": { "type": "boolean" }, "lower_rate_annual": { "type": ["number", "null"] }, "general_threshold": { "type": "number" }, "lower_threshold": { "type": "number" }, "effective_minimum": { "type": ["number", "null"] }, "skill_level": { "type": "string", "enum": ["higher", "medium", "ineligible", "unknown"] }, "isl": { "type": "boolean" }, "isl_until": { "type": ["string", "null"], "format": "date" }, "tsl": { "type": "boolean" }, "tsl_until": { "type": ["string", "null"], "format": "date" }, "eligible_skilled_worker": { "type": "boolean" }, "rules_effective_from": { "type": "string", "format": "date" }, "live_jobs": { "type": "integer" }, "live_jobs_url": { "type": "string" }, "page_url": { "type": "string" }, "source": { "$ref": "#/components/schemas/Source" } } },
      "SocList": { "type": "object", "properties": { "query": { "type": "string" }, "codes": { "type": "array", "items": { "$ref": "#/components/schemas/Soc" } }, "source": { "$ref": "#/components/schemas/Source" } } },
      "Job": { "type": "object", "properties": { "slug": { "type": "string" }, "title": { "type": "string" }, "company": { "type": ["string", "null"] }, "company_slug": { "type": ["string", "null"] }, "city": { "type": ["string", "null"] }, "salary_min": { "type": ["number", "null"] }, "salary_max": { "type": ["number", "null"] }, "currency": { "type": ["string", "null"] }, "soc_code": { "type": ["string", "null"] }, "soc_skill_level": { "type": "string" }, "new_application_eligible": { "type": ["boolean", "null"] }, "posted_at": { "type": "string", "format": "date-time" }, "url": { "type": "string" }, "apply_url": { "type": "string" } } },
      "JobsList": { "type": "object", "properties": { "total": { "type": "integer" }, "page": { "type": "integer" }, "per_page": { "type": "integer" }, "jobs": { "type": "array", "items": { "$ref": "#/components/schemas/Job" } }, "listing_url": { "type": "string" }, "source": { "$ref": "#/components/schemas/Source" } } },
      "RegisterChanges": { "type": "object", "properties": { "from": { "type": "string", "format": "date" }, "to": { "type": "string", "format": "date" }, "added_count": { "type": "integer" }, "removed_count": { "type": "integer" }, "added": { "type": "array", "items": { "$ref": "#/components/schemas/RegisterChangeRow" } }, "removed": { "type": "array", "items": { "$ref": "#/components/schemas/RegisterChangeRow" } }, "added_csv_url": { "type": ["string", "null"] }, "removed_csv_url": { "type": ["string", "null"] }, "source": { "$ref": "#/components/schemas/Source" } } },
      "RegisterChangeRow": { "type": "object", "properties": { "organisation_name": { "type": "string" }, "town": { "type": ["string", "null"] }, "route": { "type": ["string", "null"] }, "rating": { "type": ["string", "null"] }, "at": { "type": "string", "format": "date-time" } } }
  } }
}
