> This page is for API, version 2026-01-01 (Stable) (default).
> For other versions, use one of these documentation indexes:
> - 2026-01-01 (Stable) (default): https://developer.deel.com/api/stable/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developer.deel.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developer.deel.com/_mcp/server.

# Retrieve average time per interview plan stage

GET https://api.letsdeel.com/rest/ats/insights/stage-durations

Returns the average time applications spent in each interview plan stage across the selected jobs, not counting time the job was paused. Use it to find where the hiring process slows down, with results that match the ATS insights dashboard for the same filters.

 **Token scopes**: `ats:read`, `worker:read`

 **Beta**: this version requires the `X-Beta: true` request header and its contract may change before it is promoted to stable. It is scheduled to become stable on 2027-01-28.

Reference: https://developer.deel.com/api/reference/endpoints/ats/retrieve-ats-insights-stage-durations-v-2026-10-28

## Authentication

- `Authorization` header (bearer token, required) — ## Authentication The Deel API uses bearer tokens to authenticate requests. All API calls must be made over HTTPS — calls over plain HTTP or without authentication will fail. ```curl curl -X GET 'https://api.letsdeel.com/rest/v2/contracts' \ -H 'Authorization: Bearer YOUR-TOKEN-HERE' ``` [Learn more about authentication](/api/authentication)
- `Authorization` header (bearer token, required) — Standard OAuth2 security scheme based on https://swagger.io/docs/specification/authentication/

## Servers

- `https://api.letsdeel.com/rest` (Production, default)
- `https://api-staging.letsdeel.com/rest` (Demo)

## Request

### Query parameters

- `job_ids` (list of string, optional) — Only count these jobs. Jobs the caller cannot access are left out silently.
- `hiring_member_hou_ids` (list of string, optional) — Only count jobs on whose hiring team one of these HRIS organization users sits — a person's portfolio. Only narrows the jobs the caller can already see.
- `interview_plan_ids` (list of string, optional) — Only count stages of these interview plans.
- `department_ids` (list of string, optional) — Only count jobs in these departments.
- `team_ids` (list of string, optional) — Only count jobs of these teams.
- `employment_type_ids` (list of string, optional) — Only count jobs with these employment types.
- `location_ids` (list of string, optional) — Only count jobs in these locations.
- `candidate_tag_ids` (list of string, optional) — Only count applications whose candidate carries these tags.
- `candidate_tag_ids_operator` (enum, optional) — ANY (default) matches candidates with at least one of candidate_tag_ids; ALL requires every tag.
  - Allowed values: `ANY`, `ALL`
- `source_slugs` (list of string, optional) — Only count applications from these sources (slugs from the application sources endpoint).
- `job_statuses` (list of enum, optional) — Only count jobs in these statuses. Defaults to every status except ARCHIVED.
  - Allowed values: `DRAFT`, `WAITING_FOR_APPROVAL`, `APPROVED`, `NOT_APPROVED`, `OPEN`, `PAUSED`, `CLOSED`, `ARCHIVED`
- `work_arrangements` (list of enum, optional) — Only count jobs with these work arrangements.
  - Allowed values: `ON_SITE`, `HYBRID`, `REMOTE`
- `date_range_start` (string, optional) — Lower bound (ISO 8601): stage counts only include applications created at or after it; stage durations only include stage entries that started at or after it.
- `date_range_end` (string, optional) — Upper bound (ISO 8601): stage counts only include applications created at or before it; stage durations only include stage entries that started at or before it.
- `workspace_ids` (list of string, optional) — Only count jobs in these workspaces. The caller must collaborate on every workspace passed.

### Headers

- `X-Beta` (enum, required, default: true) — Opts in to the beta version of this endpoint. Must be `true`.
  - Allowed values: `true`

## Response

### 200

Average time per stage

- `data` (list of AtsInsightsStageDurationsGetResponsesContentApplicationJsonSchemaDataItems, required) — Average time applications spent in each interview plan stage.
- `has_more` (boolean, required) — Always false: the result is a single aggregate page.
- `next_cursor` (string, required, nullable) — Always null: the result is a single aggregate page.
- `total_count` (integer, required) — Number of rows in data.

