NAV
API Version:   V2 V1

DevSkiller API Overview

The DevSkiller REST API lets you interact with DevSkiller platform. You can use the API especially for:

API Endpoint

All API URLs are relative to https://api.devskiller.com/. For example, to get list of candidates you should call /candidates endpoint at https://api.devskiller.com/candidates

API Key

Each request must contain an API Key passed as HTTP header: X-Api-Key. To get your personal API key, please navigate to the Settings -> Integrations menu in the DevSkiller administration panel, and acquire your key in the API Access section.

More details about acquiring the API Key can be found in our help https://help.devskiller.com/space/TSG/2897543172/How+to+integrate+with+an+ATS

Rate Limits

Our API enforces rate limiting to ensure fair usage and stability of the service. The current rate limit configuration allows a maximum of 36 requests per 8-second period.

This means that if you make requests continuously, you are allowed to make a request approximately every 0.222 seconds. However, if you were to make 36 requests all at once, you would then need to wait 8 seconds before making the next request.

In case you exceed these limits, our API will return a 429 Too Many Requests HTTP status code.

Please design your application to adhere to these rate limits for optimal performance and to avoid service disruptions.

Candidate operations

The Candidates resources is used to create and list candidates

Listing candidates

Request

GET /candidates?query=John&count=10&page=1&status=TOKEN_SENT&tags=Tag1&tags=Tag2 HTTP/1.1
X-Api-Key: TEST-API-KEY
Accept: application/json
Host: api.devskiller.com

$ curl 'https://api.devskiller.com/candidates?query=John&count=10&page=1&status=TOKEN_SENT&tags=Tag1&tags=Tag2' -i -X GET \
    -H 'X-Api-Key: TEST-API-KEY' \
    -H 'Accept: application/json'

Response

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 642

{
  "items" : [ {
    "id" : "CANDIDATE-UUID-1234",
    "firstName" : "John",
    "lastName" : "Smith",
    "email" : "test@email.com",
    "examId" : "UUID-FOR-123",
    "status" : "TOKEN_SENT",
    "scoredPoints" : null,
    "maxPoints" : 65,
    "examUrl" : "http://exam.url/exam.html?TEST-TOKEN",
    "tags" : [ "Tag1", "Tag2" ],
    "externalId" : "EXTERNAL-1234",
    "creationDate" : "2023-05-14T14:40:39.00191Z",
    "testTimedOut" : false,
    "testStartDate" : "2023-05-15T14:40:39.00191Z",
    "testFinishDate" : "2023-05-15T15:24:39.00191Z"
  } ],
  "totalElements" : 1,
  "totalPages" : 1,
  "pageSize" : 10,
  "pageNumber" : 1
}
{
  "items" : [ {
    "id" : "CANDIDATE-UUID-1234",
    "firstName" : "John",
    "lastName" : "Smith",
    "email" : "test@email.com",
    "examId" : "UUID-FOR-123",
    "status" : "TOKEN_SENT",
    "scoredPoints" : null,
    "maxPoints" : 65,
    "examUrl" : "http://exam.url/exam.html?TEST-TOKEN",
    "tags" : [ "Tag1", "Tag2" ],
    "externalId" : "EXTERNAL-1234",
    "creationDate" : "2023-05-14T14:40:39.00191Z",
    "testTimedOut" : false,
    "testStartDate" : "2023-05-15T14:40:39.00191Z",
    "testFinishDate" : "2023-05-15T15:24:39.00191Z"
  } ],
  "totalElements" : 1,
  "totalPages" : 1,
  "pageSize" : 10,
  "pageNumber" : 1
}

GET /candidates

A GET request will list all candidates.

Request parameters:

query
Optional
Search by name,email or token
status
Optional
Filter candidates by status. Add multiple status parameters to search for several statuses.
tags
Optional
Filter candidates by tags. Add multiple tags parameters to search for several tags.
count
Optional
Maximum number of candidates to get. Default: 10, Max: 100
page
Optional
Number of the page to fetch, starting with 1. Default: 1

Response structure:

