Skip to main content

Overview

The Jobs API allows you to create, manage, and organize job postings within your company. Jobs are the foundation of the InstaView recruitment workflow, serving as the primary container for candidates and interviews.

Resource Structure

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "companyId": "987e6543-e21b-12d3-a456-426614174000",
  "title": "Senior Software Engineer",
  "description": "We are seeking an experienced software engineer...",
  "requiredSkills": ["JavaScript", "React", "Node.js", "TypeScript"],
  "niceToHaveSkills": ["GraphQL", "Docker", "AWS"],
  "languageRequirements": [
    { "language": "EN", "proficiency": "C1" },
    { "language": "ES", "proficiency": "B1" }
  ],
  "location": {
    "workMode": "HYBRID",
    "street": "123 Tech Street",
    "city": "San Francisco",
    "postalCode": "94105",
    "countryCode": "US"
  },
  "salary": {
    "min": 120000,
    "max": 180000,
    "currency": "USD",
    "period": "YEARLY"
  },
  "jobUrl": "https://company.com/careers/senior-engineer",
  "status": "OPEN",
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-01-15T10:30:00Z"
}

Required Scopes

OperationRequired Scope
List jobsread:jobs
Get job by IDread:jobs
Create jobwrite:jobs
Update jobwrite:jobs
Delete jobdelete:jobs

Creating Jobs

Basic Job Creation

curl -X POST https://api.instaview.sk/jobs \
  -H "Authorization: Bearer sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Senior Software Engineer",
    "description": "We are seeking an experienced software engineer...",
    "requiredSkills": ["JavaScript", "React", "Node.js"],
    "status": "OPEN"
  }'

Comprehensive Job Creation

const comprehensiveJob = {
  // Required fields
  title: 'Senior Software Engineer',
  description: 'We are seeking an experienced software engineer with 5+ years of experience...',
  
  // Skills
  requiredSkills: [
    'JavaScript',
    'React',
    'Node.js',
    'TypeScript',
    'REST APIs'
  ],
  niceToHaveSkills: [
    'GraphQL',
    'Docker',
    'Kubernetes',
    'AWS'
  ],
  
  // Language requirements (ISO 639-1 language codes + CEFR proficiency levels)
  languageRequirements: [
    { language: 'EN', proficiency: 'C1' },  // English - Proficient
    { language: 'ES', proficiency: 'B1' }   // Spanish - Intermediate
  ],
  
  // Location
  location: {
    workMode: 'HYBRID',  // Options: REMOTE, HYBRID, ONSITE
    street: '123 Tech Street',
    city: 'San Francisco',
    postalCode: '94105',
    countryCode: 'US'
  },
  
  // Compensation
  salary: {
    min: 120000,
    max: 180000,
    currency: 'USD',
    period: 'annual'
  },
  
  // Additional info
  jobUrl: 'https://company.com/careers/senior-engineer',
  status: 'OPEN'
};

const response = await createJob(comprehensiveJob);

Listing Jobs

List All Jobs

async function listJobs(page = 1, limit = 20) {
  const response = await fetch(
    `https://api.instaview.sk/jobs?page=${page}&limit=${limit}`,
    {
      headers: { 'Authorization': `Bearer ${apiKey}` }
    }
  );
  
  const result = await response.json();
  return result.data;
}

// Usage
const { items, pagination } = await listJobs(1, 50);
console.log(`Found ${pagination.total} jobs`);

Filter by Status

async function getActiveJobs() {
  const response = await fetch(
    'https://api.instaview.sk/jobs?status=OPEN&limit=100',
    {
      headers: { 'Authorization': `Bearer ${apiKey}` }
    }
  );
  
  return await response.json();
}

Search Jobs

async function searchJobs(query) {
  const response = await fetch(
    `https://api.instaview.sk/jobs?search=${encodeURIComponent(query)}`,
    {
      headers: { 'Authorization': `Bearer ${apiKey}` }
    }
  );
  
  return await response.json();
}

// Search by title
const engineerJobs = await searchJobs('engineer');

Updating Jobs

Partial Update

async function updateJob(jobId, updates) {
  const response = await fetch(
    `https://api.instaview.sk/jobs/${jobId}`,
    {
      method: 'PATCH',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(updates)
    }
  );
  
  return await response.json();
}

// Update only specific fields
await updateJob('job-uuid', {
  title: 'Staff Software Engineer', // Promoted!
  salary: {
    min: 150000,
    max: 220000,
    currency: 'USD',
    period: 'annual'
  }
});

Change Job Status

// Mark job as closed
await updateJob('job-uuid', { status: 'CLOSED' });

// Reopen job
await updateJob('job-uuid', { status: 'OPEN' });

Job Status Management

Available Statuses

Job is open for applications
  • Visible to candidates
  • Can schedule interviews
  • Accepts new applications

Status Workflow

class JobWorkflow {
  async createJob(jobData) {
    return await createJob({
      ...jobData,
      status: 'OPEN'  // Jobs start as OPEN
    });
  }
  
  async closeJob(jobId) {
    return await updateJob(jobId, { status: 'CLOSED' });
  }
  
  async reopenJob(jobId) {
    return await updateJob(jobId, { status: 'OPEN' });
  }
}

Location and Work Mode

Work Modes

ModeDescription
remoteFully remote position
on_siteOffice-based only
hybridMix of remote and office

Location Structure

{
  location: {
    street: '123 Tech Street',      // Optional
    city: 'San Francisco',           // Recommended
    postalCode: '94105',             // Optional
    countryCode: 'US'                // Required (ISO 3166-1 alpha-2)
  }
}

Examples