## Errors

### 400 Bad Request Error

Operation failed.

- `errors` (list of AtsInsightsStageDurationsGetResponsesContentApplicationJsonSchemaErrorsItems, required) — List of error objects

### 401 Unauthorized Error

Operation failed.

- `request` (ApiErrorRequest, optional)
- `errors` (list of ApiError, optional)

### 403 Forbidden Error

Forbidden. ATS is not enabled for this organization or insufficient permissions.

- `errors` (list of AtsInsightsStageDurationsGetResponsesContentApplicationJsonSchemaErrorsItems, required) — List of error objects

### 404 Not Found Error

Operation failed.

- `request` (ApiErrorRequest, optional)
- `errors` (list of ApiError, optional)

### 500 Internal Server Error

Operation failed.

- `errors` (list of AtsInsightsStageDurationsGetResponsesContentApplicationJsonSchemaErrorsItems, required) — List of error objects

## Types

### AtsInsightsStageDurationsGetResponsesContentApplicationJsonSchemaDataItems

- `average_seconds` (double, required) — Average seconds an application spent in the stage before leaving it, excluding time the job was paused
- `interview_plan_stage_name` (string, required) — Customer-defined stage name. Stages with the same name in different interview plans are reported once.

### AtsInsightsStageDurationsGetResponsesContentApplicationJsonSchemaErrorsItems

- `code` (string, required) — Machine-readable error code
- `message` (string, required) — Human-readable error message
- `field` (string, optional) — Request field related to the error, if applicable

### ApiErrorRequest

- `method` (string, optional) — The HTTP method of the failed request
- `url` (string, optional) — The relative URL of the failed request
- `status` (double, optional) — The status code of the response
- `api_req_id` (string, optional) — The request ID of the failed request
- `docs` (string, optional) — A link to the official documentation for the requested endpoint resource
- `source` (string, optional) — The source handler which produced the returned error
- `code` (double, optional) — The code of the source handler which produced the returned error

### ApiError

- `message` (string, optional) — A description of the returned error
- `path` (string, optional) — The JSON path where input validation failed

## Examples

**Response**

```json
{
  "data": [
    {
      "average_seconds": 345600,
      "interview_plan_stage_name": "Technical Interview"
    }
  ],
  "has_more": false,
  "next_cursor": "string",
  "total_count": 6
}
```

**SDK Code**

```python
import requests

url = "https://api.letsdeel.com/rest/ats/insights/stage-durations"

querystring = {"candidate_tag_ids":"[\"f47ac10b-58cc-4372-a567-0e02b2c3d479\"]","candidate_tag_ids_operator":"ANY","date_range_end":"2026-03-31T23:59:59.000Z","date_range_start":"2026-01-01T00:00:00.000Z","department_ids":"[\"f47ac10b-58cc-4372-a567-0e02b2c3d479\"]","employment_type_ids":"[\"f47ac10b-58cc-4372-a567-0e02b2c3d479\"]","hiring_member_hou_ids":"[\"f47ac10b-58cc-4372-a567-0e02b2c3d479\"]","interview_plan_ids":"[\"f47ac10b-58cc-4372-a567-0e02b2c3d479\"]","job_ids":"[\"f47ac10b-58cc-4372-a567-0e02b2c3d479\"]","job_statuses":"[\"OPEN\"]","location_ids":"[\"f47ac10b-58cc-4372-a567-0e02b2c3d479\"]","source_slugs":"[\"linkedin\"]","team_ids":"[\"f47ac10b-58cc-4372-a567-0e02b2c3d479\"]","work_arrangements":"[\"REMOTE\"]","workspace_ids":"[\"f47ac10b-58cc-4372-a567-0e02b2c3d479\"]"}

headers = {
    "X-Beta": "true",
    "Authorization": "Bearer <token>"
}

response = requests.get(url, headers=headers, params=querystring)

print(response.json())
```

