{
  "openapi": "3.1.0",
  "info": {
    "title": "jobreed Calculator API",
    "version": "1.0.0",
    "description": "Free, read-only calculator API for students and jobseekers: UCAS Tariff points, ACT Composite, Canada Express Entry CRS score, and IELTS/CELPIP/PTE/TCF/TEF to CLB/NCLC conversion. No authentication. Results are for guidance only.",
    "contact": {
      "email": "hello@jobreed.com",
      "url": "https://jobreed.com/developers"
    },
    "termsOfService": "https://jobreed.com/terms"
  },
  "servers": [
    {
      "url": "https://jobreed.com/api/v1"
    }
  ],
  "externalDocs": {
    "description": "Developer documentation",
    "url": "https://jobreed.com/developers"
  },
  "paths": {
    "/health": {
      "get": {
        "operationId": "health",
        "summary": "Service health",
        "responses": {
          "200": {
            "description": "Service is up",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/calculators": {
      "get": {
        "operationId": "list_calculators",
        "summary": "List calculators",
        "description": "List every live jobreed calculator with its URL and description. Optionally filter by category (education, immigration, pay).",
        "parameters": [
          {
            "name": "category",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "education",
                "immigration",
                "pay"
              ],
              "description": "Only return calculators in this category."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Live calculators",
            "content": {
              "application/json": {}
            }
          },
          "400": {
            "description": "Invalid input",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "integer"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ucas-points": {
      "post": {
        "operationId": "calculate_ucas_points",
        "summary": "Calculate UCAS Tariff points",
        "description": "Total UCAS Tariff points for a set of qualifications. Qualification types: a = A-Level (grades A*, A, B, C, D, E); as = AS-Level (standalone) (grades A, B, C, D, E); epq = EPQ (Extended Project) (grades A*, A, B, C, D, E); btec-ext-dip = BTEC National Extended Diploma (grades D*D*D*, D*DD, DDD, DDM, DMM, MMM, MMP, MPP, PPP); btec-dip = BTEC National Diploma (grades D*D*, DD, DM, MM, MP, PP); btec-ext-cert = BTEC National Extended Certificate (grades D*, D, M, P); h = Scottish Highers (grades A, B, C, D).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "qualifications"
                ],
                "additionalProperties": false,
                "properties": {
                  "qualifications": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 12,
                    "description": "One entry per qualification, e.g. three A-levels = three entries.",
                    "items": {
                      "type": "object",
                      "required": [
                        "type",
                        "grade"
                      ],
                      "additionalProperties": false,
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "a",
                            "as",
                            "epq",
                            "btec-ext-dip",
                            "btec-dip",
                            "btec-ext-cert",
                            "h"
                          ],
                          "description": "Qualification type key."
                        },
                        "grade": {
                          "type": "string",
                          "description": "Grade, e.g. \"A*\" for A-level or \"DMM\" for BTEC Extended Diploma."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result",
            "content": {
              "application/json": {}
            }
          },
          "400": {
            "description": "Invalid input",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "integer"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/act-composite": {
      "post": {
        "operationId": "calculate_act_composite",
        "summary": "Calculate ACT Composite score",
        "description": "ACT Composite score (1–36) from English, Math and Reading section scores, using the September 2025 format (Science is optional and not part of the Composite). The average is rounded half-up.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "english",
                  "math",
                  "reading"
                ],
                "additionalProperties": false,
                "properties": {
                  "english": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 36,
                    "description": "English section score (1–36)."
                  },
                  "math": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 36,
                    "description": "Math section score (1–36)."
                  },
                  "reading": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 36,
                    "description": "Reading section score (1–36)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result",
            "content": {
              "application/json": {}
            }
          },
          "400": {
            "description": "Invalid input",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "integer"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/crs-score": {
      "post": {
        "operationId": "calculate_crs_score",
        "summary": "Calculate Express Entry CRS score",
        "description": "Canada Express Entry Comprehensive Ranking System (CRS) score using the official 2026 points grid (no job-offer points since March 25, 2025). Omitted fields use defaults.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "age",
                  "education",
                  "firstLanguage"
                ],
                "additionalProperties": false,
                "properties": {
                  "hasSpouse": {
                    "type": "boolean",
                    "default": false,
                    "description": "Spouse or common-law partner is accompanying."
                  },
                  "age": {
                    "type": "integer",
                    "minimum": 17,
                    "maximum": 45,
                    "description": "Age in years (use 45 for 45 or older)."
                  },
                  "education": {
                    "type": "string",
                    "enum": [
                      "less-than-secondary",
                      "secondary",
                      "one-year",
                      "two-year",
                      "bachelors",
                      "two-plus",
                      "masters",
                      "doctoral"
                    ],
                    "description": "Highest level of education."
                  },
                  "firstLanguage": {
                    "type": "object",
                    "description": "First official language CLB level per ability. Levels: below4, 4-5, 6, 7, 8, 9, 10plus.",
                    "required": [
                      "speaking",
                      "listening",
                      "reading",
                      "writing"
                    ],
                    "additionalProperties": false,
                    "properties": {
                      "speaking": {
                        "type": "string",
                        "enum": [
                          "below4",
                          "4-5",
                          "6",
                          "7",
                          "8",
                          "9",
                          "10plus"
                        ]
                      },
                      "listening": {
                        "type": "string",
                        "enum": [
                          "below4",
                          "4-5",
                          "6",
                          "7",
                          "8",
                          "9",
                          "10plus"
                        ]
                      },
                      "reading": {
                        "type": "string",
                        "enum": [
                          "below4",
                          "4-5",
                          "6",
                          "7",
                          "8",
                          "9",
                          "10plus"
                        ]
                      },
                      "writing": {
                        "type": "string",
                        "enum": [
                          "below4",
                          "4-5",
                          "6",
                          "7",
                          "8",
                          "9",
                          "10plus"
                        ]
                      }
                    }
                  },
                  "secondLanguage": {
                    "type": "object",
                    "description": "Second official language (optional) CLB level per ability. Levels: below4, 4-5, 6, 7, 8, 9, 10plus.",
                    "required": [
                      "speaking",
                      "listening",
                      "reading",
                      "writing"
                    ],
                    "additionalProperties": false,
                    "properties": {
                      "speaking": {
                        "type": "string",
                        "enum": [
                          "below4",
                          "4-5",
                          "6",
                          "7",
                          "8",
                          "9",
                          "10plus"
                        ]
                      },
                      "listening": {
                        "type": "string",
                        "enum": [
                          "below4",
                          "4-5",
                          "6",
                          "7",
                          "8",
                          "9",
                          "10plus"
                        ]
                      },
                      "reading": {
                        "type": "string",
                        "enum": [
                          "below4",
                          "4-5",
                          "6",
                          "7",
                          "8",
                          "9",
                          "10plus"
                        ]
                      },
                      "writing": {
                        "type": "string",
                        "enum": [
                          "below4",
                          "4-5",
                          "6",
                          "7",
                          "8",
                          "9",
                          "10plus"
                        ]
                      }
                    }
                  },
                  "canadianWorkExperience": {
                    "type": "string",
                    "enum": [
                      "none",
                      "1",
                      "2",
                      "3",
                      "4",
                      "5plus"
                    ],
                    "default": "none",
                    "description": "Years of skilled Canadian work experience."
                  },
                  "foreignWorkExperience": {
                    "type": "string",
                    "enum": [
                      "none",
                      "1-2",
                      "3plus"
                    ],
                    "default": "none",
                    "description": "Years of skilled foreign work experience."
                  },
                  "certificateOfQualification": {
                    "type": "boolean",
                    "default": false,
                    "description": "Holds a Canadian provincial/territorial certificate of qualification in a skilled trade."
                  },
                  "spouseEducation": {
                    "type": "string",
                    "enum": [
                      "less-than-secondary",
                      "secondary",
                      "one-year",
                      "two-year",
                      "bachelors",
                      "two-plus",
                      "masters",
                      "doctoral"
                    ],
                    "description": "Spouse education (only used when hasSpouse is true)."
                  },
                  "spouseFirstLanguage": {
                    "type": "object",
                    "description": "Spouse first official language (only used when hasSpouse is true) CLB level per ability. Levels: below4, 4-5, 6, 7, 8, 9, 10plus.",
                    "required": [
                      "speaking",
                      "listening",
                      "reading",
                      "writing"
                    ],
                    "additionalProperties": false,
                    "properties": {
                      "speaking": {
                        "type": "string",
                        "enum": [
                          "below4",
                          "4-5",
                          "6",
                          "7",
                          "8",
                          "9",
                          "10plus"
                        ]
                      },
                      "listening": {
                        "type": "string",
                        "enum": [
                          "below4",
                          "4-5",
                          "6",
                          "7",
                          "8",
                          "9",
                          "10plus"
                        ]
                      },
                      "reading": {
                        "type": "string",
                        "enum": [
                          "below4",
                          "4-5",
                          "6",
                          "7",
                          "8",
                          "9",
                          "10plus"
                        ]
                      },
                      "writing": {
                        "type": "string",
                        "enum": [
                          "below4",
                          "4-5",
                          "6",
                          "7",
                          "8",
                          "9",
                          "10plus"
                        ]
                      }
                    }
                  },
                  "spouseCanadianWorkExperience": {
                    "type": "string",
                    "enum": [
                      "none",
                      "1",
                      "2",
                      "3",
                      "4",
                      "5plus"
                    ],
                    "description": "Spouse Canadian work experience (only used when hasSpouse is true)."
                  },
                  "provincialNomination": {
                    "type": "boolean",
                    "default": false,
                    "description": "Has a provincial or territorial nomination (+600)."
                  },
                  "siblingInCanada": {
                    "type": "boolean",
                    "default": false,
                    "description": "Sibling aged 18+ living in Canada as a citizen or permanent resident."
                  },
                  "frenchNclc7Plus": {
                    "type": "boolean",
                    "default": false,
                    "description": "Scored NCLC 7+ in all four French abilities."
                  },
                  "englishClb5Plus": {
                    "type": "boolean",
                    "default": false,
                    "description": "Also scored CLB 5+ in all four English abilities (only used when frenchNclc7Plus is true)."
                  },
                  "canadianStudy": {
                    "type": "string",
                    "enum": [
                      "none",
                      "1-2yr",
                      "3plus-yr"
                    ],
                    "default": "none",
                    "description": "Canadian post-secondary credential."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result",
            "content": {
              "application/json": {}
            }
          },
          "400": {
            "description": "Invalid input",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "integer"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/clb": {
      "post": {
        "operationId": "convert_language_score_to_clb",
        "summary": "Convert language test score to CLB/NCLC",
        "description": "Convert IELTS General Training, CELPIP General or PTE Core scores to Canadian Language Benchmark (CLB) levels, or TCF Canada / TEF Canada scores to NCLC levels, using IRCC's equivalency charts. Score ranges: IELTS 0–9 (half bands), CELPIP 0–12, PTE 0–90, TCF reading/listening 0–699 and writing/speaking 0–20, TEF 0–699.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "test",
                  "reading",
                  "writing",
                  "listening",
                  "speaking"
                ],
                "additionalProperties": false,
                "properties": {
                  "test": {
                    "type": "string",
                    "enum": [
                      "ielts",
                      "celpip",
                      "pte",
                      "tcf",
                      "tef"
                    ],
                    "description": "ielts, celpip, pte (English → CLB) or tcf, tef (French → NCLC)."
                  },
                  "reading": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 699,
                    "description": "Reading test score."
                  },
                  "writing": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 699,
                    "description": "Writing test score."
                  },
                  "listening": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 699,
                    "description": "Listening test score."
                  },
                  "speaking": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 699,
                    "description": "Speaking test score."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result",
            "content": {
              "application/json": {}
            }
          },
          "400": {
            "description": "Invalid input",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "integer"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}