Logo StartupKit
ES

Referencia de la API

Autentícate y consulta la API de Hiring para ofertas de empleo, candidatos y candidaturas.

Por qué es importante

La API de Hiring da a los sistemas externos acceso de lectura a tus datos de contratación: los portales de empleo obtienen las ofertas publicadas, los sistemas HRIS sincronizan los registros de candidatos, los dashboards rastrean las métricas del pipeline. Los scopes de los tokens garantizan que cada integración solo vea lo que necesita.

URL base

Todos los endpoints de la API son accesibles a través de:

https://startupkit.app/api/v1

Autenticación

Cada solicitud requiere un token de API en el encabezado Authorization:

Authorization: Bearer YOUR_TOKEN

Formato alternativo (ambos funcionan):

Authorization: token YOUR_TOKEN

Crea tokens en Settings > API. Cada token debe tener scopes explícitos para acceder a los endpoints de contratación.

Scope Acceso
job_postings:read Ofertas de empleo y etapas
candidates:read Datos personales del candidato (nombre, email, teléfono), metafields de la candidatura, descarga de CV
applications:read Candidaturas, historial de etapas, descarga de CV

Los tokens sin ningún scope no pueden acceder a los endpoints de contratación.

Formato y ciclo de vida del token

  • Formato: Cadena base58 de 24 caracteres (p. ej., k3Jf9pQ2mZ7xR4nL8vT6bWyH)
  • Se muestra una sola vez: El token en bruto se muestra una única vez, en la pantalla de confirmación justo después de crearlo. Cópialo en ese momento; después no se puede volver a recuperar.
  • Solo se almacena el hash: Kit solo guarda un hash SHA-256 del token, nunca el texto plano. Si pierdes el token, revócalo y crea uno nuevo; el valor original no se puede recuperar.
  • Rastreo de último uso: Cada solicitud exitosa actualiza last_used_at
  • Sin fecha de expiración: Los tokens no caducan por tiempo. No hay ninguna opción de expiración en el formulario de creación, y Settings > API no muestra ninguna: un token sigue siendo válido hasta que se revoca.
  • Alertas de inactividad: Los tokens sin usar durante más de 30 días activan notificaciones de administrador
  • Revocación automática: Los tokens se revocan automáticamente cuando un usuario es eliminado de la cuenta

Buena práctica: Crea tokens separados por integración con los scopes mínimos necesarios.

Alcance por cuenta

Cada token de API está vinculado a una cuenta específica. La cuenta se determina automáticamente a partir del token; no se necesita ningún parámetro account_id.

Cuando un miembro del equipo es eliminado de una cuenta, sus tokens para esa cuenta se revocan automáticamente.

Respuestas de error

Estado Significado Causas comunes
400 Solicitud incorrecta Contexto de cuenta ausente (caso límite en autenticación por sesión)
401 No autorizado Token ausente, inválido o revocado
403 Prohibido El token no tiene el scope requerido para este endpoint
404 No encontrado El recurso no existe o no pertenece a tu cuenta
422 Entidad no procesable Errores de validación (principalmente para endpoints fuera de contratación)

Paginación

Los endpoints de lista devuelven resultados paginados:

{
  "data": [...],
  "pagination": {
    "current_page": 1,
    "total_pages": 3,
    "total_count": 42,
    "per_page": 20
  }
}

Pasa ?page=2 para obtener las páginas siguientes.


Ofertas de empleo

Scope requerido: job_postings:read

Listar ofertas de empleo

GET /api/v1/job_postings

Ejemplo:

curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://startupkit.app/api/v1/job_postings?status=published

Parámetros:

Parámetro Tipo Descripción
status string Filtrar por draft, published, paused o closed
page integer Número de página

Respuesta:

{
  "data": [
    {
      "id": "job_abc123",
      "title": "Senior Rails Developer",
      "status": "published",
      "department": "Engineering",
      "location": "New York, NY",
      "employment_type": "full_time",
      "remote": true,
      "salary_min": "120000.0",
      "salary_max": "180000.0",
      "salary_currency": "USD",
      "salary_period": "year",
      "published_at": "2026-01-15T10:00:00Z",
      "closed_at": null,
      "created_at": "2026-01-10T08:30:00Z",
      "updated_at": "2026-02-01T14:20:00Z",
      "stages": [
        {
          "id": "stg_def456",
          "name": "Screening",
          "stage_type": "default",
          "position": 0
        }
      ],
      "counts": {
        "total_applications": 24,
        "active_applications": 18,
        "rejected": 6
      }
    }
  ],
  "pagination": { ... }
}

