{
    "openapi": "3.1.0",
    "info": {
        "title": "Concours Radar API",
        "version": "1.0.0",
        "description": "Open, read-only API listing every concours (competitive exam) in Morocco — school entrance exams, public-sector recruitment, security forces, professional exams — in French and Arabic. No key required. Please cite \"Concours Radar\" and link to the concours page (field `url`).",
        "license": {
            "name": "CC BY 4.0",
            "url": "https://creativecommons.org/licenses/by/4.0/"
        }
    },
    "servers": [
        {
            "url": "https://mail.concoursradar.com"
        }
    ],
    "paths": {
        "/api/v1/concours.json": {
            "get": {
                "operationId": "searchConcours",
                "summary": "Search and filter concours",
                "description": "Returns concours sorted by urgency (closing soon first) unless `sort` is given. Use status=open for everything you can apply to today.",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "description": "Free text (French or Arabic): school, ministry, job title, city, acronym. E.g. \"ENSA\", \"police\", \"infirmier\", \"الأساتذة\".",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "description": "Comma-separated: open (open+closing), active, closing, soon, exam, results, expected, closed.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "category",
                        "in": "query",
                        "required": false,
                        "description": "Category slug (see /api/v1/categories.json).",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "level",
                        "in": "query",
                        "required": false,
                        "description": "sans | niveau_scolaire | bac | bac+2 | bac+3 | bac+5 | doctorat",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "kind",
                        "in": "query",
                        "required": false,
                        "description": "ecole | recrutement | examen_pro",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "city",
                        "in": "query",
                        "required": false,
                        "description": "City slug (see /api/v1/cities.json), \"national\" for nationwide.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "organisme",
                        "in": "query",
                        "required": false,
                        "description": "Organisme slug (see /api/v1/organismes.json).",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "required": false,
                        "description": "deadline | exam | recent | az (default: urgency)",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "lang",
                        "in": "query",
                        "required": false,
                        "description": "fr (default) or ar — localizes title, summary, conditions.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "fields",
                        "in": "query",
                        "required": false,
                        "description": "\"compact\" to omit long text fields.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "include_closed",
                        "in": "query",
                        "required": false,
                        "description": "0 to exclude finished editions.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "required": false,
                        "description": "Page number (1-based).",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "per",
                        "in": "query",
                        "required": false,
                        "description": "Items per page, max 200 (default 50).",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "List of concours",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ConcoursList"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/concours/{slug}.json": {
            "get": {
                "operationId": "getConcours",
                "summary": "One concours with dates, conditions and official links",
                "parameters": [
                    {
                        "name": "slug",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "lang",
                        "in": "query",
                        "required": false,
                        "description": "fr or ar",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Concours",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "item": {
                                            "$ref": "#/components/schemas/Concours"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Not found"
                    }
                }
            }
        },
        "/api/v1/categories.json": {
            "get": {
                "operationId": "listCategories",
                "summary": "Categories with counts",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/api/v1/cities.json": {
            "get": {
                "operationId": "listCities",
                "summary": "Cities with counts",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/api/v1/organismes.json": {
            "get": {
                "operationId": "listOrganismes",
                "summary": "Organisers (schools, ministries, agencies) with counts",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/api/v1/stats.json": {
            "get": {
                "operationId": "getStats",
                "summary": "Counts by status, category, level and kind",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/api/v1/eligibilite.json": {
            "get": {
                "operationId": "checkEligibility",
                "summary": "Concours a candidate can take, from a profile",
                "parameters": [
                    {
                        "name": "level",
                        "in": "query",
                        "required": false,
                        "description": "Required. bac_current | bac | bac2 | bac3 | bac5 | doctorat | college | aucun",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "bac_current",
                                "bac",
                                "bac2",
                                "bac3",
                                "bac5",
                                "doctorat",
                                "college",
                                "aucun"
                            ]
                        }
                    },
                    {
                        "name": "track",
                        "in": "query",
                        "required": false,
                        "description": "Bac track: SM | PC | SVT | SAGRO | STE | STM | ECO | SGC | LET | SH | ARTS | ORIG",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "bac_year",
                        "in": "query",
                        "required": false,
                        "description": "Year the bac was obtained",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "field",
                        "in": "query",
                        "required": false,
                        "description": "Diploma field: droit | economie | gestion | lettres | sciences | informatique | ingenierie | sante | education | autre",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "age",
                        "in": "query",
                        "required": false,
                        "description": "Age in years",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "gender",
                        "in": "query",
                        "required": false,
                        "description": "male | female",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "nationality",
                        "in": "query",
                        "required": false,
                        "description": "MA (default) | other",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "lang",
                        "in": "query",
                        "required": false,
                        "description": "fr | ar",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "400": {
                        "description": "level missing"
                    }
                }
            }
        },
        "/api/v1/seuils.json": {
            "get": {
                "operationId": "listCutoffs",
                "summary": "Concours with published cut-offs (latest by bac track, formula)",
                "parameters": [
                    {
                        "name": "lang",
                        "in": "query",
                        "required": false,
                        "description": "fr | ar",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/api/v1/seuils/{key}.json": {
            "get": {
                "operationId": "getCutoffs",
                "summary": "All cut-off rows of one concours (year, track, stage, value, source)",
                "parameters": [
                    {
                        "name": "key",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "lang",
                        "in": "query",
                        "required": false,
                        "description": "fr | ar",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "404": {
                        "description": "Not found"
                    }
                }
            }
        },
        "/api/v1/preparer.json": {
            "get": {
                "operationId": "listPrepGuides",
                "summary": "Preparation guides and mock exams",
                "parameters": [
                    {
                        "name": "lang",
                        "in": "query",
                        "required": false,
                        "description": "fr | ar",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/data/seuils.csv": {
            "get": {
                "operationId": "cutoffsCsv",
                "summary": "All cut-offs as CSV",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "ConcoursList": {
                "type": "object",
                "properties": {
                    "meta": {
                        "type": "object"
                    },
                    "items": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Concours"
                        }
                    }
                }
            },
            "Concours": {
                "type": "object",
                "properties": {
                    "slug": {
                        "type": "string"
                    },
                    "title": {
                        "type": "string"
                    },
                    "title_fr": {
                        "type": "string"
                    },
                    "title_ar": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "closing",
                            "open",
                            "soon",
                            "exam",
                            "results",
                            "expected",
                            "closed"
                        ]
                    },
                    "kind": {
                        "type": "string",
                        "enum": [
                            "ecole",
                            "recrutement",
                            "examen_pro"
                        ]
                    },
                    "level": {
                        "type": "string",
                        "enum": [
                            "sans",
                            "niveau_scolaire",
                            "bac",
                            "bac+2",
                            "bac+3",
                            "bac+5",
                            "doctorat"
                        ]
                    },
                    "category": {
                        "type": "object"
                    },
                    "organisme": {
                        "type": [
                            "object",
                            "null"
                        ]
                    },
                    "cities": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "seats": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "dates": {
                        "type": "object",
                        "properties": {
                            "registration_open": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "format": "date"
                            },
                            "registration_close": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "format": "date"
                            },
                            "exam": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "format": "date"
                            },
                            "results": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "format": "date"
                            }
                        }
                    },
                    "days_left": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "next_edition": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "YYYY-MM when the next edition is usually announced"
                    },
                    "verified": {
                        "type": "boolean"
                    },
                    "summary": {
                        "type": "string"
                    },
                    "conditions": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "links": {
                        "type": "object",
                        "properties": {
                            "apply": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "official": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "source": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        }
                    },
                    "url": {
                        "type": "string"
                    },
                    "url_ar": {
                        "type": "string"
                    }
                }
            }
        }
    }
}