# Manage levels using the API

> For the complete documentation index, see [llms.txt](https://developer.rippling.com/llms.txt). Every page is available as Markdown by adding .md to its URL.

> Fetch and manage company levels using the Levels API.

Source: https://developer.rippling.com/documentation/rest-api/guides/levels

## Overview

Rippling’s Levels API lets you read and manage company-defined job levels. Levels represent seniority and role progression (for example, Senior Engineer or Engineering Manager).

*Key terms:*

- **Level**: A company-defined job level.
- **Track**: A career track that groups levels (e.g., Individual Contributor vs. Management).
- **Global level**: A number that represents seniority across the company. Higher values are more senior.
- **Rank**: The level’s order within its track.
- **Parent level**: Optional parent level.

### Available endpoints

| Endpoint | Description |
|----------|---------|
| [GET List levels](https://developer.rippling.com/documentation/rest-api/reference/list-levels.md) | Lists company levels. |
| [POST Create a new level](https://developer.rippling.com/documentation/rest-api/reference/create-levels.md) | Creates a new level. |
| [GET Retrieve a specific level](https://developer.rippling.com/documentation/rest-api/reference/get-levels.md) | Retrieves a specific level by `id`. |
| [PATCH Update a level](https://developer.rippling.com/documentation/rest-api/reference/update-levels.md) | Updates a level. |
| [DELETE Delete a level](https://developer.rippling.com/documentation/rest-api/reference/delete-levels.md) | Soft-deletes the level by `id`. |

Related endpoints:

| Endpoint | Description |
|----------|---------|
| [GET List tracks](https://developer.rippling.com/documentation/rest-api/reference/list-tracks.md) | List tracks. Use `id` as `track_id`. |
| [GET Retrieve a specific track](https://developer.rippling.com/documentation/rest-api/reference/get-tracks.md) | Retrieve a specific track by `id`. |

> **Rippling:**
> Levels that are not associated with a track are read-only and cannot be created, updated, or deleted through the API.

### Suggested workflow

1. [List tracks](https://developer.rippling.com/documentation/rest-api/reference/list-tracks.md) to get a valid `track_id`.
2. [List levels](https://developer.rippling.com/documentation/rest-api/reference/list-levels.md) to see existing names, `global_level` values, and which levels already belong to the track.
3. [Create a new level](https://developer.rippling.com/documentation/rest-api/reference/create-levels.md) with `name` and `track_id`.
4. [Retrieve a specific level](https://developer.rippling.com/documentation/rest-api/reference/get-levels.md) when you already have the `id`, and expand `parent` or `track` if you need nested objects.
5. [Update a level](https://developer.rippling.com/documentation/rest-api/reference/update-levels.md) to change display fields, seniority, or track.
6. [Delete a level](https://developer.rippling.com/documentation/rest-api/reference/delete-levels.md) only when no active worker references it. Delete soft-deletes the level and retains remaining levels in the track.

---

## Requirements

- The Rippling API SKU
- An API token with the following scopes:
  - `levels.read` to fetch levels
  - `levels.read-write` to list and manage levels
  - `tracks.read` to create new levels

---

## Fetch

### Levels

Use [GET List levels](https://developer.rippling.com/documentation/rest-api/reference/list-levels.md) to return a paginated list of company levels.

*Request:*

```json
curl -L -X GET 'https://rest.ripplingapis.com/levels/'
-H 'Accept: application/json'
-H 'Authorization: Bearer REDACTED'
```

*Response:*

```json
{
  "results": [
    {
      "id": "65699295fb7bc7c3510f4075",
      "created_at": "2023-12-01T08:00:21.551000+00:00",
      "updated_at": "2025-04-20T13:50:50.632000+00:00",
      "name": "Senior Engineer",
      "parent_id": "65699281fb7bc7c3510f44a6",
      "global_level": 4,
      "description": "Owns complex projects with limited guidance.",
      "scope_of_responsibilities": "Technical delivery for a product area",
      "experience_requirements": "Typically 5+ years",
      "rank": 3,
      "track_id": "674c17a3c3f93afc697160d2"
    }
  ],
  "next_link": null
}
```

| Response field | Description |
| ----- | ----------- |
| `id` | Unique identifier of the level. |
| `name` | Display name. Must be unique within the company. |
| `parent_id` | Parent level, if the company uses a level hierarchy. |
| `global_level` | Company-wide seniority. Higher is more senior. Used in workflows, policies, and reports. |
| `description` | Description of the level. |
| `scope_of_responsibilities` | Scope of responsibilities for the level. |
| `experience_requirements` | Experience expected at this level. |
| `rank` | Order of the level within its track. |
| `track_id` | Associated track. Empty or unset on legacy levels that are not track-backed. |

Include nested objects in the same response:

```json
curl -L -X GET 'https://rest.ripplingapis.com/levels/?expand=parent,track'
-H 'Accept: application/json'
-H 'Authorization: Bearer REDACTED'
```

Use [GET Retrieve a specific level](https://developer.rippling.com/documentation/rest-api/reference/get-levels.md) when you already have the level `id`.

*Request:*

```json
curl -L -X GET 'https://rest.ripplingapis.com/levels/65699295fb7bc7c3510f4075/'
-H 'Accept: application/json'
-H 'Authorization: Bearer REDACTED'
```

*Response:*

```json
{
  "id": "65699295fb7bc7c3510f4075",
  "created_at": "2023-12-01T08:00:21.551000+00:00",
  "updated_at": "2025-04-20T13:50:50.632000+00:00",
  "name": "Senior Engineer",
  "parent_id": "65699281fb7bc7c3510f44a6",
  "global_level": 4,
  "description": "Owns complex projects with limited guidance.",
  "scope_of_responsibilities": "Technical delivery for a product area",
  "experience_requirements": "Typically 5+ years",
  "rank": 3,
  "track_id": "674c17a3c3f93afc697160d2"
}
```

### Tracks

Use [GET List tracks](https://developer.rippling.com/documentation/rest-api/reference/list-tracks.md) to return a paginated list of company tracks.

*Request:*

```json
curl -L -X GET 'https://rest.ripplingapis.com/tracks/'
-H 'Accept: application/json'
-H 'Authorization: Bearer REDACTED'
```

*Response:*

```json
{
  "results": [
    {
      "id": "674c17a3c3f93afc697160d2",
      "created_at": "2023-12-01T08:00:21.551000+00:00",
      "updated_at": "2025-04-20T13:50:50.632000+00:00",
      "name": "Individual Contributor",
      "is_default": true,
      "order": 1,
      "start_global_level": 7
    },
    {
      "id": "674c17adc3f93afc697169d5",
      "created_at": "2023-12-01T08:00:21.551000+00:00",
      "updated_at": "2025-04-20T13:50:50.632000+00:00",
      "name": "Management",
      "is_default": false,
      "order": 2,
      "start_global_level": 9
    }
  ],
  "next_link": null
}
```

Use [GET Retrieve a specific track](https://developer.rippling.com/documentation/rest-api/reference/get-tracks.md) when you already have the track `id`.

*Request:*

```json
curl -L -X GET 'https://rest.ripplingapis.com/tracks/6569929bfb7bc7c3510f417b/'
-H 'Accept: application/json'
-H 'Authorization: Bearer REDACTED'
```

*Response:*

```json
{
  "id": "6569929bfb7bc7c3510f417b",
  "created_at": "2023-12-01T08:00:27.387000+00:00",
  "updated_at": "2023-12-01T08:00:27.387000+00:00",
  "name": "IC",
  "is_default": false,
  "order": 0,
  "start_global_level": 207
}
```

---

## Create

### Level

Use [POST Create a new level](https://developer.rippling.com/documentation/rest-api/reference/create-levels.md) to add a track-backed level.

*Request:*

```json
curl -L -X POST 'https://rest.ripplingapis.com/levels/'
-H 'Accept: application/json'
-H 'Content-Type: application/json'
-H 'Authorization: Bearer REDACTED'
```

*Request body:*

```json
{
  "name": "Staff Engineer",
  "track_id": "674c17a3c3f93afc697160d2",
  "global_level": 5,
  "description": "Sets technical direction across multiple teams.",
  "scope_of_responsibilities": "Architecture and mentoring across the org",
  "experience_requirements": "Typically 8+ years"
}
```

| Field | Required | Description |
| ----- | -------- | ----------- |
| `name` | Yes | Display name. Must be unique within the company. |
| `track_id` | Yes | Track from [GET List tracks](https://developer.rippling.com/documentation/rest-api/reference/list-tracks.md). |
| `global_level` | No | Seniority rank used by workflows, policies, and reports. |
| `description` | No | Description of the level. |
| `scope_of_responsibilities` | No | Scope of responsibilities. |
| `experience_requirements` | No | Experience expected at this level. |

*Response:*

```json
{
  "id": "66a43405af71f094991bf94f",
  "created_at": "2026-09-17T17:00:00.000000+00:00",
  "updated_at": "2026-09-17T17:00:00.000000+00:00",
  "name": "Staff Engineer",
  "parent_id": "65699295fb7bc7c3510f4075",
  "global_level": 5,
  "description": "Sets technical direction across multiple teams.",
  "scope_of_responsibilities": "Architecture and mentoring across the org",
  "experience_requirements": "Typically 8+ years",
  "rank": 4,
  "track_id": "674c17a3c3f93afc697160d2"
}
```

---

## Update

### Level

Use [PATCH Update a level](https://developer.rippling.com/documentation/rest-api/reference/update-levels.md) to change a track-backed level. All body fields are optional, and send only the fields you are changing.

> **Rippling:**
> If you change `track_id`, include `global_level` in the same request.

*Request:*

```json
curl -L -X PATCH 'https://rest.ripplingapis.com/levels/65699295fb7bc7c3510f4075/'
-H 'Accept: application/json'
-H 'Content-Type: application/json'
-H 'Authorization: Bearer REDACTED'
```

*Request body:*

```json
{
  "description": "Owns complex projects and mentors mid-level engineers.",
  "global_level": 4
}
```

| Request body field | Required | Description |
| --- | --- | --- |
| `name` | No | Display name. Must be unique within the company. |
| `global_level` | No | Seniority rank used by workflows, policies, and reports. Higher is more senior. Include this when you change `track_id`. |
| `description` | No | Description of the level. |
| `scope_of_responsibilities` | No | Scope of responsibilities. |
| `experience_requirements` | No | Experience expected at this level. |
| `track_id` | No | Track from [GET List tracks](https://developer.rippling.com/documentation/rest-api/reference/list-tracks.md). Include `global_level` in the same request when you change it. |

*Response:*

```json
{
  "id": "65699295fb7bc7c3510f4075",
  "created_at": "2023-12-01T08:00:21.551000+00:00",
  "updated_at": "2026-09-17T17:12:00.000000+00:00",
  "name": "Senior Engineer",
  "parent_id": "65699281fb7bc7c3510f44a6",
  "global_level": 4,
  "description": "Owns complex projects and mentors mid-level engineers.",
  "scope_of_responsibilities": "Technical delivery for a product area",
  "experience_requirements": "Typically 5+ years",
  "rank": 3,
  "track_id": "674c17a3c3f93afc697160d2"
}
```

---

## Delete

### Level

Use [DELETE Delete a level](https://developer.rippling.com/documentation/rest-api/reference/delete-levels.md) to remove an eligible track-backed level.

**Notes:**

- A level cannot be deleted while an active worker is assigned to it. Reassign or remove those workers first.
- Levels without a track cannot be deleted.

*Request:*

```json
curl -L -X DELETE 'https://rest.ripplingapis.com/levels/65699295fb7bc7c3510f4075/'
-H 'Accept: application/json'
-H 'Authorization: Bearer REDACTED'
```

A successful delete returns `200` and no body.

---

## FAQs

**What is the difference between a level and a title?**

A **level** is seniority or career stage (for example, L4 or Senior). A **title** is the job title (for example, Software Engineer). Workers can have both.

**What is the difference between `global_level` and `rank`?**

`global_level` is company-wide seniority, while `rank` is the level’s order **within its track**. You can send `global_level` on create and update.

**Why do I need a track to create a level?**

POST Create a new level is for track-backed levels, and a `track_id` is required. Levels with no track can be fetched but cannot be managed through the API.

**Can I set `parent_id` when I create a level?**

No. `parent_id` is returned when fetching and can be expanded as `parent`.

**What does "soft-delete" mean?**

When a level is deleted via the API, it isn't removed from the database. Instead, it is hidden from future API calls/response code and the level cannot be restored or reused.

**Why did my delete call fail?**

Typical causes can be that the level has no track or an active worker is still assigned that `level_id`. Reassign those workers, then retry the API call.

---

## See also

- [Get started with the Organizational Data API](https://developer.rippling.com/documentation/rest-api/guides/org-data-getting-started.md)
- [API tokens and permissions](https://developer.rippling.com/documentation/rest-api/essentials/api-tokens.md)
