AccoilAccoil Developer Docs
Concepts

Group Hierarchy

Model multi-level account structures in Accoil using nested group calls with parent relationships. Supports Account, Workspace, and Project levels.

Many B2B products have account structures with more than one level. A company might contain multiple workspaces. A workspace might contain multiple projects. Accoil supports these multi-level structures through group hierarchy -- nested group calls that establish parent-child relationships between accounts.

When you need hierarchy

Use group hierarchy when your product has a structure like:

  • Company > Workspace > Project (project management tools)
  • Organization > Team (collaboration platforms)
  • Account > Site > Environment (infrastructure or developer tools)
  • Company > Department > Sub-team (enterprise products)

If your product has a flat account structure (one company = one account), you do not need hierarchy. A single group call is sufficient.

How it works

Each level in the hierarchy is a separate group entity with its own groupId. Parent-child relationships are established by including a parent reference in the traits of the child group.

  Company: Acme Corp            (groupId: "acme_123")
  ├── Workspace: Engineering    (groupId: "ws_eng_456",  parent: "acme_123")
  ├── Workspace: Marketing      (groupId: "ws_mkt_789",  parent: "acme_123")
  │   └── Project: Q1 Campaign  (groupId: "proj_q1_012", parent: "ws_mkt_789")
  └── Workspace: Sales          (groupId: "ws_sales_345", parent: "acme_123")

Setting up the hierarchy

Step 1: Create the top-level account

The top-level group has no parent. This is typically the company or organization.

{
  "groupId": "acme_123",
  "traits": {
    "name": "Acme Corp",
    "created_at": "2023-01-15T12:00:00Z",
    "status": "paid",
    "plan": "enterprise",
    "mrr": 250000
  },
  "timestamp": "2025-01-28T12:00:00Z"
}

Step 2: Create child groups with a parent trait

Each child group includes a parent_group_id trait that references its parent.

{
  "groupId": "ws_eng_456",
  "userId": "user_12345",
  "traits": {
    "name": "Engineering",
    "parent_group_id": "acme_123",
    "created_at": "2023-02-01T12:00:00Z"
  },
  "timestamp": "2025-01-28T12:00:00Z"
}
{
  "groupId": "ws_mkt_789",
  "userId": "user_67890",
  "traits": {
    "name": "Marketing",
    "parent_group_id": "acme_123",
    "created_at": "2023-03-10T12:00:00Z"
  },
  "timestamp": "2025-01-28T12:00:00Z"
}

Step 3: Add deeper levels

For a third level (e.g., projects within a workspace), the child references its immediate parent.

{
  "groupId": "proj_q1_012",
  "userId": "user_67890",
  "traits": {
    "name": "Q1 Campaign",
    "parent_group_id": "ws_mkt_789",
    "created_at": "2025-01-05T12:00:00Z"
  },
  "timestamp": "2025-01-28T12:00:00Z"
}

Full example: server-side setup

Here is a practical example of a function that sends group calls for a multi-level structure when a new workspace is created:

const API_BASE = "https://in.accoil.com";
const API_KEY = process.env.ACCOIL_API_KEY;

async function sendGroup(payload) {
  await fetch(`${API_BASE}/v2/group`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Basic ${API_KEY}`,
    },
    body: JSON.stringify(payload),
  });
}

// When a new workspace is created under an existing company
async function onWorkspaceCreated(company, workspace, createdByUser) {
  // Ensure the parent company group exists and is up to date
  await sendGroup({
    groupId: company.id,
    traits: {
      name: company.name,
      status: company.status,
      plan: company.plan,
      mrr: company.mrrCents,
      created_at: company.createdAt,
    },
    timestamp: new Date().toISOString(),
  });

  // Create the workspace as a child group
  await sendGroup({
    groupId: workspace.id,
    userId: createdByUser.id,
    traits: {
      name: workspace.name,
      parent_group_id: company.id,
      created_at: workspace.createdAt,
    },
    timestamp: new Date().toISOString(),
  });
}

User association in a hierarchy

When a user works within a child group (e.g., a workspace), associate them with that specific group by including userId in the group call. Accoil will attribute activity to both the child group and its parent through the hierarchy.

{
  "groupId": "ws_eng_456",
  "userId": "user_12345",
  "traits": {
    "name": "Engineering",
    "parent_group_id": "acme_123"
  },
  "timestamp": "2025-01-28T12:00:00Z"
}

Best practices

  1. Use stable IDs at every level. Each group in the hierarchy needs its own unique, immutable identifier.
  2. Always set parent_group_id. Without it, child groups appear as independent accounts with no relationship to their parent.
  3. Create parents before children. While not strictly required (Accoil processes asynchronously), sending the parent group call first ensures the hierarchy is established cleanly.
  4. Keep hierarchy shallow. Two or three levels is typical. Deep nesting adds complexity without proportional analytical value.
  5. Apply revenue traits at the right level. Typically, mrr and plan belong on the top-level account, not on individual workspaces or projects.

On this page