jobiwork

API reference

Base address https://api.jobiwork.com · schema version 2 · updated 27 Oct 2026

Authentication and keys

Send your key in the X-API-Key header to https://api.jobiwork.com/rpc/<endpoint>. Every data call is a POST with a JSON body; the Logo API is a GET so it works in an image tag.

KeyLooks likeUse itCan read
Secretjwk_ + 48 charactersFrom your server only, in the X-API-Key headerThe datasets on the key: Company Data API, logos, and (on request) the jobs and companies feeds
Publishablepk_ + 32 charactersIn web pages, as key= in a logo link; lock it to your websitesLogos only
  • A key is shown once. Jobiwork stores only its SHA-256 fingerprint and first 12 characters; a lost key is revoked and replaced.
  • Make free keys under Account → API keys after confirming your email. Feed access, paid plans and higher limits are set up after an access request.
  • Never put a secret key in a website, a mobile app or a public repository.
  • Revoking or rotating a key takes effect on the next call.

Errors

Errors answer with an HTTP status and a JSON body whose message explains the problem in plain words: {"message": "…"}.

StatusMeaningRetry?
400Bad input (the message says which)No: fix the request
401Key missing, wrong or revokedNo
403The key may not use this endpoint or dataset, or is locked to other websitesNo
404Nothing found (lookups that find nothing are not counted)No
429Per-minute or monthly limit reached; Retry-After: 60Yes, after Retry-After
5xxSomething went wrong on our sideYes, with exponential back-off

Rate limits and monthly use

  • Each key has a calls-per-minute limit from its plan; over it, calls answer 429 with Retry-After: 60.
  • Each plan has monthly allowances for logos and company records. Free keys stop at the allowance; paid plans continue and extra company records are billed per 1,000.
  • api_account shows your plan, limits and this month's use at no cost.
  • Refused calls (bad key, over a limit) are not counted.

Jobs feed

POST/rpc/partner_jobsSecret key (server)dataset jobs.read

Read the jobs change feed

Jobs in the order they changed. Start with no cursor, keep sending the returned next until has_more is false, store the last next and start from it on your next run.

ParameterTypeRequiredDescription
sincetimestamp | nullno (default null)Cursor time from the last next (null: from the beginning)
after_idintegerno (default 0)Cursor id from the last next
page_sizeintegerno (default 500)1 to 1,000 jobs a page
marketstringnoOnly one market: India or United States
active_onlybooleanno (default false)Keep false when syncing, so you also learn which jobs to remove
include_descriptionbooleanno (default true)Leave out the full description to save bandwidth

Response fields

FieldTypeMeaning
idintegerImmutable job id, never reused
activebooleanOpen, published, not a duplicate, not expired and the company is not hidden
status / closed_at / expires_at / duplicate_ofvariousWhy a job is no longer active
title, job_function, seniority, departmentstringAs published; job_function and seniority normalised
employment_type, work_modestringFull-time, Contract… / On-site, Hybrid, Remote
location, city, state, country, marketstringWhere the job is
salaryobjectmin, max, currency, period, when the employer published pay
summary, description, skillsstring / string[]Description text and an extracted skills list
apply_url, apply_via, direct_applystring / booleanThe employer's own application page
posted_at, first_seen_at, last_checked_at, changed_attimestampDates; changed_at drives the cursor
companyobjectid, name, slug, website, domain, verified, logo_url, logo_version_at, jobiwork_url

Errors

  • 400 page_size outside 1 to 1,000 or a bad cursor
  • 401 The key is missing, wrong or revoked
  • 403 The key may not read this dataset (or a publishable key was used for data)
  • 429 Per-minute or monthly limit reached; wait for Retry-After (60 seconds)

Counts as: Calls and jobs returned are recorded per key (feeds are not charged per record).

Empty fields are left out of each job.

Store next only after you have committed the page; replaying a stored cursor never skips a record.

POST/rpc/partner_jobSecret key (server)dataset jobs.read

Read one job

