14. Edit Schedule

14. Edit Schedule

Definition

This  POST  API is used to edit a schedule/ test link.
      *PDF documentation reference - Section 5.2 Edit Schedule for a particular Assessment

Endpoints

  1. https://api.mettl.com/v2/schedules/{access-key}/edit
  2. https://api.mettl.com/v1/schedules/{access-key}/edit
where, access-key is the unique key of the schedule/ test link you want to edit.

You can get an access-key from the test link settings in your dashboard (alphanumeric key at the end of the 'Link to Share') or via API by using Create Schedule API , Get All Schedules in Assessment API or Get All Schedules in Account API.

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 edited. The format for the JSON is given below


 POST  request syntax with mandatory parameters:
https://api.mettl.com/v2/schedules/{access-key}/edit?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 edited.


PropertySub PropertySub PropertyDescription
name

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

Name of your application. This value is a string.
access

Schedule access settings, shown as the Private access only checkbox in your Test Link Settings in dashboard. This value is a nested JSON.
type
Schedule access type, can be either public access or private access only. This string is always 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 value is a boolean, false by default and only works when access type is "ByInvitation".

If you are trying to use this API to send start test emails from a Mercer | Mettl Id, always remember to set sendEmail as true in each API call when adding candidates.
isCandidateCrfPrefilled
Determines whether the candidate registration fields, except for email, already provided when adding candidates will be skipped before starting the test. This value is a boolean, false by default and only works when access type is "ByInvitation".
candidates
Candidates to be added or removed who have access to "ByInvitation" schedule. This value is a nested JSON.

add
Details of candidates to be added "ByInvitation" schedule. This value is a list of nested JSON(s) with the following nested properties.

↳  email
Candidate's  email id. This string is mandatory in each candidates add JSON.

↳  name
Candidate's name. This string is mandatory in each candidates add JSON.

↳  *exact name of other Candidate Registration Fields
This 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.

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"}]

remove
Emails Ids of candidates to be removed from "ByInvitation" schedule. This value is a list of string(s) and accepts only emails id which are already added to the schedule.

scheduleType

Schedule access time , can be either Anytime access or Fixed access. This values is a string 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 value is a nested JSON.
fixedAccessOption
Determines whether the test link will be accessible at any time of day or only during certain hours or slots. This value is a string 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 value is a JSON and disabled by default.
enabled
Determines whether Browsing tolerance is enabled. This value is a boolean 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 value is an integer and should be more than or equal to 0.
showRemainingCounts
Determines whether remaining counts of Browsing tolerance are shown. This value is a boolean and false by default.
visualProctoring

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

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

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

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

Determines whether OTP sent on email Id is required before starting the test. This string is optional and only accepts "OtpOnEmail" to enable, "NotEnabled" to disable with the default value being "NotEnabled".
testStartNotificationUrl

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

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

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

URL to configure expired test resume webhook notifications. This value is a string 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 value is a string with the default behavior being no authentication sent in webhook notifications.
testGradeNotification

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

ipAccessRestriction

IP address restriction settings. This value is a JSON and disabled by default.
enabled
Determines whether IP address restriction is enabled. This value is a boolean and false by default.
type
Configures whether  IP address restriction  will be applicable on a single or a range of IP addresses. This value is a string 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 value is a string and accepts the given format.

eg. "0.0.0.0", "255.255.255.255"
ranges
Range of IP addresses in IPv4 format. This value is a list of JSON(s) 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 value is a string

