13. Create Schedule

13. Create Schedule

Definition

This  POST  API is used to create a schedule/ test link for a specific assessment.
      *PDF documentation reference - Section 5.1 Create Schedule for a particular Assessment

Endpoints

  1. https://api.mettl.com/v2/assessments/{assessment-id}/schedules
  2. https://api.mettl.com/v1/assessments/{assessment-id}/schedules
where, assessment-id is the unique Id of the assessment for which you want to create a new schedule/ test link.

Remarks

Using this API you can create schedules/test links in your assessment and get their Access Key which can be used uniquely identify any schedule/ test link and is used in other API calls such as Register Candidates in Schedule API , Edit Schedule API or Get Result of Candidate in Schedule API.

This API is also used in the second step of our sample API Integration Flow, where a test link and its access key can be created using the assessment Id and proctoring settings captured from a user. This access key can further used to register candidates to the created test link for generating unique test links for each candidate to send emails from your own system in the third step or alternatively editing a private schedule with candidate info to send emails from Mercer | Mettl.

In this API you can also configure webhooks for sending live test and result notifications of a schedule/ test link to your system.

Webhooks

This API has support for configuring webhooks for sending live test and result notifications at the schedule/ test link level. You can also get live notifications of following events by setting the callback URL in the schedule properties within the  sc  JSON-
  1. When a candidate’s test starts (testStartNotificationUrl)
  2. When a candidate’s test ends (testFinishNotificationUrl)
  3. When a candidate’s test result gets generated (testGradedNotificationUrl)
  4. When a candidate is allowed to resume their expired test (testResumeEnabledForExpiredTestURL)

Query Parameters

In our REST APIs, Query Parameters have to be URL encoded as the data is being transmitted in the request URL. This is especially important for the  asgn  parameter and any parameters with JSON as they always contain characters that need to be URL encoded. Since  ak  and  ts   parameters don't contain any characters that need to be URL encoded, URL encoding of these parameters can be skipped.

Mandatory parameters


Query Parameter


Description

ak

This is your Public-API-Key, which Mettl uses to identify your account.

ts

This is the current UNIX or Epoch Timestamp (the number of seconds between 1970-01-01 00:00:00 and current UTC Time). Any current generated Timestamp will be valid for 24 hours only.

asgn

This is a unique Signature which has to be generated  for each API request .

The Signature is generated by creating a String-to-Sign and hashing it with your Private-API-Key using the HMAC-SHA256 (for version v2 and v3) or HMAC-SHA1 (for v1) hashing algorithm with Base-64 and URL encoding.

Read more about the above Signature Generation Process in API Authentication and Signature Generation.

sc

This is a JSON string containing the details of the schedule/ test link to be created. The format for the JSON is given below


 POST  request syntax with mandatory parameters:
https://api.mettl.com/v2/assessments/{assessment-id}/schedules?ak={Public-Api-Key}&ts={Timestamp}&asgn={Signature}&sc={Schedule-JSON}  

JSON ( sc )

Format of JSON string to be passed in query parameter  sc  can be found in the table below. This JSON describes the details of the Schedule/ Test Link to be created.
Note: In the  sc  JSON below, a property can become mandatory or optional depending on other properties, but  properties  highlighted with the color yellow are always mandatory.

PropertySub PropertySub PropertyDescription
name

Name of the schedule/ test link to be created. This string is  mandatory and has to be unique for each schedule in your assessment.
sourceApp

Name of your application. This string is mandatory.
access

Schedule access settings, shown as the Private access only checkbox in your Test Link Settings in dashboard. This nested JSON is mandatory.
type
Schedule access type, can be either public access or private access only. This string is mandatory within access JSON and only accepts "OpenForAll" or "ByInvitation".

When "ByInvitation" is chosen, details of candidates are required to be configured in the candidates property below.
sendEmail
Determines whether a start test mail will be sent to the candidates when their details are added to "ByInvitation" schedule. This boolean is optional, false by default and only works when access type is "ByInvitation".
isCandidateCrfPrefilled
Determines whether the candidate registration fields, except for email, already provided when adding candidates will be skipped before starting the test. This boolean is optional, false by default and only works when access type is "ByInvitation".
candidates
Details of candidates who have access to "ByInvitation" schedule. This list of nested JSON(s) is mandatory when access type is "ByInvitation".

