Back to top

Toggl Hire

Toggl Hire API lets you export candidate data for custom integrations or analytics.

Versioning

Breaking changes in the API are released as new minor versions of the API. The API version is specified in the URL, for example https://api.hire.toggl.com/api/v2.1. The latest version of the API is always available as v2. We recommend using an exact version of the API.

To view the documentation for a specific API version use on of the links below.

  • Latest

  • v2.2

  • v2.1 - Deprecated; no longer available.

  • v2.0 - Deprecated; no longer available.

Authentication

All endpoints require an API key to be supplied in the request. API keys for each workspace in Toggl Hire can be generated on the integration settings page.

Once you have the API key, set the Authorization header to the value Bearer [your-api-key], for example:

Authorization: Bearer 11ZU1ZOJ0PDOQPVEZ12PPZTPRR933L6VE25LM0R0BEP7961KY3JVDE8VJZY2U28

Errors

If a request fails, the API will return a 4xx or 5xx response with error details in the response body. Currently only the error.type field is provided, which contains the type of the error that occurred. The type should not be shown to the user, but it is human-readable.

{
    "error": {
        "type": "NotFoundError"
    }
}

Pagination

Some endpoints do not return all records, but only a limited amount. This amount is specified using the limit parameter, which has a certain maximum value. To fetch more records than the maximum value, use the URL in the links.next attribute in the response.

Toggl Hire API uses seek pagination, where each page is identified by the ID of the record from the previous page. For example, if an endpoint returns 3 records with IDs 100, 101 and 102 for the URL /example-endpoint?limit=3, you can get the next 3 endpoints using the ID of the last record: /example-endpoint?limit=3&after_id=102.

Job openings

Job openings collection

List all job openings
GET/openings

Example URI

GET https://api.hire.toggl.com/api/v2/openings
Request
HideShow
Headers
Authorization: Bearer xyz
Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "data": [
    {
      "id": "100",
      "name": "Senior JavaScript Developer",
      "slug": "JFHSAK2879FLKJE",
      "created_at": "2020-02-10T10:00:00",
      "published_at": "2020-02-10T10:00:00",
      "closed_at": "2020-02-10T10:00:00"
    }
  ]
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the job opening"
          },
          "name": {
            "type": "string",
            "description": "Name of the job opening"
          },
          "slug": {
            "type": "string",
            "description": "Public unique identifier for the job opening\n\nThe job opening link can be constructed by appending the slug to `https://apply.hire.toggl.com/`, for example `https://apply.hire.toggl.com/KLJFD9283FLKDJ`."
          },
          "created_at": {
            "type": "string",
            "description": "Date and time when the job opening was created"
          },
          "published_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "Date and time when the job opening was published\n\nThis is usually the same as when the job opening was created, except for some older job openings."
          },
          "closed_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "Date and time when the job opening was closed\n\nIf this value is not `null` the job opening is closed and candidates cannot take the test anymore"
          }
        }
      }
    }
  }
}

Job opening

Get a single job opening
GET/openings/{id}

Example URI

GET https://api.hire.toggl.com/api/v2/openings/100
URI Parameters
HideShow
id
string (required) Example: 100

ID of the requested job opening

Request
HideShow
Headers
Authorization: Bearer xyz
Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "id": "100",
  "name": "Senior JavaScript Developer",
  "slug": "JFHSAK2879FLKJE",
  "created_at": "2020-02-10T10:00:00",
  "published_at": "2020-02-10T10:00:00",
  "closed_at": "2020-02-10T10:00:00"
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "Unique identifier for the job opening"
    },
    "name": {
      "type": "string",
      "description": "Name of the job opening"
    },
    "slug": {
      "type": "string",
      "description": "Public unique identifier for the job opening\n\nThe job opening link can be constructed by appending the slug to `https://apply.hire.toggl.com/`, for example `https://apply.hire.toggl.com/KLJFD9283FLKDJ`."
    },
    "created_at": {
      "type": "string",
      "description": "Date and time when the job opening was created"
    },
    "published_at": {
      "type": [
        "string",
        "null"
      ],
      "description": "Date and time when the job opening was published\n\nThis is usually the same as when the job opening was created, except for some older job openings."
    },
    "closed_at": {
      "type": [
        "string",
        "null"
      ],
      "description": "Date and time when the job opening was closed\n\nIf this value is not `null` the job opening is closed and candidates cannot take the test anymore"
    }
  }
}

