Refresh token

/api/token/refresh

Creates new access and refresh tokens

Request format:

        
            {
                "refresh_token": "9ea7b7aa7f7225794..."
            }
        
    

User GET

/api/user

Returns all users.

/api/user/{id}

Returns user.

User POST

/api/user

Returns current user

Empty body

REGISTER POST

/api/register

Creates a user via email and password

Request format:

        
            {
                "email": "string",
                "username": "string",
                "password": "string",

                "role" : "ROLE_EMPLOYER"  ***(optional parameter, logs in as EMPLOYER)***
            }
        
    

LOGIN POST

/api/media/login

Logs in / Creates a user via social media

Request format:

        
            {
                "id": int,
                "media": "string",  ***('google' or 'facebook' value only)***
                "username": "string",

                "role" : "ROLE_EMPLOYER"  ***(optional parameter, logs in as EMPLOYER)***
            }
        
    

/api/user-login

Logs in a user via email and password

Request format:

        
            {
                "email": "string",
                "password": "string",

                "role" : "ROLE_EMPLOYER"  ***(optional parameter, logs in as EMPLOYER)***
            }
        
    

/api/delete-user

Deletes a user (current user will be deleted)

/api/update-email

Updates email and password

Request format:

        
            {
                "email": "string",
                "newPassword": "string",

                "password": "string"  ***((old password) optional parameter, needed only if user already has email and password)***
            }
        
    

/api/update-name

Updates name and surname

Request format:

        
            {
                "name": "string",
                "surname": "string"  ***(optional parameter)***
            }
        
    

/api/media/connect

Connects social media to current user

Request format:

        
            {
                "id": int,
                "media": "string"  ***('google' or 'facebook' value only)***
            }
        
    

/api/upload-avatar

Creates user's avatar

Request format: form-data

        
            "image": file
        
    

/api/notifications-settings

Sets notifications settings

Request format:

        
            {
                "key": "string",  ***('website_notifications', 'email_notifications' or 'email_subscription' value only)***
                "value": boolean
            }
        
    

TELEGRAM

/login/telegram

Logs in / Creates a user via telegram. Optional parameter ?role=ROLE_EMPLOYER

Request format:

Redirect user to this route: /login/telegram

After, user will be redirected to '/' with tokens inside cookies

==========================

/api/connect/telegram

Adds telegram to social media connections

After, user will be redirected to '/'

Request format:

        
            {
                "connect": boolean  ***(true to connect, false to disconnect)***
            }
        
    

APPLICATION EMPLOYEE GET

/api/employee-application/{page}

// default page=1

Returns employee-application teasers

Possible filters:

        
Press for details ?localization=Poland,Krakow,Warsaw &language=en,pl &minExperience={int} // days of experience &maxExperience={int} // days of experience &minAge={int} // years (age) &maxAge={int} // years (age) &age=20-25,40-55 // years (age) &specialization=building,it &skill=building%201 &maxSalary=25 &minSalary=25 &jobType=regular &education=high &gender=sp,male,female &s=asc / desc

/api/my-employee-application

Returns full Application

Request format: json

        
Press for details { "applicationId": {int} }

APPLICATION EMPLOYEE POST

/api/create-employee-application

Create employee-application