eg. [{"name": "Name", "email": "name@email.com", "Date of birth": "Sep 16 1998"},{"name": "Name2", "email": "name2@email.com", "Date of birth": "Jan 1 1996"}]

emailCandidate's email id. This string is mandatory in each candidates JSON.

nameCandidate's name. This string is mandatory in each candidates JSON.

compensatory_timeThis parameter is used to to extend the test time as an accessibility compliance. This integer is optional and should be more than or equal to 0.

*exact name of other Candidate Registration FieldsThis property represents all other candidate registration fields and the name of the property is the exact name of the registration field. This string is optional.
scheduleType

Schedule access time, can be either Anytime access or Fixed access. This string is mandatory and only accepts "AlwaysOn" or "Fixed".

When "AlwaysOn" is chosen, the test link is accessible at any time.

When "Fixed" is chosen, the test link is accessible at only at specific times and settings for the exact access time are required to be configured in the scheduleWindow JSON below.
scheduleWindow

Fixed access time settings. This nested JSON is mandatory when scheduleType is "Fixed".
fixedAccessOption
Determines whether the test link will be accessible at any time of day or only during certain hours or slots. This string is optional and only accepts "ExactTime" or "SlotWise" with the default value being "ExactTime".

With "ExactTime", the test is accessible during any time of day between the start and end, time and date.

With "SlotWise", the test is accessible during specific time of day between the start and end date.
startsOnDate
Start date for access period. This string is mandatory in scheduleWindow JSON in the given format.

eg. "Wed, 20 Oct 2021", "Fri, 11 Feb 2022"
startsOnTime
Start time for access period.  This string is mandatory in scheduleWindow JSON in the given format.

eg. "09:00:00", "12:00:00"
endsOnDate
End date for access period.  This string is mandatory in scheduleWindow JSON in the given format.

eg. "Thu, 21 Oct 2021", "Sat, 12 Feb 2022"
endsOnTime
End time for access period.  This string is mandatory in scheduleWindow JSON in the given format.

eg. "15:00:00", "18:00:00"
timeZone
Time zone represented as UTC offset defined in tz database. This string is mandatory when locationTimeZone is not used in the scheduleWindow JSON in the given format.

eg. "UTC+05:30", "UTC-08:00"
locationTimeZone
Time zone location in the format defined in tz database. This string is mandatory when timeZone is not used in the scheduleWindow JSON in the given format.

eg. "Asia/Kolkata", "America/Los_Angeles"
webProctoring

Browsing tolerance settings. This nested JSON is optional and disabled by default.
enabled
Determines whether Browsing tolerance is enabled. This boolean is optional and false by default.
count
Number of times a test taker is allowed to navigate away from the test window, before the test ends. This integer is optional and should be more than or equal to 0.
showRemainingCounts
Determines whether remaining counts of Browsing tolerance are shown. This boolean is optional and false by default.
visualProctoring

Advanced Visual Proctoring settings. This JSON is optional and disabled by default.
mode
Determines whether Advanced Visual Proctoring is enabled when  "PHOTO" is chosen. This string is optional and only accepts "PHOTO" or "OFF" with the default value being "OFF"
options
Additional settings when Advanced Visual Proctoring is enabled. This nested JSON is optional and disabled by default.

candidateScreenCaptureDetermines whether time-interval based screen-grabs of candidates test screen are taken. This boolean is optional and false by default.

candidateAuthorizationDetermines whether a manual live authorization process is enabled for starting the test. This boolean is optional and false by default.
secureBrowser

Mettl Secure Browser setting. This nested JSON is optional and disabled by default.
enabled
Determines whether Mettl Secure Browser is enabled. This boolean is optional and false by default.
protected

Determines whether OTP sent on email Id is required before starting the test. This string is optional, only accepts "OtpOnEmail" to enable and is disabled by default.
testStartNotificationUrl

URL to configure start test webhook notifications. This string is optional and only accepts a valid URL.
testFinishNotificationUrl

URL to configure finish test webhook notifications. This string is optional and only accepts a valid URL.
testGradedNotificationUrl