Candidates

Candidates collection

Note that the candidates collection will return only candidates who have submitted the test and it will not return any demo candidates.

The parameters are combined using the AND operator, meaning that the candidate must match every parameter to be included in the result.

List candidates
GET/candidates{?job_opening_id,category_id,tag_ids,hire_state,min_score,max_score,min_rating,max_rating,email,after_id,limit,order}

Example URI

GET https://api.hire.toggl.com/api/v2/candidates?job_opening_id=100&category_id=200&tag_ids=300,301,302&hire_state=possible-hire&min_score=40&max_score=70&min_rating=1&max_rating=3&email=john@example.com&after_id=200&limit=30&order=asc
URI Parameters
HideShow
job_opening_id
string (optional) Example: 100

Returns candidates from the specified job opening

category_id
string (optional) Example: 200

Returns candidates from the specified category

tag_ids
string (optional) Example: 300,301,302

Returns candidates that have all of the specified tags

To specify multiple tags, separate the IDs with a comma, for example: 100,200,300

hire_state
string (optional) Example: possible-hire

Returns candidates with the specified hire state

Choices: possible-hire rejected

min_score
number (optional) Example: 40

Returns candidates with at least the specified score

max_score
number (optional) Example: 70

Returns candidates with at most the specified score

min_rating
number (optional) Example: 1

Returns candidates with at least the specified rating

Rating corresponds to the stars in the application, so 1 star = rating value 1, 3 stars = rating value 3.

max_rating
number (optional) Example: 3

Returns candidates with at most the specified rating

email
string (optional) Example: john@example.com

Returns candidates with the specified email address

after_id
string (optional) Example: 200

Used for pagination; returns candidates after the candidate with the specified ID

limit
number (optional) Default: 100 Example: 30

Returns only at most the specified number of candidates

order
string (optional) Default: asc Example: asc

Sorts the candidates based on the started_at attribute in ascending or descending order

Choices: asc desc