pageNumber
Type: Number Content: Standard
Number of the current page
pageSize
Type: Number Content: Standard
Maximum number of elements for a page
totalElements
Type: Number Content: Standard
Total number of candidates matching criteria
totalPages
Type: Number Content: Standard
Total number of pages matching criteria
items
Type: Array Content: Standard
An array with candidates
items[].id
Type: String Content: Standard
The candidate’s id
items[].externalId
Type: String Content: Standard
The candidate’s external id
items[].firstName
Type: String Content: Standard
The candidate’s first name
items[].lastName
Type: String Content: Standard
The candidate’s last name
items[].email
Type: String Content: Standard
The candidate’s email address
items[].examId
Type: String Content: Standard
The exam’s id that the candidate has been asked to solve
items[].status
Type: String Content: Standard
The candidate’s status. Possible values: TOKEN_SENT, TOKEN_EXPIRED, TEST_STARTED, TEST_FINISHED, AUTO_ASSESSMENT_READY, IN_ASSESSMENT, ASSESSMENT_READY, ACCEPTED, REJECTED
items[].scoredPoints
Type: Null Content: Standard
The candidate’s score. Null if candidate has not been assessed yet
items[].maxPoints
Type: Number Content: Standard
The maximum number of points, that candidate might get from assigned exam
items[].examUrl
Type: String Content: Standard
The url to the test for candidate
items[].tags
Type: Array Content: Standard
The candidate’s tags (array of strings)
items[].creationDate
Type: String Content: Standard
Creation date (ISO_8601)
items[].testTimedOut
Type: Boolean Content: Standard
Did the test time-out (true/false)
items[].testStartDate
Type: String Content: Standard
Test start date (ISO_8601)
items[].testFinishDate
Type: String Content: Standard
Test finish date (ISO_8601)

Creating a candidate

Request

POST /candidates HTTP/1.1
Content-Type: application/json
X-Api-Key: TEST-API-KEY
Accept: application/json
Content-Length: 236
Host: api.devskiller.com

{
    "communicationDisabled": false,
    "firstName": "John",
    "lastName": "Smith",
    "examId": "UUID-FOR-123",
    "tags": [
        "Tag1",
        "Tag2"
    ],
    "email": "test@email.com",
    "externalId": "EXTERNAL-1234"
}
$ curl 'https://api.devskiller.com/candidates' -i -X POST \
    -H 'Content-Type: application/json' \
    -H 'X-Api-Key: TEST-API-KEY' \
    -H 'Accept: application/json' \
    -d '{
    "communicationDisabled": false,
    "firstName": "John",
    "lastName": "Smith",
    "examId": "UUID-FOR-123",
    "tags": [
        "Tag1",
        "Tag2"
    ],
    "email": "test@email.com",
    "externalId": "EXTERNAL-1234"
}'

Response

HTTP/1.1 201 Created
Location: https://api.devskiller.com/candidates/CANDIDATE-UUID-1234
Content-Type: application/json
Content-Length: 508

{
  "id" : "CANDIDATE-UUID-1234",
  "firstName" : "John",
  "lastName" : "Smith",
  "email" : "test@email.com",
  "examId" : "UUID-FOR-123",
  "status" : "TOKEN_SENT",
  "scoredPoints" : null,
  "maxPoints" : 65,
  "examUrl" : "http://exam.url/exam.html?TEST-TOKEN",
  "tags" : [ "Tag1", "Tag2" ],
  "externalId" : "EXTERNAL-1234",
  "creationDate" : "2023-05-14T14:40:39.00243Z",
  "testTimedOut" : false,
  "testStartDate" : "2023-05-15T14:40:39.00243Z",
  "testFinishDate" : "2023-05-15T15:24:39.00243Z"
}
{
  "id" : "CANDIDATE-UUID-1234",
  "firstName" : "John",
  "lastName" : "Smith",
  "email" : "test@email.com",
  "examId" : "UUID-FOR-123",
  "status" : "TOKEN_SENT",
  "scoredPoints" : null,
  "maxPoints" : 65,
  "examUrl" : "http://exam.url/exam.html?TEST-TOKEN",
  "tags" : [ "Tag1", "Tag2" ],
  "externalId" : "EXTERNAL-1234",
  "creationDate" : "2023-05-14T14:40:39.00243Z",
  "testTimedOut" : false,
  "testStartDate" : "2023-05-15T14:40:39.00243Z",
  "testFinishDate" : "2023-05-15T15:24:39.00243Z"
}

