API Reference

Users

Descripción General

La API de Usuarios permite gestionar empleados de tu empresa con estados activo e inactivo, basándose en sus asignaciones a centros de costos y subsidiarias.

Estado de Usuario

Un usuario puede estar en uno de dos estados:

  • Activo (is_active: true): Tiene acceso para reportar gastos a través de asignaciones a centros de costos
  • Inactivo (is_active: false): No tiene asignaciones activas y no puede reportar gastos

El campo is_active es calculado automáticamente por el sistema basándose en las asignaciones del usuario.


Endpoints

Base URL

https://api.xpendit.com/public/v1/enterprises/{enterprise_id}/users

Reemplaza {enterprise_id} con el ID de tu empresa.


1. Crear Usuario

Crea un nuevo usuario en tu empresa.

Endpoint

POST /public/v1/enterprises/{enterprise_id}/users/

Headers

Content-Type: application/json
Authorization: Api-Key en_sk_xxxxx

Parámetros del Body

CampoTipoRequeridoDescripción
first_namestringNoNombre del usuario
last_namestringNoApellido del usuario
emailstringCondicionalEmail del usuario
phonestringCondicionalTeléfono en formato E164 (ej: +56912345678)
government_idstringNoRUT u otro identificador gubernamental
internal_idstringNoIdentificador interno de tu sistema
allocationsarrayNoAsignaciones a subsidiarias y centros de costos

* Al menos uno de email o phone es requerido

Estructura de Allocations

{
  "allocations": [
    {
      "subsidiary_id": "uuid",              // O usar subsidiary_internal_id
      "is_responsible": false,              // Opcional
      "user_manager_id": "uuid",            // O usar user_manager_internal_id. Opcional
      "cost_centers": [                     // Opcional. Si está vacío, se asigna a TODOS
        {
          "id": "uuid",                     // O usar internal_id
          "is_responsible": false           // Opcional
        }
      ]
    }
  ]
}

Ejemplo: Crear Usuario Inactivo

POST /public/v1/enterprises/660e8400-e29b-41d4-a716-446655440000/users/
Content-Type: application/json
Authorization: Api-Key en_sk_xxxxx

{
  "first_name": "Juan",
  "last_name": "Pérez",
  "email": "[email protected]",
  "phone": "+56912345678",
  "government_id": "12345678-9",
  "internal_id": "EMP-001",
  "allocations": []
}

Response 201 Created:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "first_name": "Juan",
  "last_name": "Pérez",
  "email": "[email protected]",
  "phone": "+56912345678",
  "government_id": "12345678-9",
  "internal_id": "EMP-001",
  "enterprise_id": "660e8400-e29b-41d4-a716-446655440000",
  "is_active": false,
  "created_at": "2025-10-08T10:00:00Z",
  "updated_at": "2025-10-08T10:00:00Z"
}

Ejemplo: Crear Usuario Activo

POST /public/v1/enterprises/660e8400-e29b-41d4-a716-446655440000/users/
Content-Type: application/json
Authorization: Api-Key en_sk_xxxxx

{
  "first_name": "María",
  "last_name": "López",
  "email": "[email protected]",
  "phone": "+56987654321",
  "allocations": [
    {
      "subsidiary_id": "770e8400-e29b-41d4-a716-446655440000",
      "cost_centers": [
        {
          "id": "990e8400-e29b-41d4-a716-446655440000",
          "is_responsible": true
        }
      ]
    }
  ]
}

Response 201 Created:

{
  "id": "550e8400-e29b-41d4-a716-446655440001",
  "first_name": "María",
  "last_name": "López",
  "email": "[email protected]",
  "phone": "+56987654321",
  "enterprise_id": "660e8400-e29b-41d4-a716-446655440000",
  "is_active": true,
  "created_at": "2025-10-08T10:05:00Z",
  "updated_at": "2025-10-08T10:05:00Z"
}

Comportamiento Especial de Cost Centers

  • cost_centers vacío o no especificado: El usuario se asigna automáticamente a TODOS los centros de costos activos de la subsidiaria
  • cost_centers con IDs específicos: El usuario se asigna solo a esos centros de costos

2. Obtener Usuario

Obtiene la información detallada de un usuario específico.

Endpoint

GET /public/v1/enterprises/{enterprise_id}/users/{user_id}/

Query Parameters

ParámetroTipoDescripción
expandstringCampos adicionales a incluir. Valores:enterprise

Ejemplo