```javascript
const url = 'https://api.letsdeel.com/rest/ats/insights/stage-durations?candidate_tag_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&candidate_tag_ids_operator=ANY&date_range_end=2026-03-31T23%3A59%3A59.000Z&date_range_start=2026-01-01T00%3A00%3A00.000Z&department_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&employment_type_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&hiring_member_hou_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&interview_plan_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&job_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&job_statuses=%5B%22OPEN%22%5D&location_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&source_slugs=%5B%22linkedin%22%5D&team_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&work_arrangements=%5B%22REMOTE%22%5D&workspace_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D';
const options = {method: 'GET', headers: {'X-Beta': 'true', Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.letsdeel.com/rest/ats/insights/stage-durations?candidate_tag_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&candidate_tag_ids_operator=ANY&date_range_end=2026-03-31T23%3A59%3A59.000Z&date_range_start=2026-01-01T00%3A00%3A00.000Z&department_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&employment_type_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&hiring_member_hou_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&interview_plan_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&job_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&job_statuses=%5B%22OPEN%22%5D&location_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&source_slugs=%5B%22linkedin%22%5D&team_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&work_arrangements=%5B%22REMOTE%22%5D&workspace_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("X-Beta", "true")
	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.letsdeel.com/rest/ats/insights/stage-durations?candidate_tag_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&candidate_tag_ids_operator=ANY&date_range_end=2026-03-31T23%3A59%3A59.000Z&date_range_start=2026-01-01T00%3A00%3A00.000Z&department_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&employment_type_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&hiring_member_hou_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&interview_plan_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&job_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&job_statuses=%5B%22OPEN%22%5D&location_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&source_slugs=%5B%22linkedin%22%5D&team_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&work_arrangements=%5B%22REMOTE%22%5D&workspace_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["X-Beta"] = 'true'
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://api.letsdeel.com/rest/ats/insights/stage-durations?candidate_tag_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&candidate_tag_ids_operator=ANY&date_range_end=2026-03-31T23%3A59%3A59.000Z&date_range_start=2026-01-01T00%3A00%3A00.000Z&department_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&employment_type_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&hiring_member_hou_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&interview_plan_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&job_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&job_statuses=%5B%22OPEN%22%5D&location_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&source_slugs=%5B%22linkedin%22%5D&team_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&work_arrangements=%5B%22REMOTE%22%5D&workspace_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D")
  .header("X-Beta", "true")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.letsdeel.com/rest/ats/insights/stage-durations?candidate_tag_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&candidate_tag_ids_operator=ANY&date_range_end=2026-03-31T23%3A59%3A59.000Z&date_range_start=2026-01-01T00%3A00%3A00.000Z&department_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&employment_type_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&hiring_member_hou_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&interview_plan_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&job_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&job_statuses=%5B%22OPEN%22%5D&location_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&source_slugs=%5B%22linkedin%22%5D&team_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&work_arrangements=%5B%22REMOTE%22%5D&workspace_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'X-Beta' => 'true',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.letsdeel.com/rest/ats/insights/stage-durations?candidate_tag_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&candidate_tag_ids_operator=ANY&date_range_end=2026-03-31T23%3A59%3A59.000Z&date_range_start=2026-01-01T00%3A00%3A00.000Z&department_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&employment_type_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&hiring_member_hou_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&interview_plan_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&job_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&job_statuses=%5B%22OPEN%22%5D&location_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&source_slugs=%5B%22linkedin%22%5D&team_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&work_arrangements=%5B%22REMOTE%22%5D&workspace_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D");
var request = new RestRequest(Method.GET);
request.AddHeader("X-Beta", "true");
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "X-Beta": "true",
  "Authorization": "Bearer <token>"
]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.letsdeel.com/rest/ats/insights/stage-durations?candidate_tag_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&candidate_tag_ids_operator=ANY&date_range_end=2026-03-31T23%3A59%3A59.000Z&date_range_start=2026-01-01T00%3A00%3A00.000Z&department_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&employment_type_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&hiring_member_hou_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&interview_plan_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&job_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&job_statuses=%5B%22OPEN%22%5D&location_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&source_slugs=%5B%22linkedin%22%5D&team_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D&work_arrangements=%5B%22REMOTE%22%5D&workspace_ids=%5B%22f47ac10b-58cc-4372-a567-0e02b2c3d479%22%5D")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```