endEnding IP address in the range of addresses. This value is a string

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.
Sample  sc  JSON with all properties:
{
"name": "Test Link Name",
"sourceApp": "App Name",
"access": {
"type": "ByInvitation",
"sendEmail": true,
"isCandidateCrfPrefilled": true,
"candidates": {
"add": [
{
"name": "Name",
"email": "name@email.com"
}
],
"remove": ["name2@email.com"]
}
},
"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/schedules/0x0x0x0x0x/edit?ak=ab12c345-6789-0123-456d-78e9f0123456&ts=1635976200&sc=%7B%22access%22%3A%7B%22type%22%3A%22ByInvitation%22%2C%22sendEmail%22%3Atrue%2C%22candidates%22%3A%7B%22add%22%3A%5B%7B%22name%22%3A%22Name%22%2C%22email%22%3A%22name%40email.com%22%7D%5D%7D%7D%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/schedules/0x0x0x0x0x/edit" + "\n" + "ab12c345-6789-0123-456d-78e9f0123456" + "\n" + "{"access":{"type":"ByInvitation","sendEmail":true,"candidates":{"add":[{"name":"Name","email":"name@email.com"}]}}}" + "\n" + "1635976200"
c. Output of the Sting-to-Sign created above
ab12c345-6789-0123-456d-78e9f0123456
{"access":{"type":"ByInvitation","sendEmail":true,"candidates":{"add":[{"name":"Name","email":"name@email.com"}]}}}
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)
GA9wqLFkhyTzmLcZDfZcYadMolX6JB0gRy5zN5crG18%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/schedules/0x0x0x0x0x/edit?ak=ab12c345-6789-0123-456d-78e9f0123456&ts=1635976200&sc=%7B%22access%22%3A%7B%22type%22%3A%22ByInvitation%22%2C%22sendEmail%22%3Atrue%2C%22candidates%22%3A%7B%22add%22%3A%5B%7B%22name%22%3A%22Name%22%2C%22email%22%3A%22name%40email.com%22%7D%5D%7D%7D%7D&asgn=GA9wqLFkhyTzmLcZDfZcYadMolX6JB0gRy5zN5crG18%3D

Response

Upon making a successful request, if there are no errors, you will receive a JSON in the given format
{
"status": "SUCCESS",
"schedule": {
"id": 9999999,
"name": "Test Link Name",
"accessKey": "0x0x0x0x0x",
"accessUrl": "https://tests.mettl.com/authenticateKey/0x0x0x0x0x",
"status": "ACTIVE",
"createdAt": "Fri, 11 Feb 2022 23:05:57 GMT",
"imageProctoring": true,
"webProctoring": {
"enabled": true,
"count": 10,
"showRemainingCounts": true
},
"scheduleType": "Fixed",
"scheduleWindow": {
"fixedAccessOption": "SlotWise",
"startsOnDate": "Mon, 07 Feb 2022",
"endsOnDate": "Fri, 11 Feb 2022",
"startsOnTime": "12:00:00",
"endsOnTime": "18:00:00",
"timeZone": "UTC+05:30",
"locationTimeZone": "Asia/Kolkata"
},
"access": {
"type": "ByInvitation",
"candidates": [
{
"name": "Name",
"submissionDate": null,
"email": "name@email.com"
}
],
"sendEmail": true,
"sendReminders": false,
"isCandidateCrfPrefilled": false
},
"ipAccessRestriction": {
"enabled": true,
"type": "RANGE",
"ranges": [
{
"start": "128.128.128.128",
"end": "128.128.128.130"
}
]
},
"sourceApp": "App Name",
"testResumeEnabledForExpiredTestURL": "https://www.application.com/path/post_call_listener",
"isCandidateAuthProctored": true,
"testGradeNotification": {
"enabled": true,
"recipients": ["admin@email.com", "admin2@email.com"]
},
"visualProctoring": {
"options": {
"candidateScreenCapture": true,
"candidateAuthorization": true,
"audioOptional": true,
"isAudioProctoring": false
},
"mode": "PHOTO"
},
"allowTestResume": "UnSuperVised",
"secureBrowser": {
"enabled": true
},
"assessmentDetails": {
"id": 769688,
"duration": 10,
"name": "Assessment Name",
"instructions": "Instructions for attempting the assessment",
"createdAt": "Fri, 11 Feb 2022 23:05:57 GMT"
},
"protected": "NotEnabled"
}
}

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",
"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",
"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

Finish and Completion Modes

In the above webhook response JSONs, you will also receive a 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.