# India Jobs API (`asgardlabs/india-jobs-api`) Actor

One search across Foundit, Shine, Instahyre and Internshala, returned as one clean table with salaries in rupees and duplicates removed. Half a cent per search, a fifth of a cent per job.

- **URL**: https://apify.com/asgardlabs/india-jobs-api.md
- **Developed by:** [Asgard Labs](https://apify.com/asgardlabs) (community)
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 jobs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## India Jobs API – Foundit, Shine, Instahyre, Internshala

Give it job keywords and Indian cities. Get jobs from four Indian job boards at once, Foundit (formerly Monster India), Shine, Instahyre and Internshala, in one identical format: title, company, cities, experience range, salary in rupees per year, skills, employment type, posting date, apply link. The same posting on several boards is delivered once.

Run it again with **only new** on and you get only jobs not seen before. Schedule it daily and you have a job alert for any keyword and city.

Public search endpoints only. No login, no proxies, no browser.

### India job data per posting

- **id, provider, jobId, title, company, url, applyUrl**
- **location** – raw text, cities (Bangalore and Bengaluru become one), remote, hybrid, country
- **experience** – min, max, text; **salary** – min, max in INR per year (lakh converted), text
- **skills, employmentType, functions, industries, postedAt, postedText, extra** (board-specific: recruiter contact on Shine, walk-in venue on Foundit, company size on Instahyre)
- **query, isNew, firstSeenAt**

### Use cases

- Job boards and aggregators.
- Recruiters tracking a skill in a city.
- Career coaches.
- Market research on hiring and salaries.

### Input

| Field | Default | Meaning |
|---|---|---|
| `keywords`, `locations` | – | Every keyword × city combination is one search per board. Spelling and case variants count once. Leave `locations` empty for all of India. |
| `boards` | all four | Any of foundit, shine, instahyre, internshala. |
| `maxJobsPerBoard` | 100 | Per board per search. |
| `onlyNew` | false | Only jobs not seen in earlier runs. The seen list lives in a key-value store per board and search. |
| `dedupeAcrossBoards` | true | Deliver the same posting once when it appears on several boards. |
| `minExperience`, `maxExperience`, `minSalary`, `remoteOnly`, `excludeKeywords` | – | Filters. Jobs hidden by a filter are not marked seen, so widening the filter later surfaces them as new. |
| `timeoutSecs` | 300 | Time budget per board search. |
| `concurrency` | 4 | Searches in parallel. |
| `stateStoreName` | india-jobs-state | Where the seen list lives. Use a different name for a separate watchlist. |

### Output example

```json
{ "id": "shine:19381323", "provider": "shine", "title": "Senior Python Developer", "company": "Vontier",
  "location": { "raw": "Bangalore, Chennai", "cities": ["Bengaluru", "Chennai"], "remote": false, "hybrid": false, "country": "IN" }, "remote": false,
  "experience": { "min": 5, "max": 9, "text": "5 to 9 Yrs" }, "salary": { "min": 700000, "max": 1200000, "currency": "INR", "period": "year", "text": "Rs 7 - 12 Lakh/Yr" },
  "skills": ["python", "django", "aws"], "employmentType": "Full time", "industries": ["IT Services & Consulting"],
  "postedAt": "2026-08-04T02:22:25.000Z", "url": "https://www.shine.com/jobs/…", "applyUrl": "https://…", "extra": { "expiresAt": "2026-10-02T00:00:00", "walkIn": false, "vacancies": 99 },
  "query": { "keyword": "python developer", "location": "bengaluru" }, "firstSeenAt": "2026-09-05T…", "isNew": true }
```

### How to use

1. Paste your keywords and cities into the input form. The example input is ready to run as is.
2. Click **Start**. Rows appear in the **Output** tab as they are found.
3. Download the table as CSV, JSON or Excel, or read it through the API.
4. For monitoring, create a **Schedule** and switch on `onlyNew`: later runs return only what changed, and only that is charged.

### Pricing

Pay per event: **`search` $0.005** per board search that answered, **`job` $0.002** per job in the output. Four boards, one keyword and city, 100 jobs each is about $0.82. A daily `onlyNew` alert run is a few cents. Searches that fail are free.

### Board notes

- **Foundit**: structured experience; salary and company are hidden on some postings.
- **Shine**: salary text, expiry date, sometimes recruiter contact. Its search service answers in about 30 seconds per page, so a Shine search is slow but complete.
- **Instahyre**: the public search does not publish experience, salary or posting date, so those fields are empty for this board. Keyword and city matching are done by the actor: the first keyword must appear in the title, or every keyword in title plus skills; only jobs in the requested city (or remote) are kept.
- **Internshala**: jobs and internships; salary is often "Competitive".
- **Not covered**: Naukri (blocks automated access), TimesJobs, NaukriGulf.
- **Errors are in plain words:** `timeout`, `blocked (403)`, `rate limited (429)`, `ENOTFOUND (domain not found)`. Stopping at your spend limit is safe: the seen list is not touched by a stopped run.

### Use from code or an AI agent

Every run can be started and read through the Apify API, the JavaScript and Python clients, or an AI agent with tool access. Open the **API** tab on this page for ready-made snippets. Pricing is per event, so an agent pays only for what it receives.

### FAQ

**Is Naukri included?**
No. It blocks automated access. Foundit, Shine, Instahyre and Internshala are covered.

**Why is salary missing on some jobs?**
Instahyre's public search has no salary, experience or date. Other boards return them when the posting states them. Salary is normalised to rupees per year.

**Do city spellings matter?**
No. Bangalore and Bengaluru, Gurgaon and Gurugram, and case or spacing differences map to one search.

**Can I get only new jobs each run?**
Yes. Switch on `onlyNew`; job ids are remembered per board and query in your account.

**Is there a remote filter?**
Yes, `remoteOnly` keeps postings marked remote or work from home.

# Actor input Schema

## `keywords` (type: `array`):

Job titles or skills, one per line, e.g. "python developer", "sales manager". Each keyword is searched on every selected board.

## `locations` (type: `array`):

e.g. Bangalore, Hyderabad, Pune. Leave empty for all of India. Spelling and case variants (Bangalore / Bengaluru) count as one search.

## `boards` (type: `array`):

Which boards to search. All four by default.

## `maxJobsPerBoard` (type: `integer`):

Per board and per keyword-city pair. Shine answers in about 30 seconds per 100 jobs.

## `onlyNew` (type: `boolean`):

Remembers job ids per board and query in a key-value store; later runs return only postings not seen before.

## `dedupeAcrossBoards` (type: `boolean`):

The same title at the same company in the same city is delivered once even when several boards list it. Duplicates are not charged.

## `minExperience` (type: `integer`):

Keep jobs asking for at least this many years, when the board states experience. Applied after download, not charged.

## `maxExperience` (type: `integer`):

Keep jobs asking for at most this many years, when the board states experience. Applied after download, not charged.

## `minSalary` (type: `integer`):

Keep jobs whose stated salary reaches this yearly amount in rupees, when the board states salary. Applied after download, not charged.

## `remoteOnly` (type: `boolean`):

Keep only postings marked remote or work from home.

## `excludeKeywords` (type: `array`):

Drop postings whose title, company or skills contain any of these words.

## `timeoutSecs` (type: `integer`):

A board search that takes longer is reported as timed out; jobs already delivered stay delivered.

## `concurrency` (type: `integer`):

How many board searches to run at the same time. Instahyre rate-limits bursts; four is safe.

## `stateStoreName` (type: `string`):

Key-value store in your account that keeps the seen list for "only new". Letters, digits and dashes.

## Actor input object example

```json
{
  "keywords": [
    "python developer"
  ],
  "locations": [
    "Bangalore"
  ],
  "boards": [
    "foundit",
    "shine",
    "instahyre",
    "internshala"
  ],
  "maxJobsPerBoard": 25,
  "onlyNew": false,
  "dedupeAcrossBoards": true,
  "remoteOnly": false,
  "excludeKeywords": [],
  "timeoutSecs": 300,
  "concurrency": 4,
  "stateStoreName": "india-jobs-state"
}
```

# Actor output Schema

## `results` (type: `string`):

One row per job: provider, title, company, cities, experience, salary in INR/year, skills, postedAt, url, isNew.

## `summary` (type: `string`):

Counts, skipped inputs with reasons, errors in plain words, charge-limit state.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": [
        "python developer"
    ],
    "locations": [
        "Bangalore"
    ],
    "maxJobsPerBoard": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("asgardlabs/india-jobs-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "keywords": ["python developer"],
    "locations": ["Bangalore"],
    "maxJobsPerBoard": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("asgardlabs/india-jobs-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": [
    "python developer"
  ],
  "locations": [
    "Bangalore"
  ],
  "maxJobsPerBoard": 25
}' |
apify call asgardlabs/india-jobs-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,asgardlabs/india-jobs-api"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/3Jd57dKW8jg9jGcEh/builds/7TLCawiwLG0OIR6s2/openapi.json