URL to configure test results webhook notifications. This string is optional and only accepts a valid URL.
testResumeEnabledForExpiredTestURL

URL to configure expired test resume webhook notifications. This string is optional and only accepts a valid URL.
testNotificationBasicAuthHeader

Basic Authentication header which is returned in the above webhook notifications. You can input a value in the format base64encoded(username:password) in order to receive additional individual headers for username and password as well. This string is optional with the default behavior being no authentication sent in webhook notifications.
testGradeNotification

Settings for sending test result email notifications. This nested JSON is optional and disabled by default.
enabled
Determines whether test result email notifications are enabled.  This boolean is optional and false by default.
recipients
Email ids of the recipients for test result email notifications. This list of string(s) is mandatory when testGradeNotification is enabled and accepts only valid email ids in the given format,

ipAccessRestriction

IP address restriction settings. This nested JSON is optional and disabled by default.
enabled
Determines whether IP address restriction is enabled. This boolean is optional and false by default.
type
Configures whether IP address restriction will be applicable on a single or a range of IP addresses. This string is mandatory when ipAccessRestriction is enabled and only accepts either "SINGLE" or "RANGE"

When "SINGLE" is selected, the restricted IP address is set using the  ip property below.

When "RANGE" is used, the range of restricted IP address is set using the ranges property.
ip
Single IP address in IPv4 format. This string is mandatory when ipAccessRestriction type is "SINGLE" and accepts the given format.

eg. "0.0.0.0", "255.255.255.255"
ranges
Range of IP addresses in IPv4 format. This list of nested JSON(s) is mandatory when ipAccessRestriction type is "RANGE" and accepts the given format.

eg. [{"start":"128.128.128.128","end":"128.128.128.130"}, {"start":"64.64.64.64","end":"64.64.64.67"}]


startStarting IP address in the range of addresses. This string is mandatory in ranges JSON.

endEnding IP address in the range of addresses. This string is mandatory in ranges JSON.



For easier readability, the sample  sc  JSONs below have pretty formatting, but in your actual request and for signature generation, they should be ideally minified.
1) Sample  sc  JSON with only mandatory properties:
{
"name": "Test Link Name",
"sourceApp": "App Name",
"access": {
"type": "OpenForAll"
},
"scheduleType": "AlwaysOn"
}

2) Sample  sc  JSON with all properties:
{
"name": "Test Link Name",
"sourceApp": "App Name",
"access": {
"type": "ByInvitation",
"sendEmail": true,
"isCandidateCrfPrefilled": true,
"candidates": [
{
"name": "Name",
"email": "name@email.com",
                                 "compensatory_time": 20
}
]
},
"scheduleType": "Fixed",
"scheduleWindow": {
"fixedAccessOption": "SlotWise",
"startsOnDate": "Mon, 07 Feb 2022",
"startsOnTime": "12:00:00",
"endsOnDate": "Fri, 11 Feb 2022",
"endsOnTime": "18:00:00",
"timeZone": "UTC+05:30",
"locationTimeZone": "Asia/Kolkata"
},
"webProctoring": {
"enabled": true,
"count": 10,
"showRemainingCounts": true
},
"visualProctoring": {
"mode": "PHOTO",
"options": {
"candidateScreenCapture": true,
"candidateAuthorization": true
}
},
"secureBrowser": {
"enabled": true
},
"protected": "OtpOnEmail",
"testResumeEnabledForExpiredTestURL": "https://www.application.com/path/post_call_listener",
"testNotificationBasicAuthHeader": "dXNlcm5hbWU6cGFzc3dvcmQ=",
"testGradeNotification": {
"enabled": true,
"recipients": ["admin@email.com", "admin2@email.com"]
},
"ipAccessRestriction": {
"enabled": true,
"type": "RANGE",
"ranges": [
{
"start": "128.128.128.128",
"end": "128.128.128.130"
}
]
}
}

Example