Obtener una oferta de empleo

GET /api/v1/job_postings/:id

Devuelve la misma estructura que un elemento de la respuesta de lista.

Listar etapas

GET /api/v1/job_postings/:job_posting_id/stages

Respuesta:

{
  "data": [
    {
      "id": "stg_def456",
      "name": "Screening",
      "stage_type": "default",
      "position": 0
    }
  ]
}

Las etapas están ordenadas por posición. Sin paginación.


Candidatos

Scope requerido: candidates:read

Listar candidatos

GET /api/v1/candidates

Ejemplo:

curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://startupkit.app/api/v1/[email protected]

Parámetros:

Parámetro Tipo Descripción
search string Buscar por nombre o email
page integer Número de página

Respuesta:

{
  "data": [
    {
      "id": "cand_ghi789",
      "first_name": "John",
      "last_name": "Doe",
      "email": "[email protected]",
      "phone": "+1-555-0100",
      "status": "active",
      "github_username": "johndoe",
      "created_at": "2026-01-20T09:15:00Z",
      "applications": [
        {
          "id": "app_jkl012",
          "job_posting_id": "job_abc123",
          "job_posting_title": "Senior Rails Developer",
          "current_stage_name": "Interview",
          "status": "active",
          "submitted_at": "2026-01-20T09:15:00Z"
        }
      ]
    }
  ],
  "pagination": { ... }
}

Obtener un candidato

GET /api/v1/candidates/:id

Devuelve la misma estructura que un elemento de la respuesta de lista.


Candidaturas

Scope requerido: applications:read

Listar candidaturas

GET /api/v1/applications

Ejemplo:

curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://startupkit.app/api/v1/applications?job_posting_id=job_abc123&status=active

Parámetros:

Parámetro Tipo Descripción
job_posting_id string Filtrar por ID con prefijo de la oferta de empleo
status string Filtrar por active o rejected
page integer Número de página

Respuesta:

{
  "data": [
    {
      "id": "app_jkl012",
      "job_posting_id": "job_abc123",
      "candidate_id": "cand_ghi789",
      "current_stage_name": "Interview",
      "status": "active",
      "submitted_at": "2026-01-20T09:15:00Z",
      "created_at": "2026-01-20T09:15:00Z",
      "updated_at": "2026-02-10T11:30:00Z",
      "candidate": {
        "id": "cand_ghi789",
        "first_name": "John",
        "last_name": "Doe",
        "email": "[email protected]"
      },
      "stage_history": [
        {
          "id": "sp_mno345",
          "stage_name": "Screening",
          "stage_type": "default",
          "status": "completed",
          "started_at": "2026-01-20T09:15:00Z",
          "completed_at": "2026-01-25T16:00:00Z"
        },
        {
          "id": "sp_pqr678",
          "stage_name": "Interview",
          "stage_type": "interview",
          "status": "in_progress",
          "started_at": "2026-01-25T16:00:00Z",
          "completed_at": null
        }
      ],
      "metafields": [
        {
          "key": "years_of_experience",
          "label": "Years of Experience",
          "field_type": "number",
          "value": "8",
          "source": "ai",
          "confidence": 0.92,
          "extracted_at": "2026-01-20T09:18:00Z",
          "edited": false,
          "original_value": null
        },
        {
          "key": "salary_expectation",
          "label": "Salary Expectation",
          "field_type": "number",
          "value": "150000",
          "source": "ai",
          "confidence": 0.75,
          "extracted_at": "2026-01-20T09:18:00Z",
          "edited": true,
          "original_value": "140000"
        }
      ]
    }
  ],
  "pagination": { ... }
}

Datos de metafields

Scope requerido: candidates:read

Los valores de los metafields contienen datos personales del candidato extraídos por la IA, así que el array metafields está protegido por el scope candidates:read —el mismo que protege el bloque candidate— y no por applications:read. Un token con applications:read pero sin candidates:read recibe las respuestas de candidaturas sin ninguna clave metafields. La respuesta de ejemplo anterior es la que ve un token que tiene ambos scopes.

Cuando el token sí tiene candidates:read, cada candidatura incluye un array metafields que contiene campos de datos estructurados extraídos o introducidos para esa candidatura. Cada entrada tiene:

