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
Operation Required Scope List jobs read:jobsGet job by ID read:jobsCreate job write:jobsUpdate job write:jobsDelete job delete: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
Position has been filled or paused
Not visible to new candidates
Existing candidates retained
No new applications accepted
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
Mode Description 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 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' ]
Separate Required vs Nice-to-Have
{
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
Job title (1-200 characters)
Detailed job description (max 10,000 characters)
Array of required skills (max 50 items, each max 100 chars)
One of: remote, on_site, hybrid
ISO 3166-1 alpha-2 country code (e.g., “US”, “GB”, “DE”)
ISO 4217 currency code (e.g., “USD”, “EUR”, “GBP”)
One of: OPEN, CLOSED, UNDEFINED Note : 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