Request without Signature
a.  POST  request URL, with queries  ak  ,  ts  and  sc  (URL encoded) but without  asgn  (Signature)
https://api.mettl.com/v2/assessments/999999/schedules?ak=ab12c345-6789-0123-456d-78e9f0123456&ts=1635976200&sc=%7B%22name%22%3A%22Test%20Link%20Name%22%2C%22sourceApp%22%3A%22App%20Name%22%2C%22access%22%3A%7B%22type%22%3A%22OpenForAll%22%7D%2C%22scheduleType%22%3A%22AlwaysOn%22%2C%22testGradedNotificationUrl%22%3A%22https%3A%2F%2Fwww.application.com%2Fpath%2Fpost_call_listener%22%7D

b. Creating a String-to-Sign, calculated with Method + Endpoint + Values of query parametersin new lines and in ascending order of the parameter name (i.e., the new line characters "\n" followed by values of  ak  ,  sc  and  ts  in order, for this example)
String-to-Sign = "POST" + "https://api.mettl.com/v2/assessments/999999/schedules" + "\n" + "ab12c345-6789-0123-456d-78e9f0123456" + "\n" + "{"name":"Test Link Name","sourceApp":"App Name","access":{"type":"OpenForAll"},"scheduleType":"AlwaysOn","testGradedNotificationUrl":"https://www.application.com/path/post_call_listener"}" + "\n" + "1635976200"
c. Output of the Sting-to-Sign created above
ab12c345-6789-0123-456d-78e9f0123456
{"name":"Test Link Name","sourceApp":"App Name","access":{"type":"OpenForAll"},"scheduleType":"AlwaysOn","testGradedNotificationUrl":"https://www.application.com/path/post_call_listener"}
1635976200
d. Private-API-Key to sign/hash the above Sting-to-Sign using HMAC-SHA256 (since API version is v2)
zy98x765-4321-0987-654w-32v1u0987654
e. Output of the generated Signature for  asgn  using the Sting-to-Sign and your Private-API-Key, hashed with HMAC-SHA256 (Base-64 and URL Encoded)
bwWR7GZLgOPR23DqLzWS47lKwBxCEFKDAlHmdr43pgo%3D
Read more about the above Signature Generation Process in API Authentication and Signature Generation

Request with Signature
f. Final  POST  request URL with queries  ak  ,  ts  ,  sc  (URL encoded) and  asgn  (URL Encoded)
https://api.mettl.com/v2/assessments/999999/schedules?ak=ab12c345-6789-0123-456d-78e9f0123456&ts=1635976200&sc=%7B%22name%22%3A%22Test%20Link%20Name%22%2C%22sourceApp%22%3A%22App%20Name%22%2C%22access%22%3A%7B%22type%22%3A%22OpenForAll%22%7D%2C%22scheduleType%22%3A%22AlwaysOn%22%2C%22testGradedNotificationUrl%22%3A%22https%3A%2F%2Fwww.application.com%2Fpath%2Fpost_call_listener%22%7D&asgn=bwWR7GZLgOPR23DqLzWS47lKwBxCEFKDAlHmdr43pgo%3D

Response

Upon making a successful request, if there are no errors, you will receive a JSON in the given format
{
"status": "SUCCESS",
"createdSchedule": {
"assessmentId": 999999,
"id": 10000,
"name": "Test Link Name",
"accessKey": "0x0x0x0x0x",
"status": "ACTIVE"
}
}

Webhook Responses

You can also get notifications using the 4 callback URLs in the given format

1. When a candidate’s test starts (testStartNotificationUrl)
{
"EVENT_TYPE": "startAssessment",
"invitation_key": "0x0x0x0x0x",
"assessment_id": 999999,
"candidate_instance_id": 99999999,
"context_data": null,
"timestamp_GMT": "Fri, 11 Feb 2022 23:08:02 GMT",
"source_app": "App Name",
"name": "Name ",
"email": "name@email"
}

2. When a candidate’s test ends (testFinishNotificationUrl)
{
"EVENT_TYPE": "finishTest",
"invitation_key": "0x0x0x0x0x",
"assessment_id": 999999,
"candidate_instance_id": 99999999,
"context_data": null,
"timestamp_GMT": "Fri, 11 Feb 2022 23:08:02 GMT",
"source_app": "App Name",
"name": "Name ",
"email": "name@email",
"finish_mode": "NormalSubmission"
}

