Operating Data Model: How Projects, Positions, Allocations, and Time Entries Fit Together

This guide explains how Operating organizes data and why entities relate the way they do. Understanding the data model is essential for building integrations, writing efficient queries, and avoiding common mistakes.

Overview: The Core Entity Chain

At the heart of Operating is a chain of entities that represent work, from high-level planning to detailed execution:

Planning work:

Project → Position (optionally: Person + Role) → Allocation

Tracking work:

Person + Project → Time Entry

The key insights:

  • Allocations (planned work) flow through positions. You create a position on a project (optionally assigning a person and role), then create allocations on that position.
  • Time entries (actual work) are independent. They link a person directly to a project and are not connected to allocations or positions.

Why This Structure Exists

Consulting businesses have complex needs:

  • The same person might play multiple roles on the same project (e.g., both Developer and Tech Lead)
  • Billing rates often depend on role, seniority, and location
  • Plans change constantly (tentative vs confirmed work)
  • Reporting needs to distinguish between planned work and actual work

Operating's data model handles these realities by separating planning (allocations) from execution (time entries) and using positions as the layer where roles and rates are determined.

Core Entities Explained

Organization

Your Operating instance. All data belongs to one organization.

In the API:

  • Not exposed as an entity (implicit in all requests)
  • All entities are scoped to your organization

Company

A legal entity within your organization. Multi-company organizations (e.g., holding companies with multiple subsidiaries) use this to separate invoicing and accounting.

In the API:

  • GET /companies — List companies
  • GET /companies/{id} — Get company details

Key relationships:

  • Each Project belongs to one Company
  • Each Person belongs to one Company

When to use: Most organizations have one company. Use multiple companies if you need separate invoicing configurations for different legal entities or for reporting.

Site

A physical or logical location (office, region, etc.). Sites are used for:

  • Organizational reporting
  • Filtering people and projects
  • Managing default working time and holiday calendars of persons

In the API:

  • GET /sites — List sites
  • POST /sites — Create site

Key relationships:

  • Each Project belongs to one Site
  • Each Person belongs to one Site

Client

A customer company purchasing services. Clients can be external (real customers) or internal (for internal projects).

In the API:

  • GET /clients — List clients
  • POST /clients — Create client
  • PATCH /clients/{id} — Update client

Key relationships:

  • Each Project optionally has one Client (required for billable projects)

Internal clients: Mark a client as internal (isInternal: true) to define internal projects that shouldn't appear in client-facing reports.

Project

The central entity. Projects organize work, track budgets, and determine billing.

In the API:

  • GET /projects — List projects
  • POST /projects — Create project
  • PATCH /projects/{id} — Update project

Three project types:

  1. Client projects (client is an external client) — Work for external clients can be billable or non-billable
  2. Internal projects (client is an internal client) — Internal work, no revenue
  3. Time off project (isTimeOff: true) — Special system project for vacation/leave

Key relationships:

  • Projects have one Client
  • Projects have many Positions
  • Projects optionally have many Budgets (especially for fixed-price projects)
  • Projects optionally have many Tasks

Person

An individual in your organization (employee or external contractor).

In the API:

  • GET /persons — List persons
  • POST /persons — Create person
  • PATCH /persons/{id} — Update person

Key relationships:

  • Persons have many Positions (assignments to projects)
  • Persons have many Competence Role Assignments (what roles they can play)
  • Persons have many Person Costs (cost rates for different date ranges)
  • Persons have many Time Entries (actual work done)

Position

This is the critical layer. A position represents an assignment on a project, optionally with a person and role.

Why positions exist:

  1. Open positions: Can exist without a person assigned (unfilled staffing needs)
  2. Same person, multiple roles: Maria can be both "Senior Developer" and "Tech Lead" on the same project (two positions)
  3. Organizational clarity: Clear assignment of who is working on what project in what capacity

In the API:

  • GET /positions — List positions
  • POST /positions — Create position
  • PATCH /positions/{id} — Update position

Key relationships:

  • Each Position has many Allocations (planned work)

Note: Time entries are not linked to positions. They are tracked directly on person + project.

Creating positions: Always create the position first, then create allocations on it. You cannot create allocations directly on a person+project.

Allocation

Planned work. An allocation says "this position is planned to work X% of their time from date A to date B."

In the API:

  • GET /allocations — List allocations
  • POST /allocations — Create allocation
  • PATCH /allocations/{id} — Update allocation

Percentage encoding:

  • 100% = 1,000,000
  • 50% = 500,000
  • 25% = 250,000

Confirmed vs Tentative:

  • Confirmed: Committed work, treated as certain in forecasts
  • Tentative: Planned but not locked in (e.g., for pipeline deals that might not close)

Overlapping allocations: The API allows creating allocations that sum to >100% for a person (intentional for overbooking scenarios). Validation is up to the client. Allocations for a single position cannot overlap.

Key relationships:

  • Each Allocation belongs to one Position

Time Entry

Actual work done. A time entry records "person X worked Y hours on project Z on date D."

In the API:

  • GET /time-entries — List time entries
  • POST /time-entries — Create time entry
  • POST /time-entries/bulk — Create multiple time entries
  • PATCH /time-entries/{id} — Update time entry
  • DELETE /time-entries/{id} — Delete time entry

Key relationships:

  • Each Time Entry belongs to one Person
  • Each Time Entry belongs to one Project
  • Each Time Entry optionally belongs to one Task

Budget

A monetary value assigned to a project or project phase. Particularly important for fixed-price projects.

In the API:

  • GET /budgets — List budgets
  • POST /budgets — Create budget
  • PATCH /budgets/{id} — Update budget

Key constraints:

  • Budgets for the same project cannot overlap in time
  • A project can have zero, one, or many budgets

Task

Optional granular work items within a project. Tasks allow tracking work at a more detailed level than just project-level.

In the API:

  • GET /tasks — List tasks
  • POST /tasks — Create task
  • PATCH /tasks/{id} — Update task

When to use: Tasks are optional. Use them when:

  • You need detailed tracking for invoicing
  • Project management requires task-level visibility
  • Reporting needs to break down work by deliverable

Time entry relationship: Time entries can optionally reference a task for granular tracking.