Request
HideShow
Headers
Authorization: Bearer xyz
Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "data": [
    {
      "id": "100",
      "name": "Cord Briemer",
      "email": "rosario84@real.com",
      "profile_url": "https://github.com/debitis",
      "contact_info": {
        "full_name": "Cord Briemer",
        "contact_email": "acarmona@duran-gomez.info",
        "linkedin": "https://linkedin.com/in/debitis",
        "phone": "+49(0)9859 103312",
        "city": "Lake Justinville",
        "country": "Gibraltar"
      },
      "points": 12,
      "score": 85.714286,
      "rating": 0,
      "hire_state": "possible-hire",
      "category_id": "100",
      "job_opening_id": "100",
      "utm_source": "facebook",
      "utm_medium": "social_media",
      "utm_campaign": "our_facebook_ad",
      "referrer_url": "http://facebook.com",
      "ip_address": "192.168.0.1",
      "tests": [
        {
          "type": "quiz",
          "started_at": "2019-03-10T02:39:32.59275",
          "finished_at": "2019-03-10T02:53:29.05823",
          "points": 12,
          "score": 85.714286
        }
      ]
    }
  ],
  "links": {
    "next": "Hello, world!"
  },
  "total": 1
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the candidate"
          },
          "name": {
            "type": "string",
            "description": "Name of the candidate retrieved from their third party login provider\n\nNote that this can be an empty string, for example if the candidate has no name set in their GitHub profile."
          },
          "email": {
            "type": "string",
            "description": "Email of the candidate retrieved from their third party login provider"
          },
          "profile_url": {
            "type": "string",
            "description": "Profile URL retrieved from the candidate's third party login provider\n\nNote that the profile URL is available only if the candidate uses GitHub to log in."
          },
          "contact_info": {
            "type": "object",
            "properties": {
              "full_name": {
                "type": "string",
                "description": "Candidate's full name"
              },
              "contact_email": {
                "type": "string",
                "description": "Candidate's preferred contact email address"
              },
              "linkedin": {
                "type": "string",
                "description": "Candidate's LinkedIn profile URL"
              },
              "phone": {
                "type": "string",
                "description": "Candidate's phone number"
              },
              "city": {
                "type": "string",
                "description": "Candidate's city"
              },
              "country": {
                "type": "string",
                "description": "Candidate's country"
              }
            },
            "description": "Contact info submitted by the candidate after they have finished the test"
          },
          "points": {
            "type": "number",
            "description": "Total number of points that the candidate scored for all answers on their first test"
          },
          "score": {
            "type": "number",
            "description": "Percentage score calculated as `(actual points) / (maximum points)` on candidate's first test"
          },
          "rating": {
            "type": "number",
            "enum": [
              0,
              1,
              2,
              3
            ],
            "description": "Candidate's star rating"
          },
          "hire_state": {
            "type": "string",
            "enum": [
              "possible-hire",
              "rejected",
              "(empty string)"
            ],
            "description": "Candidate's hire state"
          },
          "category_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "ID of the candidate's category"
          },
          "job_opening_id": {
            "type": "string",
            "description": "ID of the candidate's job opening"
          },
          "utm_source": {
            "type": "string",
            "description": "The utm_source query param the candidate visited the test with"
          },
          "utm_medium": {
            "type": "string",
            "description": "The utm_medium query param the candidate visited the test with"
          },
          "utm_campaign": {
            "type": "string",
            "description": "The utm_campaign query param the candidate visited the test with"
          },
          "referrer_url": {
            "type": "string",
            "description": "The referer the candidate navigated to the test from"
          },
          "ip_address": {
            "type": "string",
            "description": "Candidate's IP address"
          },
          "tests": {
            "type": "array",
            "description": "Tests the candidate partticipated in"
          }
        }
      }
    },
    "links": {
      "type": "object",
      "properties": {
        "next": {
          "type": "string",
          "description": "URL that can be used to fetch the next page"
        }
      }
    },
    "total": {
      "type": "number",
      "description": "Total number of candidates matching the parameters"
    }
  }
}

Candidate

Fetch a candidate
GET/candidates/{id}

Example URI

GET https://api.hire.toggl.com/api/v2/candidates/id
URI Parameters
HideShow
id
string (required) 

ID of the requested candidate

