Hireable LogoHireable
Backend API

Waitlist API

Waitlist endpoints for talent and employer registration

Overview

The waitlist API allows users to join the platform waitlist before full launch. It supports separate flows for talent and employers.

Endpoints

MethodEndpointDescription
POST/api/waitlist/talentJoin waitlist as talent
POST/api/waitlist/employerJoin waitlist as employer
GET/api/waitlistList waitlist entries (admin)
GET/api/waitlist/statusCheck waitlist position

Join as Talent

Register interest as a job seeker.

Request

POST /api/waitlist/talent
Content-Type: application/json
 
{
  "firstName": "John",
  "lastName": "Doe",
  "email": "john.doe@example.com",
  "role": "Software Engineer",
  "agree": true
}

Request Body

FieldTypeRequiredDescription
firstNamestringYes2-50 characters, letters only
lastNamestringYes2-50 characters, letters only
emailstringYesValid email, max 254 characters
rolestringNoJob title/role (max 100 chars)
agreebooleanYesMust be true

Response

{
  "message": "Successfully added to waitlist",
  "success": true,
  "data": {
    "id": "507f1f77bcf86cd799439011",
    "timestamp": "2024-01-15T10:30:00.000Z"
  }
}

Error Responses

// 400 Bad Request - Validation error
{
  "message": "Email is required"
}
 
// 409 Conflict - Already registered
{
  "message": "This email is already on the waitlist."
}
 
// 500 Internal Server Error
{
  "message": "Error saving data"
}

Join as Employer

Register interest as a hiring company.

Request

POST /api/waitlist/employer
Content-Type: application/json
 
{
  "firstName": "Jane",
  "lastName": "Smith",
  "email": "jane.smith@company.com",
  "company": "Tech Corp Inc",
  "companySize": "51-200",
  "industry": "technology",
  "role": "HR Manager",
  "agree": true
}

Request Body

FieldTypeRequiredDescription
firstNamestringYes2-50 characters, letters only
lastNamestringYes2-50 characters, letters only
emailstringYesValid email, max 254 characters
companystringYes2-100 characters
companySizestringYesCompany size range
industrystringYesIndustry category
rolestringNoJob title (max 100 chars)
agreebooleanYesMust be true

Company Size Options

  • 1-10
  • 11-50
  • 51-200
  • 201-500
  • 500+

Industry Options

  • technology
  • finance
  • healthcare
  • education
  • retail
  • manufacturing
  • other

Response

{
  "message": "Successfully added to waitlist",
  "success": true,
  "data": {
    "id": "507f1f77bcf86cd799439012",
    "timestamp": "2024-01-15T11:00:00.000Z"
  }
}

List Waitlist Entries

Get paginated list of waitlist entries (admin only).

Request

GET /api/waitlist?page=1&limit=10&sortBy=createdAt&sortOrder=desc
Authorization: Bearer <admin_token>

Query Parameters

ParameterTypeDefaultDescription
pagenumber1Page number
limitnumber10Items per page
sortBystringcreatedAtSort field
sortOrderstringdescasc or desc

Response

{
  "data": [
    {
      "id": "507f1f77bcf86cd799439011",
      "firstName": "John",
      "lastName": "Doe",
      "email": "john.doe@example.com",
      "role": "talent",
      "createdAt": "2024-01-15T10:30:00.000Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 150,
    "totalPages": 15
  }
}

Check Waitlist Status

Check position in the waitlist by email.

Request

GET /api/waitlist/status?email=john.doe@example.com

Response

{
  "position": 42,
  "total": 1000
}

Database Models

Talent Model

interface ITalent extends Document {
  firstName: string;
  lastName: string;
  email: string;      // unique
  role: string;
  agree: boolean;
  createdAt?: Date;
  updatedAt?: Date;
}

Employer Model

interface IEmployer extends Document {
  firstName: string;
  lastName: string;
  email: string;      // unique
  company: string;
  companySize: string;
  industry: string;
  role: string;
  agree: boolean;
  createdAt?: Date;
  updatedAt?: Date;
}

Validation

All inputs are validated using SecurityValidator from @hireable/shared:

import { SecurityValidator } from "@hireable/shared";
 
// Validate email
const emailResult = SecurityValidator.validateEmail(email);
if (!emailResult.isValid) {
  return res.status(400).json({ message: emailResult.errors[0] });
}
 
// Validate name
const nameResult = SecurityValidator.validateFirstName(firstName);
if (!nameResult.isValid) {
  return res.status(400).json({ message: nameResult.errors[0] });
}
 
// Use sanitized data
const sanitizedEmail = emailResult.sanitizedData;

Validation Rules

ValidatorRules
validateEmailRequired, valid format, max 254 chars, lowercase trimmed
validateFirstNameRequired, 2-50 chars, letters/spaces/hyphens only
validateLastNameRequired, 2-50 chars, letters/spaces/hyphens only
validateCompanyRequired, 2-100 chars, alphanumeric with common symbols
validateCompanySizeRequired, valid format
validateIndustryRequired, valid format
validateRoleOptional, max 100 chars, sanitized
validateAgreeRequired, must be true

Frontend Integration

import { waitlistService } from "@/features/waitlist";
 
// Join as talent
try {
  const result = await waitlistService.joinTalent({
    firstName: "John",
    lastName: "Doe",
    email: "john@example.com",
    role: "Software Engineer",
    agree: true,
  });
  console.log("Joined waitlist:", result.data.id);
} catch (error) {
  console.error("Failed to join:", error.message);
}
 
// Join as employer
try {
  const result = await waitlistService.joinEmployer({
    firstName: "Jane",
    lastName: "Smith",
    email: "jane@company.com",
    company: "Tech Corp",
    companySize: "51-200",
    industry: "technology",
    role: "HR Manager",
    agree: true,
  });
  console.log("Joined waitlist:", result.data.id);
} catch (error) {
  console.error("Failed to join:", error.message);
}