One job in its current state, with its full description.

ParameterTypeRequiredDescription
idintegeryesJob id

Errors

  • 404 Job not found
  • 401 The key is missing, wrong or revoked
  • 403 The key may not read this dataset (or a publishable key was used for data)
  • 429 Per-minute or monthly limit reached; wait for Retry-After (60 seconds)
POST/rpc/partner_job_idsSecret key (server)dataset jobs.read

List every active job id (reconciliation)

Every active job id with its changed_at, by id. Compare with what you show: anything not listed is no longer active; anything listed that you lack, or hold with an older changed_at, can be read with partner_job.

ParameterTypeRequiredDescription
after_idintegerno (default 0)Continue after this id (next_after_id of the last page)
page_sizeintegerno (default 10000)1 to 20,000 ids a page
marketstringnoOnly one market

Errors

  • 401 The key is missing, wrong or revoked
  • 403 The key may not read this dataset (or a publishable key was used for data)
  • 429 Per-minute or monthly limit reached; wait for Retry-After (60 seconds)
POST/rpc/partner_statusSecret key (server)dataset jobs.read

Check your key and the feed

The key's name, datasets and per-minute limit, how many jobs are active and when Jobiwork last synced.

No parameters: send {}.

Errors

  • 401 The key is missing, wrong or revoked
  • 403 The key may not read this dataset (or a publishable key was used for data)
  • 429 Per-minute or monthly limit reached; wait for Retry-After (60 seconds)

Company Data API

POST/rpc/company_lookupSecret key (server)dataset companies.lookup

Look up one company

Send a website, a registration number, a Jobiwork id, or a name with a country. You get one company and how it was matched.

ParameterTypeRequiredDescription
domainstringnoWebsite or domain, e.g. example.com
registrationstringnoRegister number: CIN, ACN, SEC CIK, state id
idstringnoJobiwork id (JW-…)
namestringnoCompany name (send country too)
countrystringnoCountry for a name match

Response fields

FieldTypeMeaning
match.method / match.confidencestring / 0-100registration 100, website confirmed 95 or known 85, exact name in the country 75 (50 when several share it)
status, status_changed_atstring / dateAs filed with the register
registryobjectname, number, tax_id, lei, checked_at
location, industry, sizeobjectRegistered location, industry group/sector/NIC or SIC, size band and capital
classificationobjectIndian companies: NIC code with edition, division, description and source; listing, ownership, capital tier, status group
websiteobjectdomain, and whether it was confirmed on the company's own site
logoobjectavailable, versioned Logo API url
groupobjectparent, ultimate_parent, subsidiaries
hiringobjectopen_jobs today from the company's careers site; employer_verified

Errors

  • 400 No domain, registration, id or name was given
  • 404 No company found for this input (not counted)
  • 401 The key is missing, wrong or revoked
  • 403 The key may not read this dataset (or a publishable key was used for data)
  • 429 Per-minute or monthly limit reached; wait for Retry-After (60 seconds)

Counts as: One company record per match.

POST/rpc/company_enrichSecret key (server)dataset companies.lookup

Enrich up to 100 companies

The lookup for a list: each item gets its own result. Items without a match come back with match: null.

ParameterTypeRequiredDescription
itemsobject[]yes1 to 100 items, each with domain, registration, id, or name + country

Errors

  • 400 Send 1 to 100 items
  • 401 The key is missing, wrong or revoked
  • 403 The key may not read this dataset (or a publishable key was used for data)
  • 429 Per-minute or monthly limit reached; wait for Retry-After (60 seconds)

Counts as: One company record per matched item.

POST/rpc/company_groupSecret key (server)dataset companies.lookup

Group structure

Parent companies up to the top of the group, and the top company's subsidiaries (GLEIF and Wikidata).

ParameterTypeRequiredDescription
idstringyesJobiwork id

Errors

  • 404 No company with this id
  • 401 The key is missing, wrong or revoked
  • 403 The key may not read this dataset (or a publishable key was used for data)
  • 429 Per-minute or monthly limit reached; wait for Retry-After (60 seconds)