Campo Tipo Descripción
key string Identificador legible por máquina del campo
label string Nombre visible legible por humanos
field_type string Tipo de dato: exactamente uno de estos nueve: text, textarea, number, date, select, boolean, url, rating, tags
value string | null Valor actual (siempre serializado como string)
source string Cómo se definió el valor: exactamente uno de dos valores: manual (introducido o editado por una persona) o ai (extraído o definido por la IA)
confidence float | null Puntuación de confianza de la IA (0.0–1.0) cuando source es ai; null en caso contrario
extracted_at timestamp | null Cuándo se definió o extrajo el valor
edited boolean true solo cuando un valor de origen IA se sobrescribió después con algo distinto de la extracción original de la IA (en la práctica, mediante una llamada MCP hiring_update_metafield_value). Las ediciones que hace una persona en la propia interfaz de Kit guardan source: manual y siempre indican edited: false.
original_value string | null El valor original extraído por la IA antes de las ediciones humanas; null si nunca se editó

Dentro de un token que tiene candidates:read, el array metafields no se filtra además según el indicador de visibilidad managers_only. Cada metacampo definido en la oferta de empleo —incluidos los campos marcados como managers_only en la configuración de la oferta— se devuelve, independientemente del rol del propietario del token. Por tanto, candidates:read es el único control sobre la exposición de los metafields: si un campo contiene información sensible que no quieres exponer a una integración, no le concedas el scope candidates:read, ya que la API no aplica el filtrado de visibilidad para managers que sí se usa en otras partes de la aplicación. Conceder solo applications:read es seguro en este sentido: devuelve el historial de etapas y el estado de la candidatura sin los metafields.

Obtener una candidatura

GET /api/v1/applications/:id

Devuelve la misma estructura que un elemento de la respuesta de lista. Cuando el token tiene el scope candidates:read y la candidatura tiene un CV adjunto, la respuesta incluye metadatos del CV:

{
  "id": "app_jkl012",
  "resume_filename": "john_doe_resume.pdf",
  "resume_content_type": "application/pdf",
  "resume_byte_size": 245760,
  ...
}

Estos campos se omiten cuando no hay CV adjunto o cuando falta el scope candidates:read.

Descargar CV

Scopes requeridos: applications:read + candidates:read

GET /api/v1/applications/:application_id/resume

Descarga el CV del candidato para la candidatura indicada. Devuelve una redirección 302 a una URL firmada con tiempo limitado (válida durante 30 minutos).

Ejemplo:

curl -L -H "Authorization: Bearer YOUR_TOKEN" \
  -o resume.pdf \
  https://startupkit.app/api/v1/applications/app_jkl012/resume

Respuesta:

  • 302 Found – Redirección a la URL de descarga firmada. Usa -L (seguir redirecciones) con curl.
  • 403 Forbidden – El token no tiene el scope applications:read o candidates:read.
  • 404 Not Found – Candidatura no encontrada, o sin CV adjunto.

Notas:

  • Las URL firmadas expiran a los 30 minutos. Si expira, solicita una nueva.
  • El encabezado Content-Disposition está configurado como attachment (inicia la descarga en el navegador).
  • Tipos de archivo de CV: PDF, DOC, DOCX (según lo subido por el candidato).

Ocultamiento de datos personales del candidato

Cuando un token tiene applications:read pero no candidates:read, los datos del candidato en las respuestas de candidaturas se ocultan y solo muestran el ID:

{
  "candidate": {
    "id": "cand_ghi789"
  }
}

Los campos first_name, last_name y email no se incluyen. El array metafields y los campos de metadatos del CV se omiten por completo por la misma regla, ya que también pueden contener datos personales del candidato. Esto permite que las integraciones de portales de empleo rastreen el estado de las candidaturas sin exponer la información de contacto de los candidatos.


Diagnóstico de problemas

Problemas de autenticación

401 Unauthorized

Si recibes una respuesta 401, verifica:

  1. Formato del token: Asegúrate de que el token coincida con el valor que se muestra una sola vez al crearlo (cadena base58 de 24 caracteres). Si ya no lo tienes, revoca el token y crea uno nuevo: Kit solo guarda un hash y no puede volver a mostrarlo.
  2. Encabezado Authorization: Debe ser Authorization: Bearer TOKEN o Authorization: token TOKEN
  3. El token sigue existiendo: Confirma que el token siga apareciendo en Settings > API: un token revocado se elimina, no se desactiva
  4. Membresía en la cuenta: Confirma que el propietario del token sigue siendo miembro de la cuenta

403 Forbidden

