Vocations
API Docs
Integrate job-offer monitoring and company intelligence directly into your recruiting workflow.
Authentication
All endpoints under /v2 require a valid API key, including those that do not consume usage.
Endpoints under /playground do not require an API key.
For /v2 endpoints, the key must be passed in the Authorization HTTP header with value Bearer <key>.
Authorization: Bearer 5tg••••••••••••••••8ux
Shared types
? after any key in a type means the value is optional.[] after any type means the value, if provided, must be an array.
All ids have a length of 16 characters.
Search endpoints accept page (zero-based, default 0) and pageSize (minimum 1, maximum 128, default 10).
Filter arrays accept up to 64 items, except names, cities, provinces, regions, nations, postalCodes, italy.ivas, italy.ateco, spain.cifNifs and spain.cnae, which accept up to 256. Batch endpoints accept between 1 and 128 IDs. Exceeding a limit returns 400.
Every authenticated response returns X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset for the current minute window. A 429 also returns Retry-After.
type ErrorResponse = { message: string };
type CountryKey = "italy" | "spain";
type LocationLevel = {
level: 4 | 6 | 8;
value: string;
};
type LocationFilter = {
country: CountryKey;
levels: LocationLevel[];
};
type Location = {
city?: string;
province?: string;
region?: string;
nation?: string;
latitude?: number;
longitude?: number;
};
type PendingStatus =
| "idle"
| "pending"
| "completed"
| "notAvailable"
| "failed";
type NumericRange =
| { min: number; max: number }
| { min: number; max?: undefined }
| { min?: undefined; max: number };
type YearlySalaryRange = {
min?: number;
max?: number;
currency: string;
};
type YearlyValue = {
year: number;
value: number;
};
type SortType =
| "default"
| "name"
| "city"
| "province"
| "region"
| "sectors"
| "currentTotalRevenue"
| "currentEmployees"
| "currentOpenPositions";
type SortOrder = "asc" | "desc";
type PositionSource = "vocations" | "linkedIn" | "indeed" | "infoJobs";
type Hours = "full" | "part" | "shift";
type CompanyStatus = "open" | "bankruptcy" | "liquidation";
type ValueTrend = "increasing" | "decreasing" | "stable";
type ExperienceLevel = "0" | "0-1" | "1-3" | "3-5" | "5-10" | "10+";
type Contract =
| "temporary"
| "internship"
| "permanent"
| "contract"
| "apprenticeship"
| "freelance";
type Collar = "blue" | "white";
type SmartWorking = "yes" | "no" | "hybrid";
type BusinessUnit =
| "finance"
| "hr"
| "purchasing"
| "marketing"
| "sales"
| "customerService"
| "research"
| "operations"
| "it"
| "legal"
| "strategy"
| "sustainability"
| "administration";
type SectorKey =
| "administrationAccounting"
| "textileClothing"
| "mediaCommunicationMarketing"
| "aeronauticsNavalDefense"
| "realEstate"
| "agriculture"
| "horeca"
| "food"
| "artHistoryArchitecture"
| "furniture"
| "craftsmanship"
| "insurance"
| "socialCooperativesAssociations"
| "automotive"
| "banking"
| "biomedical"
| "broadcastingMusicFilm"
| "outsourcingBusinessServices"
| "retail"
| "manufacturingIndustrial"
| "chemical"
| "energyOilGas"
| "trade"
| "consultingITConsulting"
| "consumerGoods"
| "pharmaceutical"
| "environmentSustainabilityEcology"
| "publishing"
| "educationTraining"
| "electronicsElectrotechnics"
| "industrialEngineeringServices"
| "sportsCultureEntertainment"
| "publicEntitiesNonProfitPublicAdmin"
| "financeFinancialServices"
| "gamingBetting"
| "rubberPlastic"
| "largeScaleRetail"
| "healthHygiene"
| "humanResources"
| "warehousePackaging"
| "cybersecurityIT"
| "legalCompliance"
| "logistics"
| "transportShipping"
| "medical"
| "metallurgyMechanics"
| "exhibitionsFairsEvents"
| "motors"
| "cleaning"
| "securitySurveillance"
| "personalServices"
| "professionalFirm"
| "telecommunications"
| "tourismTravel"
| "designFashion"
| "multiservices"
| "technologyScienceData"
| "automation"
| "other";
type ItalyLegalForm =
| "AA"
| "AC"
| "AE"
| "AF"
| "AI"
| "AL"
| "AM"
| "AN"
| "AP"
| "AR"
| "AS"
| "AT"
| "AU"
| "AZ"
| "CC"
| "CE"
| "CF"
| "CI"
| "CL"
| "CM"
| "CN"
| "CO"
| "CR"
| "CS"
| "CZ"
| "DI"
| "EC"
| "ED"
| "EE"
| "EI"
| "EL"
| "EM"
| "EN"
| "EP"
| "ER"
| "ES"
| "FI"
| "FO"
| "GE"
| "IC"
| "ID"
| "IF"
| "IR"
| "LL"
| "MA"
| "OC"
| "OO"
| "OS"
| "PA"
| "PC"
| "PF"
| "PS"
| "RC"
| "RR"
| "RS"
| "SA"
| "SC"
| "SD"
| "SE"
| "SF"
| "SG"
| "SI"
| "SL"
| "SM"
| "SN"
| "SO"
| "SP"
| "SR"
| "SS"
| "ST"
| "SU"
| "SV"
| "SZ";
type SpainLegalForm =
| "GE"
| "IE"
| "IU"
| "PO"
| "AC"
| "CJ"
| "CB"
| "CD"
| "BI"
| "PH"
| "CG"
| "CL"
| "EX"
| "PV"
| "NL"
| "NR"
| "PJ"
| "FN"
| "FJ"
| "FD"
| "MT"
| "MU"
| "OA"
| "PP"
| "AG"
| "SM"
| "SA"
| "ES"
| "SD"
| "SE"
| "SB"
| "SF"
| "SU"
| "CV"
| "CP"
| "CO"
| "CA"
| "CS"
| "SC"
| "SG"
| "GR"
| "LD"
| "SL"
| "LL"
| "LP"
| "NE"
| "LF"
| "LU"
| "UC"
| "UT"
| "OR";Legal form codes
Legal forms use country-specific codes. Expand a country to see the official meaning of every value accepted and returned by the API.
Use these codes in italy.legalForms or spain.legalForms when searching. Company enrichment returns a single code in italy.legalForm or spain.legalForm.
Italy · ItalyLegalForm (73 values)
| Code | Meaning |
|---|---|
| AA | Società in accomandita per azioni (S.a.p.A.) |
| AC | Associazione |
| AE | Società consortile in accomandita semplice |
| AF | Altre forme |
| AI | Associazione impresa |
| AL | Azienda speciale di ente locale |
| AM | Azienda municipale |
| AN | Società consortile in nome collettivo |
| AP | Azienda provinciale |
| AR | Azienda regionale |
| AS | Società in accomandita semplice (S.a.s.) |
| AT | Azienda autonoma statale |
| AU | Società per azioni con socio unico |
| AZ | Azienda speciale |
| CC | Consorzio con attività esterna |
| CE | Comunione ereditaria |
| CF | Consorzio fidi |
| CI | Società cooperativa a responsabilità illimitata |
| CL | Società cooperativa a responsabilità limitata |
| CM | Consorzio municipale |
| CN | Società consortile |
| CO | Consorzio |
| CR | Consorzio intercomunale |
| CS | Consorzio senza attività esterna |
| CZ | Consorzio di cui al D.Lgs. 267/2000 |
| DI | Impresa individuale |
| EC | Ente pubblico commerciale |
| ED | Ente diritto pubblico |
| EE | Ente ecclesiastico |
| EI | Ente impresa |
| EL | Ente sociale |
| EM | Ente morale |
| EN | Ente |
| EP | Ente pubblico economico |
| ER | Ente ecclesiastico civilmente riconosciuto |
| ES | Ente di cui alla L.R. 21-12-93 N.88 |
| FI | Fondazione impresa |
| FO | Fondazione |
| GE | Gruppo europeo di interesse economico (GEIE) |
| IC | Istituto di credito |
| ID | Istituto di credito di diritto pubblico |
| IF | Impresa familiare |
| IR | Istituto religioso |
| LL | Azienda speciale di cui al D.Lgs. 267/2000 |
| MA | Mutua assicurazione |
| OC | Società cooperativa consortile |
| OO | Cooperativa sociale |
| OS | Società consortile cooperativa a responsabilità limitata |
| PA | Associazione in partecipazione |
| PC | Piccola società cooperativa |
| PF | Persona fisica |
| PS | Piccola società cooperativa a responsabilità limitata |
| RC | Contratto di rete dotato di soggettività giuridica |
| RR | Società a responsabilità limitata a capitale ridotto |
| RS | Società a responsabilità limitata semplificata (S.r.l.s.) |
| SA | Società anonima |
| SC | Società cooperativa (Soc. Coop.) |
| SD | Società europea |
| SE | Società semplice (S.s.) |
| SF | Società di fatto |
| SG | Società cooperativa europea (SCE) |
| SI | Società irregolare |
| SL | Società consortile a responsabilità limitata |
| SM | Società di mutuo soccorso |
| SN | Società in nome collettivo (S.n.c.) |
| SO | Società consortile per azioni |
| SP | Società per azioni (S.p.A.) |
| SR | Società a responsabilità limitata (S.r.l.) |
| SS | Società costituita in base a leggi di altro stato |
| ST | Soggetto estero |
| SU | Società a responsabilità limitata con unico socio |
| SV | Società tra professionisti (S.t.p.) |
| SZ | Società non prevista dalla legislazione italiana |
Spain · SpainLegalForm (51 values)
| Code | Meaning |
|---|---|
| GE | Agrup. Eur. de Interés Económico |
| IE | Agrupación de Interés Económico |
| IU | Agrupación de Interés Urbanístico |
| PO | Agrupación Portuaria de Interés Económico |
| AC | Asociación |
| CJ | Caja |
| CB | Club Deportivo Básico |
| CD | Club Deportivo Elemental |
| BI | Comunidad de Bienes |
| PH | Comunidad de Propietarios en Régimen de Propiedad Horizontal |
| CG | Congregación o Institución Religiosa |
| CL | Corporación Local |
| EX | Empresa Extranjera |
| PV | Entidad de Previsión Social Voluntaria |
| NL | Entidad no Lucrativa |
| NR | Entidad no Residente |
| PJ | Entidad sin personalidad jurídica |
| FN | Fondo |
| FJ | Forma jurídica sin identificar |
| FD | Fundación |
| MT | Mutua |
| MU | Mutualidad de Previsión Social |
| OA | Organismo Autónomo |
| PP | Partido Político |
| AG | Sociedad Agraria de Transformación |
| SM | Sociedad Anonima Municipal |
| SA | Sociedad Anónima |
| ES | Sociedad Anónima de Gestión de Estibadores Portuarios |
| SD | Sociedad Anónima Deportiva |
| SE | Sociedad Anónima Europea |
| SB | Sociedad Anónima Laboral |
| SF | Sociedad Anónima Profesional |
| SU | Sociedad Anónima Unipersonal |
| CV | Sociedad Civil |
| CP | Sociedad Civil Profesional |
| CO | Sociedad Colectiva / Sociedad de Responsabilidad Colectiva |
| CA | Sociedad Comanditaria por Acciones |
| CS | Sociedad Comanditaria Simple / Sociedad en Comandita |
| SC | Sociedad Cooperativa |
| SG | Sociedad Cooperativa Europea |
| GR | Sociedad de Garantía Recíproca |
| LD | Sociedad Limitada |
| SL | Sociedad Limitada |
| LL | Sociedad Limitada Laboral |
| LP | Sociedad Limitada Laboral Profesional |
| NE | Sociedad Limitada Nueva Empresa |
| LF | Sociedad Limitada Profesional |
| LU | Sociedad Limitada Unipersonal |
| UC | Sucursal en España |
| UT | Unión Temporal de Empresas |
| OR | Órgano de la Administración |
Playground
Use the playground to explore endpoints without an API key. The playground base path is https://vocations.io/api/playground, it mirrors the v2 endpoints exactly and runs on synthetic Italian and Spanish data.
curl -X POST https://vocations.io/api/playground/companies \
-H "Content-Type: application/json" \
-d '{
"page": 0,
"company": {
"locations": [
{
"country": "spain",
"levels": [{ "level": 4, "value": "Cataluña" }]
}
],
"sectors": ["technologyScienceData"],
"employees": [{ "min": 11, "max": 200 }]
},
"sortType": "name",
"sortOrder": "asc",
"withPositions": true
}'{
"companyIDs": [
"pc0000000000000f",
"pc0000000000001j",
"pc0000000000002b"
],
"totalPages": 22,
"totalResults": 217
}Companies
POST /companies
✓ Does not consume creditsRequest
type APICompanyFilter = {
ids?: string[];
parentHoldingIDs?: string[];
names?: string[];
workAgency?: boolean;
locations?: LocationFilter[];
postalCodes?: string[];
italy?: {
ivas?: string[];
ateco?: string[];
legalForms?: ItalyLegalForm[];
};
spain?: {
cifNifs?: string[];
cnae?: string[];
legalForms?: SpainLegalForm[];
};
sectors?: SectorKey[];
employees?: NumericRange[];
totalRevenue?: NumericRange[];
totalRevenueTrend?: ValueTrend[];
employeesCostTrend?: ValueTrend[];
positionCountTrend?: ValueTrend[];
companyStatuses?: CompanyStatus[];
createdAt?: NumericRange[];
};
type V2CompaniesRequest = {
page?: number;
pageSize?: number;
company: APICompanyFilter;
notCompany?: APICompanyFilter;
sortType?: SortType;
sortOrder?: SortOrder;
withPositions?: boolean;
};ids matches company IDs only. parentHoldingIDs matches companies whose parent holding is one of the listed IDs. The same distinction applies to the company and notCompany filters in position searches.
Body example (JSON)
{
"page": 0,
"company": {
"locations": [
{
"country": "italy",
"levels": [{ "level": 4, "value": "Lombardia" }]
},
{
"country": "spain",
"levels": [{ "level": 4, "value": "Cataluña" }]
}
],
"sectors": ["technologyScienceData"],
"employees": [{ "min": 11, "max": 200 }]
},
"sortType": "name",
"sortOrder": "asc",
"withPositions": true
}withPositions: true makes the endpoint return only companies with open positions.
Response 200
type V2CompanySearchResult = {
companyIDs: string[];
totalPages: number;
totalResults: number;
};totalPages is the number of pages available for the current filters, at the pageSize you requested.
Possible errors
POST /companies/enrich
💳 1 credit/company · 2 credits with financial dataPerforms company enrich using provided IDs.
Request
type V2CompanyEnrichRequest = {
companyIDs: string[];
};Response 200
type V2EnrichedCompany = {
companyID: string;
parentHolding?: string;
name: string;
workAgency: boolean;
openPositionCount: number;
url?: string;
imageFile?: string;
linkedInURL?: string;
indeedURL?: string;
infoJobsURL?: string;
address?: string;
location?: LocationLevel[];
nation?: string;
sectors: SectorKey[];
employees: YearlyValue[];
totalRevenue: YearlyValue[];
employeesCost: YearlyValue[];
netProfit: YearlyValue[];
italy?: {
ragioneSociale: string;
iva?: string;
ateco?: string;
atecoCode?: string;
rea?: string;
shareCapital?: number;
legalForm?: ItalyLegalForm;
chamberOfCommerce?: string;
};
spain?: {
razonSocial: string;
cifNif?: string;
cnae?: string;
cnaeCode?: string;
legalForm?: SpainLegalForm;
shareCapital?: number;
};
createdAt?: number;
validationKey: string;
};
type V2CompanyEnrichResult = {
companies: V2EnrichedCompany[];
notFoundCompanyIDs: string[];
insufficientCreditsCompanyIDs: string[];
};imageFile contains only the file name. To access the logo use CDN: https://cdn.vocations.io/logos/<imageFile>
notFoundCompanyIDs lists IDs that do not exist or are not visible to your key. insufficientCreditsCompanyIDs lists existing companies skipped because credits ran out during the batch: request those again once you have credits. A 402 is returned only when no requested company was affordable.
Possible errors
POST /companies/status
✓ Does not consume creditsChecks whether the data you already hold is still current. Send each companyID together with the validationKey returned by /companies/enrich.
Request
type V2CompanyStatusRequest = {
companies: {
companyID: string;
validationKey: string;
}[];
};Body example (JSON)
{
"companies": [
{
"companyID": "cmp1a2b3c4d5e6f7g",
"validationKey": "eyJhbGciOiJIUzI1NiJ9..."
},
{
"companyID": "cmp8h9i0j1k2l3m4n",
"validationKey": "eyJhbGciOiJIUzI1NiJ9..."
}
]
}Response 200
type V2CompanyStatusResult = {
upToDateIDs: string[];
outdatedIDs: string[];
invalidIDs: string[];
};outdatedIDs contains companies whose data changed since your validationKey was issued: enrich those again. invalidIDs contains unknown companies, or keys that do not belong to the companyID they were sent with.
Possible errors
Positions
POST /positions
💳 3 credits if there are resultsRequest
type APIPositionFilter = {
ids?: string[];
sources?: PositionSource[];
names?: string[];
cities?: string[];
provinces?: string[];
regions?: string[];
nations?: string[];
languages?: string[];
targets?: string[];
smartWorking?: SmartWorking[];
collar?: (Collar | null)[];
hours?: (Hours | null)[];
contract?: (Contract | null)[];
experience?: (ExperienceLevel | null)[];
protectedCategories?: (boolean | null)[];
skills?: string[];
benefits?: string[];
certifications?: string[];
courses?: string[];
businessUnits?: BusinessUnit[];
yearlySalary?: NumericRange[];
createdAt?: NumericRange[];
};
type V2PositionsRequest = {
page?: number;
pageSize?: number;
position?: APIPositionFilter;
notPosition?: APIPositionFilter;
company?: APICompanyFilter;
notCompany?: APICompanyFilter;
includeNoMatch?: boolean;
};Body example (JSON)
{
"page": 0,
"position": {
"sources": ["vocations", "linkedIn"],
"regions": ["Lombardia"],
"contract": ["permanent"],
"experience": ["1-3", "3-5"]
},
"company": {
"sectors": ["technologyScienceData"]
}
}includeNoMatch: true also includes positions without a linked company.
Response 200
type V2PositionSearchResult = {
positionIDs: string[];
totalPages: number;
totalResults: number;
};Possible errors
POST /positions/enrich
💳 1 credit every 5 positionsRequest
type V2PositionEnrichRequest = {
positionIDs: string[];
};Response 200
type V2PositionCompanyContext = {
companyID: string;
workAgency: boolean;
italy?: { ragioneSociale: string; iva?: string };
spain?: { razonSocial: string; cifNif?: string };
};
type V2EnrichedPosition = {
positionID: string;
companyContext: V2PositionCompanyContext;
name: string;
description: string;
urls: string[];
sources: PositionSource[];
targets: string[];
cities: string[];
provinces: string[];
regions: string[];
sites: Location[];
skills: string[];
benefits: string[];
languages: string[];
certifications: string[];
courses: string[];
experience?: ExperienceLevel;
contract?: Contract;
hours?: Hours;
smartWorking: SmartWorking;
collar?: Collar;
protectedCategories?: boolean;
yearlySalaryRange?: YearlySalaryRange;
createdAt: number;
republishedAt?: number;
companyName?: string;
validationKey: string;
};
type V2PositionEnrichResult = {
positions: V2EnrichedPosition[];
failedPositionIDs: string[];
};To get full company data use endpoint /companies/enrich.
Possible errors
POST /positions/check
✓ Does not consume creditsReturns the status of one or more positions.
Request
type V2PositionsCheckRequest = {
positionIDs: string[];
};Response 200
type V2PositionCheckResult = {
openIDs: string[];
closedIDs: string[];
invalidIDs: string[];
};Possible errors
Contacts
POST /contacts
✓ Does not consume creditsSearches contacts linked to a company.
Request
type V2ContactsRequest = {
companyID: string;
jobTitles?: string[];
page?: number;
};Response 200
type V2ContactSearchItem = {
contactID: string;
firstName?: string;
lastName?: string;
jobTitle?: string;
hasEmail: boolean;
hasCity: boolean;
};
type V2ContactSearchResult = {
contacts: V2ContactSearchItem[];
totalPages: number;
totalResults: number;
};Possible errors
POST /contacts/enrich
💳 3 credits · +2 credits with phone numberRequest
type V2ContactEnrichRequest = {
contactID: string;
enrichPhoneNumber?: boolean;
};Response 200
type V2EnrichedContact = {
contactID: string;
firstName?: string;
lastName?: string;
jobTitle?: string;
headline?: string;
linkedInURL?: string;
photoURL?: string;
departments: string[];
email?: string;
emailStatus?: PendingStatus;
mobilePhone?: string;
phoneStatus?: PendingStatus;
location: LocationLevel[];
validationKey: string;
};Possible errors
POST /contacts/poll
💳 2 credits when a phone number arrivesReturns the current state of a contact you already enriched. Use it when enrichPhoneNumber returned phoneStatus: "pending": the phone reveal is asynchronous and lands here once resolved.
Request
type V2ContactPollRequest = {
contactID: string;
};Response 200
type V2ContactPollResult = {
email?: string;
emailStatus?: PendingStatus;
mobilePhone?: string;
phoneStatus: PendingStatus;
};The 2 phone credits are charged only when a number is actually returned. A reveal that ends as notAvailable or failed costs nothing.
Possible errors
Usage
GET /usage
✓ Does not consume creditsReturns current API key usage status.
Response 200
type V2UsageSnapshot = {
usedCredits: number;
maxCredits: number;
areCreditsShared: boolean;
lastResetAt: number;
};