Counts as: One company record.

POST/rpc/partner_companiesSecret key (server)dataset companies.read

Read the companies change feed

Companies in the order they changed (details or logo), with the same cursor as the jobs feed.

ParameterTypeRequiredDescription
sincetimestamp | nullno (default null)Cursor time from the last next
after_idintegerno (default 0)Cursor id from the last next
page_sizeintegerno (default 500)1 to 1,000

Errors

  • 401 The key is missing, wrong or revoked
  • 403 The key may not read this dataset (or a publishable key was used for data)
  • 429 Per-minute or monthly limit reached; wait for Retry-After (60 seconds)

merged_into names the company it was merged into; that company's id now carries its jobs.

POST/rpc/new_companiesSecret key (server)dataset companies.read

Read new company registrations (India)

Every company and LLP registered with India's Ministry of Corporate Affairs, in registration order (date, then id), with Jobiwork's research of each one: website confirmed on its own site, logo, industry and NIC, capital band, careers site and hiring status.

ParameterTypeRequiredDescription
sincedate | nullno (default null)Cursor date from the last next (or a registration date to start from, e.g. 2026-04-01)
after_idintegerno (default 0)Cursor id from the last next
page_sizeintegerno (default 500)1 to 1,000
statestring | nullnoA state or territory, e.g. Maharashtra
industrystring | nullnoA Jobiwork industry group, e.g. Technology & IT
classstring | nullnoPrivate, Public, OPC, LLP or Other
min_capitalnumber | nullnoPaid-up capital at least this many rupees (companies without it are left out)
researched_onlybooleanno (default false)Only companies our research has finished

Response fields

