Engineering · Primavera P6

Why integrating Primavera P6 schedule data is so painful

November 2026 · 8 min read

If you've tried to programmatically read a Primavera P6 XER file, you already know the frustration. You open the file expecting something like JSON or XML, and instead you get a wall of tab-separated text with cryptic headers, undocumented column names, and no official format specification anywhere on the internet.

This post explains why that happens, what specifically makes XER files hard to work with, and what your options look like in 2026.

What is a .xer file, exactly?

XER stands for Oracle Primavera Proprietary Exchange Format — and Oracle chose every word in that name carefully. It is proprietary. It is not documented publicly. It was designed as a database dump mechanism, not as a data interchange format.

Open any XER file in a text editor and you'll see something like this:

ERMHDR	19.12	2024-03-15	Project	admin		America/New_York	0.0	0.0	USD
%T	PROJECT
%F	proj_id	proj_short_name	plan_start_date	scd_end_date	...
%R	1234	BRIDGE-2024	2024-01-15 00:00	2026-06-30 00:00	...
%T	TASK
%F	task_id	proj_id	task_code	task_name	target_start_date	...
%R	5001	1234	A1010	Excavation	2024-03-01 07:00	...

The %T marker starts a table. %F defines the columns for that table. %R is a data row. The file is essentially a relational database export — multiple tables, with relationships between them, serialised as flat text. No schema documentation. No official spec.

The seven things that break your parser

1. CP1252 encoding, not UTF-8

P6 is a Windows application. When a user on a Windows machine exports a schedule, the resulting XER file uses Windows-1252 (CP1252) encoding, not UTF-8. Activity names with accented characters, em dashes, degree symbols, or anything outside basic ASCII will appear as garbled bytes if you open the file as UTF-8.

This breaks silently — no exception, no error, just corrupted text in your database. The fix requires detecting the encoding per-file, since P6 Cloud exports tend to be UTF-8 while P6 Professional desktop exports are CP1252.

2. No published column spec

The %F header row defines columns dynamically. Different P6 versions export different columns. Optional fields appear only when the project uses that feature. You cannot hardcode column positions — you must parse the %F row for each table, every time, and handle missing columns gracefully.

There is no Oracle documentation that lists all possible column names. The only way to know what columns exist is to export from every P6 version you need to support and catalogue what appears.

3. Version fragmentation

The XER format has changed between P6 versions without announcement. P6 15.2 files have a different structure than P6 19.12 files. The version is embedded in the ERMHDR header:

ERMHDR	19.12	...

But the version alone doesn't tell you which columns are present in which tables. P6 15.2.5 removed the row checksum that earlier versions included. Files from P6 16.1 and above cannot be imported into Primavera Risk Analysis. Each version change is an undocumented delta you discover by testing, not by reading a changelog.

4. Corrupt and partial exports from real projects

Construction sites don't have ideal IT environments. XER files exported from projects with thousands of activities, complex calendars, or non-standard P6 configurations are frequently malformed:

A parser that works on clean demo files will fail on real project data within the first week of production use.

5. The relational joins are your problem

The raw XER tables don't give you useful data directly. An activity row in TASK has a proj_id and a wbs_id — but to get the WBS path, you need to traverse the PROJWBS table recursively. To get predecessors, you join TASKPRED back to TASK. To get calendar hours, you join CALENDAR and parse the calendar data format, which is itself a mini-language inside the XER row.

Duration fields are stored in hours (target_drtn_hr_cnt), but whether those are work-hours or calendar-hours depends on the activity type and calendar assignment. Converting to "days" means knowing the hours-per-day value from the assigned calendar.

6. No REST API for the format itself

Oracle does have a REST API — for Primavera Cloud. But it requires an active Primavera Cloud subscription, authentication against Oracle's servers, and returns XML/XER blobs rather than structured JSON. It is designed for Oracle-to-Oracle integration, not for third-party developers who just want to read a file a contractor sent over email.

For P6 Professional (the on-premise version most contractors use), there is no REST API at all unless you have P6 EPPM running. The XER file is the export mechanism.

7. No language-agnostic solution

The best open-source parsers — xerparser and PyP6Xer — are Python-only. If your stack is Node.js, Go, Ruby, PHP, .NET, or anything else, you're either calling a Python subprocess, maintaining a sidecar service, or writing your own parser from scratch. The TypeScript options on npm have single-digit weekly downloads and no active maintenance.

Why this gap has persisted

The engineers who know XER deeply are construction schedulers and project controls specialists — they build desktop tools and Excel macros, not REST APIs. The engineers who build REST APIs and subscription services have never heard of Primavera P6. The gap requires both skill sets simultaneously, which is rare.

The market is also vertical enough that no VC-funded team has targeted it. P6 is used by roughly 2,000–36,000 companies worldwide (construction, oil & gas, defense, government) — a great bootstrapped SaaS opportunity, but not interesting to funds that need massive scale.

The result: until recently, your options were either self-host a Python parser or pay $990/year for a Windows desktop application.

❌ Building it yourself

  • Handle CP1252 encoding per-file
  • Parse dynamic column headers
  • Handle missing/corrupt rows
  • Maintain across P6 versions
  • Build auth, billing, rate limiting
  • Python-only ecosystem

✓ Using the API

  • POST a file, get structured JSON
  • Activities, WBS, relationships, resources
  • DCMA 14-point assessment
  • Baseline variance per activity
  • Works from any language
  • Files never stored

What the output looks like

One HTTP call returns everything normalised and joined:

curl -X POST https://p6parser.com/parse \
  -H "Authorization: Bearer YOUR_KEY" \
  --data-binary "@schedule.xer"
{
  "export_info": { "version": "19.12", "currency": "USD" },
  "schedule_summary": {
    "total_activities": 847,
    "critical_activities": 112,
    "percent_complete": 34.2
  },
  "activities": [
    {
      "activity_id": "A1010",
      "name": "Excavation",
      "wbs_path": "BRIDGE.FOUNDATION.EXCAVATION",
      "start": "2024-03-01T07:00:00Z",
      "finish": "2024-03-15T17:00:00Z",
      "original_duration_days": 10,
      "total_float_days": 0,
      "is_critical": true,
      "predecessors": [{ "activity_id": "A1000", "type": "FS", "lag_days": 0 }]
    }
  ],
  "wbs": [ ... ],
  "relationships": [ ... ],
  "dcma": { "overall_score": 78, "overall_passed": false, "checks": [ ... ] }
}

On data privacy: XER files often contain sensitive project data — resource rates, costs, personnel names. Files sent to this API are parsed in memory and deleted immediately after the response. Nothing is logged or stored. GDPR data-processing agreements are available for Enterprise customers.

Pricing and getting started

There's a free tier of 50 parses — no card required, instant API key. That's enough to integrate and test against your real project files before committing to anything.

Skip the painful part

50 parses free · no card · instant key · works from any language

Get your free API key →