Request format: formData

        
Press for details HTML ( changed '<>' to '{}' ) {form id="create-product" enctype="application/json"} {label for="avatar"}Upload Avatar{/label} {input type="file" name="avatar" id="avatar"> {label for="portfolio"}Upload Portfolio{/label} {input type="file" id="portfolio" name="portfolio[]" multiple accept="image/*"} {label for="relatedAvatar"}Upload Related Avatar{/label} {input type="file" name="relatedAvatar" id="relatedAvatar"} {label for="relatedPortfolio"}Upload Related Portfolio{/label} {input type="file" id="relatedPortfolio" name="relatedPortfolio[]" multiple accept="image/*"} {button type="submit"}Submit{/button} {/form} {script} const experience = [ { name: 'name_1', start: '2025-01-01', end: '2025-02-01' }, { name: 'name_2', start: '2025-03-01', end: 'now' } ]; const relatedApplication = { name: 'related name', surname: 'related surname', birthday: '2025-03-24', annotation: 'related annotation', videoLink: 'https://www.youtube.com/watch=iy5ig4trkfd', gender: 'female', localization: ['Warsaw', 'Poland'], specialization: ['building', 'it'], skills: ['building 1', 'it 1'], education: 'high', jobType: 'regular', experience: JSON.stringify(experience), language: ['en', 'ua'], salary: 60, aboutUser: 'about related user', showContacts: false, phone: 'phone', email: 'email', telegram: 'telegram', facebook: 'facebook', } const language = ['en', 'ua'] const localization = ['Warsaw', 'Poland'] const specialization = ['building', 'it'] const skills = ['building 1', 'it 1'] const createProductForm = document.getElementById('create-product'); createProductForm.addEventListener("submit", async (event) => { event.preventDefault(); const imageFile = createProductForm.querySelector('#avatar').files[0]; const relatedImageFile = createProductForm.querySelector('#relatedAvatar').files[0]; const formData = new FormData(); formData.append("name", 'user name'); formData.append("surname", 'user surname'); formData.append("birthday", '2025-03-24'); formData.append("annotation", 'user annotation'); formData.append("videoLink", 'https://www.youtube.com/watch=iy...'); formData.append("gender", 'sssp'); formData.append("localization", localization); formData.append("specialization", specialization); formData.append("skills", skills); formData.append("education", 'high'); formData.append("jobType", 'regular'); formData.append("experience", JSON.stringify(experience)); formData.append("language", language); formData.append("relatedApplication", JSON.stringify(relatedApplication)); formData.append("salary", 23); formData.append("aboutUser", 'about user text'); formData.append("needHousing", false); formData.append("lookingUrgently", false); formData.append("showContacts", true); formData.append("phone", 'user phone'); formData.append("email", 'user email'); formData.append("telegram", 'user telegram'); formData.append("facebook", 'user facebook'); formData.append("status", true); formData.append("visibility", true); formData.append("avatar", imageFile); formData.append("relatedAvatar", relatedImageFile); const portfolioFiles = document.getElementById('portfolio').files; for (let i = 0; i < portfolioFiles.length; i++) { formData.append('portfolio[]', portfolioFiles[i]); } const relatedPortfolioFiles = document.getElementById('relatedPortfolio').files; for (let i = 0; i < relatedPortfolioFiles.length; i++) { formData.append('relatedPortfolio[]', relatedPortfolioFiles[i]); } try { const response = await fetch("/api/create-employee-application", { method: "POST", headers: { 'Authorization': 'Bearer ' + 'eyJ0eXAiOiJK...' }, body: formData }); if (!response.ok) { throw new Error("error"); } const result = await response.json(); console.log(result); } catch (error) { console.error("error:", error); } }); {/script}

/api/edit-employee-application

Edit employee-application

Request format: formData

        
Press for details HTML ( changed '<>' to '{}' ) {form id="create-product" enctype="application/json"} {label for="avatar"}Upload Avatar{/label} {input type="file" name="avatar" id="avatar"> {label for="portfolio"}Upload Portfolio{/label} {input type="file" id="portfolio" name="portfolio[]" multiple accept="image/*"} {label for="relatedAvatar"}Upload Related Avatar{/label} {input type="file" name="relatedAvatar" id="relatedAvatar"} {label for="relatedPortfolio"}Upload Related Portfolio{/label} {input type="file" id="relatedPortfolio" name="relatedPortfolio[]" multiple accept="image/*"} {button type="submit"}Submit{/button} {/form} {script} const experience = [ { name: 'name_1', start: '2025-01-01', end: '2025-02-01' }, { name: 'name_2', start: '2025-03-01', end: 'now' } ]; const relatedApplication = { name: 'related name', surname: 'related surname', birthday: '2025-03-24', annotation: 'related annotation', videoLink: 'https://www.youtube.com/watch=iy5ig4trkfd', gender: 'female', localization: ['Warsaw', 'Poland'], specialization: ['building', 'it'], skills: ['building 1', 'it 1'], education: 'high', jobType: 'regular', experience: JSON.stringify(experience), language: ['en', 'ua'], salary: 60, aboutUser: 'about related user', showContacts: false, phone: 'phone', email: 'email', telegram: 'telegram', facebook: 'facebook', avatar: "/uploads/user/employee_application/avatar/67f74668e9c96.svg", portfolio: ["/uploads/user/employee_application/avatar/67f74668e9c96.svg", "/uploads/user/employee_application/avatar/67f74668e9c96.svg"] // empty array [] to delete images } const language = ['en', 'ua'] const localization = ['Warsaw', 'Poland'] const specialization = ['building', 'it'] const skills = ['building 1', 'it 1'] const createProductForm = document.getElementById('create-product'); createProductForm.addEventListener("submit", async (event) => { event.preventDefault(); const imageFile = createProductForm.querySelector('#avatar').files[0]; const relatedImageFile = createProductForm.querySelector('#relatedAvatar').files[0]; const formData = new FormData(); formData.append("id", 1); formData.append("name", 'user name'); formData.append("surname", 'user surname'); formData.append("birthday", '2025-03-24'); formData.append("annotation", 'user annotation'); formData.append("videoLink", 'https://www.youtube.com/watch=iy...'); formData.append("gender", 'sp'); formData.append("localization", localization); formData.append("specialization", specialization); formData.append("skills", skills); formData.append("education", 'high'); formData.append("jobType", 'regular'); formData.append("experience", JSON.stringify(experience)); formData.append("language", language); formData.append("relatedApplication", JSON.stringify(relatedApplication)); formData.append("salary", 23); formData.append("aboutUser", 'about user text'); formData.append("needHousing", false); formData.append("lookingUrgently", false); formData.append("showContacts", true); formData.append("phone", 'user phone'); formData.append("email", 'user email'); formData.append("telegram", 'user telegram'); formData.append("facebook", 'user facebook'); formData.append("status", true); formData.append("visibility", true); formData.append("avatar", imageFile); formData.append("relatedAvatar", relatedImageFile); formData.append("avatar", '/uploads/user/employee_application/avatar/67f88154be200.svg'); formData.append("portfolio", ["/uploads/user/employee_application/avatar/67f74668e9c96.svg", "/uploads/user/employee_application/avatar/67f74668e9c96.svg"]); // empty array [] to delete images const portfolioFiles = document.getElementById('portfolio').files; for (let i = 0; i < portfolioFiles.length; i++) { formData.append('portfolio[]', portfolioFiles[i]); } const relatedPortfolioFiles = document.getElementById('relatedPortfolio').files; for (let i = 0; i < relatedPortfolioFiles.length; i++) { formData.append('relatedPortfolio[]', relatedPortfolioFiles[i]); } try { const response = await fetch("/api/edit-employee-application", { method: "POST", headers: { 'Authorization': 'Bearer ' + 'eyJ0eXAiOiJK...' }, body: formData }); if (!response.ok) { throw new Error("error"); } const result = await response.json(); console.log(result); } catch (error) { console.error("error:", error); } }); {/script}

/api/delete-employee-application

Deletes Application

Request format: json

        
Press for details { "applicationId": {int} }

/api/my-employee-applications/{page}

// default page=1

returns applications of the current user

Empty body

    

/employee-application

Returns application of the user (for spectators)

Request format: json

        
Press for details { "applicationId": {int} }

COMPANY APPLICATION POST

/api/my-company-applications

Returns current user company-application

Empty body

    

/api/create-company-applications

Creates company application

Request format: formData

        
Press for details {form id="create-company-employee" enctype="application/json"} {label for="create-company-employee-avatar"}Upload Avatar{/label} {input type="file" name="create-company-employee-avatar" id="create-company-employee-avatar"} {label for="create-company-employee-avatar2"}Upload Avatar{/label} {input type="file" name="create-company-employee-avatar2" id="create-company-employee-avatar2"} {button type="submit"}Submit{/button} {/form} {script> const companyName = 'company name' const description = 'company description' const addressCity = 'company addressCity' const addressStreet = 'company addressStreet' const phone = 'company phone' const email = 'company email' const telegram = 'company telegram' const name = 'company name' const surname = 'company surname' const birthday = '2000-01-01' const gender = 'male' const status = 'success' const createProductForms = document.getElementById('create-company-employee'); createProductForms.addEventListener("submit", async (event) => { event.preventDefault(); const imageFiles = createProductForms.querySelector('#create-company-employee-avatar').files[0]; const formData = new FormData(); formData.append("applicationId", 4); formData.append("avatar", imageFiles); formData.append("companyName", companyName); formData.append("description", description); formData.append("addressCity", addressCity); formData.append("addressStreet", addressStreet); formData.append("phone", phone); formData.append("email", email); formData.append("telegram", telegram); formData.append("name", name); formData.append("surname", surname); formData.append("birthday", birthday); formData.append("gender", gender); formData.append("status", status); try { const response = await fetch("/api/create-company-applications", { method: "POST", headers: { 'Authorization': 'Bearer ' + 'eyJ0eXAi...' }, body: formData }); if (!response.ok) { throw new Error("Помилка під час надсилання даних"); } const result = await response.json(); console.log(result); } catch (error) { console.error("Помилка:", error); } }) {/script>

/api/edit-company-applications

Edits company application

Request format: formData

        
Press for details {form id="create-company-employee" enctype="application/json"} {label for="create-company-employee-avatar"}Upload Avatar{/label} {input type="file" name="create-company-employee-avatar" id="create-company-employee-avatar"} {label for="create-company-employee-avatar2"}Upload Avatar{/label} {input type="file" name="create-company-employee-avatar2" id="create-company-employee-avatar2"} {button type="submit"}Submit{/button} {/form} {script> const companyName = 'company name' const description = 'company description' const addressCity = 'company addressCity' const addressStreet = 'company addressStreet' const phone = 'company phone' const email = 'company email' const telegram = 'company telegram' const name = 'company name' const surname = 'company surname' const birthday = '2000-01-01' const gender = 'male' const status = 'success' const createProductForms = document.getElementById('create-company-employee'); createProductForms.addEventListener("submit", async (event) => { event.preventDefault(); const imageFiles = createProductForms.querySelector('#create-company-employee-avatar').files[0]; const formData = new FormData(); formData.append("applicationId", 4); formData.append("avatar", imageFiles); formData.append("companyName", companyName); formData.append("description", description); formData.append("addressCity", addressCity); formData.append("addressStreet", addressStreet); formData.append("phone", phone); formData.append("email", email); formData.append("telegram", telegram); formData.append("name", name); formData.append("surname", surname); formData.append("birthday", birthday); formData.append("gender", gender); formData.append("status", status); formData.append("avatar", "/uploads/user/employee_application/avatar/67f8aae1058c5.webp"); try { const response = await fetch("/api/edit-company-applications", { method: "POST", headers: { 'Authorization': 'Bearer ' + 'eyJ0eXAi...' }, body: formData }); if (!response.ok) { throw new Error("Помилка під час надсилання даних"); } const result = await response.json(); console.log(result); } catch (error) { console.error("Помилка:", error); } }) {/script>

/api/delete-company-application

Deletes company application

Request format: json

        
Press for details { "applicationId": {int} }

VACANCY POST

/api/create-vacancy

Creates Vacancy

Request format: formData

        
Press for details {form id="create-vacancy" enctype="application/json"> {div>create vacancy Images{/div> {label for="vacancyAvatar">Upload vacancy Avatar{/label> {input type="file" name="vacancyAvatar" id="vacancyAvatar"> {label for="create-vacancy-portfolio">Upload vacancy images{/label> {input type="file" id="create-vacancy-portfolio" name="create-vacancy-portfolio[]" multiple accept="image/*"> {button type="submit">Submit{/button> {/form> {script> const vacancyName = 'vacancy name' const vacancyType = 'vacancy' const vacancyDescription = 'company addressStreet' const vacancyLocalization = ['Warsaw', 'Krakow'] const vacancySpecialization = ['building', 'it'] const minAge = 20 const maxAge = 30 const vacancyGender = ['male', 'female'] const shift = 3 const vacancySalary = 25 const workHours = 40 const vacancyJobType = 'jobType 1' const vacancyEducation = ['high', 'medium'] const vacancyLanguage = ['en', 'pl'] const visibleContacts = true const isOpen = true const vacancyStatus = 'success' const housing = { rooms: 2, area: 34, videoLinks: ['link1'] } const createVacancy = document.getElementById('create-vacancy'); createVacancy.addEventListener("submit", async (event) => { event.preventDefault(); const vacancyAvatar = createVacancy.querySelector('#vacancyAvatar').files[0]; const formData = new FormData(); formData.append("avatar", vacancyAvatar); formData.append("name", vacancyName); formData.append("vacancyType", vacancyType); formData.append("description", vacancyDescription); formData.append("localization", vacancyLocalization); formData.append("specialization", vacancySpecialization); formData.append("minAge", minAge); formData.append("maxAge", maxAge); formData.append("gender", vacancyGender); formData.append("shift", shift); formData.append("salary", vacancySalary); formData.append("workHours", workHours); formData.append("jobType", vacancyJobType); formData.append("education", vacancyEducation); formData.append("language", vacancyLanguage); formData.append("visibleContacts", visibleContacts); formData.append("isOpen", isOpen); formData.append("status", vacancyStatus); formData.append("housing", JSON.stringify(housing)); const vacancyFiles = document.getElementById('create-vacancy-portfolio').files; for (let i = 0; i < vacancyFiles.length; i++) { formData.append('portfolio[]', vacancyFiles[i]); } try { const response = await fetch("/api/create-vacancy", { method: "POST", headers: { 'Authorization': 'Bearer ' + 'eyJ0eX...' }, body: formData }); if (!response.ok) { throw new Error("error"); } const result = await response.json(); console.log(result); } catch (error) { console.error("error:", error); } }) {/script>

/api/edit-vacancy

edits Vacancy

Request format: formData

        
Press for details {form id="create-vacancy" enctype="application/json"> {div>create vacancy Images{/div> {label for="vacancyAvatar">Upload vacancy Avatar{/label> {input type="file" name="vacancyAvatar" id="vacancyAvatar"> {label for="create-vacancy-portfolio">Upload vacancy images{/label> {input type="file" id="create-vacancy-portfolio" name="create-vacancy-portfolio[]" multiple accept="image/*"> {button type="submit">Submit{/button> {/form> {script> const vacancyName = 'vacancy name' const vacancyType = 'vacancy' const vacancyDescription = 'company addressStreet' const vacancyLocalization = ['Warsaw', 'Krakow'] const vacancySpecialization = ['building', 'it'] const minAge = 20 const maxAge = 30 const vacancyGender = ['male', 'female'] const shift = 3 const vacancySalary = 25 const workHours = 40 const vacancyJobType = 'jobType 1' const vacancyEducation = ['high', 'medium'] const vacancyLanguage = ['en', 'pl'] const visibleContacts = true const isOpen = true const vacancyStatus = 'success' const housing = { rooms: 2, area: 34, videoLinks: ['link1'] portfolio: ["/uploads/user/employee_application/portfolio/67f8aa0c609d6.svg", "/uploads/user/employee_application/portfolio/67f8aa0c60d8d.webp"] // empty array [] to delete images } const createVacancy = document.getElementById('create-vacancy'); createVacancy.addEventListener("submit", async (event) => { event.preventDefault(); const vacancyAvatar = createVacancy.querySelector('#vacancyAvatar').files[0]; const formData = new FormData(); formData.append("applicationId", 5); formData.append("avatar", vacancyAvatar); formData.append("name", vacancyName); formData.append("vacancyType", vacancyType); formData.append("description", vacancyDescription); formData.append("localization", vacancyLocalization); formData.append("specialization", vacancySpecialization); formData.append("minAge", minAge); formData.append("maxAge", maxAge); formData.append("gender", vacancyGender); formData.append("shift", shift); formData.append("salary", vacancySalary); formData.append("workHours", workHours); formData.append("jobType", vacancyJobType); formData.append("education", vacancyEducation); formData.append("language", vacancyLanguage); formData.append("visibleContacts", visibleContacts); formData.append("isOpen", isOpen); formData.append("status", vacancyStatus); formData.append("housing", JSON.stringify(housing)); formData.append("avatar", '/uploads/user/employee_application/avatar/67f8aa0c615ea.svg'); const vacancyFiles = document.getElementById('create-vacancy-portfolio').files; for (let i = 0; i < vacancyFiles.length; i++) { formData.append('portfolio[]', vacancyFiles[i]); } try { const response = await fetch("/api/edit-vacancy", { method: "POST", headers: { 'Authorization': 'Bearer ' + 'eyJ0eX...' }, body: formData }); if (!response.ok) { throw new Error("error"); } const result = await response.json(); console.log(result); } catch (error) { console.error("error:", error); } }) {/script>

/api/delete-vacancy

Deletes vacancy

Request format: json

        
Press for details { "vacancyId": {int} }

/api/my-vacancy

returns current user vacancy (

Request format: json

        
Press for details { "vacancyId": {int} }

/vacancy

returns user vacancy

Request format: json

        
Press for details { "vacancyId": {int} }

/api/my-vacancies/{page}

// default page=1

returns user vacancies

empty body

    

/VACANCY GET

/api/vacancies{page}

// default page=1

returns vacancies (with filters)

possible filters

        
Press for details ?localization=Poland,Krakow,Warsaw &language=en,pl &needHousing=true &minAge={int} // years (age) &maxAge={int} // years (age) &specialization=building,it &minSalary=25 &jobType=vacancy &education=high &gender=sp,male,female &s=asc / desc &q=word1+word2%20word3

APPLICATION_VACANCY POST

/api/send-application

sends an Application to Employer

        
Press for details { "vacancyId": {int} "applicationId": {int} "message": {string} // optional }

APPLICATION_VACANCY POST

/api/invite-application

invites an Application

        
Press for details { "vacancyId": {int} "applicationId": {int} "message": {string} // optional }

APPLICATION_VACANCY POST

/api/cancel-send-application

cancels sending an Application to Employer

        
Press for details { "vacancyId": {int} }

APPLICATION_VACANCY POST

/api/cancel-invite-application

cancels sending an Invitation to Employee

        
Press for details { "applicationId": {int} }

APPLICATION_VACANCY POST

/api/approve-application

approves an Application sent to Employer

        
Press for details { "applicationId": {int} }

APPLICATION_VACANCY POST

/api/reject-application

rejects an Application sent to Employer

        
Press for details { "applicationId": {int} }

APPLICATION_VACANCY POST

/api/approve-invitation

approves an Invitation sent to Employee

        
Press for details { "vacancyId": {int} }

APPLICATION_VACANCY POST

/api/reject-invitation

rejects an Invitation sent to Employee

        
Press for details { "vacancyId": {int} }

APPLICATION_VACANCY POST

/api/vacancy-job-completed

sends proposition to Employer to end the job / ends the job

        
Press for details { "vacancyId": {int} }

APPLICATION_VACANCY POST

/api/application-job-completed

sends proposition to Employee to end the job / ends the job

        
Press for details { "applicationId": {int} }

APPLICATION_VACANCY POST

/api/get-vacancy-status

endpoint for Employee: returns status of interaction with Vacancy

        
Press for details { "vacancyId": {int} }

APPLICATION_VACANCY POST

/api/get-application-status

endpoint for Employer: returns status of interaction with Application

        
Press for details { "applicationId": {int} }

APPLICATION_VACANCY POST

/api/delete-connection/{vacancyApplicationId}

endpoint for testing. ( vacancyApplicationId - (int)id of interaction, can be found here: /api/vacancy-connections or /api/employee-connections )

deletes interaction between application and vacancy

empty body

    

APPLICATION_VACANCY POST

/api/employee-interactions/{page}

// default page=1

returns interactions of the Employee

        
Press for details { "s": asc / desc }

APPLICATION_VACANCY POST

/api/vacancy-interactions/{page}

// default page=1

returns interactions of the Employer

        
Press for details { "s": asc / desc }

APPLICATION_VACANCY POST

/api/my-application-interactions/{page}

// default page=1

returns interactions with the Application

        
Press for details { "applicationId": int "s": asc / desc // optional }

APPLICATION_VACANCY POST

/api/my-vacancy-interactions/{page}

// default page=1

returns interactions with the Vacancy

        
Press for details { "vacancyId": int "s": asc / desc // optional }

REVIEW POST

/api/create-review

endpoint for Employer: returns status of interaction with Application

        
Press for details { "target_user": int "content": string "rating": int // 1 - 5 }

EMPLOYEE_APPLICATION POST

/count-employee-application-by-localization

возвращает количество анкет в конкретном городе

        
Press for details { "localization": string }

VACANCY POST

/vacancies/count-by-category-and-localization

возвращает количество вакансий по категориям в конкретном городе

        
Press for details { "localization": string }

INTERACTIONS POST

/api/interactions-read

помечает взаимодействия прочитанными

        
Press for details { "interactionIds": [1,2] }

REVIEW POST

/api/create-review

создает отзыв

        
Press for details { "targetUserId": int "content": string "rating": int // 1 - 5 }

REVIEW POST

/api/user-reviews/{page}

// default page=1

возвращает отзывы юзера

        
Press for details { "targetUserId": int }

REVIEW POST

/api/my-chats/{page}

// default page=1

взвращает мои чатыо

empty body

    

SHAT POST

/api/mark-messages-viewed

помечает сообщения прочитанными

        
Press for details { "messagesIds": [1,2,3] }

CHAT WEBSOCKET

        
Press for details {input type="text" id="message" placeholder="enter message"> {button onclick="sendMessage()">send{/button> {input type="file" id="imageInput"> {button onclick="sendImage()">send image{/button> {script> const token = "eyJ0eXAi..."; const recipientId = 5; const ws = new WebSocket(`wss://mrowkibeckend.website/chat?token=${token}&recipient_id=${recipientId}`); ws.onopen = () => console.log("connected to WebSocket-server"); ws.onmessage = (event) => { console.log(event.data) }; ws.onclose = () => console.log("connection closed"); function sendMessage() { const msg = document.getElementById("message").value; const payload = { type: 'message', content: msg }; ws.send(JSON.stringify(payload)); document.getElementById("message").value = ""; } function sendImage() { const fileInput = document.getElementById('imageInput'); const file = fileInput.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = function (event) { const base64Image = event.target.result; const payload = { type: 'image', content: base64Image, filename: file.name }; ws.send(JSON.stringify(payload)); }; reader.readAsDataURL(file); } {/script>

ADMIN

ADMIN POST

/api/admin/statistic

возвращает отзывы юзера

        
Press for Request details { "date": "2025-04-11" // optional }
Press for Response details { "vacancies": { "statusCounters": { "pending": 0, "success": 8, "rejected": 0, "requires_editing": 0 }, "localizationCounters": { "Poland": 0, "Warsaw": 8, "Krakow": 8 } }, "companyApplications": { "statusCounters": { "pending": 0, "success": 0, "rejected": 0, "requires_editing": 0 } }, "employeeApplications": { "statusCounters": { "pending": 0, "success": 0, "rejected": 0, "requires_editing": 0 }, "localizationCounters": { "Poland": 0, "Warsaw": 0, "Krakow": 0 } } }

ADMIN GET

/api/admin/employee-applications/{page} // default page=1

возвращает список анкет

Список фильтров:

        
Press for Request details ?status=success,rejected,requiresEditing,pending &s=asc / desc &q=word1+word2%20word3
Press for Response details { "totalPages": 1, "data": [ { "id": 1, "name": "user name", "specialization": [ "building", "it" ], "avatar": "/uploads/user/employee_application/avatar/67f88154be200.svg", "status": "success", "rating": "4.25" }, ] }

ADMIN POST

/api/admin/employee-application

возвращает анкету

        
Press for Request details { "applicationId": "int }
Press for Response details { "id": 1, "avatar": "/uploads/user/employee_application/avatar/67f88154be200.svg", "rating": "4.25", "name": "user name", "surname": "user surname dsadasdas", "birthday": "2025-03-24", "annotation": "user annotation", "videoLink": "https://www.youtube.com/watch=iy5ig4trk", "gender": "sp", "education": "high", "jobType": "regular", "experience": [ { "end": "2025-02-01", "name": "name_1", "start": "2025-01-01" }, { "end": "now", "name": "name_2", "start": "2025-03-01" } ], "salary": 24, "aboutUser": "about user text", "needHousing": false, "lookingUrgently": false, "showContacts": false, "contacts": { "phone": "user phone", "email": "user email", "telegram": "user telegram", "facebook": "user facebook" }, "portfolio": [ "/uploads/user/employee_application/portfolio/67f74668e9fd1.svg", "/uploads/user/employee_application/portfolio/67f74668ea206.jpg" ], "relatedApplication": { "name": "related name", "email": "email", "phone": "phone", "avatar": "/uploads/user/employee_application/avatar/67f74668e9c96.svg", "gender": "male", "salary": 60, "skills": [ "building 1", "it 1" ], "jobType": "regular", "surname": "related surname", "birthday": "2025-03-24", "facebook": "facebook", "language": [ "en", "ua" ], "telegram": "telegram", "aboutUser": "about related user", "education": "high", "portfolio": [ "/uploads/user/employee_application/portfolio/67f74668e9fd1.svg", "/uploads/user/employee_application/portfolio/67f74668ea206.jpg" ], "videoLink": "https://www.youtube.com/watch=iy5ig4trkfd", "annotation": "related annotation", "experience": [ { "end": "2025-02-01", "name": "name_1", "start": "2025-01-01" }, { "end": "now", "name": "name_2", "start": "2025-03-01" } ], "localization": [ "Warsaw", "Poland" ], "showContacts": false, "specialization": [ "building", "it" ], "totalExperience": 72 }, "visibility": true, "languages": [ "en", "pl", "ua" ], "localizations": [ "Poland", "Warsaw", "Krakow" ], "specializations": [ "building", "it" ], "skills": [ "building 1", "it 1" ], "status": "success", "createdAt": null }

ADMIN POST

/api/admin/change-application-status

изменяет статус анкеты

        
Press for Request details { "applicationId": "int "status": string // ('success', 'rejected', 'requiresEditing', 'pending') "message": string // optional }

ADMIN GET

/api/admin/vacancies/{page} // default page=1

возвращает список вакансий

Список фильтров:

        
Press for Request details ?status=success,rejected,requiresEditing,pending &localization=Warsaw,Krakow &minSalary=10 &maxSalary=20 &s=asc / desc &q=word1+word2%20word3
Press for Response details { "totalPages": 5, "data": [ { "id": 3, "vacancyName": "vacancy name", "vacancyAvatar": "/uploads/user/employee_application/portfolio/67f74668e9fd1.svg", "status": "success", "ownerName": "company name company surname", "localization": [ "Warsaw", "Krakow" ] }, ] }

ADMIN POST

/api/admin/vacancy

возвращает вакансию

        
Press for Request details { "vacancyId": "int }
Press for Response details { "id": 11, "name": "vacancy name 1", "vacancyType": "regular", "description": "company addressStreet", "minAge": 20, "maxAge": 30, "salary": 25, "shift": 3, "workHours": 40, "jobType": "regular", "housing": [], "status": "success", "visibleContacts": true, "isOpen": true, "needHousing": false, "avatar": "/uploads/user/employee_application/avatar/67f900d03d55d.svg", "createdAt": { "date": "2025-04-11 11:45:20.000000", "timezone_type": 3, "timezone": "UTC" }, "applicationsCount": 1, "views": 0, "localizations": [ "Warsaw", "Krakow" ], "gender": [ "male", "female" ], "educations": [ "high", "medium" ], "languages": [ "en", "pl" ], "specializations": [ "building", "it" ] }

ADMIN POST

/api/admin/change-vacancy-status

изменяет статус вакансии

        
Press for Request details { "vacancyId": "int "status": string // ('success', 'rejected', 'requiresEditing', 'pending') "message": string // optional }

ADMIN GET

/api/admin/company-applications/{page} // default page=1

возвращает список компаний

Список фильтров:

        
Press for Request details ?status=success,rejected,requiresEditing,pending &s=asc / desc &q=word1+word2%20word3
Press for Response details { "totalPages": 5, "data": [ { "id": 6, "name": "company 6", "avatar": "/uploads/user/employee_application/avatar/67f6fcabd5a29.svg", "status": null, "description": "company description" }, ] }

ADMIN POST

/api/admin/company-application

возвращает компанию

        
Press for Request details { "companyId": "int }
Press for Response details { "id": 8, "avatar": "/uploads/user/employee_application/avatar/67f8aae1058c5.webp", "companyName": "company 8", "status": "success", "description": "company description", "addressCity": "company addressCity", "phone": "company phone", "email": "company email", "telegram": "company telegram", "name": "company name", "surname": "company surname", "birthday": "2000-01-01", "gender": "male" }

ADMIN POST

/api/admin/change-company-status

изменяет статус компании

        
Press for Request details { "companyId": "int "status": string // ('success', 'rejected', 'requiresEditing', 'pending') "message": string // optional }

ADMIN GET

/api/admin/reviews/{page} // default page=1

возвращает список отзывов

Список фильтров:

            
Press for Request details ?status=success,rejected,blocked,pending &q=word1+word2%20word3
Press for Response details { "totalPages": int, "data": [ { "id": int, "name": ?string, "surname": ?string, "content": string, "applicationId": ?int, "vacancyId": ?int, "targetUserId": ?int, "status": string, "createdAt": { "date": "2025-05-16 16:21:25.000000", "timezone_type": 3, "timezone": "UTC" } }, ] }

ADMIN POST

/api/admin/review

возвращает отзыв

            
Press for Request details { "reviewId": "int }
Press for Response details "id": int, "name": ?string, "surname": ?string", "content": string, "applicationId": ?int, "vacancyId": ?int, "targetUserId": ?int, "status": string, "createdAt": { "date": "2025-05-16 16:21:25.000000", "timezone_type": 3, "timezone": "UTC" }

ADMIN POST

/api/admin/change-review-status

изменяет статус отзыва

            
Press for Request details { "companyId": int "status": string // ('success', 'rejected', 'blocked') "message": string // optional }

ADMIN GET

/api/admin/moderation-history/{page} // default page=1

возвращает историю модерации

Список фильтров:

        
Press for Request details ?status=success,rejected,requiresEditing,pending &s=asc / desc &sortBy=id / username / type / action
Press for Response details { "totalPages": 2, "data": [ { "id": 4, "date": { "date": "2025-05-15 00:28:10.000000", "timezone_type": 3, "timezone": "UTC" }, "moderator": { "id": 1, "username": "admin", "email": "admin@gmail.com" }, "data": { "type": "application", "id": 1 }, "action": "rejected", "message": "kadfkadbkfbadlbgflaglbvfalgbafjlgblfgb" }, ] }

ADMIN GET

/api/admin/administrators/{page} // default page=1

возвращает список администраторов

        
Press for Response details { "totalPages": 2, "data": [ { "id": 5, "username": "testsuser", "email": "testa@example.com", "access": [ "application", "company", "vacancy" ] }, ] }

ADMIN POST

/api/admin/create-admin

создаёт нового администратора

после создания на почту суперАдмина будет отправлен пароль

        
Press for Request details { "username": string "phone": string "email": string "access": ["application", "company", "vacancy", "review"] }

ADMIN POST

/api/admin/reset-admin-password

создаёт новый пароль для администратора

после создания на почту суперАдмина будет отправлен пароль

        
Press for Request details { "userId": int }

RESET (MY)ADMIN PASSWORD POST

/reset-my-admin-password

сбрасывает пароль админа по почте и отправляет новый пароль суперадмину на почту

            
Press for Request details { "email": string }

NOTIFICATION GET

/api/user-notifications/{page} // default page=1

возвращает уведомления юзера

Cуществуют 3 вида уведомлений: moderation, interaction, review

У каждого вида свой интерфейс

        
Press for Response details { "totalPages": int, "data": [ // moderation // { "id": int, "type": "moderation", "title": string (application / company / vacancy) "details": { "status": string "message": ?string "vacancyId": int }, "createdAt": { "date": "2025-05-16 16:16:28.000000", "timezone_type": 3, "timezone": "UTC" }, "isViewed": bool }, // interaction // { "id": int, "type": "interaction", "title": string // interaction status (sent / you_approved / candidate...) "details": { "status": string // interaction status (sent / you_approved / candidate...) "vacancyId": int, "applicationId": int "vacancyName": string // отображается у стороны соискателя "applicationName": string // отображается у стороны работодателя т.е. если я (Работодатель) приглашаю соискателя, ему придет уведомление с полем "vacancyName" о том что ему предложили работу а мне (Работодателю) придет уведомление с полем "applicationName", что я пригласил соискателя на работу и наоборот, если я (Соискатель) подаю анкету, то работодателю придет уведомление с полем "applicationName", что я прошусь на работу а мне (Соискателю) придет уведомление с полем "vacancyName", о том что я отправил заявку }, "createdAt": { "date": "2025-05-16 15:52:54.000000", "timezone_type": 3, "timezone": "UTC" }, "isViewed": bool }, // review // { "id": int, // notification id "type": "review", "title": "review", "details": { "id": int // review id "author": int // user id "rating": int "content": string "createdAt": "2025-04-27 03:35:29" }, "createdAt": { "date": "2025-04-27 03:35:29.000000", "timezone_type": 3, "timezone": "UTC" }, "isViewed": bool }, ] }

NOTIFICATION POST

/api/notification-viewed

Помечает уведомления пользователя прочитанными

        
Press for Request details { "notificationsIds": [1,2,3] // id уведомлений }

NOTIFICATION POST

/api/new-notifications-count

возвращает количество непрочитанных уведомлений

    

RESET PASSWORD POST

/request-reset-password

сюда указывать почту юзера, для которого нужно сбросить пароль

        
Press for Request details { "email": string }

RESET PASSWORD POST

/reset-password

сюда указывать новый пароль и токен для сброса пароля

        
Press for Request details { "password": string, "token": string }