GET /public/v1/enterprises/660e8400-e29b-41d4-a716-446655440000/users/550e8400-e29b-41d4-a716-446655440000/
Authorization: Api-Key en_sk_xxxxx

Response 200 OK:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "first_name": "Juan",
  "last_name": "Pérez",
  "email": "[email protected]",
  "phone": "+56912345678",
  "government_id": "12345678-9",
  "internal_id": "EMP-001",
  "enterprise_id": "660e8400-e29b-41d4-a716-446655440000",
  "is_active": true,
  "created_at": "2025-10-08T10:00:00Z",
  "updated_at": "2025-10-08T10:15:00Z",
  "status": 200,
  "error": ""
}

Ejemplo con Expand

GET /public/v1/enterprises/660e8400-e29b-41d4-a716-446655440000/users/550e8400-e29b-41d4-a716-446655440000/?expand=enterprise
Authorization: Api-Key en_sk_xxxxx

Response 200 OK:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "first_name": "Juan",
  "last_name": "Pérez",
  "email": "[email protected]",
  "is_active": true,
  "enterprise_id": "660e8400-e29b-41d4-a716-446655440000",
  "enterprise": {
    "id": "660e8400-e29b-41d4-a716-446655440000",
    "name": "Empresa Demo",
    "legal_name": "Empresa Demo S.A.",
    "internal_id": "ENT-001",
    "created_at": "2025-01-01T00:00:00Z"
  },
  "created_at": "2025-10-08T10:00:00Z",
  "updated_at": "2025-10-08T10:00:00Z",
  "status": 200,
  "error": ""
}

3. Listar Usuarios

Obtiene la lista paginada de usuarios de tu empresa.

Endpoint

GET /public/v1/enterprises/{enterprise_id}/users/

Query Parameters

ParámetroTipoDescripción
statusstringFiltrar por estado. Valores:active, inactive
emailstringFiltrar por email exacto
phonestringFiltrar por teléfono (con o sin +)
expandstringCampos adicionales. Valores:enterprise
pageintegerNúmero de página (inicia en 1)
page_sizeintegerCantidad de resultados por página (máx: 100)

Ejemplo: Todos los Usuarios

GET /public/v1/enterprises/660e8400-e29b-41d4-a716-446655440000/users/
Authorization: Api-Key en_sk_xxxxx

Response 200 OK:

{
  "count": 25,
  "next": "https://api.xpendit.com/public/v1/enterprises/660e8400-e29b-41d4-a716-446655440000/users/?page=2",
  "previous": null,
  "results": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "first_name": "Juan",
      "last_name": "Pérez",
      "email": "[email protected]",
      "phone": "+56912345678",
      "is_active": true,
      "created_at": "2025-10-08T10:00:00Z",
      "updated_at": "2025-10-08T10:00:00Z"
    }
  ]
}

Ejemplo: Solo Usuarios Activos

GET /public/v1/enterprises/660e8400-e29b-41d4-a716-446655440000/users/?status=active
Authorization: Api-Key en_sk_xxxxx

Ejemplo: Solo Usuarios Inactivos

GET /public/v1/enterprises/660e8400-e29b-41d4-a716-446655440000/users/?status=inactive
Authorization: Api-Key en_sk_xxxxx

Ejemplo: Buscar por Email

GET /public/v1/enterprises/660e8400-e29b-41d4-a716-446655440000/users/[email protected]
Authorization: Api-Key en_sk_xxxxx

Ejemplo: Buscar por Teléfono

GET /public/v1/enterprises/660e8400-e29b-41d4-a716-446655440000/users/?phone=+56912345678
Authorization: Api-Key en_sk_xxxxx

4. Actualizar Usuario

Actualiza la información de un usuario existente.

Endpoint

PATCH /public/v1/enterprises/{enterprise_id}/users/{user_id}/

Headers

Content-Type: application/json
Authorization: Api-Key en_sk_xxxxx

Campos Actualizables

CampoTipoDescripción
first_namestringNombre del usuario
last_namestringApellido del usuario
emailstringEmail del usuario
phonestringTeléfono en formato E164
government_idstringIdentificador gubernamental
internal_idstringIdentificador interno
allocationsarrayAsignaciones (reemplaza las existentes)

Campos Read-Only (No Modificables)

  • id
  • enterprise_id
  • is_active (se calcula automáticamente)
  • created_at
  • updated_at

Ejemplo: Actualizar Datos Personales

