REST API · v2

Vocations
Documentación

Integra el rastreo de vacantes y la información empresarial directamente en tu flujo de trabajo de selección.

Introducción

Autenticación

Todos los endpoints bajo /v2 requieren una clave de API válida, incluidos los que no consumen créditos.

Los endpoints de la ruta /playground no requieren clave de API.

En el caso de los endpoints /v2, la clave debe indicarse en el encabezado HTTP «Authorization» con el valor «Bearer <clave>».

http header
Authorization: Bearer 5tg••••••••••••••••8ux
Introducción

Tipos compartidos

ℹ️

? Cuando aparece «?» después de una clave, el valor es opcional.
[] «[]» después de cualquier tipo indica que el valor debe ser un array.
Todos los identificadores tienen una longitud de 16 caracteres.
Los endpoints de búsqueda aceptan page (empieza en 0, valor por defecto 0) y pageSize (mínimo 1, máximo 128, valor por defecto 10).
Los arrays de filtros aceptan hasta 64 elementos, salvo names, cities, provinces, regions, nations, postalCodes, italy.ivas, italy.ateco, spain.cifNifs y spain.cnae, que aceptan hasta 256. Los endpoints por lotes aceptan entre 1 y 128 identificadores. Superar un límite devuelve 400.
Cada respuesta autenticada devuelve X-RateLimit-Limit, X-RateLimit-Remaining y X-RateLimit-Reset para la ventana del minuto actual. Un 429 también devuelve Retry-After.

shared types
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";
Introducción

Entorno de pruebas

Usa el entorno de pruebas para explorar los endpoints sin necesidad de clave de API. La ruta base es https://vocations.io/api/playground, replica exactamente los endpoints v2 y funciona con datos sintéticos italianos y españoles.

API Playground — vocations.io
NO SE REQUIERE CLAVE DE API
Empresas
Vacantes
Contactos
Uso
POSTvocations.io/api/playground/companies
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
  }'
🔒 No se requiere clave de API en el entorno de pruebas
Respuesta200 OK
{
  "companyIDs": [
    "pc0000000000000f",
    "pc0000000000001j",
    "pc0000000000002b"
  ],
  "totalPages": 22,
  "totalResults": 217
}
Esta es una vista previa visual. Para usar el entorno de pruebas real, accede a vocations.io/api/playground → vocations.io/api/playground →
1.2 ENRIQUECIMIENTO DE EMPRESAS

POST /companies/enrich

💳 1 crédito por empresa · 2 créditos con datos financieros

Enriquece los datos de empresa a partir de los IDs proporcionados.

Solicitud

request type
type V2CompanyEnrichRequest = {
  companyIDs: string[];
};

Respuesta 200

response
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 contiene solo el nombre del archivo. Para acceder al logotipo, usa la CDN: https://cdn.vocations.io/logos/<imageFile>

ℹ️

notFoundCompanyIDs enumera los identificadores que no existen o no son visibles para tu clave. insufficientCreditsCompanyIDs enumera las empresas existentes omitidas porque los créditos se agotaron durante el lote: vuelve a solicitarlas cuando tengas créditos. Solo se devuelve un 402 cuando no había créditos suficientes para ninguna de las empresas solicitadas.

Posibles errores

400
Solicitud incorrecta
Cuerpo JSON inválido o payload no válido.
401
No autorizado
Falta la clave de API o no es válida.
429
Límite de solicitudes excedido
500
Error interno del servidor
1.3 ESTADO DE EMPRESAS

POST /companies/status

✓ No consume créditos
Límite de solicitudes: máximo 60 solicitudes por minuto · 3600 solicitudes por hora

Comprueba si los datos que ya tienes siguen vigentes. Envía cada companyID junto con la validationKey devuelta por /companies/enrich.

Solicitud

request type
type V2CompanyStatusRequest = {
  companies: {
    companyID: string;
    validationKey: string;
  }[];
};

Ejemplo de cuerpo (JSON)

json
{
  "companies": [
    {
      "companyID": "cmp1a2b3c4d5e6f7g",
      "validationKey": "eyJhbGciOiJIUzI1NiJ9..."
    },
    {
      "companyID": "cmp8h9i0j1k2l3m4n",
      "validationKey": "eyJhbGciOiJIUzI1NiJ9..."
    }
  ]
}

Respuesta 200

response
type V2CompanyStatusResult = {
  upToDateIDs: string[];
  outdatedIDs: string[];
  invalidIDs: string[];
};
💡