// Fully remote position
{
  location: {
    workMode: 'REMOTE',
  location: {
    countryCode: 'US' // Country for legal/tax purposes
  }
}

// Hybrid with specific office
{
  location: {
    workMode: 'HYBRID',
  location: {
    street: '1 Apple Park Way',
    city: 'Cupertino',
    postalCode: '95014',
    countryCode: 'US'
  }
}

// On-site position
{
  workMode: 'on_site',
  location: {
    city: 'New York',
    countryCode: 'US'
  }
}

Salary Information

Salary Structure

{
  salary: {
    min: 100000,           // Minimum compensation
    max: 150000,           // Maximum compensation
    currency: 'USD',       // ISO 4217 currency code
    period: 'YEARLY'       // Options: 'YEARLY', 'MONTHLY', 'HOURLY'
  }
}

Examples

// Annual salary range
{
  salary: {
    min: 120000,
    max: 180000,
    currency: 'USD',
    period: 'annual'
  }
}

// Hourly rate
{
  salary: {
    min: 75,
    max: 125,
    currency: 'USD',
    period: 'hourly'
  }
}

// Monthly salary (common in some regions)
{
  salary: {
    min: 8000,
    max: 12000,
    currency: 'EUR',
    period: 'monthly'
  }
}

// Omit salary (not disclosed)
{
  // salary field can be omitted entirely
}

Skills Management

Best Practices

// ✅ Good: Specific technologies
requiredSkills: ['React 18+', 'Node.js', 'PostgreSQL', 'TypeScript']

// ❌ Too vague
requiredSkills: ['Frontend', 'Backend', 'Database']
{
  requiredSkills: [
    'JavaScript',
    'React',
    'REST APIs'
  ],
  niceToHaveSkills: [
    'TypeScript',
    'GraphQL',
    'Docker'
  ]
}
// ✅ Consistent
requiredSkills: ['JavaScript', 'TypeScript', 'Node.js']

// ❌ Inconsistent casing/spelling
requiredSkills: ['javascript', 'Typescript', 'NodeJS']

Deleting Jobs

Soft Delete

Jobs are soft-deleted by default:
async function deleteJob(jobId) {
  const response = await fetch(
    `https://api.instaview.sk/jobs/${jobId}`,
    {
      method: 'DELETE',
      headers: { 'Authorization': `Bearer ${apiKey}` }
    }
  );
  
  return await response.json();
}
Deleted jobs are not returned in list queries but maintain their relationships with candidates and interviews for audit purposes.

Before Deleting

Consider the impact:
async function safeDeleteJob(jobId) {
  // Check for active candidates
  const candidates = await listCandidates({ jobId });
  
  if (candidates.pagination.total > 0) {
    console.warn(`Job has ${candidates.pagination.total} candidates`);
    const confirm = await askUser('Delete anyway?');
    if (!confirm) return;
  }
  
  // Proceed with deletion
  return await deleteJob(jobId);
}

Common Patterns

Bulk Job Creation

async function bulkCreateJobs(jobsData) {
  const results = [];
  const errors = [];
  
  for (const jobData of jobsData) {
    try {
      const job = await createJob(jobData);
      results.push(job);
      
      // Rate limiting: wait between requests
      await sleep(200);
    } catch (error) {
      errors.push({
        jobData,
        error: error.message
      });
    }
  }
  
  return { results, errors };
}

Job Synchronization

async function syncJobsFromATS(atsJobs) {
  const existingJobs = await listAllJobs();
  const existingJobsMap = new Map(
    existingJobs.map(j => [j.externalId, j])
  );
  
  for (const atsJob of atsJobs) {
    const existing = existingJobsMap.get(atsJob.id);
    
    if (!existing) {
      // Create new job
      await createJob(transformAtsJob(atsJob));
    } else if (hasChanges(existing, atsJob)) {
      // Update existing job
      await updateJob(existing.id, transformAtsJob(atsJob));
    }
  }
}

Job Analytics

async function getJobStats(jobId) {
  const [candidates, interviews] = await Promise.all([
    listCandidates({ jobId }),
    listInterviews({ jobId })
  ]);
  
  return {
    totalCandidates: candidates.pagination.total,
    activeCandidates: candidates.items.filter(
      c => c.status === 'OPEN'
    ).length,
    totalInterviews: interviews.pagination.total,
    completedInterviews: interviews.items.filter(
      i => i.status === 'completed'
    ).length
  };
}

Validation Rules

title
string
required
Job title (1-200 characters)
description
string
Detailed job description (max 10,000 characters)
requiredSkills
array
Array of required skills (max 50 items, each max 100 chars)
workMode
enum
One of: remote, on_site, hybrid
location.countryCode
string
required
ISO 3166-1 alpha-2 country code (e.g., “US”, “GB”, “DE”)
salary.currency
string
ISO 4217 currency code (e.g., “USD”, “EUR”, “GBP”)
status
enum
One of: OPEN, CLOSED, UNDEFINEDNote: In practice, use OPEN (accepting applications) or CLOSED (no longer hiring)

Error Scenarios

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid work mode",
    "details": {
      "field": "workMode",
      "provided": "flexible",
      "allowed": ["remote", "on_site", "hybrid"]
    }
  }
}
{
  "error": {
    "code": "RESOURCE_NOT_FOUND",
    "message": "Job not found",
    "details": {
      "resourceType": "Job",
      "resourceId": "invalid-uuid"
    }
  }
}
{
  "error": {
    "code": "RESOURCE_ACCESS_DENIED",
    "message": "Access denied to this job",
    "details": {
      "reason": "Job belongs to different company"
    }
  }
}

Best Practices

Use Draft Status

Create jobs as drafts while preparing content

Consistent Skills

Maintain a standardized skill taxonomy

Include Salary

Transparency improves candidate quality

Update Regularly

Keep job descriptions current and accurate

Next Steps