{
  "openapi": "3.1.0",
  "info": {
    "title": "Интеграционный API OdamiAI",
    "version": "1.0.0",
    "description": "Чтение вакансий и кандидатов компании и приём откликов извне. Все запросы идут под сервисным ключом компании; области доступа: vacancies:read, candidates:read, applications:write."
  },
  "servers": [
    {
      "url": "https://api.odamiai.kz/api"
    },
    {
      "url": "https://api.odamiai.uz/api"
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Сервисный ключ компании. Выпускается в интерфейсе платформы, в разделе «Сервисные ключи»."
      }
    },
    "schemas": {
      "Vacancy": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "paused",
              "closed",
              "archived",
              "draft"
            ]
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "officeAddress": {
            "type": [
              "string",
              "null"
            ]
          },
          "experience": {
            "type": [
              "string",
              "null"
            ]
          },
          "workFormat": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "remote",
              "office",
              "hybrid",
              "other"
            ]
          },
          "workFormats": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "salaryFrom": {
            "type": [
              "number",
              "null"
            ]
          },
          "salaryTo": {
            "type": [
              "number",
              "null"
            ]
          },
          "salaryCurrency": {
            "type": [
              "string",
              "null"
            ]
          },
          "salaryGross": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "employmentForm": {
            "type": [
              "string",
              "null"
            ]
          },
          "workSchedule": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "skills": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "professionalRoles": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "responsibilities": {
            "type": [
              "string",
              "null"
            ]
          },
          "positionsCount": {
            "type": [
              "number",
              "null"
            ]
          },
          "sourceUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "publishedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "title",
          "status",
          "city",
          "officeAddress",
          "experience",
          "workFormat",
          "workFormats",
          "salaryFrom",
          "salaryTo",
          "salaryCurrency",
          "salaryGross",
          "employmentForm",
          "workSchedule",
          "skills",
          "languages",
          "professionalRoles",
          "description",
          "responsibilities",
          "positionsCount",
          "sourceUrl",
          "publishedAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "VacancyPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Vacancy"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Курсор следующей страницы. `null` — страница последняя."
          }
        },
        "required": [
          "items",
          "nextCursor"
        ]
      },
      "Referral": {
        "type": [
          "object",
          "null"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "company": {
            "type": [
              "string",
              "null"
            ]
          },
          "relationship": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "name",
          "email",
          "phone",
          "company",
          "relationship"
        ]
      },
      "Candidate": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "vacancyId": {
            "type": [
              "string",
              "null"
            ]
          },
          "vacancyTitle": {
            "type": [
              "string",
              "null"
            ]
          },
          "stage": {
            "type": [
              "string",
              "null"
            ]
          },
          "source": {
            "type": "string"
          },
          "externalId": {
            "type": [
              "string",
              "null"
            ]
          },
          "coverLetter": {
            "type": [
              "string",
              "null"
            ]
          },
          "candidate": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "email": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "phone": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "location": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "birthDate": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "gender": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "citizenship": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "name",
              "email",
              "phone",
              "location",
              "birthDate",
              "gender",
              "citizenship"
            ]
          },
          "resume": {
            "type": "object",
            "properties": {
              "role": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "summary": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "experienceYears": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "skills": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "skillsDescription": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "experience": {},
              "education": {},
              "additionalEducation": {},
              "languages": {},
              "certificates": {},
              "portfolio": {},
              "expectedSalary": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "expectedSalaryCurrency": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "preferredWorkFormat": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "preferredEmployment": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "relocation": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "sourceUrl": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "role",
              "summary",
              "experienceYears",
              "skills",
              "skillsDescription",
              "expectedSalary",
              "expectedSalaryCurrency",
              "preferredWorkFormat",
              "preferredEmployment",
              "relocation",
              "sourceUrl"
            ]
          },
          "referral": {
            "$ref": "#/components/schemas/Referral"
          },
          "createdAt": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "vacancyId",
          "vacancyTitle",
          "stage",
          "source",
          "externalId",
          "coverLetter",
          "candidate",
          "resume",
          "referral",
          "createdAt",
          "updatedAt"
        ]
      },
      "CandidatePage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Candidate"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Курсор следующей страницы. `null` — страница последняя."
          }
        },
        "required": [
          "items",
          "nextCursor"
        ]
      },
      "ApplicationDuplicate": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "duplicate"
            ]
          }
        },
        "required": [
          "id",
          "status"
        ]
      },
      "ApplicationCreated": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "created"
            ]
          }
        },
        "required": [
          "id",
          "status"
        ]
      }
    },
    "parameters": {}
  },
  "paths": {
    "/integration/v1/vacancies": {
      "get": {
        "summary": "Вакансии компании",
        "description": "Область доступа `vacancies:read`. Для инкрементальной синхронизации передавайте `since` — сравнивается с отметкой правки, поэтому в выборку попадают и вакансии, у которых изменился статус или вилка.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "required": false,
            "name": "since",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "paused",
                "closed",
                "archived",
                "draft",
                "all"
              ],
              "default": "open"
            },
            "required": false,
            "name": "status",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Страница вакансий",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VacancyPage"
                }
              }
            }
          },
          "400": {
            "description": "Запрос не прошёл проверку"
          },
          "401": {
            "description": "Ключ отсутствует, отозван или недействителен"
          },
          "403": {
            "description": "Ключу не выдана нужная область доступа"
          },
          "429": {
            "description": "Превышен лимит запросов. См. заголовок Retry-After"
          }
        }
      }
    },
    "/integration/v1/candidates": {
      "get": {
        "summary": "Кандидаты компании",
        "description": "Область доступа `candidates:read`. Карточки переносов между вакансиями в выборку не попадают — иначе один отклик считался бы дважды. `since` сравнивается и с отметкой правки кандидата, и с отметкой правки его резюме.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "required": false,
            "name": "since",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "vacancyId",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Страница кандидатов",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CandidatePage"
                }
              }
            }
          },
          "400": {
            "description": "Запрос не прошёл проверку"
          },
          "401": {
            "description": "Ключ отсутствует, отозван или недействителен"
          },
          "403": {
            "description": "Ключу не выдана нужная область доступа"
          },
          "429": {
            "description": "Превышен лимит запросов. См. заголовок Retry-After"
          }
        }
      }
    },
    "/integration/v1/applications": {
      "post": {
        "summary": "Прислать отклик",
        "description": "Область доступа `applications:write`. Идемпотентно по `externalId`: повтор возвращает `200` и идентификатор ранее созданной карточки. Заполненный блок `referral` делает отклик рефералом.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "externalId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "vacancyId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64
                  },
                  "source": {
                    "type": "string",
                    "maxLength": 60
                  },
                  "candidate": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 300
                      },
                      "email": {
                        "type": "string",
                        "maxLength": 320,
                        "format": "email"
                      },
                      "phone": {
                        "type": "string",
                        "maxLength": 60
                      },
                      "location": {
                        "type": "string",
                        "maxLength": 200
                      },
                      "birthDate": {
                        "type": [
                          "string",
                          "null"
                        ]
                      }
                    },
                    "required": [
                      "name"
                    ]
                  },
                  "coverLetter": {
                    "type": "string",
                    "maxLength": 20000
                  },
                  "resume": {
                    "type": "object",
                    "properties": {
                      "role": {
                        "type": "string",
                        "maxLength": 300
                      },
                      "summary": {
                        "type": "string",
                        "maxLength": 20000
                      },
                      "experienceYears": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 80
                      },
                      "skills": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "maxLength": 120
                        },
                        "maxItems": 200,
                        "default": []
                      },
                      "experience": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "company": {
                              "type": "string",
                              "maxLength": 300,
                              "default": ""
                            },
                            "role": {
                              "type": "string",
                              "maxLength": 300,
                              "default": ""
                            },
                            "period": {
                              "type": "string",
                              "maxLength": 120,
                              "default": ""
                            },
                            "description": {
                              "type": "string",
                              "maxLength": 5000
                            }
                          }
                        },
                        "maxItems": 100,
                        "default": []
                      },
                      "education": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "institution": {
                              "type": "string",
                              "maxLength": 300,
                              "default": ""
                            },
                            "degree": {
                              "type": "string",
                              "maxLength": 300,
                              "default": ""
                            },
                            "period": {
                              "type": "string",
                              "maxLength": 120,
                              "default": ""
                            }
                          }
                        },
                        "maxItems": 100,
                        "default": []
                      },
                      "expectedSalary": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "expectedSalaryCurrency": {
                        "type": "string",
                        "maxLength": 10
                      }
                    }
                  },
                  "referral": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 300
                      },
                      "email": {
                        "type": "string",
                        "maxLength": 320,
                        "format": "email"
                      },
                      "phone": {
                        "type": "string",
                        "maxLength": 60
                      },
                      "company": {
                        "type": "string",
                        "maxLength": 300
                      },
                      "relationship": {
                        "type": "string",
                        "maxLength": 200
                      }
                    },
                    "required": [
                      "name"
                    ]
                  }
                },
                "required": [
                  "externalId",
                  "vacancyId",
                  "candidate"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Такой отклик уже принимали — карточка не дублируется",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApplicationDuplicate"
                }
              }
            }
          },
          "201": {
            "description": "Отклик принят, карточка создана",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApplicationCreated"
                }
              }
            }
          },
          "400": {
            "description": "Запрос не прошёл проверку"
          },
          "401": {
            "description": "Ключ отсутствует, отозван или недействителен"
          },
          "403": {
            "description": "Ключу не выдана нужная область доступа"
          },
          "404": {
            "description": "Вакансия не найдена или принадлежит другой компании"
          },
          "429": {
            "description": "Превышен лимит запросов. См. заголовок Retry-After"
          }
        }
      }
    }
  },
  "webhooks": {}
}