PATCH /public/v1/enterprises/660e8400-e29b-41d4-a716-446655440000/users/550e8400-e29b-41d4-a716-446655440000/
Content-Type: application/json
Authorization: Api-Key en_sk_xxxxx

{
  "first_name": "Juan Carlos",
  "last_name": "Pérez González",
  "phone": "+56912345999",
  "email": "[email protected]"
}

Response 200 OK:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "first_name": "Juan Carlos",
  "last_name": "Pérez González",
  "email": "[email protected]",
  "phone": "+56912345999",
  "government_id": "12345678-9",
  "internal_id": "EMP-001",
  "enterprise_id": "660e8400-e29b-41d4-a716-446655440000",
  "is_active": true,
  "created_at": "2025-10-08T10:00:00Z",
  "updated_at": "2025-10-08T12:30:00Z"
}

Nota: Si no incluyes el campo allocations, las asignaciones actuales del usuario no se modifican.

Ejemplo: Activar Usuario (Agregar Allocations)

PATCH /public/v1/enterprises/660e8400-e29b-41d4-a716-446655440000/users/550e8400-e29b-41d4-a716-446655440000/
Content-Type: application/json
Authorization: Api-Key en_sk_xxxxx

{
  "allocations": [
    {
      "subsidiary_id": "770e8400-e29b-41d4-a716-446655440000",
      "cost_centers": [
        {
          "id": "990e8400-e29b-41d4-a716-446655440000"
        }
      ]
    }
  ]
}

Response 200 OK:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "first_name": "Juan Carlos",
  "last_name": "Pérez González",
  "email": "[email protected]",
  "is_active": true,
  "created_at": "2025-10-08T10:00:00Z",
  "updated_at": "2025-10-08T12:35:00Z"
}

El campo is_active cambia automáticamente a true cuando se asignan centros de costos.

Ejemplo: Inactivar Usuario (Remover Allocations)

PATCH /public/v1/enterprises/660e8400-e29b-41d4-a716-446655440000/users/550e8400-e29b-41d4-a716-446655440001/
Content-Type: application/json
Authorization: Api-Key en_sk_xxxxx

{
  "allocations": []
}

Response 200 OK:

{
  "id": "550e8400-e29b-41d4-a716-446655440001",
  "first_name": "María",
  "last_name": "López",
  "email": "[email protected]",
  "is_active": false,
  "created_at": "2025-10-08T10:05:00Z",
  "updated_at": "2025-10-08T12:40:00Z"
}

El campo is_active cambia automáticamente a false cuando se eliminan todas las asignaciones.

Nota Importante: Al enviar allocations: [], el sistema automáticamente:

  • ✅ Revoca todos los permisos de centros de costos
  • ✅ Elimina todas las responsabilidades de centros de costos
  • ✅ Desactiva el rol EMPLOYEE en todas las subsidiarias
  • ✅ Elimina todas las responsabilidades de subsidiarias

El usuario quedará completamente desvinculado de todas las áreas y sin permisos para reportar gastos.

Ejemplo: Cambiar Asignaciones (Transferir de Departamento)

PATCH /public/v1/enterprises/660e8400-e29b-41d4-a716-446655440000/users/550e8400-e29b-41d4-a716-446655440001/
Content-Type: application/json
Authorization: Api-Key en_sk_xxxxx

{
  "allocations": [
    {
      "subsidiary_id": "880e8400-e29b-41d4-a716-446655440000",
      "is_responsible": true,
      "cost_centers": [
        {
          "id": "aa0e8400-e29b-41d4-a716-446655440000",
          "is_responsible": true
        },
        {
          "id": "bb0e8400-e29b-41d4-a716-446655440000",
          "is_responsible": false
        }
      ]
    }
  ]
}

Nota: El array allocations reemplaza completamente las asignaciones existentes. Incluye todas las subsidiarias y centros de costos que deseas mantener.


5. Uso de Internal IDs

Puedes usar internal_id en lugar de UUIDs para referenciar entidades. Esto es útil para integrar con tus sistemas internos.

Ejemplo Completo con Internal IDs

POST /public/v1/enterprises/660e8400-e29b-41d4-a716-446655440000/users/
Content-Type: application/json
Authorization: Api-Key en_sk_xxxxx

{
  "first_name": "Carlos",
  "last_name": "Ramírez",
  "email": "[email protected]",
  "internal_id": "EMP-002",
  "allocations": [
    {
      "subsidiary_internal_id": "SUBS-001",
      "user_manager_internal_id": "EMP-001",
      "cost_centers": [
        {
          "internal_id": "CC-VENTAS",
          "is_responsible": true
        },
        {
          "internal_id": "CC-MARKETING",
          "is_responsible": false
        }
      ]
    }
  ]
}