POST /candidates

A POST request is used to create a candidate. After successfully creating a candidate, an email with the invitation will be send to the candidate.

Request fields:

email
Type: String Required
The candidate's email address
firstName
Type: String Required
The candidate's first name
lastName
Type: String Required
The candidate's last name
examId
Type: String Required
The exam's id that the candidate has been asked to solve
tags
Type: Array Optional
The candidate's tags (array of strings)
communicationDisabled
Type: Boolean Optional
Should the outbound communication to the candidate be disabled. Default: "false"
externalId
Type: String Optional
Unique identifier of the candidate used in your system

Possible response codes

200 OK
The request completed successfully
400 Bad Request
The request was malformed. The response body will include an error providing further information
412 Precondition failed
Requested exam cannot be used (it doesn't exist or is in wrong state)
417 Expectation failed
There are insufficient credits to complete the request

Details of a candidate

Request

GET /candidates/CANDIDATE-UUID-1234 HTTP/1.1
X-Api-Key: TEST-API-KEY
Accept: application/json
Host: api.devskiller.com

$ curl 'https://api.devskiller.com/candidates/CANDIDATE-UUID-1234' -i -X GET \
    -H 'X-Api-Key: TEST-API-KEY' \
    -H 'Accept: application/json'

Response

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 508

{
  "id" : "CANDIDATE-UUID-1234",
  "firstName" : "John",
  "lastName" : "Smith",
  "email" : "test@email.com",
  "examId" : "UUID-FOR-123",
  "status" : "TOKEN_SENT",
  "scoredPoints" : null,
  "maxPoints" : 65,
  "examUrl" : "http://exam.url/exam.html?TEST-TOKEN",
  "tags" : [ "Tag1", "Tag2" ],
  "externalId" : "EXTERNAL-1234",
  "creationDate" : "2023-05-14T14:40:39.00261Z",
  "testTimedOut" : false,
  "testStartDate" : "2023-05-15T14:40:39.00262Z",
  "testFinishDate" : "2023-05-15T15:24:39.00262Z"
}
{
  "id" : "CANDIDATE-UUID-1234",
  "firstName" : "John",
  "lastName" : "Smith",
  "email" : "test@email.com",
  "examId" : "UUID-FOR-123",
  "status" : "TOKEN_SENT",
  "scoredPoints" : null,
  "maxPoints" : 65,
  "examUrl" : "http://exam.url/exam.html?TEST-TOKEN",
  "tags" : [ "Tag1", "Tag2" ],
  "externalId" : "EXTERNAL-1234",
  "creationDate" : "2023-05-14T14:40:39.00261Z",
  "testTimedOut" : false,
  "testStartDate" : "2023-05-15T14:40:39.00262Z",
  "testFinishDate" : "2023-05-15T15:24:39.00262Z"
}

GET /candidates/{id}

A GET request will retrieve the details of a candidate

Response structure

id
Type: String Content: Standard
The candidate's id
externalId
Type: String Content: Standard
The candidate's external id
status
Type: String Content: Standard
The candidate's status. Possible values: TOKEN_SENT, TOKEN_EXPIRED, TEST_STARTED, TEST_FINISHED, AUTO_ASSESSMENT_READY, IN_ASSESSMENT, ASSESSMENT_READY, ACCEPTED, REJECTED, ERROR
email
Type: String Content: Standard
The candidate's email address
firstName
Type: String Content: Standard
The candidate's first name
lastName
Type: String Content: Standard
The candidate's last name
scoredPoints
Type: Null Content: Standard
The candidate's score. Null if candidate has not been assessed yet
maxPoints
Type: Number Content: Standard
The maximum number of points, that candidate might get from assigned exam
examUrl
Type: String Content: Standard
The url to the test for candidate
examId
Type: String Content: Standard
The exam's id that the candidate has been asked to solve
tags
Type: Array Content: Standard
The candidate's tags (array of strings)
creationDate
Type: String Content: Standard
Creation date (ISO_8601)
testTimedOut
Type: Boolean Content: Standard
Did the test time-out (true/false)
testStartDate
Type: String Content: Standard
Test start date (ISO_8601)
testFinishDate
Type: String Content: Standard
Test finish date (ISO_8601)

Results for a candidate

Request

GET /candidates/CANDIDATE-UUID-5678/results HTTP/1.1
X-Api-Key: TEST-API-KEY
Accept: application/json
Host: api.devskiller.com

$ curl 'https://api.devskiller.com/candidates/CANDIDATE-UUID-5678/results' -i -X GET \
    -H 'X-Api-Key: TEST-API-KEY' \
    -H 'Accept: application/json'

Response

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 564

{
  "reportUrl" : "https://report.devskiller.com/candidate-report.html?REPORT-UUID/REPORT-UUID2",
  "pdfReportUrl" : null,
  "scoredPoints" : 45,
  "maxPoints" : 65,
  "skills" : [ {
    "name" : "Skill1",
    "scoredPoints" : 50,
    "maxPoints" : 100
  }, {
    "name" : "Skill2",
    "scoredPoints" : 36,
    "maxPoints" : 100
  } ],
  "note" : "Some note about candidate",
  "askedForContractData" : true,
  "financialExpectations" : 5000,
  "noticePeriod" : "one month",
  "replySent" : false,
  "examDurationInMinutes" : 44,
  "examTimeLimitInMinutes" : 60
}
{
  "reportUrl" : "https://report.devskiller.com/candidate-report.html?REPORT-UUID/REPORT-UUID2",
  "pdfReportUrl" : null,
  "scoredPoints" : 45,
  "maxPoints" : 65,
  "skills" : [ {
    "name" : "Skill1",
    "scoredPoints" : 50,
    "maxPoints" : 100
  }, {
    "name" : "Skill2",
    "scoredPoints" : 36,
    "maxPoints" : 100
  } ],
  "note" : "Some note about candidate",
  "askedForContractData" : true,
  "financialExpectations" : 5000,
  "noticePeriod" : "one month",
  "replySent" : false,
  "examDurationInMinutes" : 44,
  "examTimeLimitInMinutes" : 60
}

GET /candidates/{id}/results

A GET request will retrieve the results for a candidate

Response structure

maxPoints
Type: Number Content: Standard
Maximum points that candidate could get for the test
scoredPoints
Type: Number Content: Standard
The candidate's score
examDurationInMinutes
Type: Number Content: Standard
How long did it take to complete the test
examTimeLimitInMinutes
Type: Number Content: Standard
Exam's time limit
askedForContractData
Type: Boolean Content: Standard
True if candidate has been asked for contract data
financialExpectations
Type: Number Content: Standard
Financial expectations, available if candidate has been asked for contract data.
noticePeriod
Type: String Content: Standard
Notice period, available if candidate has been asked for contract data
note
Type: String Content: Standard
Optional note about candidate, made by assessor
replySent
Type: Boolean Content: Standard
True if a feedback mail has been sent to the candidate
reportUrl
Type: String Content: Standard
The candidate's report URL.
pdfReportUrl
Type: Null Content: Standard
The candidate's report URL (PDF download).
skills
Type: Array Content: Standard
The candidate's skills results.
skills[].name
Type: String Content: Standard
The skill's name.
skills[].scoredPoints
Type: Number Content: Standard
The skil's scored points.
skills[].maxPoints
Type: Number Content: Standard
The skill's max points.

Exam operations

The Exams resources is used to list exams

List exams

Request

GET /exams?count=10&page=1 HTTP/1.1
X-Api-Key: TEST-API-KEY
Accept: application/json
Host: api.devskiller.com

$ curl 'https://api.devskiller.com/exams?count=10&page=1' -i -X GET \
    -H 'X-Api-Key: TEST-API-KEY' \
    -H 'Accept: application/json'

Response

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 558

{
  "items" : [ {
    "id" : "UUID-FOR-123",
    "name" : "Test exam 123",
    "durationInMinutes" : 100,
    "automaticAssessmentPossible" : true,
    "numberOfPages" : 2,
    "numberOfTasks" : 4,
    "skillTags" : [ "Java", "Hibernate" ]
  }, {
    "id" : "UUID-FOR-456",
    "name" : "Test exam 456",
    "durationInMinutes" : 100,
    "automaticAssessmentPossible" : true,
    "numberOfPages" : 2,
    "numberOfTasks" : 4,
    "skillTags" : [ "Java", "Hibernate" ]
  } ],
  "totalElements" : 2,
  "totalPages" : 1,
  "pageSize" : 10,
  "pageNumber" : 1
}
{
  "items" : [ {
    "id" : "UUID-FOR-123",
    "name" : "Test exam 123",
    "durationInMinutes" : 100,
    "automaticAssessmentPossible" : true,
    "numberOfPages" : 2,
    "numberOfTasks" : 4,
    "skillTags" : [ "Java", "Hibernate" ]
  }, {
    "id" : "UUID-FOR-456",
    "name" : "Test exam 456",
    "durationInMinutes" : 100,
    "automaticAssessmentPossible" : true,
    "numberOfPages" : 2,
    "numberOfTasks" : 4,
    "skillTags" : [ "Java", "Hibernate" ]
  } ],
  "totalElements" : 2,
  "totalPages" : 1,
  "pageSize" : 10,
  "pageNumber" : 1
}

GET /exams

A GET request will list all candidates.

Request parameters:

count
Optional
Maximum number of exams to get. Default: 10, Max: 100
page
Optional
Number of the page to fetch, starting with 1. Default: 1

Response structure

pageNumber
Type: Number Content: Standard
Number of the current page
pageSize
Type: Number Content: Standard
Maximum number of elements for a page
totalElements
Type: Number Content: Standard
Total number of exams matching criteria
totalPages
Type: Number Content: Standard
Total number of pages matching criteria
items
Type: Array Content: Standard
An array of exams
items[].id
Type: String Content: Standard
The exam’s id that the candidate has been asked to solve
items[].name
Type: String Content: Standard
The exam’s name
items[].durationInMinutes
Type: Number Content: Standard
How long did it take to complete the test
items[].automaticAssessmentPossible
Type: Boolean Content: Standard
Is automatic assessment of candidate’s answers is possible? If false, some of candidate’s answers needs manual assessment
items[].numberOfPages
Type: Number Content: Standard
The exam’s number of pages
items[].numberOfTasks
Type: Number Content: Standard
The exam’s number of tasks
items[].skillTags
Type: Array Content: Standard
Array of skills tested with this exam

Details of an exam

Request

GET /exams/UUID-FOR-123 HTTP/1.1
X-Api-Key: TEST-API-KEY
Accept: application/json
Host: api.devskiller.com

$ curl 'https://api.devskiller.com/exams/UUID-FOR-123' -i -X GET \
    -H 'X-Api-Key: TEST-API-KEY' \
    -H 'Accept: application/json'

Response

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 211

{
  "id" : "UUID-FOR-123",
  "name" : "Test exam 123",
  "durationInMinutes" : 100,
  "automaticAssessmentPossible" : true,
  "numberOfPages" : 2,
  "numberOfTasks" : 4,
  "skillTags" : [ "Java", "Hibernate" ]
}
{
  "id" : "UUID-FOR-123",
  "name" : "Test exam 123",
  "durationInMinutes" : 100,
  "automaticAssessmentPossible" : true,
  "numberOfPages" : 2,
  "numberOfTasks" : 4,
  "skillTags" : [ "Java", "Hibernate" ]
}

GET /exams/{id}

A GET request will retrieve the details of an exam

Response structure

id
Type: String Content: Standard
The exam's id
name
Type: String Content: Standard
The exam's name
durationInMinutes
Type: Number Content: Standard
The exam's duration in minutes
numberOfPages
Type: Number Content: Standard
The exam's number of pages
numberOfTasks
Type: Number Content: Standard
The exam's number of tasks
skillTags
Type: Array Content: Standard
Array of skills tested with this exam
automaticAssessmentPossible
Type: Boolean Content: Standard
Is automatic assessment of candidate's answers is possible? If false, some of candidate's answers needs manual assessment

Webhooks

Webhooks are inverted API endpoints which allows you to receive push notifications from DevSkiller.

To receive DevSkiller's push notifications you have to register your webhook endpoint address in the administration panel. You will also find here the webhook secret which is used to secure all requests sent by DevSkiller. The secret is always passed in the "X-Hook-Secret" header.

Receive push notification

Request

POST /devskillerWebhooks/ HTTP/1.1
Content-Type: application/json
X-Hook-Secret: TEST-SECRET
Content-Length: 299
Host: api.yourdomain.com

[
    {
        "candidateId": "CANDIDATE-UUID-1234",
        "candidateExternalId": "EXTERNAL-1234",
        "candidateEmail": "test@email.com",
        "examId": "UUID-FOR-123",
        "examName": "Test exam 123",
        "status": "ASSESSMENT_COMPLETED",
        "event": "EXAM_FINISHED"
    }
]
$ curl 'https://api.yourdomain.com/devskillerWebhooks/' -i -X POST \
    -H 'Content-Type: application/json' \
    -H 'X-Hook-Secret: TEST-SECRET' \
    -d '[
    {
        "candidateId": "CANDIDATE-UUID-1234",
        "candidateExternalId": "EXTERNAL-1234",
        "candidateEmail": "test@email.com",
        "examId": "UUID-FOR-123",
        "examName": "Test exam 123",
        "status": "ASSESSMENT_COMPLETED",
        "event": "EXAM_FINISHED"
    }
]'

