{
  "openapi": "3.1.0",
  "info": {
    "title": "CareerStudent API",
    "version": "1.0.0",
    "summary": "Openbare, alleen-lezen API met de actuele vacatures van CareerStudent.",
    "description": "CareerStudent bemiddelt werkstudenten, stagiairs en starters aan werkgevers in Nederland (werving en plaatsing, no cure no pay).\n\nDeze API geeft dezelfde vacatures als https://careerstudent.nl/vacatures/ in JSON. Er is geen sleutel nodig. Antwoorden worden enkele minuten gecachet.\n\nFouten komen altijd als `application/problem+json` (RFC 9457) met een vaste `code`, een `hint` en een link naar de documentatie.\n\nElke pagina van de website is ook als Markdown op te vragen met `Accept: text/markdown` op dezelfde URL.",
    "contact": {
      "name": "CareerStudent",
      "url": "https://careerstudent.nl/contact/",
      "email": "info@careerstudent.nl"
    },
    "termsOfService": "https://careerstudent.nl/algemene-voorwaarden/"
  },
  "externalDocs": {
    "description": "Documentatie voor ontwikkelaars",
    "url": "https://careerstudent.nl/developers/"
  },
  "servers": [
    {
      "url": "https://careerstudent.nl",
      "description": "Productie"
    }
  ],
  "tags": [
    {
      "name": "Vacatures",
      "description": "Actuele vacatures voor studenten en starters."
    },
    {
      "name": "Discovery",
      "description": "Ingangen voor agents en ontwikkelaars."
    }
  ],
  "paths": {
    "/api/": {
      "get": {
        "tags": [
          "Discovery"
        ],
        "operationId": "getApiIndex",
        "summary": "Overzicht van de API",
        "description": "Naam, versie en links naar de endpoints en de documentatie.",
        "responses": {
          "200": {
            "description": "API-overzicht.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiIndex"
                }
              }
            }
          }
        }
      }
    },
    "/api/vacatures/": {
      "get": {
        "tags": [
          "Vacatures"
        ],
        "operationId": "listVacancies",
        "summary": "Alle vacatures",
        "description": "Alle vacatures die op careerstudent.nl staan, nieuwste eerst. `current` is false als een vacature langer dan 42 dagen niet is bevestigd.",
        "responses": {
          "200": {
            "description": "De lijst met vacatures.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VacancyList"
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          }
        }
      }
    },
    "/api/vacatures/{slug}/": {
      "get": {
        "tags": [
          "Vacatures"
        ],
        "operationId": "getVacancy",
        "summary": "Eén vacature",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "De slug uit de vacature-URL, bijvoorbeeld `werkstudent-marketing`.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9][a-z0-9-]{0,199}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "De vacature.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VacancyDetail"
                }
              }
            }
          },
          "404": {
            "description": "Geen vacature met deze slug (`vacancy_not_found`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "410": {
            "description": "De vacature is gesloten of verlopen (`vacancy_closed`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Vacancy": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "slug",
          "title",
          "url",
          "applyUrl",
          "category",
          "employmentType",
          "location",
          "city",
          "country",
          "hoursPerWeek",
          "salary",
          "education",
          "summary",
          "description",
          "datePosted",
          "current"
        ],
        "properties": {
          "slug": {
            "type": "string",
            "description": "Vaste sleutel van de vacature."
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "De vacaturepagina."
          },
          "applyUrl": {
            "type": "string",
            "format": "uri",
            "description": "Het sollicitatieformulier."
          },
          "category": {
            "type": [
              "string",
              "null"
            ]
          },
          "employmentType": {
            "type": [
              "string",
              "null"
            ],
            "description": "Werkvorm zoals op de site, bijvoorbeeld Werkstudent, Stage of Starter."
          },
          "location": {
            "type": "string",
            "description": "Plaats, of Remote of Hybride, zoals de site hem toont."
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "country": {
            "type": [
              "string",
              "null"
            ]
          },
          "hoursPerWeek": {
            "type": [
              "string",
              "null"
            ],
            "description": "Uren per week als tekst, bijvoorbeeld 16-24."
          },
          "salary": {
            "type": [
              "string",
              "null"
            ],
            "description": "Vergoeding als tekst, zoals de werkgever hem opgaf."
          },
          "education": {
            "type": [
              "string",
              "null"
            ],
            "description": "Gevraagd opleidingsniveau."
          },
          "summary": {
            "type": [
              "string",
              "null"
            ],
            "description": "Korte omschrijving."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Volledige omschrijving, platte tekst."
          },
          "datePosted": {
            "type": "string",
            "format": "date-time",
            "description": "Laatste bevestiging dat de vacature open is (anders de plaatsingsdatum)."
          },
          "current": {
            "type": "boolean",
            "description": "False na 42 dagen zonder bevestiging."
          }
        }
      },
      "VacancyList": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data",
          "meta",
          "links"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Vacancy"
            }
          },
          "meta": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "count",
              "generatedAt"
            ],
            "properties": {
              "count": {
                "type": "integer",
                "minimum": 0
              },
              "generatedAt": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "links": {
            "$ref": "#/components/schemas/Links"
          }
        }
      },
      "VacancyDetail": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data",
          "links"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Vacancy"
          },
          "links": {
            "$ref": "#/components/schemas/Links"
          }
        }
      },
      "Links": {
        "type": "object",
        "additionalProperties": {
          "type": "string",
          "format": "uri"
        },
        "required": [
          "self",
          "docs",
          "openapi"
        ],
        "properties": {
          "self": {
            "type": "string",
            "format": "uri"
          },
          "docs": {
            "type": "string",
            "format": "uri"
          },
          "openapi": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "ApiIndex": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "name",
          "version",
          "description",
          "links"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "links": {
            "$ref": "#/components/schemas/Links"
          }
        }
      },
      "Problem": {
        "type": "object",
        "description": "RFC 9457 Problem Details met drie extensies: code, hint en docs.",
        "required": [
          "type",
          "title",
          "status",
          "detail",
          "instance",
          "code",
          "hint",
          "docs"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer",
            "minimum": 400,
            "maximum": 599
          },
          "detail": {
            "type": "string"
          },
          "instance": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "enum": [
              "not_found",
              "vacancy_not_found",
              "vacancy_closed",
              "method_not_allowed",
              "unauthorized",
              "not_configured",
              "upstream_unavailable"
            ]
          },
          "hint": {
            "type": "string"
          },
          "docs": {
            "type": "string",
            "format": "uri"
          }
        }
      }
    },
    "responses": {
      "MethodNotAllowed": {
        "description": "Alleen GET (en HEAD) is toegestaan (`method_not_allowed`).",
        "headers": {
          "Allow": {
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      }
    }
  }
}