Reglas de Uso

  • ✅ Puedes usar id (UUID) O internal_id para cada entidad
  • No mezcles ambos para la misma entidad
  • ✅ Puedes combinar: usar UUID para subsidiaria e internal_id para cost centers

Casos de Uso Comunes

1. Onboarding de Empleado Nuevo

# Paso 1: Crear usuario sin asignaciones (inactivo)
POST /public/v1/enterprises/{enterprise_id}/users/
{
  "email": "[email protected]",
  "first_name": "Nuevo",
  "last_name": "Empleado",
  "allocations": []
}

# Paso 2: Cuando esté listo, activar con asignaciones
PATCH /public/v1/enterprises/{enterprise_id}/users/{user_id}/
{
  "allocations": [
    {
      "subsidiary_id": "...",
      "cost_centers": [{"id": "..."}]
    }
  ]
}

2. Transferencia de Departamento

PATCH /public/v1/enterprises/{enterprise_id}/users/{user_id}/
{
  "allocations": [
    {
      "subsidiary_id": "nueva-subsidiaria-id",
      "cost_centers": [
        {"id": "nuevo-centro-costos-id"}
      ]
    }
  ]
}

3. Suspensión Temporal de Usuario

PATCH /public/v1/enterprises/{enterprise_id}/users/{user_id}/
{
  "allocations": []
}

Esto inactiva al usuario sin eliminarlo del sistema.

4. Actualización de Datos sin Afectar Permisos

PATCH /public/v1/enterprises/{enterprise_id}/users/{user_id}/
{
  "first_name": "Nombre Actualizado",
  "email": "[email protected]",
  "phone": "+56999999999"
}

No incluyas allocations para mantener las asignaciones actuales.


Validaciones y Restricciones

Formato de Teléfono

Los teléfonos deben estar en formato E164:

  • ✅ Correcto: +56912345678
  • ✅ Correcto: 56912345678 (se acepta sin +)
  • ❌ Incorrecto: 9 1234 5678
  • ❌ Incorrecto: (569) 1234-5678

Formato de Email

  • Debe ser un email válido: [email protected]
  • Es case-sensitive (diferencia mayúsculas/minúsculas)

Unicidad

  • email: Debe ser único globalmente en toda la plataforma
  • phone: Debe ser único globalmente en toda la plataforma
  • internal_id: Puede repetirse entre diferentes empresas

Restricciones de Allocations

  • Las subsidiarias deben pertenecer a tu empresa
  • Los centros de costos deben pertenecer a la subsidiaria especificada
  • El manager debe pertenecer a la misma subsidiaria
  • No se permite asignar recursos de otras empresas

Códigos de Estado HTTP

CódigoDescripción
200 OKOperación exitosa (GET, PATCH)
201 CreatedUsuario creado exitosamente (POST)
400 Bad RequestDatos inválidos en la petición
401 UnauthorizedAPI Key inválida o faltante
403 ForbiddenNo tienes permisos para esta operación
404 Not FoundUsuario no encontrado
500 Internal Server ErrorError del servidor

Manejo de Errores

Ejemplo de Error 400

{
  "phone": [
    "A user with this phone number already exists."
  ]
}

Ejemplo de Error 404

{
  "detail": "Not found."
}

Ejemplo de Error 400 con Validaciones de Allocations

{
  "allocations": [
    {
      "cost_centers": [
        "Cost centers {'aa0e8400-e29b-41d4-a716-446655440000'} do not belong to the specified subsidiary."
      ]
    }
  ]
}

Límites de la API

  • Rate Limiting: Consulta con tu representante de Xpendit
  • Page Size Máximo: 100 resultados por página
  • Timeout: 30 segundos por petición

Comportamiento del Campo is_active

El campo is_active es calculado automáticamente y no puede ser modificado directamente.

¿Cuándo es un usuario activo?

Un usuario es activo cuando tiene al menos una asignación a un centro de costos que le permita reportar gastos.

Cambios Automáticos

  • Agregar allocationsis_active cambia a true
  • Eliminar todas las allocationsis_active cambia a false
  • Modificar allocationsis_active se actualiza según corresponda

Importante

  • El estado se calcula en tiempo real con cada petición
  • No se almacena en base de datos, siempre es el estado actual
  • No intentes enviar is_active en POST o PATCH, será ignorado