Files
skills-build-team/personio-headcount/references/data-schemas.md
T

3.6 KiB

Data Schemas

Snapshot Structure

{
  "last_refreshed": "2026-03-04T19:00:00Z",
  "total_records": 755,
  "summary": {
    "ACTIVE": 177,
    "INACTIVE": 574,
    "ONBOARDING": 1,
    "LEAVE": 3
  },
  "employees": [
    {
      "personio_id": "35653993",
      "status": "ONBOARDING",
      "team_id": "417186",
      "department_id": "1291054",
      "office_id": "501083",
      "start_date": "2026-05-01",
      "end_date": null
    }
  ]
}

Team Mapping Structure

Maps Personio team IDs to human-readable names:

{
  "total_teams": 65,
  "teams": [
    {
      "team_id": "4400959",
      "team_name": "AI & Automation",
      "active_headcount": 6,
      "total_records": 7
    }
  ]
}

Department Mapping Structure

Groups teams under departments with real names from department-mapping.csv:

{
  "total_departments": 19,
  "departments": [
    {
      "department_id": "1291054",
      "department_name": "Finance & Business Navigation",
      "active_headcount": 11,
      "total_records": 45,
      "team_ids": ["417186", "417184", "3442693", "3443053", "572110"],
      "teams": ["Data", "Finance & Administration", "M&A", "Pricing", "Rev Ops"]
    }
  ]
}

Office Mapping Structure

{
  "total_offices": 8,
  "offices": [
    {
      "office_id": "501083",
      "active_headcount": 120,
      "total_records": 500
    }
  ]
}

MCP Tool Reference

Tool: Call_Personio_Get_Employees_ (full ID: mcp__n8n-personio__Call_Personio_Get_Employees_)

Parameter Type Default Description
limit number 50 Records per page (use 50 for balance)
cursor string "" Pagination cursor from previous page

Pass parameters as a JSON string in the input field:

  • First page: {"limit": 50}
  • Subsequent pages: {"limit": 50, "cursor": "<nextCursor>"}

Employee Record Fields (from API)

Each employee record from the MCP tool contains:

  • id → store as personio_id
  • status → ACTIVE, INACTIVE, ONBOARDING, or LEAVE
  • team_id → Personio team ID (look up name in team_mapping.json)
  • department_id → Personio department ID
  • office_id → Personio office ID
  • start_date → employment start
  • end_date → contract end date (null if ongoing)
  • first_name, last_name, email → NEVER STORE THESE — strip before saving

Incremental Refresh (Delta Update)

  1. Read existing snapshot
  2. Fetch all pages from Personio (no "modified since" filter available)
  3. Compare each employee by personio_id:
    • ID exists → update the record (status, team_id, etc. may have changed)
    • ID is new → add it
    • ID in snapshot but not in fresh data → keep (historical)
  4. Recalculate summary counts
  5. Update last_refreshed timestamp
  6. Rebuild team_mapping.json counts
  7. Save all files

PDF Report Contents

The PDF report has 6 pages:

  1. Cover page — KPI cards (active, onboarding, on leave, inactive)
  2. Headcount by Team — all active teams ranked by headcount with percentages
  3. Headcount by Department — departments with team listings
  4. New Joiners — monthly breakdown since Jan 2025, with team attribution
  5. Departures — monthly breakdown since Jan 2025, with team attribution
  6. Net Workforce Movement — joiners vs leavers with cumulative net change

XML Escaping

The report uses xml_escape() for special characters in names (e.g., "M&A" → "M&A"). This is required because reportlab's Paragraph class uses an XML parser internally.