3. When a candidate’s test result gets generated (testGradedNotificationUrl)
{
"EVENT_TYPE": "gradedAssessment",
"invitation_key": "0x0x0x0x0x",
"assessmentId": 999999,
"candidate_instance_id": 99999999,
"context_data": null,
"timestamp_GMT": "Fri, 29 Oct 2021 09:27:01 GMT",
"source_app": "App Name",
"name": "Name",
"email": "name@email.com",
"finish_mode": "NormalSubmission",
"start_time_GMT": "Fri, 29 Oct 2021 09:25:56 UTC",
"end_time_GMT": "Fri, 29 Oct 2021 09:27:01 UTC",
"marks_scored": 5.0,
"max_marks": 10.0,
"total_attempt_time": 64,
"percentile": 100.0,
"assessment_name": "Assessment Name",
"client_id": 99999,
"schedule_title": "Test Link Name",
"start_time": "Fri, 29 Oct 2021 14:55:56 IST",
"end_time": "Fri, 29 Oct 2021 14:57:01 IST",
"sectional_scores": "[{\"sectionName\":\"Section #1\",\"sectionScore\":5.0,\"sectionMaxScore\":10.0}]",
"grading_type": "NormalGrading",
"registrationDetails": {
"Email Address": "name@email.com",
"First Name": "Name"
},
"proctoringDetails": null,
"testStatus": {
"status": "Completed",
                "overallStatus": "Completed",
                "detailedStatus": "Test-taker Completed",
"startTime": "Fri, 29 Oct 2021 14:55:56 IST",
"endTime": "Fri, 29 Oct 2021 14:57:01 IST",
"completionMode": "Completed",
"result": {
"totalMarks": 5.0,
"maxMarks": 10.0,
"percentile": 100.0,
"attemptTime": 64.0,
"candidateCredibilityIndex": "Low",
                        "codePlagiarism": "NA",
"totalQuestion": 2.0,
"totalCorrectAnswers": 1.0,
"totalUnAnswered": 0.0,
"sectionMarks": [{
"sectionName": "Section Name",
"totalMarks": 5.0,
"maxMarks": 10.0,
"timeTaken": 0.0,
"totalQuestion": 2.0,
"totalCorrectAnswers": 1.0,
"totalUnAnswered": 0.0,
"skillMarks": [{
"skillName": "Skill Name",
"totalMarks": 5.0,
"maxMarks": 10.0,
"timeTaken": 64.0,
"totalQuestion": 2.0,
"totalCorrectAnswers": 1.0,
"totalUnAnswered": 0.0,
"difficultyMarks": [{
"level": "EASY",
"totalQuestion": 2,
"totalMarks": 5.0,
"totalUnAnswered": 0,
"maxMarks": 10.0,
"timeTaken": 64,
"totalCorrectAnswers": 1
}]
}],
"difficultyMarks": [{
"level": "EASY",
"totalQuestion": 2,
"totalMarks": 5.0,
"totalUnAnswered": 0,
"maxMarks": 10.0,
"timeTaken": 64,
"totalCorrectAnswers": 1
}],
"questionWiseResponse": null
}],
"performanceCategory": null,
"performanceCategoryVersion": null,
"difficultyMarks": [{
"level": "EASY",
"totalQuestion": 2,
"totalMarks": 5.0,
"totalUnAnswered": 0,
"maxMarks": 10.0,
"timeTaken": 64,
"totalCorrectAnswers": 1
}]
},
"analysis": {
"responseStyles": [{
"title": "Genuine",
"description": "If questions are answered in a sufficiently varied manner."
}],
"recommendation": [{
"type": "Recommendation",
"value": "Not Recommended"
}]
}
},
}
}

4. When an expired candidate is allowed to resume (testResumeEnabledForExpiredTestURL)
{
"EVENT_TYPE": "candidateTestResumed",
"invitation_key": "0x0x0x0x0x",
"assessment_id": 999999,
"candidate_instance_id": 99999999,
"context_data": null,
"timestamp_GMT": "Fri, 11 Feb 2022 23:08:02 GMT",
"source_app": "App Name",
"name": "Name ",
"email": "name@email"
}