Request
HideShow
Headers
Authorization: Bearer xyz
Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "id": "100",
  "name": "Cord Briemer",
  "email": "rosario84@real.com",
  "profile_url": "https://github.com/debitis",
  "contact_info": {
    "full_name": "Cord Briemer",
    "contact_email": "acarmona@duran-gomez.info",
    "linkedin": "https://linkedin.com/in/debitis",
    "phone": "+49(0)9859 103312",
    "city": "Lake Justinville",
    "country": "Gibraltar"
  },
  "points": 3,
  "score": 100,
  "rating": 1,
  "hire_state": "possible-hire",
  "category_id": "100",
  "job_opening_id": "100",
  "tag_ids": [
    "100",
    "200",
    "300"
  ],
  "utm_source": "facebook",
  "utm_medium": "social_media",
  "utm_campaign": "our_facebook_ad",
  "referrer_url": "http://facebook.com",
  "ip_address": "192.168.0.1",
  "tests": [
    {
      "type": "quiz",
      "started_at": "2019-03-10T02:39:32.59275",
      "finished_at": "2019-03-10T02:53:29.05823",
      "points": 1,
      "score": 100,
      "questions": [
        {
          "id": "400",
          "question_type": "single-choice",
          "content": "Which one describes **you** better?",
          "points": 3,
          "options": [
            {
              "id": "500",
              "content": "Done is better than perfect",
              "correct": true
            },
            {
              "id": "501",
              "content": "I'm a perfectionist in everything I do",
              "correct": false
            }
          ]
        },
        {
          "id": "401",
          "question_type": "free-text",
          "content": "What is your professional experience?",
          "points": 0,
          "options": []
        }
      ],
      "answers": [
        {
          "question_id": "400",
          "text_answer": "",
          "points": 3,
          "chosen_option_ids": [
            "500"
          ]
        },
        {
          "question_id": "401",
          "text_answer": "I am the best in the world at everything I do.",
          "points": 0,
          "chosen_option_ids": []
        }
      ],
      "skills": [
        {
          "skill": "Golang",
          "score": 75.5
        }
      ]
    },
    {
      "type": "video",
      "started_at": "2019-03-10T03:39:32.59275",
      "finished_at": "2019-03-10T03:53:29.05823",
      "points": 0,
      "questions": [
        {
          "id": "702",
          "skill": null,
          "content": "What was the best thing that happened to you this week?",
          "points": 1,
          "options": []
        }
      ],
      "answers": [
        {
          "question_id": "702",
          "text_answer": "",
          "recording_url": "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
          "points": null,
          "chosen_option_ids": []
        }
      ],
      "skills": []
    }
  ]
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "Unique identifier for the candidate"
    },
    "name": {
      "type": "string",
      "description": "Name of the candidate retrieved from their third party login provider\n\nNote that this can be an empty string, for example if the candidate has no name set in their GitHub profile."
    },
    "email": {
      "type": "string",
      "description": "Email of the candidate retrieved from their third party login provider"
    },
    "profile_url": {
      "type": "string",
      "description": "Profile URL retrieved from the candidate's third party login provider\n\nNote that the profile URL is available only if the candidate uses GitHub to log in."
    },
    "contact_info": {
      "type": "object",
      "properties": {
        "full_name": {
          "type": "string",
          "description": "Candidate's full name"
        },
        "contact_email": {
          "type": "string",
          "description": "Candidate's preferred contact email address"
        },
        "linkedin": {
          "type": "string",
          "description": "Candidate's LinkedIn profile URL"
        },
        "phone": {
          "type": "string",
          "description": "Candidate's phone number"
        },
        "city": {
          "type": "string",
          "description": "Candidate's city"
        },
        "country": {
          "type": "string",
          "description": "Candidate's country"
        }
      },
      "description": "Contact info submitted by the candidate after they have finished the test"
    },
    "points": {
      "type": "number",
      "description": "Total number of points that the candidate scored for all answers on their first test"
    },
    "score": {
      "type": "number",
      "description": "Percentage score calculated as `(actual points) / (maximum points)` on candidate's first test"
    },
    "rating": {
      "type": "number",
      "enum": [
        0,
        1,
        2,
        3
      ],
      "description": "Candidate's star rating"
    },
    "hire_state": {
      "type": "string",
      "enum": [
        "possible-hire",
        "rejected",
        "(empty string)"
      ],
      "description": "Candidate's hire state"
    },
    "category_id": {
      "type": [
        "string",
        "null"
      ],
      "description": "ID of the candidate's category"
    },
    "job_opening_id": {
      "type": "string",
      "description": "ID of the candidate's job opening"
    },
    "utm_source": {
      "type": "string",
      "description": "The utm_source query param the candidate visited the test with"
    },
    "utm_medium": {
      "type": "string",
      "description": "The utm_medium query param the candidate visited the test with"
    },
    "utm_campaign": {
      "type": "string",
      "description": "The utm_campaign query param the candidate visited the test with"
    },
    "referrer_url": {
      "type": "string",
      "description": "The referer the candidate navigated to the test from"
    },
    "ip_address": {
      "type": "string",
      "description": "Candidate's IP address"
    },
    "tests": {
      "type": "array",
      "description": "Tests the candidate partticipated in"
    },
    "tag_ids": {
      "type": "array",
      "description": "IDs of tags assigned to the candidate"
    }
  }
}