outdatedIDs contiene las empresas cuyos datos han cambiado desde que se emitió tu validationKey: vuelve a enriquecerlas. invalidIDs contiene empresas desconocidas, o claves que no pertenecen al companyID con el que se enviaron.

Posibles errores

400
Solicitud incorrecta
Cuerpo JSON inválido o payload no válido.
401
No autorizado
Falta la clave de API o no es válida.
429
Límite de solicitudes excedido
500
Error interno del servidor
2.2 ENRIQUECIMIENTO DE VACANTES

POST /positions/enrich

💳 1 crédito por cada 5 posiciones

Solicitud

request type
type V2PositionEnrichRequest = {
  positionIDs: string[];
};

Respuesta 200

response
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[];
};
ℹ️

Para obtener todos los datos de la empresa, utiliza el endpoint /companies/enrich.

Posibles errores

400
Solicitud incorrecta
Cuerpo JSON inválido o payload no válido.
401
No autorizado
Falta la clave de API o no es válida.
402
Créditos insuficientes
429
Límite de solicitudes excedido
500
Error interno del servidor
2.3 VERIFICACIÓN DE VACANTES

POST /positions/check

✓ No consume créditos
Límite de solicitudes: máximo 60 solicitudes por minuto · 3600 solicitudes por hora

Devuelve el estado de una o varias vacantes.

Solicitud

request type
type V2PositionsCheckRequest = {
  positionIDs: string[];
};

Respuesta 200

response
type V2PositionCheckResult = {
  openIDs: string[];
  closedIDs: string[];
  invalidIDs: string[];
};

Posibles errores

400
Solicitud incorrecta
Cuerpo JSON inválido o payload no válido.
401
No autorizado
Falta la clave de API o no es válida.
429
Límite de solicitudes excedido
500
Error interno del servidor
3.2 ENRIQUECIMIENTO DE CONTACTOS

POST /contacts/enrich

💳 3 créditos · +2 créditos con número de teléfono
Límite de solicitudes: máximo 20 solicitudes por minuto · 600 solicitudes por hora

Solicitud

request type
type V2ContactEnrichRequest = {
  contactID: string;
  enrichPhoneNumber?: boolean;
};

Respuesta 200

response
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;
};

Posibles errores

400
Solicitud incorrecta
Cuerpo JSON inválido o payload no válido.
401
No autorizado
Falta la clave de API o no es válida.
402
Créditos insuficientes
404
No se ha encontrado el contacto
No se ha encontrado el contacto.
429
Límite de solicitudes excedido
500
Error interno del servidor
3.3 CONSULTA DE CONTACTOS

POST /contacts/poll

💳 2 créditos cuando llega un número
Límite de solicitudes: máximo 20 solicitudes por minuto · 600 solicitudes por hora

Devuelve el estado actual de un contacto ya enriquecido. Úsalo cuando enrichPhoneNumber haya devuelto phoneStatus: "pending": la obtención del número es asíncrona y llega aquí una vez resuelta.

Solicitud

request type
type V2ContactPollRequest = {
  contactID: string;
};

Respuesta 200

response
type V2ContactPollResult = {
  email?: string;
  emailStatus?: PendingStatus;

  mobilePhone?: string;
  phoneStatus: PendingStatus;
};
💡

Los 2 créditos del teléfono se cobran solo cuando se devuelve un número. Una búsqueda que termina en notAvailable o failed no cuesta nada.

Posibles errores

400
Solicitud incorrecta
Cuerpo JSON inválido o payload no válido.
401
No autorizado
Falta la clave de API o no es válida.
402
Créditos insuficientes
404
No se ha encontrado el contacto
Contacto no encontrado o nunca enriquecido.
429
Límite de solicitudes excedido
500
Error interno del servidor
4. Uso

Uso

GET /usage

✓ No consume créditos
Límite de solicitudes: máximo 10 solicitudes por minuto · 300 solicitudes por hora

Devuelve el estado actual de uso de la clave de API.

GEThttps://vocations.io/api/v2/usage

Respuesta 200

response
type V2UsageSnapshot = {
  usedCredits: number;
  maxCredits: number;

  areCreditsShared: boolean;
  lastResetAt: number;
};

Posibles errores

401
No autorizado
Falta la clave de API o no es válida.
429
Límite de solicitudes excedido
500
Error interno del servidor