{"openapi": "3.0.3", "info": {"title": "Zim JobHunters API", "version": "v1", "description": "REST API for the Zim JobHunters platform, covering account onboarding, candidate registration, employer workflows, jobs, opportunities, events, notifications, payments, and administrator tools."}, "servers": [{"url": "https://api.jobhunters.co.zw"}], "tags": [{"name": "Administrator", "description": "Administrative and management operations across the platform."}, {"name": "Candidates", "description": "Operations for candidate onboarding and candidate profiles."}, {"name": "Employers", "description": "Operations for employer onboarding, employer memberships, and employer-owned job management."}, {"name": "Jobs", "description": "Public job discovery endpoints for active job listings."}, {"name": "Notifications", "description": "Targeted notification delivery and authenticated user inbox operations."}], "paths": {"/api/candidates/register/": {"post": {"tags": ["Candidates"], "summary": "Register a candidate account", "description": "Creates or links an AppUser record, then creates the candidate profile and assigns the candidate role in a single transaction.", "operationId": "registerCandidate", "security": [], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CandidateRegistrationRequest"}, "examples": {"candidateRegistration": {"summary": "Candidate registration request", "value": {"user": {"firebase_uid": "firebase-register-1", "email_address": "candidate@example.com", "phone_number": "+263700000010", "first_name": "Tariro", "last_name": "Moyo"}, "candidate": {"candidate_category": "white_collar", "candidate_type": "graduate", "professional_title": "Junior Developer", "professional_summary": "Looking for graduate opportunities.", "skills": ["Python", "Django"], "years_of_experience": 1, "availability_status": "available", "preferred_job_type": "full_time", "preferred_location": "Harare"}}}}}}}, "responses": {"201": {"description": "Candidate registered successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CandidateRegistrationResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}, "examples": {"duplicateCandidate": {"summary": "Candidate profile already exists", "value": {"user": ["A candidate profile already exists for this account."]}}}}}}}}}, "/api/jobs/": {"get": {"tags": ["Jobs"], "summary": "List active jobs", "description": "Public endpoint that returns active job postings only, ordered by newest creation date first with pagination, search, and sector, location, employment, experience, and salary filters.", "operationId": "listPublicActiveJobs", "security": [], "parameters": [{"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}, "description": "Page number."}, {"name": "page_size", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}, "description": "Number of results per page."}, {"name": "search", "in": "query", "schema": {"type": "string"}, "description": "Search across title, description, requirements, sector, employer name, and location fields."}, {"name": "sector", "in": "query", "schema": {"type": "string"}, "description": "Filter by sector slug or exact sector name."}, {"name": "sector_id", "in": "query", "schema": {"type": "integer"}, "description": "Filter by sector ID."}, {"name": "location", "in": "query", "schema": {"type": "string"}, "description": "Filter by location slug, name, city, province, or country."}, {"name": "location_id", "in": "query", "schema": {"type": "integer"}, "description": "Filter by location ID."}, {"name": "country", "in": "query", "schema": {"type": "string"}, "description": "Filter by location country."}, {"name": "province", "in": "query", "schema": {"type": "string"}, "description": "Filter by location province."}, {"name": "city", "in": "query", "schema": {"type": "string"}, "description": "Filter by location city."}, {"name": "is_remote", "in": "query", "schema": {"type": "boolean"}, "description": "Filter remote versus on-site locations."}, {"name": "employment_type", "in": "query", "schema": {"type": "string", "enum": ["full_time", "part_time", "contract", "temporary", "internship", "freelance"]}, "description": "Filter by employment type."}, {"name": "experience_level", "in": "query", "schema": {"type": "string", "enum": ["entry_level", "junior", "mid_level", "senior", "lead", "executive"]}, "description": "Filter by experience level."}, {"name": "salary_min", "in": "query", "schema": {"type": "string", "format": "decimal"}, "description": "Filter jobs whose advertised maximum salary meets this minimum."}, {"name": "salary_max", "in": "query", "schema": {"type": "string", "format": "decimal"}, "description": "Filter jobs whose advertised minimum salary stays within this ceiling."}], "responses": {"200": {"description": "Active jobs returned successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicJobListResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}}}}, "/api/administrator/employers/": {"get": {"tags": ["Administrator"], "summary": "List employers", "description": "Returns employer organisation records for authenticated clients. Each response includes the current user's membership for that employer when one exists.", "operationId": "listEmployers", "security": [{"bearerAuth": []}], "responses": {"200": {"description": "Employer list returned successfully.", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/EmployerResponse"}}}}}}}, "post": {"tags": ["Administrator"], "summary": "Create an employer organisation", "description": "Creates an employer record from employer fields only and assigns the authenticated user as the initial owner membership.", "operationId": "createEmployer", "security": [{"bearerAuth": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerWriteRequest"}, "examples": {"employerCreate": {"summary": "Standalone employer create request", "value": {"company_name": "Bright Labs", "email_address": "contact@brightlabs.example", "phone_number": "+263700000021", "sector": "Technology", "description": "Talent and software services.", "location": "Harare", "employer_type": "company"}}}}}}, "responses": {"201": {"description": "Employer created successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}}}}, "/api/administrator/employers/{employer_id}/": {"get": {"tags": ["Administrator"], "summary": "Retrieve an employer", "description": "Returns a single employer organisation by ID.", "operationId": "retrieveEmployer", "security": [{"bearerAuth": []}], "responses": {"200": {"description": "Employer returned successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerResponse"}}}}, "404": {"description": "Employer not found."}}}, "put": {"tags": ["Administrator"], "summary": "Replace an employer", "description": "Replaces the mutable employer fields. Only active owner/admin memberships or platform admins can perform this operation.", "operationId": "updateEmployer", "security": [{"bearerAuth": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerWriteRequest"}}}}, "responses": {"200": {"description": "Employer updated successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "403": {"description": "You do not have permission to modify this employer."}, "404": {"description": "Employer not found."}}}, "patch": {"tags": ["Administrator"], "summary": "Update part of an employer", "description": "Partially updates mutable employer fields. Only active owner/admin memberships or platform admins can perform this operation.", "operationId": "partialUpdateEmployer", "security": [{"bearerAuth": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerWriteRequest"}}}}, "responses": {"200": {"description": "Employer updated successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "403": {"description": "You do not have permission to modify this employer."}, "404": {"description": "Employer not found."}}}, "delete": {"tags": ["Administrator"], "summary": "Delete an employer", "description": "Deletes an employer organisation. Only active owner/admin memberships or platform admins can perform this operation.", "operationId": "deleteEmployer", "security": [{"bearerAuth": []}], "responses": {"204": {"description": "Employer deleted successfully."}, "403": {"description": "You do not have permission to modify this employer."}, "404": {"description": "Employer not found."}}}}, "/api/administrator/jobs/": {"get": {"tags": ["Administrator"], "summary": "List all jobs", "description": "Returns all jobs for platform administrators with pagination, filtering, search, and newest-first ordering.", "operationId": "listAdministratorJobs", "security": [{"bearerAuth": []}], "parameters": [{"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}, "description": "Page number."}, {"name": "page_size", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}, "description": "Number of results per page."}, {"name": "status", "in": "query", "schema": {"type": "string", "enum": ["draft", "active", "closed", "expired", "archived", "pending_approval"]}, "description": "Filter by job status."}, {"name": "employer_id", "in": "query", "schema": {"type": "integer"}, "description": "Filter by employer ID."}, {"name": "posted_by_id", "in": "query", "schema": {"type": "integer"}, "description": "Filter by creator user ID."}, {"name": "sector", "in": "query", "schema": {"type": "string"}, "description": "Filter by sector slug or exact sector name."}, {"name": "sector_id", "in": "query", "schema": {"type": "integer"}, "description": "Filter by sector ID."}, {"name": "location", "in": "query", "schema": {"type": "string"}, "description": "Filter by location slug, name, city, province, or country."}, {"name": "location_id", "in": "query", "schema": {"type": "integer"}, "description": "Filter by location ID."}, {"name": "country", "in": "query", "schema": {"type": "string"}, "description": "Filter by location country."}, {"name": "province", "in": "query", "schema": {"type": "string"}, "description": "Filter by location province."}, {"name": "city", "in": "query", "schema": {"type": "string"}, "description": "Filter by location city."}, {"name": "is_remote", "in": "query", "schema": {"type": "boolean"}, "description": "Filter remote versus on-site locations."}, {"name": "employment_type", "in": "query", "schema": {"type": "string", "enum": ["full_time", "part_time", "contract", "temporary", "internship", "freelance"]}, "description": "Filter by employment type."}, {"name": "experience_level", "in": "query", "schema": {"type": "string", "enum": ["entry_level", "junior", "mid_level", "senior", "lead", "executive"]}, "description": "Filter by experience level."}, {"name": "salary_min", "in": "query", "schema": {"type": "string", "format": "decimal"}, "description": "Filter jobs whose advertised maximum salary meets this minimum."}, {"name": "salary_max", "in": "query", "schema": {"type": "string", "format": "decimal"}, "description": "Filter jobs whose advertised minimum salary stays within this ceiling."}, {"name": "apply_option", "in": "query", "schema": {"type": "string", "enum": ["external_source", "in_app"]}, "description": "Filter by application flow."}, {"name": "search", "in": "query", "schema": {"type": "string"}, "description": "Search across title, description, requirements, sector, location, employer name, and creator email."}], "responses": {"200": {"description": "Jobs returned successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AdministratorJobListResponse"}}}}, "403": {"description": "Administrator access is required."}}}, "post": {"tags": ["Administrator"], "summary": "Create a job as an administrator", "description": "Creates a job on behalf of an employer and records the authenticated administrator as the user who entered the job.", "operationId": "createAdministratorJob", "security": [{"bearerAuth": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AdministratorJobWriteRequest"}}}}, "responses": {"201": {"description": "Job created successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AdministratorJobMutationResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "403": {"description": "Administrator access is required."}}}}, "/api/administrator/jobs/{job_id}/": {"get": {"tags": ["Administrator"], "summary": "Retrieve a job", "description": "Returns a single job for administrator review.", "operationId": "retrieveAdministratorJob", "security": [{"bearerAuth": []}], "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "integer"}, "description": "Job identifier."}], "responses": {"200": {"description": "Job returned successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerJobResponse"}}}}, "403": {"description": "Administrator access is required."}, "404": {"description": "Job not found."}}}, "put": {"tags": ["Administrator"], "summary": "Replace a job", "description": "Replaces mutable job fields as an administrator.", "operationId": "updateAdministratorJob", "security": [{"bearerAuth": []}], "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "integer"}, "description": "Job identifier."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AdministratorJobWriteRequest"}}}}, "responses": {"200": {"description": "Job updated successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AdministratorJobMutationResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "403": {"description": "Administrator access is required."}, "404": {"description": "Job not found."}}}, "patch": {"tags": ["Administrator"], "summary": "Update part of a job", "description": "Partially updates mutable job fields as an administrator.", "operationId": "partialUpdateAdministratorJob", "security": [{"bearerAuth": []}], "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "integer"}, "description": "Job identifier."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AdministratorJobWriteRequest"}}}}, "responses": {"200": {"description": "Job updated successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AdministratorJobMutationResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "403": {"description": "Administrator access is required."}, "404": {"description": "Job not found."}}}, "delete": {"tags": ["Administrator"], "summary": "Delete a job", "description": "Deletes a job as an administrator.", "operationId": "deleteAdministratorJob", "security": [{"bearerAuth": []}], "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "integer"}, "description": "Job identifier."}], "responses": {"200": {"description": "Job deleted successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AdministratorJobDeleteResponse"}}}}, "403": {"description": "Administrator access is required."}, "404": {"description": "Job not found."}}}}, "/api/administrator/jobs/{job_id}/approve/": {"post": {"tags": ["Administrator"], "summary": "Approve a job", "description": "Promotes a draft or pending-approval job to the active/published state.", "operationId": "approveAdministratorJob", "security": [{"bearerAuth": []}], "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "integer"}, "description": "Job identifier."}], "responses": {"200": {"description": "Job approved successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AdministratorJobMutationResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "403": {"description": "Administrator access is required."}, "404": {"description": "Job not found."}}}}, "/api/administrator/sectors/": {"get": {"tags": ["Administrator"], "summary": "List job sectors", "description": "Returns paginated job sector taxonomy records for administrators.", "operationId": "listJobSectors", "security": [{"bearerAuth": []}], "parameters": [{"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}, "description": "Page number."}, {"name": "page_size", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}, "description": "Number of results per page."}, {"name": "search", "in": "query", "schema": {"type": "string"}, "description": "Search across name, slug, and description."}, {"name": "is_active", "in": "query", "schema": {"type": "boolean"}, "description": "Filter active versus inactive sectors."}], "responses": {"200": {"description": "Job sectors returned successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SectorListResponse"}}}}, "403": {"description": "Administrator access is required."}}}, "post": {"tags": ["Administrator"], "summary": "Create a job sector", "description": "Creates a new job sector taxonomy record.", "operationId": "createJobSector", "security": [{"bearerAuth": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SectorWriteRequest"}}}}, "responses": {"201": {"description": "Job sector created successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SectorMutationResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "403": {"description": "Administrator access is required."}}}}, "/api/administrator/sectors/{sector_id}/": {"get": {"tags": ["Administrator"], "summary": "Retrieve a job sector", "description": "Returns a single job sector taxonomy record.", "operationId": "retrieveJobSector", "security": [{"bearerAuth": []}], "responses": {"200": {"description": "Job sector returned successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SectorResponse"}}}}, "403": {"description": "Administrator access is required."}, "404": {"description": "Job sector not found."}}}, "put": {"tags": ["Administrator"], "summary": "Replace a job sector", "description": "Replaces mutable fields on a job sector record.", "operationId": "updateJobSector", "security": [{"bearerAuth": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SectorWriteRequest"}}}}, "responses": {"200": {"description": "Job sector updated successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SectorMutationResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "403": {"description": "Administrator access is required."}, "404": {"description": "Job sector not found."}}}, "patch": {"tags": ["Administrator"], "summary": "Update part of a job sector", "description": "Partially updates a job sector record.", "operationId": "partialUpdateJobSector", "security": [{"bearerAuth": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SectorWriteRequest"}}}}, "responses": {"200": {"description": "Job sector updated successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SectorMutationResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "403": {"description": "Administrator access is required."}, "404": {"description": "Job sector not found."}}}, "delete": {"tags": ["Administrator"], "summary": "Delete a job sector", "description": "Deletes a job sector when no protected job records still reference it.", "operationId": "deleteJobSector", "security": [{"bearerAuth": []}], "responses": {"200": {"description": "Job sector deleted successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteResponse"}}}}, "400": {"description": "Delete blocked by validation rules."}, "403": {"description": "Administrator access is required."}, "404": {"description": "Job sector not found."}}}}, "/api/administrator/locations/": {"get": {"tags": ["Administrator"], "summary": "List locations", "description": "Returns paginated location taxonomy records for administrators.", "operationId": "listLocations", "security": [{"bearerAuth": []}], "parameters": [{"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}, "description": "Page number."}, {"name": "page_size", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}, "description": "Number of results per page."}, {"name": "search", "in": "query", "schema": {"type": "string"}, "description": "Search across name, slug, country, province, and city."}, {"name": "is_active", "in": "query", "schema": {"type": "boolean"}, "description": "Filter active versus inactive locations."}, {"name": "is_remote", "in": "query", "schema": {"type": "boolean"}, "description": "Filter remote versus non-remote locations."}, {"name": "country", "in": "query", "schema": {"type": "string"}, "description": "Filter by country."}, {"name": "province", "in": "query", "schema": {"type": "string"}, "description": "Filter by province."}, {"name": "city", "in": "query", "schema": {"type": "string"}, "description": "Filter by city."}], "responses": {"200": {"description": "Locations returned successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LocationListResponse"}}}}, "403": {"description": "Administrator access is required."}}}, "post": {"tags": ["Administrator"], "summary": "Create a location", "description": "Creates a new location taxonomy record.", "operationId": "createLocation", "security": [{"bearerAuth": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LocationWriteRequest"}}}}, "responses": {"201": {"description": "Location created successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LocationMutationResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "403": {"description": "Administrator access is required."}}}}, "/api/administrator/locations/{location_id}/": {"get": {"tags": ["Administrator"], "summary": "Retrieve a location", "description": "Returns a single location taxonomy record.", "operationId": "retrieveLocation", "security": [{"bearerAuth": []}], "responses": {"200": {"description": "Location returned successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LocationResponse"}}}}, "403": {"description": "Administrator access is required."}, "404": {"description": "Location not found."}}}, "put": {"tags": ["Administrator"], "summary": "Replace a location", "description": "Replaces mutable fields on a location record.", "operationId": "updateLocation", "security": [{"bearerAuth": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LocationWriteRequest"}}}}, "responses": {"200": {"description": "Location updated successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LocationMutationResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "403": {"description": "Administrator access is required."}, "404": {"description": "Location not found."}}}, "patch": {"tags": ["Administrator"], "summary": "Update part of a location", "description": "Partially updates a location record.", "operationId": "partialUpdateLocation", "security": [{"bearerAuth": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LocationWriteRequest"}}}}, "responses": {"200": {"description": "Location updated successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LocationMutationResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "403": {"description": "Administrator access is required."}, "404": {"description": "Location not found."}}}, "delete": {"tags": ["Administrator"], "summary": "Delete a location", "description": "Deletes a location when no protected job records still reference it.", "operationId": "deleteLocation", "security": [{"bearerAuth": []}], "responses": {"200": {"description": "Location deleted successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteResponse"}}}}, "400": {"description": "Delete blocked by validation rules."}, "403": {"description": "Administrator access is required."}, "404": {"description": "Location not found."}}}}, "/api/employers/{employer_id}/jobs/": {"get": {"tags": ["Employers"], "summary": "List employer jobs", "description": "Returns job records for the employer identified in the path, provided the authenticated user belongs to that employer.", "operationId": "listEmployerJobs", "security": [{"bearerAuth": []}], "parameters": [{"name": "employer_id", "in": "path", "required": true, "schema": {"type": "integer"}, "description": "Employer identifier."}], "responses": {"200": {"description": "Employer jobs returned successfully.", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/EmployerJobResponse"}}}}}, "404": {"description": "Employer not found."}}}, "post": {"tags": ["Employers"], "summary": "Create an employer job", "description": "Creates a new job for the employer in the path and automatically records the authenticated user as the job creator. Jobs can be saved as drafts or submitted for approval.", "operationId": "createEmployerJob", "security": [{"bearerAuth": []}], "parameters": [{"name": "employer_id", "in": "path", "required": true, "schema": {"type": "integer"}, "description": "Employer identifier."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerJobWriteRequest"}, "examples": {"submitForApproval": {"summary": "Submit a job for approval", "value": {"sector_id": 1, "location_id": 1, "title": "Backend Engineer", "description": "Build APIs and internal tooling.", "requirements": "Python, Django, PostgreSQL", "employment_type": "full_time", "experience_level": "mid_level", "apply_option": "in_app", "salary_min": "1200.00", "salary_max": "1800.00", "currency": "USD", "submission_action": "submit_for_approval"}}, "saveDraft": {"summary": "Save a draft job", "value": {"sector_id": 1, "location_id": 1, "title": "Engineering Manager", "description": "Draft role awaiting review.", "requirements": "Leadership and delivery experience", "employment_type": "full_time", "experience_level": "senior", "apply_option": "in_app", "submission_action": "save_as_draft"}}}}}}, "responses": {"201": {"description": "Employer job created successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerJobResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "404": {"description": "Employer not found."}}}}, "/api/employers/{employer_id}/jobs/{job_id}/": {"get": {"tags": ["Employers"], "summary": "Retrieve a single employer job", "description": "Returns one job belonging to the employer in the path.", "operationId": "retrieveEmployerJob", "security": [{"bearerAuth": []}], "parameters": [{"name": "employer_id", "in": "path", "required": true, "schema": {"type": "integer"}, "description": "Employer identifier."}, {"name": "job_id", "in": "path", "required": true, "schema": {"type": "integer"}, "description": "Job identifier."}], "responses": {"200": {"description": "Employer job returned successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerJobResponse"}}}}, "404": {"description": "Employer or job not found."}}}, "put": {"tags": ["Employers"], "summary": "Replace an employer job", "description": "Replaces mutable job fields for a job owned by the authenticated employer. Use `submission_action` to save as draft or resubmit for approval.", "operationId": "updateEmployerJob", "security": [{"bearerAuth": []}], "parameters": [{"name": "employer_id", "in": "path", "required": true, "schema": {"type": "integer"}, "description": "Employer identifier."}, {"name": "job_id", "in": "path", "required": true, "schema": {"type": "integer"}, "description": "Job identifier."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerJobWriteRequest"}}}}, "responses": {"200": {"description": "Employer job updated successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerJobResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "404": {"description": "Employer or job not found."}}}, "patch": {"tags": ["Employers"], "summary": "Update part of an employer job", "description": "Partially updates a job owned by the authenticated employer. Use `submission_action` to save as draft or submit for approval.", "operationId": "partialUpdateEmployerJob", "security": [{"bearerAuth": []}], "parameters": [{"name": "employer_id", "in": "path", "required": true, "schema": {"type": "integer"}, "description": "Employer identifier."}, {"name": "job_id", "in": "path", "required": true, "schema": {"type": "integer"}, "description": "Job identifier."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerJobWriteRequest"}}}}, "responses": {"200": {"description": "Employer job updated successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerJobResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "404": {"description": "Employer or job not found."}}}, "delete": {"tags": ["Employers"], "summary": "Delete an employer job", "description": "Deletes a job owned by the authenticated employer.", "operationId": "deleteEmployerJob", "security": [{"bearerAuth": []}], "parameters": [{"name": "employer_id", "in": "path", "required": true, "schema": {"type": "integer"}, "description": "Employer identifier."}, {"name": "job_id", "in": "path", "required": true, "schema": {"type": "integer"}, "description": "Job identifier."}], "responses": {"204": {"description": "Employer job deleted successfully."}, "404": {"description": "Employer or job not found."}}}}, "/api/employers/register/": {"post": {"tags": ["Employers"], "summary": "Register an employer account", "description": "Creates or links an AppUser record, creates the employer organisation, and creates the first EmployerUser owner in a single transaction.", "operationId": "registerEmployer", "security": [], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerRegistrationRequest"}, "examples": {"employerRegistration": {"summary": "Employer registration request", "value": {"user": {"firebase_uid": "firebase-employer-1", "email_address": "owner@brightlabs.example", "phone_number": "+263700000020", "first_name": "Rudo", "last_name": "Ncube"}, "employer": {"company_name": "Bright Labs", "email_address": "contact@brightlabs.example", "phone_number": "+263700000021", "sector": "Technology", "description": "Talent and software services.", "location": "Harare", "employer_type": "company"}}}}}}}, "responses": {"201": {"description": "Employer registered successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmployerRegistrationResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}}}}, "/api/notifications/": {"get": {"tags": ["Notifications"], "summary": "List notifications for the authenticated user", "description": "Returns only notifications delivered to the authenticated user, with pagination, filtering, archive visibility, search, and ordering support.", "operationId": "listNotifications", "security": [{"bearerAuth": []}], "parameters": [{"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}, "description": "Page number."}, {"name": "page_size", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}, "description": "Number of results per page."}, {"name": "status", "in": "query", "schema": {"type": "string", "enum": ["unread", "read", "archived"]}, "description": "Filter by read/unread status."}, {"name": "notification_type", "in": "query", "schema": {"type": "string", "enum": ["employer_approved", "employer_rejected", "job_application_received", "job_application_status_changed", "payment_received", "system_alert", "general"]}, "description": "Filter by notification type."}, {"name": "target_audience", "in": "query", "schema": {"type": "string", "enum": ["single_user", "multiple_users", "global", "candidates", "employer_users", "admins", "employer_company_users"]}, "description": "Filter by the audience used when the notification was sent."}, {"name": "is_archived", "in": "query", "schema": {"type": "boolean"}, "description": "When true, returns archived notifications instead of the active inbox."}, {"name": "search", "in": "query", "schema": {"type": "string"}, "description": "Search across title, message, sender email, and employer company name."}, {"name": "ordering", "in": "query", "schema": {"type": "string", "enum": ["latest", "oldest"]}, "description": "Choose newest-first or oldest-first ordering."}], "responses": {"200": {"description": "Notifications returned successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/NotificationListResponse"}}}}, "403": {"description": "Authentication credentials were not provided."}}}}, "/api/notifications/unread-count/": {"get": {"tags": ["Notifications"], "summary": "Get the unread notification count", "description": "Returns the unread inbox count for the authenticated user.", "operationId": "getNotificationUnreadCount", "security": [{"bearerAuth": []}], "responses": {"200": {"description": "Unread count returned successfully.", "content": {"application/json": {"schema": {"type": "object", "properties": {"unread_count": {"type": "integer"}}}}}}}}}, "/api/admin/notifications/send/": {"post": {"tags": ["Notifications"], "summary": "Send a targeted notification", "description": "Administrator-only endpoint that creates a notification campaign and delivers notifications to one user, multiple users, all users, candidates, employer users, admins, or every active member of a specific employer company.", "operationId": "sendNotification", "security": [{"bearerAuth": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/NotificationSendRequest"}}}}, "responses": {"201": {"description": "Notification sent successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/NotificationSendResponse"}}}}, "400": {"description": "Validation failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationError"}}}}, "403": {"description": "Administrator access is required to send notifications."}}}}, "/api/admin/notifications/sent/": {"get": {"tags": ["Notifications"], "summary": "List sent notification campaigns", "description": "Returns sent notification campaigns for administrator review.", "operationId": "listSentNotificationCampaigns", "security": [{"bearerAuth": []}], "responses": {"200": {"description": "Sent notification campaigns returned successfully."}}}}, "/api/admin/notifications/{campaign_id}/delivery/": {"get": {"tags": ["Notifications"], "summary": "List delivery status for a notification campaign", "description": "Returns per-user delivery state for a sent notification campaign.", "operationId": "listNotificationCampaignDelivery", "security": [{"bearerAuth": []}], "responses": {"200": {"description": "Notification delivery returned successfully."}, "404": {"description": "Notification campaign not found."}}}}, "/api/notifications/{notification_id}/read/": {"post": {"tags": ["Notifications"], "summary": "Mark a notification as read", "description": "Marks one notification as read for the authenticated user.", "operationId": "markNotificationRead", "security": [{"bearerAuth": []}], "responses": {"200": {"description": "Notification marked as read.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/NotificationMutationResponse"}}}}, "404": {"description": "Notification not found."}}}}, "/api/notifications/read-all/": {"post": {"tags": ["Notifications"], "summary": "Mark all notifications as read", "description": "Marks all active inbox notifications as read for the authenticated user.", "operationId": "markAllNotificationsRead", "security": [{"bearerAuth": []}], "responses": {"200": {"description": "Notifications marked as read.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/NotificationMarkAllReadResponse"}}}}}}}, "/api/notifications/{notification_id}/archive/": {"post": {"tags": ["Notifications"], "summary": "Archive a notification", "description": "Archives one notification for the authenticated user.", "operationId": "archiveNotification", "security": [{"bearerAuth": []}], "responses": {"200": {"description": "Notification archived successfully.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/NotificationMutationResponse"}}}}, "404": {"description": "Notification not found."}}}}}, "components": {"securitySchemes": {"bearerAuth": {"type": "http", "scheme": "bearer", "bearerFormat": "Firebase ID Token", "description": "Firebase ID token supplied as `Authorization: Bearer <token>`."}}, "schemas": {"CandidateRegistrationUser": {"type": "object", "required": ["firebase_uid", "email_address"], "properties": {"firebase_uid": {"type": "string", "maxLength": 128}, "email_address": {"type": "string", "format": "email"}, "phone_number": {"type": "string", "maxLength": 30, "nullable": true}, "first_name": {"type": "string", "maxLength": 100}, "last_name": {"type": "string", "maxLength": 100}, "date_of_birth": {"type": "string", "format": "date", "nullable": true}, "profile_picture": {"type": "string", "format": "uri", "nullable": true}}}, "CandidateRegistrationProfile": {"type": "object", "required": ["candidate_category"], "properties": {"candidate_category": {"type": "string", "enum": ["white_collar", "blue_collar"]}, "candidate_type": {"type": "string", "enum": ["graduate", "intern", "worker"], "nullable": true}, "professional_title": {"type": "string", "maxLength": 150}, "professional_summary": {"type": "string"}, "skills": {"type": "array", "items": {"type": "string"}, "default": []}, "years_of_experience": {"type": "integer", "minimum": 0}, "availability_status": {"type": "string", "maxLength": 50}, "preferred_job_type": {"type": "string", "maxLength": 100}, "preferred_location": {"type": "string", "maxLength": 150}}}, "CandidateRegistrationRequest": {"type": "object", "required": ["user", "candidate"], "properties": {"user": {"$ref": "#/components/schemas/CandidateRegistrationUser"}, "candidate": {"$ref": "#/components/schemas/CandidateRegistrationProfile"}}}, "AppUser": {"type": "object", "properties": {"id": {"type": "integer"}, "firebase_uid": {"type": "string"}, "email_address": {"type": "string", "format": "email"}, "phone_number": {"type": "string", "nullable": true}, "first_name": {"type": "string"}, "last_name": {"type": "string"}, "date_of_birth": {"type": "string", "format": "date", "nullable": true}, "profile_picture": {"type": "string", "format": "uri", "nullable": true}, "status": {"type": "string"}, "date_joined": {"type": "string", "format": "date-time"}}}, "CandidateRegistrationResponse": {"type": "object", "properties": {"id": {"type": "integer"}, "user": {"$ref": "#/components/schemas/AppUser"}, "candidate_category": {"type": "string"}, "candidate_type": {"type": "string", "nullable": true}, "professional_title": {"type": "string"}, "professional_summary": {"type": "string"}, "skills": {"type": "array", "items": {"type": "string"}}, "years_of_experience": {"type": "integer"}, "availability_status": {"type": "string"}, "preferred_job_type": {"type": "string"}, "preferred_location": {"type": "string"}, "created_at": {"type": "string", "format": "date-time"}, "updated_at": {"type": "string", "format": "date-time"}}}, "EmployerRegistrationCompany": {"type": "object", "required": ["company_name", "email_address", "sector", "employer_type"], "properties": {"company_name": {"type": "string", "maxLength": 200}, "email_address": {"type": "string", "format": "email"}, "phone_number": {"type": "string", "maxLength": 30}, "sector": {"type": "string", "maxLength": 150}, "description": {"type": "string"}, "location": {"type": "string", "maxLength": 200}, "employer_type": {"type": "string", "enum": ["agent", "company", "recruiter"]}}}, "EmployerRegistrationRequest": {"type": "object", "required": ["user", "employer"], "properties": {"user": {"$ref": "#/components/schemas/CandidateRegistrationUser"}, "employer": {"$ref": "#/components/schemas/EmployerRegistrationCompany"}}}, "EmployerWriteRequest": {"$ref": "#/components/schemas/EmployerRegistrationCompany"}, "EmployerUserMembership": {"type": "object", "properties": {"id": {"type": "integer"}, "role": {"type": "string"}, "status": {"type": "string"}, "date_added": {"type": "string", "format": "date-time"}}}, "JobEmployerSummary": {"type": "object", "properties": {"id": {"type": "integer"}, "company_name": {"type": "string"}}}, "JobPostedBySummary": {"type": "object", "properties": {"id": {"type": "integer"}, "email_address": {"type": "string", "format": "email"}, "first_name": {"type": "string"}, "last_name": {"type": "string"}, "full_name": {"type": "string"}}}, "SectorResponse": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}, "slug": {"type": "string"}, "description": {"type": "string"}, "is_active": {"type": "boolean"}, "created_at": {"type": "string", "format": "date-time"}, "updated_at": {"type": "string", "format": "date-time"}}}, "SectorWriteRequest": {"type": "object", "required": ["name", "slug"], "properties": {"name": {"type": "string", "maxLength": 150}, "slug": {"type": "string", "maxLength": 180}, "description": {"type": "string"}, "is_active": {"type": "boolean", "default": true}}}, "SectorListResponse": {"type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "nullable": true}, "previous": {"type": "string", "format": "uri", "nullable": true}, "results": {"type": "array", "items": {"$ref": "#/components/schemas/SectorResponse"}}}}, "SectorMutationResponse": {"type": "object", "properties": {"message": {"type": "string"}, "sector": {"$ref": "#/components/schemas/SectorResponse"}}}, "LocationResponse": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}, "slug": {"type": "string"}, "country": {"type": "string"}, "province": {"type": "string"}, "city": {"type": "string"}, "is_remote": {"type": "boolean"}, "is_active": {"type": "boolean"}, "display_name": {"type": "string"}, "created_at": {"type": "string", "format": "date-time"}, "updated_at": {"type": "string", "format": "date-time"}}}, "LocationWriteRequest": {"type": "object", "required": ["name", "slug"], "properties": {"name": {"type": "string", "maxLength": 150}, "slug": {"type": "string", "maxLength": 180}, "country": {"type": "string", "maxLength": 100, "default": "Zimbabwe"}, "province": {"type": "string", "maxLength": 100}, "city": {"type": "string", "maxLength": 100}, "is_remote": {"type": "boolean", "default": false}, "is_active": {"type": "boolean", "default": true}}}, "LocationListResponse": {"type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "nullable": true}, "previous": {"type": "string", "format": "uri", "nullable": true}, "results": {"type": "array", "items": {"$ref": "#/components/schemas/LocationResponse"}}}}, "LocationMutationResponse": {"type": "object", "properties": {"message": {"type": "string"}, "location": {"$ref": "#/components/schemas/LocationResponse"}}}, "DeleteResponse": {"type": "object", "properties": {"message": {"type": "string"}}}, "AdministratorJobWriteRequest": {"type": "object", "required": ["employer_id", "sector_id", "location_id", "title", "description", "requirements", "employment_type", "experience_level", "apply_option"], "properties": {"employer_id": {"type": "integer"}, "sector_id": {"type": "integer"}, "location_id": {"type": "integer"}, "title": {"type": "string", "maxLength": 200}, "description": {"type": "string"}, "requirements": {"type": "string"}, "employment_type": {"type": "string", "enum": ["full_time", "part_time", "contract", "temporary", "internship", "freelance"]}, "experience_level": {"type": "string", "enum": ["entry_level", "junior", "mid_level", "senior", "lead", "executive"]}, "apply_option": {"type": "string", "enum": ["external_source", "in_app"]}, "apply_url": {"type": "string", "format": "uri", "nullable": true}, "salary_min": {"type": "string", "format": "decimal", "nullable": true}, "salary_max": {"type": "string", "format": "decimal", "nullable": true}, "currency": {"type": "string", "maxLength": 10}, "status": {"type": "string", "enum": ["draft", "pending_approval"], "default": "pending_approval"}}}, "AdministratorJobListResponse": {"type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "nullable": true}, "previous": {"type": "string", "format": "uri", "nullable": true}, "results": {"type": "array", "items": {"$ref": "#/components/schemas/ManagedJobResponse"}}}}, "AdministratorJobMutationResponse": {"type": "object", "properties": {"message": {"type": "string"}, "job": {"$ref": "#/components/schemas/ManagedJobResponse"}}}, "AdministratorJobDeleteResponse": {"$ref": "#/components/schemas/DeleteResponse"}, "EmployerJobWriteRequest": {"type": "object", "required": ["sector_id", "location_id", "title", "description", "requirements", "employment_type", "experience_level", "apply_option"], "properties": {"sector_id": {"type": "integer"}, "location_id": {"type": "integer"}, "title": {"type": "string", "maxLength": 200}, "description": {"type": "string"}, "requirements": {"type": "string"}, "employment_type": {"type": "string", "enum": ["full_time", "part_time", "contract", "temporary", "internship", "freelance"]}, "experience_level": {"type": "string", "enum": ["entry_level", "junior", "mid_level", "senior", "lead", "executive"]}, "apply_option": {"type": "string", "enum": ["external_source", "in_app"]}, "apply_url": {"type": "string", "format": "uri", "nullable": true}, "salary_min": {"type": "string", "format": "decimal", "nullable": true}, "salary_max": {"type": "string", "format": "decimal", "nullable": true}, "currency": {"type": "string", "maxLength": 10}, "submission_action": {"type": "string", "enum": ["save_as_draft", "submit_for_approval"], "default": "submit_for_approval"}}}, "ManagedJobResponse": {"type": "object", "properties": {"id": {"type": "integer"}, "employer": {"$ref": "#/components/schemas/JobEmployerSummary"}, "posted_by": {"allOf": [{"$ref": "#/components/schemas/JobPostedBySummary"}], "nullable": true}, "sector": {"$ref": "#/components/schemas/SectorResponse"}, "location": {"$ref": "#/components/schemas/LocationResponse"}, "title": {"type": "string"}, "description": {"type": "string"}, "requirements": {"type": "string"}, "employment_type": {"type": "string"}, "experience_level": {"type": "string"}, "apply_option": {"type": "string"}, "apply_url": {"type": "string", "format": "uri", "nullable": true}, "salary_min": {"type": "string", "format": "decimal", "nullable": true}, "salary_max": {"type": "string", "format": "decimal", "nullable": true}, "currency": {"type": "string"}, "date_posted": {"type": "string", "format": "date-time", "nullable": true}, "expiry_date": {"type": "string", "format": "date-time", "nullable": true}, "status": {"type": "string"}, "created_at": {"type": "string", "format": "date-time"}, "updated_at": {"type": "string", "format": "date-time"}}}, "EmployerJobResponse": {"$ref": "#/components/schemas/ManagedJobResponse"}, "PublicJobResponse": {"type": "object", "properties": {"id": {"type": "integer"}, "employer": {"$ref": "#/components/schemas/JobEmployerSummary"}, "sector": {"$ref": "#/components/schemas/SectorResponse"}, "location": {"$ref": "#/components/schemas/LocationResponse"}, "title": {"type": "string"}, "description": {"type": "string"}, "requirements": {"type": "string"}, "employment_type": {"type": "string"}, "experience_level": {"type": "string"}, "apply_option": {"type": "string"}, "apply_url": {"type": "string", "format": "uri", "nullable": true}, "salary_min": {"type": "string", "format": "decimal", "nullable": true}, "salary_max": {"type": "string", "format": "decimal", "nullable": true}, "currency": {"type": "string"}, "date_posted": {"type": "string", "format": "date-time", "nullable": true}, "expiry_date": {"type": "string", "format": "date-time", "nullable": true}, "status": {"type": "string"}, "created_at": {"type": "string", "format": "date-time"}, "updated_at": {"type": "string", "format": "date-time"}}}, "PublicJobListResponse": {"type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "nullable": true}, "previous": {"type": "string", "format": "uri", "nullable": true}, "results": {"type": "array", "items": {"$ref": "#/components/schemas/PublicJobResponse"}}}}, "EmployerResponse": {"type": "object", "properties": {"id": {"type": "integer"}, "company_name": {"type": "string"}, "email_address": {"type": "string", "format": "email"}, "phone_number": {"type": "string"}, "sector": {"type": "string"}, "description": {"type": "string"}, "location": {"type": "string"}, "employer_type": {"type": "string"}, "status": {"type": "string"}, "date_added": {"type": "string", "format": "date-time"}, "approved_at": {"type": "string", "format": "date-time", "nullable": true}, "rejection_reason": {"type": "string"}, "current_user_membership": {"allOf": [{"$ref": "#/components/schemas/EmployerUserMembership"}], "nullable": true}}}, "EmployerRegistrationResponse": {"type": "object", "properties": {"id": {"type": "integer"}, "company_name": {"type": "string"}, "email_address": {"type": "string", "format": "email"}, "phone_number": {"type": "string"}, "sector": {"type": "string"}, "description": {"type": "string"}, "location": {"type": "string"}, "employer_type": {"type": "string"}, "status": {"type": "string"}, "date_added": {"type": "string", "format": "date-time"}, "initial_user": {"$ref": "#/components/schemas/AppUser"}, "employer_user": {"$ref": "#/components/schemas/EmployerUserMembership"}}}, "NotificationSenderSummary": {"type": "object", "nullable": true, "properties": {"id": {"type": "integer"}, "email_address": {"type": "string", "format": "email"}, "first_name": {"type": "string"}, "last_name": {"type": "string"}, "full_name": {"type": "string"}}}, "NotificationEmployerSummary": {"type": "object", "nullable": true, "properties": {"id": {"type": "integer"}, "company_name": {"type": "string"}}}, "NotificationSendRequest": {"type": "object", "required": ["title", "message", "target_audience"], "properties": {"title": {"type": "string", "maxLength": 255}, "message": {"type": "string"}, "target_audience": {"type": "string", "enum": ["single_user", "multiple_users", "global", "candidates", "employer_users", "admins", "employer_company_users"]}, "notification_type": {"type": "string", "enum": ["employer_approved", "employer_rejected", "job_application_received", "job_application_status_changed", "payment_received", "system_alert", "general"], "default": "general"}, "employer_id": {"type": "integer", "nullable": true}, "related_entity_type": {"type": "string", "maxLength": 100}, "related_entity_id": {"type": "integer", "minimum": 1, "nullable": true}}}, "NotificationDeliverySummary": {"type": "object", "properties": {"title": {"type": "string"}, "message": {"type": "string"}, "target_audience": {"type": "string"}, "notification_type": {"type": "string"}, "recipient_count": {"type": "integer"}, "date_created": {"type": "string", "format": "date-time"}, "sender": {"$ref": "#/components/schemas/NotificationSenderSummary"}, "employer": {"$ref": "#/components/schemas/NotificationEmployerSummary"}}}, "NotificationSendResponse": {"type": "object", "properties": {"message": {"type": "string"}, "delivery": {"$ref": "#/components/schemas/NotificationDeliverySummary"}}}, "NotificationResponse": {"type": "object", "properties": {"id": {"type": "integer"}, "title": {"type": "string"}, "message": {"type": "string"}, "notification_type": {"type": "string"}, "target_audience": {"type": "string"}, "status": {"type": "string"}, "sender": {"$ref": "#/components/schemas/NotificationSenderSummary"}, "employer": {"$ref": "#/components/schemas/NotificationEmployerSummary"}, "related_entity_type": {"type": "string"}, "related_entity_id": {"type": "integer", "nullable": true}, "is_archived": {"type": "boolean"}, "archived_at": {"type": "string", "format": "date-time", "nullable": true}, "date_created": {"type": "string", "format": "date-time"}, "date_opened": {"type": "string", "format": "date-time", "nullable": true}}}, "NotificationListResponse": {"type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "nullable": true}, "previous": {"type": "string", "format": "uri", "nullable": true}, "results": {"type": "array", "items": {"$ref": "#/components/schemas/NotificationResponse"}}}}, "NotificationMutationResponse": {"type": "object", "properties": {"message": {"type": "string"}, "notification": {"$ref": "#/components/schemas/NotificationResponse"}}}, "NotificationMarkAllReadResponse": {"type": "object", "properties": {"message": {"type": "string"}, "updated_count": {"type": "integer"}}}, "ValidationError": {"type": "object", "additionalProperties": {"oneOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}}, {"type": "object", "additionalProperties": {"oneOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}}]}}]}}}}}