Categories

Categories collection

List all categories
GET/categories{?job_opening_id}

Example URI

GET https://api.hire.toggl.com/api/v2/categories?job_opening_id=
URI Parameters
HideShow
job_opening_id
string (optional) 

Returns only categories from the specified job opening

Request
HideShow
Headers
Authorization: Bearer xyz
Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "data": [
    {
      "id": "100",
      "name": "Interview",
      "job_opening_id": "200"
    }
  ]
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the category"
          },
          "name": {
            "type": "string",
            "description": "Name of the category"
          },
          "job_opening_id": {
            "type": "string",
            "description": "ID of the job opening the category belongs to"
          }
        }
      }
    }
  }
}

Tags

Tags collection

List all tags
GET/tags

Example URI

GET https://api.hire.toggl.com/api/v2/tags
Request
HideShow
Headers
Authorization: Bearer xyz
Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "data": [
    {
      "id": "100",
      "name": "optimistic"
    }
  ]
}
Schema
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "data": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the tag"
          },
          "name": {
            "type": "string",
            "description": "Name of the tag"
          }
        }
      }
    }
  }
}

Webhooks

Webhook settings can be found on the integrations tab under workspace settings.

Overview

Webhooks serve as alerts to ensure synchronization between your systems and Toggl Hire with actions performed within Toggl Hire. However, it is important to note that webhooks themselves should not be considered actionable items.

Toggl Hire has the capability to send webhooks to any publicly accessible server. Whenever an event in Toggl Hire triggers a webhook (such as a candidate submitting their answers), Toggl Hire will make an attempt to deliver this notification to the specified endpoint(s) you have provided.

For Toggl Hire to confirm successful delivery of a notification, it must receive a timely response with a valid status code. In other words:

  • Your endpoint should be reachable through ports 80 (HTTP) or 443 (HTTPS) since Toggl Hire does not support other ports.

  • Your endpoint should respond within 5 seconds.

  • Your endpoint should respond with a 2XX status code (e.g., 200, 201, 204, etc.). Toggl Hire does not follow redirects or consider them as successful responses.

Automatic retries

In the event that Toggl Hire encounters an error response when sending a webhook to your specified URL, the system will automatically attempt to retry the delivery. After ten consecutive failed attempts, Toggl Hire will cease further delivery attempts for that particular notification.

Notifications are sent in the order they were created, and the interval between retries follows an approximate formula of 10 + x^4 seconds, where x represents the current number of failed attempts. As a result, the intervals between the initial retries will be relatively short, but will progressively increase exponentially as the number of retries rises.

Payload

The webhooks provide light weight payloads containing information about the type of event (e.g. updated, created, etc.), context regarding the object (e.g. candidate) and object identifiers that can be used to obtain the most up to date information via Toggl Hire API.

{
  "id": "2000",
  "object_type": "candidate",
  "event_type": "test.finished",
  "event_time": "2023-07-17T12:41:02.032859-06:00",
  "workspace_id": "100"
}

Candidate notifications

Test finished

Sent when a candidate submits their answers.

{
  "id": "2000",
  "object_type": "candidate",
  "event_type": "test.finished",
  "event_time": "2023-07-17T12:41:02.032859-06:00",
  "workspace_id": "100"
}

Coming soon

Additional notifications are coming soon. Help us make our webhooks better, contact customer support for requesting additional notification type.

Generated by aglio on 28 Nov 2024