Cuando recibes un 403, el token es válido pero no tiene el scope requerido:

  1. Verifica los scopes requeridos: Cada endpoint documenta su scope requerido (p. ej., job_postings:read)
  2. Añade los scopes faltantes: Edita el token en Settings > API y añade el scope necesario
  3. Formato del scope: Debe coincidir exactamente: job_postings:read, no job_postings ni read

Problemas de acceso a datos

Array data vacío en las respuestas

Si la API devuelve {"data": [], "pagination": {...}} pero esperas resultados:

  1. Aislamiento por cuenta: Los tokens de API solo ven datos de la cuenta a la que están vinculados
  2. Verifica la cuenta: Comprueba a qué cuenta pertenece el token en Settings > API
  3. Acceso entre cuentas: Los tokens no pueden acceder a datos de otras cuentas, incluso si el usuario es miembro de ellas

Los datos personales del candidato están ocultos

Si solo ves {"candidate": {"id": "cand_..."}} sin nombre ni email:

  1. Comportamiento esperado: Esto ocurre cuando el token tiene applications:read pero no candidates:read
  2. Añade el scope: Para ver los detalles completos del candidato, añade el scope candidates:read a tu token
  3. Privacidad por diseño: Esto permite que las integraciones rastreen candidaturas sin exponer información de contacto

Falta metafields en las respuestas de candidaturas

El array metafields está protegido por el scope candidates:read, no por applications:read, porque los valores de los metafields pueden contener datos personales del candidato extraídos por la IA. Si las respuestas no traen ninguna clave metafields, al token le falta candidates:read. Añade ese scope solo si la integración también debe ver nombres, correos y CV de los candidatos: ambas cosas van juntas.

Problemas de consultas y filtros

404 al buscar recursos específicos

  1. Usa IDs con prefijo: Las ofertas de empleo usan el formato job_abc123, no IDs de base de datos como 42
  2. Sensibilidad a mayúsculas: Los IDs con prefijo distinguen entre mayúsculas y minúsculas
  3. Alcance de la cuenta: El recurso debe pertenecer a la cuenta del token

Los parámetros de filtro no funcionan

  1. Valores de estado válidos:
    • Ofertas de empleo: draft, published, paused, closed (distingue mayúsculas)
    • Candidaturas: active, rejected (distingue mayúsculas)
  2. Formato de parámetros: Usa ?status=published, no ?status=Published ni ?filter[status]=published

Preguntas frecuentes

¿Cómo funciona la paginación?

Todos los endpoints de lista devuelven 20 elementos por página (fijo). Usa ?page=2 para la siguiente página. El objeto pagination muestra total_pages y total_count.

¿Los tokens expiran automáticamente?

No. No hay ninguna opción de expiración al crear un token, así que un token permanece válido hasta que:

  • Se revoquen manualmente en Settings > API
  • El usuario sea eliminado de la cuenta
  • La cuenta sea eliminada

¿Debo usar un solo token para múltiples integraciones?

No. La buena práctica es un token por integración con los scopes mínimos. Esto facilita:

  • Auditar qué integración está haciendo solicitudes (a través de last_used_at)
  • Revocar el acceso a una integración específica sin afectar a las demás
  • Otorgar permisos diferentes a distintos sistemas

¿Cuál es la relación entre los webhooks y la API?

Los webhooks te notifican de eventos (nueva candidatura, cambio de etapa). La API te permite consultar el estado actual. Usa los webhooks para activar tu sistema y luego usa la API para obtener los detalles completos.

¿Puedo obtener más de 20 elementos por página?

No. El tamaño de página está fijado en 20 elementos para garantizar un rendimiento estable. Usa el parámetro page para iterar sobre todos los resultados.

Lista de comprobación rápida

  • Crea un token de API en Settings > API – cada token está vinculado a esa cuenta
  • Asigna solo los scopes que tu integración necesita (buena práctica: un token por integración con los scopes mínimos)
  • No concedas candidates:read salvo que la integración deba ver los datos personales del candidato: ese scope también controla el array metafields y el acceso al CV
  • Incluye Authorization: Bearer TOKEN en cada solicitud
  • Usa IDs con prefijo (p. ej., job_abc123) en las URLs, no IDs de base de datos
  • Maneja las respuestas 400 y 422 para errores de validación
  • Maneja las respuestas 401 – puede que tu token haya sido revocado
  • Maneja las respuestas 403 – a tu token puede faltarle un scope requerido
  • Usa el parámetro page para paginar grandes conjuntos de resultados (20 elementos por página)

Escriba para buscar...