In addition to the above the notification JSONs, you can also receive Basic Authentication in the webhook notification headers by using the "testNotificationBasicAuthHeader" in the  sc  JSON above. On providing the value for "testNotificationBasicAuthHeader" in the format base64encoded(username:password), you will receive the following additional authorization headers.
authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
php-auth-user: username
php-auth-pw: password

OverallStatus and DetailedStatus

Overall Status
Detailed Status
Description
Yet to Start
Mapped
Test-takers have been added to a test-link via candidate banks or manual entry, but an email hasn’t been sent.
Yet to Start
Invited
Test-taker has been invited for the test via email.
Yet to Start
Registered
Test-taker has registered by clicking on proceed/submit button on the test-taker portal. 
Not Started
Access Expired
1-Test-taker didn't start the test and access time elapsed. 
2- Test-taker has registered by saving registration fields on test-taker portal but didn’t start the test and access time elapsed.
3- In case of deadline-based assessments, this status will be displayed when submission date is elapsed.
In-progress
In-progress
Test –taker has started the test 
In-progress
Awaiting Resume Permission
Test-taker got disconnected and is awaiting resume permission from admin (if Supervised resume is enabled). 
Completed
Test-taker completed
Test-taker clicked on the Finish button to submit the test. 
Completed
Time Over
The test was auto-submitted as the test-taker ran out of time. 
Test Stopped
Mic Mute Limit exceeded
The test was stopped because of exceeding mic mute count.
Test Stopped
Browsing Tolerance Limit Exceeded
The test was stopped because of exceeding Browsing Tolerance.
Test Stopped
Proctor Stopped 
Proctor stopped the test.
Test Stopped
Suspicious Software Detected
The test was stopped because of suspicious software. 
Test Stopped
Multiple Screen Detected
The test was stopped because of multiple screens detected.
Test Stopped
Prohibited Apps Running
The test was stopped because of prohibited apps running. 
Test Stopped
Screen Capture/Recording Detected
The test was stopped because of screen capture/recording. 
Test Stopped
Screen Sharing/Remote Access Detected 
The test was stopped because of screen share/remote access.
Blocked
Authorizer Blocked
The authorizer blocked the test-taker from starting the test.
Disconnected
Disconnected from Server
The test-taker got disconnected because of power failure/bad internet and couldn't resume within 30 minutes. 
Disconnected
Test Window Closed
Test-taker closed the window and navigated away from the screen. Test-taker didn't resume the test in 30 mins. 
Disconnected
Awaiting Test-taker Resume
The test-taker got disconnected and admin resumed the test (normal resume). 


Finish and Completion Modes

In the above webhook response JSONs, you will also receive parameters called finish_mode in "testFinishNotificationUrl" and both finish_mode and completionMode in "testGradedNotificationUrl". These can be helpful in understanding how a candidate's test got finished. The possible values for these parameters and their description can be found in table below- 

finish_mode (in webhook response)completionMode (in webhook response)Test Finish Mode (in candidate reports)

Description

TimeExpired AutoCompletedAuto SubmitTest Time finished before candidate could attempt all questions.
BlockedNABlocked Candidate blocked at the authorization stage (For Proctored Test with Authorization On).
BrowsingToleranceExceededBrowsingToleranceExceededBrowsing Tolerance ExceededWhen browsing tolerance is set and test taker navigates away from the test window more than the permissible number or times (browsing tolerance limit).
TestExpiredExpiredExpiredIf candidate gets disconnect (Loss of internet connection, etc) or his/her system shuts down abruptly and he/she is unable to resume the test.
NormalSubmissionCompletedNormal Finish Test button Clicked.
ParentFinish ParentFinishedNormalThe background parent window is closed.
ProctoredFinishProctoredFinish Proctored Finish Image Proctored Test ended by Proctor.
NAResumeEnabledResume EnabledCandidate allowed to resume tests from same point where test got over, only can be done if initial status was Expired.
SuspiciousSoftwareFinishSuspiciousSoftwareFinish Suspicious Software FinishSuspicious Software detected Eg TeamViewer, SplashTop etc also found running and Mettl automatically closes test.
CandidateClosedCandidateClosed Test Window ClosedTest Window Closed without clicking on Finish Test.