FieldTypeMeaning
cin / llpinstringThe MCA identifier (companies have a CIN, LLPs an LLPIN)
classstringPrivate, Public, OPC (one person company), LLP or Other
state_sourcestringHow the state is known: State code in CIN, Register file, Registered office address, RoC office, RoC office and PIN, RoC office (main state)
industry.sourcestringNIC code, or Activity description (the register's activity heading) when there is no NIC code
capital.bandstring100cr_plus, 10_100cr, 1_10cr, 10l_1cr or below_10l, when paid-up capital is known
research.statusstringresearched, in_progress, queued, or not_scheduled (registered more than 12 months ago)
research.websiteobjectOnly a domain whose homepage showed the company's name or CIN, with what it showed (evidence)
research.website_resultstringfound, review (a possible match a person checks), none or error
research.role_mailboxstringA role mailbox (info@, hr@ …) on the confirmed domain, never a person's address
employer_verifiedbooleantrue only when the employer claimed its Jobiwork page
data_up_todateThe latest registration date we hold (MCA publishes monthly)

Errors

  • 401 The key is missing, wrong or revoked
  • 403 The key may not read this dataset (or a publishable key was used for data)
  • 429 Per-minute or monthly limit reached; wait for Retry-After (60 seconds)

Counts as: Each record returned counts towards your plan's new-company records for the month

The registered office address, directors and personal emails or phone numbers are never included.

Registrations reach us when MCA publishes them (monthly), so a month can grow after you read it: keep reading from your cursor, and re-read the last 45 days when a new month arrives (records carry imported_at).

For a push instead of polling, save a watchlist with the event type registration and a filter; matching companies arrive as company.registered webhooks.

POST/rpc/api_accountAny key

Your plan and this month's use

The key's plan, per-minute and monthly limits and what it has used this month. Free; works with secret and publishable keys.

No parameters: send {}.

Errors

  • 401 Send a valid key in the X-API-Key header

Logo API

GET/rpc/logo_apiPublishable keydataset logos.read

Get a logo image

Returns the image itself (PNG, JPG or WebP; an SVG letter square with fallback=monogram). Use the address directly in an <img> tag.

ParameterTypeRequiredDescription
domainstringnoCompany website or domain
idstringnoJobiwork id (JW-…)
registrationstringnoRegister number
keystringyesYour publishable key (pk_…); or send X-API-Key
fallback404 | monogramno (default 404)monogram: the company's initials when there is no logo
vstringnoLogo version from a logo url; with the current v the image is cached for a year

Errors

  • 404 No logo for this company yet (add fallback=monogram)
  • 304 Not modified (If-None-Match matched the ETag)
  • 401 The key is missing, wrong or revoked
  • 403 The key may not read this dataset (or a publishable key was used for data)
  • 429 Per-minute or monthly limit reached; wait for Retry-After (60 seconds)

Counts as: One logo per image served (404s are not counted).

A key locked to websites only works on pages of those websites (requests without a referrer pass).

Free plan: show a small “Logos by Jobiwork” link on pages with logos.

Listed-company alerts

POST/rpc/alert_watchlistsSecret key (server)

Your watchlists, limits and use

Every watchlist of your account (all your keys share them), how many alerts you used this month against your plan, and which event types and kinds you can choose.

No parameters: send {}.

Errors

  • 401 The key is missing, wrong or revoked
  • 403 Alerts are part of the paid plans, a publishable key was used, or a plan limit (watchlists, companies per watchlist) was reached
  • 429 Per-minute limit (Retry-After 60) or this month's alerts are used

Counts as: Not counted.

POST/rpc/alert_watchlist_createSecret key (server)

Create a watchlist

Name companies (Jobiwork ids or slugs), securities (ISIN, NSE:SYMBOL, BSE:CODE) or a filter. The watchlist follows the data: a filter such as every NSE-listed company includes new listings as they arrive.

ParameterTypeRequiredDescription
namestringyesUp to 80 characters
companiesstring[]noJobiwork ids (JW-…) or slugs
securitiesstring[]noISINs, NSE:SYMBOL or BSE:CODE
filtersobjectnolisted (NSE, BSE or any), capital_bands, industries, states; for registration also classes (Private, Public, OPC, LLP) and min_capital, e.g. {"listed": "NSE", "industries": ["Banks"]} or {"states": ["Maharashtra"], "classes": ["LLP"]}
event_typesstring[]no (default ["listing", "activity"])listing, activity, registration (new companies in India matching the filter; no companies needed) — price only once share prices are licensed
kindsstring[]no (default [])Only these kinds (empty: every kind of the chosen types)
webhookbooleanno (default true)Send to your webhooks for listing.changed / company.activity
email_digestoff | daily | weeklyno (default off)A digest to your account email

Errors

  • 400 Unknown companies, a security that is not an ISIN or EXCHANGE:SYMBOL, or no companies / securities / filter
  • 401 The key is missing, wrong or revoked
  • 403 Alerts are part of the paid plans, a publishable key was used, or a plan limit (watchlists, companies per watchlist) was reached
  • 429 Per-minute limit (Retry-After 60) or this month's alerts are used

Counts as: Not counted.

Only events detected after the watchlist was made are delivered; the events feed also shows the last 90 days.

size is the number of companies the watchlist covers now; it must stay within your plan's companies per watchlist.

POST/rpc/alert_watchlist_updateSecret key (server)

Change a watchlist

Send the id and only what changes; active: false pauses it.

ParameterTypeRequiredDescription
idintegeryesWatchlist id
namestringnoNew name
companiesstring[]noReplaces the companies
securitiesstring[]noReplaces the securities
filtersobjectnoReplaces the filter
event_typesstring[]nolisting, activity, registration
kindsstring[]noOnly these kinds
webhookbooleannoSend to your webhooks
email_digestoff | daily | weeklynoEmail digest
activebooleannofalse pauses the watchlist

Errors

  • 404 Watchlist not found
  • 401 The key is missing, wrong or revoked
  • 403 Alerts are part of the paid plans, a publishable key was used, or a plan limit (watchlists, companies per watchlist) was reached
  • 429 Per-minute limit (Retry-After 60) or this month's alerts are used

Counts as: Not counted.

POST/rpc/alert_watchlist_deleteSecret key (server)

Delete a watchlist

Stops its alerts at once.

ParameterTypeRequiredDescription
idintegeryesWatchlist id

Errors

  • 404 Watchlist not found
  • 401 The key is missing, wrong or revoked
  • 403 Alerts are part of the paid plans, a publishable key was used, or a plan limit (watchlists, companies per watchlist) was reached
  • 429 Per-minute limit (Retry-After 60) or this month's alerts are used

Counts as: Not counted.

POST/rpc/alert_eventsSecret key (server)

Read the events feed

Events on your watchlists in the order they were detected, with the same cursor rules as the jobs feed: keep sending next until has_more is false and store the last next. A page never contains an event that a slower write could still place before it.

ParameterTypeRequiredDescription
sincetimestamp | nullno (default null)Cursor time (null: the last 90 days)
after_idintegerno (default 0)Cursor id from the last next
page_sizeintegerno (default 100)1 to 500 events a page
watchlist_idintegernoOnly one watchlist

Response fields

FieldTypeMeaning
idintegerEvent id, never reused
eventstringlisting.changed or company.activity (the webhook event it belongs to)
type, category, kind, labelstringe.g. listing.suspended / listing / suspended / Suspended
companyobjectid (JW-…), name, slug, cin when matched to the MCA register, jobiwork_url
securityobjectexchange, symbol (BSE: security code), isin
before, afterobjectWhat changed, e.g. {status: Active} → {status: Suspended}; open_jobs and change_pct for job changes
detected_at, sourcetimestamp / stringWhen Jobiwork detected it and from what (exchange file, careers sites, register)
watchlistsinteger[]Your watchlists that include the company

Errors

  • 404 Watchlist not found
  • 401 The key is missing, wrong or revoked
  • 403 Alerts are part of the paid plans, a publishable key was used, or a plan limit (watchlists, companies per watchlist) was reached
  • 429 Per-minute limit (Retry-After 60) or this month's alerts are used

Counts as: Each event counts once a month towards your plan's alerts, whether it reaches you by webhook, digest or this feed.

Listing kinds: new_listing, relisted, delisted (removed from the exchange list), suspended, resumed, series_change, status_change, name_change, symbol_change, isin_change, face_value_change.

Activity kinds: hiring_started, hiring_stopped, jobs_up / jobs_down (past a set share and number of jobs), careers_site_found, website_confirmed, website_changed, logo_changed, register_status_changed.

Share price events are not included: exchange prices need a data licence, which is not in place yet (price_events_included says so).

POST/rpc/alert_testSecret key (server)

Send a test alert

Queues one delivery to each of your webhooks that takes alert events. The payload has "test": true and an event marked "example": true with made-up values.

No parameters: send {}.

Errors

  • 400 No webhook takes listing.changed or company.activity yet
  • 401 The key is missing, wrong or revoked
  • 403 Alerts are part of the paid plans, a publishable key was used, or a plan limit (watchlists, companies per watchlist) was reached
  • 429 Per-minute limit (Retry-After 60) or this month's alerts are used

Counts as: Not counted; at most 20 test sends an hour per webhook.

Platform

POST/rpc/data_coverageNo key

What the data covers (no key)

Public counts behind the API: companies, register coverage, confirmed websites, logos, open jobs and the public plans.

No parameters: send {}.

Webhook events

EventThe key needsids areSent when
jobs.changedjobs.readjob idsJobs were added, changed, closed or expired.
companies.changedcompanies.read or companies.lookupcompany JW idsCompany details or logos changed.
logo.changedlogos.read, companies.read or companies.lookupcompany JW idsA logo people can see changed; data.logos lists each new address.
listing.changeda paid plan with alertsevents (data.events)A listing on one of your watchlists changed: new listing, delisting, suspension, name, symbol, ISIN, face value or series.
company.activitya paid plan with alertsevents (data.events)A watched company started or stopped hiring, its open jobs moved past the threshold, or its careers site, website, logo or register status changed.
company.registereda paid plan with alertsevents (data.events)A company or LLP matching one of your registration watchlists (state, industry, class, capital) was registered in India.
price.movednot offered yetevents (data.events)A big close-to-close share price move. Only once share prices are licensed for redistribution.
pinganynoneSent by “Send a test” in your account.

Pagination and cursors

Feeds (partner_jobs, partner_companies) page by change time with a cursor of since + after_id. Each page returns next; send it back unchanged to read the following page.

  • Pages are ordered by (change time, id) and hold 1 to 1,000 records.
  • A page only contains changes older than complete_until, so no write still in progress can land behind your cursor: replaying from a stored cursor after any failure never skips a record.
  • has_more: false with an empty page means you are caught up. Cursors never expire; an old cursor returns the current state of everything changed since then.
  • since: null replays everything (a full snapshot).
  • company_search pages with page and page_size (up to 100 a page, 10,000 results). partner_job_ids pages by id with after_id (up to 20,000 a page).
A safe sync loop
cursor = load_cursor()                  # {"since": null, "after_id": 0} the first time
while True:
    page = post("partner_jobs", {**cursor, "page_size": 1000})
    for job in page["jobs"]:
        upsert(job) if job["active"] else hide(job["id"])
    commit()
    cursor = page["next"]; save_cursor(cursor)   # only after the page is committed
    if not page["has_more"]:
        break

Closures and tombstones

  • Jobs are never hard-deleted. A job that closes, expires, is merged into a duplicate, is unpublished, or whose company is hidden is sent again with active: false and the reason (status, closed_at, expires_at, duplicate_of).
  • Remove inactive jobs from search; do not delete jobs because a run timed out or returned few rows. A job can become active again.
  • Companies carry hidden and merged_into. Jobs of a merged company move to the company it was merged into.

Reconciliation

Run a reconciliation now and then (for example daily) in addition to the change feed.

  • Page through partner_job_ids until has_more is false.
  • Anything you show that is not listed is no longer active: hide it.
  • Anything listed that you lack, or hold with an older changed_at, should be read with partner_job.

Logo versions and caching

  • Every logo address carries a version (v=). It changes whenever the logo people see changes: a new or replaced image, or a logo hidden or shown again.
  • A logo change also counts as a change to the company and to its open jobs, so the feeds send them again with the new address, usually within seconds, and logo.changed webhooks fire.
  • Replace the stored logo address every time a job or company arrives. A versioned address can be cached for a year (immutable).
  • Without v= (or with an old one) the Logo API is cached for 5 minutes; ETag and X-Logo-Version carry the version and If-None-Match answers 304 while it is unchanged.

Webhooks: delivery, signing and retries

Add up to 5 webhooks per key under Account → API keys → Webhooks. Addresses must be https:// on a public network; redirects are not followed. About every 20 seconds (within seconds for logo changes) the worker posts what changed since the last delivery.

Example delivery
POST <your address>
X-Jobiwork-Event: companies.changed
X-Jobiwork-Delivery: whd_123
X-Jobiwork-Signature: t=1792570000,v1=<hex HMAC-SHA256 of "<t>.<raw body>" with your signing secret>

{"id": "whd_123", "event": "companies.changed", "created_at": "2026-10-14T12:40:05Z", "webhook_id": 7,
 "data": {"count": 2, "ids": ["JW-000123", "JW-000456"], "changed_from": "…", "changed_to": "…", "more": false}}
  • ids are job ids for jobs.changed and company JW ids otherwise (at most 500; more: true means another delivery follows). Read the records with your key.
  • logo.changed also lists each company's new address: "logos": [{"id": "JW-000123", "logo_url": "…&v=1792737567", "version_at": "…"}] (logo_url is null when the logo was hidden).
  • Answer with any 2xx within 15 seconds. Anything else is retried after 1 min, 5 min, 30 min, 2 h, 6 h and 12 h. After 50 failures in a row the webhook is switched off.
  • The signing secret (whsec_…) is shown once; make a new one from the same page. Check the timestamp to refuse replays.
  • Deliveries are kept for 30 days and can be sent again from your account.

Alert events (listing.changed, company.activity) come from your watchlists and carry the events themselves: "data": {"count": 1, "events": [{"id": 90211, "type": "listing.suspended", "company": {...}, "security": {...}, "before": {...}, "after": {...}, "watchlists": [12]}]}, at most 100 events per delivery. A test alert has "test": true.

Verify a signature (Node.js)
import crypto from "node:crypto";

// raw: the request body exactly as received (a string or Buffer), header: X-Jobiwork-Signature
export function verify(raw, header, secret, toleranceSeconds = 300) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${t}.${raw}`).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1 ?? ""));
}
Verify a signature (Python)
import hashlib, hmac, time

def verify(raw: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    t = int(parts.get("t", "0"))
    if abs(time.time() - t) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + raw, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))

Where the data comes from

  • Company records start in official company registers (India MCA, Australia ASIC, US SEC and state registers) and are refreshed weekly or monthly.
  • Websites count as confirmed only after they are checked on the company's own site. Group structure comes from GLEIF (Legal Entity Identifiers) and Wikidata.
  • Jobs come only from employers' own careers sites and the job systems they use; never from job aggregators. Show “via Jobiwork” and link apply_url.
  • Company facts only: no directors, personal emails or phone numbers. contact.email is a company's role mailbox (info@, careers@ …) from its register filing, given only when its website is confirmed and the mailbox is on that domain. A register match is not a verified employer; employer_verified means the company confirmed its page with us.
  • capital ranks compare paid-up capital among active Indian companies on the MCA register (1 = largest); paid-up capital is not revenue or headcount.

Changelog

Schema version 2. Fields are only added within a version; a breaking change gets a new version and advance notice.

  1. New company registrations (India)

    • new_companies: every company and LLP registered with MCA, in registration order with a no-skip cursor, filters for state, industry, class, paid-up capital and research status, and the research of each company.
    • Watchlists take the event type registration with a filter (states, industries, classes, capital_bands, min_capital); webhook event company.registered.
    • Plans carry a monthly allowance of new-company records.
  2. Listed-company alerts

    • Watchlists (alert_watchlists, alert_watchlist_create, alert_watchlist_update, alert_watchlist_delete) by company, ISIN / symbol or filter.
    • Events feed alert_events with the no-skip cursor; webhook events listing.changed and company.activity; alert_test.
    • Every NSE and BSE equity listing is now a company record (company.cin is empty until the MCA record is matched).
  3. Paid-up capital bands and ranks

    • Company records carry capital: band, rank in India, in the state and in the industry, and a percentile (Indian companies).
    • company_search takes capital_band, min_paidup_capital and sort=capital.
    • contact.email: a company's role mailbox, only when its website is confirmed and the mailbox is on it.
  4. Instant logo versions

    • Every logo address carries a version (v=); versioned addresses are cacheable for a year.
    • logo.changed webhooks list each company's new logo_url; ETag, X-Logo-Version and 304 on the Logo API.
  5. Feed contract, schema version 2

    • schema_version and complete_until in every feed page; replaying a stored cursor never skips a record.
    • New partner_job_ids for reconciliation.
  6. Webhooks and per-key datasets

    • Signed webhooks for jobs.changed, companies.changed and logo.changed, with retries.
    • Datasets can be set per key; key rotation.
  7. Company Data API and Logo API

    • company_lookup, company_enrich, company_search, company_group and api_account; publishable keys and the Logo API; plans.
  8. Jobs and companies feeds

    • partner_jobs, partner_job, partner_companies and partner_status.

Request API access

Tell us what you are building

For the jobs and companies feeds, webhooks, paid plans or higher limits. Free Company Data and Logo API keys can be made straight away in your account.

Datasets you want

No card needed. Nothing is emailed to you automatically.