POST https://your_endpoint_address_here

A POST request will push events to your endpoint.

If your endpoint responded 4xx or 5xx DevSkiller will retry the request with a given schedule:

Request headers

Name Description
X-Hook-Secret The webhook secret key

Request structure

[]
Type: Array Always
An array of events
[].candidateId
Type: String Always
The candidate's id
[].candidateExternalId
Type: String If used
The candidate's external id
[].candidateEmail
Type: String Always
The candidate's email
[].examId
Type: String Always
The id of the exam
[].examName
Type: String Always
The name of the exam
[].event
Type: String Always
Event type. Possible values: EXAM_FINISHED, EXAM_STARTED, TOKEN_EXPIRED, ERROR
[].status
Type: String Always
Event type status. Possible values: WAITING_FOR_ASSESSMENT, EXAM_STARTED, ASSESSMENT_COMPLETED, TOKEN_EXPIRED, ERROR

Errors

Response

HTTP/1.1 400 Bad Request
Content-Type: application/json
Content-Length: 249

{
  "code" : 400,
  "errorId" : "6d77c358-a91a-4360-8c2f-568cbace8130",
  "details" : "Validation error",
  "validationErrors" : [ {
    "field" : "email",
    "value" : "incorrect mail",
    "message" : "must be a well-formed email address"
  } ]
}
{
  "code" : 400,
  "errorId" : "6d77c358-a91a-4360-8c2f-568cbace8130",
  "details" : "Validation error",
  "validationErrors" : [ {
    "field" : "email",
    "value" : "incorrect mail",
    "message" : "must be a well-formed email address"
  } ]
}

Whenever an error response (status code >= 400) is returned, the body will contain a JSON object that describes the problem. The error object has the following structure:

code
Type: Number Content: Standard
Error code
errorId
Type: String Content: Standard
Unique error id, you can use it when contacting with us
details
Type: String Content: Standard
Error description
validationErrors
Type: Array Content: Standard
Validation errors details
validationErrors[].field
Type: String Content: Standard
Name of the field
validationErrors[].value
Type: String Content: Standard
Rejected value
validationErrors[].message
Type: String Content: Standard
Message

For example, a request that attempts to apply a non-existent tag to a note will produce a 400 Bad Request response