This is the documentation page for the 2020Q1 version of the API. For the latest version, click here.
The TrueNorth Enterprise API allows customers to integrate with the TrueNorth and WebCAPE 2.0 platform.
All usage examples are given as curl commands.
The API uses a url-based versioning scheme which indicates when it was released, such as /2020q1 for quarter 1 of 2020.
All endpoints are versioned together when we release a new version.
For the best consumer experience, you should use the same version for all requests; avoid making some requests to older endpoints.
Version updates are planned to be infrequent to minimize the work clients need to do to upgrade to the latest versions. Breaking changes will be documented for each affected endpoint. Minor, non-breaking changes may be made to existing endpoints for maintenance without updating the version.
The base url for accessing the /2020q1 version of the API is: https://api.truenorthtest.com/2020q1
Documentation for other versions of the API can be found here.
An API key is required with every request to the API.
It must be sent in an Authorization header as a Bearer token.
A missing or invalid API key will result in a 401 response status code.
To obtain an API key, log into the administrative dashboard. Under "Settings" then "API Keys" there is a UI for generating new API keys and revoking old ones that are no longer needed.
In the endpoint documentation below, the example requests indicate the required header in the curl commands like this:
-H "Authorization: Bearer {api-key}"
Replace {api-key} with your actual API key in your requests.
In order to safeguard the performance of the Enterprise API, we rate limit the number of requests that will be accepted.
Each account may make up to 2,000 requests per 20 minutes, and no faster than 5 requests per second.
If requests are made too quickly they will not be processed and will result in a 429 status code.
Each account may register a webhook via the Enterprise API in order to be notified whenever key events occur.
The registered URL will be sent a POST request with a JSON body (Content-Type: application/json)
containing relevant data for the event.
We strongly recommend that you only register a webhook that uses a secure tunnel (TLS/HTTPS). When your server is called, please attempt to respond within 5 seconds. This means you should avoid processing the data or calling our API as part of receiving the webhook event.
The assessments endpoint returns the list of assessments available to your account.
curl -H 'Authorization: Bearer {api-key}' \
https://api.truenorthtest.com/2020q1/assessments
name and assessmentId for each assessment.
The assessmentId values may be required to use other endpoints.
{
"assessments": [
{
"name": "English Grammar",
"assessmentId": "de83346f-aa2d-4c4f-a250-0d3a09d609e3"
},
{
"name": "English Listening",
"assessmentId": "0b5c0072-7cc9-4ef0-96e8-635a4ce012fd"
},
{
"name": "English Speaking",
"assessmentId": "c66496f2-35a7-465d-bb3b-58f6af5caedb"
},
{
"name": "English Speaking Demo",
"assessmentId": "6ce10c60-0761-4dc7-b193-9f73977a9510"
},
]
}
The GET groups endpoint gets a list of all groups on the account.
Groups can be managed from the administrator dashboard within the product,
or new groups can be created via the create group endpoint.
curl -H 'Authorization: Bearer {api-key}' \
https://api.truenorthtest.com/2020q1/groups
name and groupId for each group associated with your account.
{
"groups": [
{
"name": "English speaking",
"groupId": "80843e92-5be1-46aa-9472-2862d11413b3"
},
{
"name": "grammar",
"groupId": "90dc068c-31bf-4303-a536-fb4398b47f5d"
},
{
"name": "New Group",
"groupId": "23b3ac80-0309-4553-91f8-a4f28fdb2b18"
},
{
"name": "Only WebCAPE",
"groupId": "1cffe784-d006-4f1b-87d4-70d07d7d2dc3"
}
]
}
The POST groups endpoint creates a new group on the account.
curl -H 'Authorization: Bearer {api-key}' \
-H 'Content-Type: application/json' \
-d '{"name": "English speaking"}' \
-X POST https://api.truenorthtest.com/2020q1/groups
name and groupId of the newly created group.
{
"name": "English speaking",
"groupId": "80843e92-5be1-46aa-9472-2862d11413b3"
}
The assign endpoint allows you to create a new user and assign an assessment to the user, or if the user already exists, assign an assessment to that user.
You may provide an optional unique identifier that will be associated with the user which you can use on other endpoints to specify this same user.
assessmentId for the assessment you are assigning (see the assessments endpoint)emailAddress or uniqueIdentifier is required.
Note that if you do not provide an email address, some features will be unavailable (such as account recovery or score notification).
emailAddress or uniqueIdentifier is required.
uniqueIdentifier above, you will also need to provide it here in order to have this value returned as studentId in the scoring endpoints.
groupId values matching the groups that you want the user to be added to.
These values can be obtained from the groups endpoint.
curl -H 'Authorization: Bearer {api-key}' \
-H 'Content-Type: application/json' \
-d '{ "assessmentId": "C66496F2-35A7-465D-BB3B-58F6AF5CAEDB", "givenName": "Steve", "surName": "Stevenson", "emailAddress": "steve.stevenson@example.com"}' \
-X POST https://api.truenorthtest.com/2020q1/assign/
On success, the response contains the TrueNorth userId of the user for whom the assessment was assigned
and the userAssessmentId which is the unique id of that assessment.
It will also include a signInUrl as described in the generate auto sign in link endpoint.
On failure, the response returns an array of errors which describe the problem.
The HTTP status code will be 400 if the request was unacceptable, or 409 if the request could not be processed.
{
"userId": "a3a0ff2d-6817-47b9-b9db-fc6674bced8a",
"userAssessmentId": "79fb94aa-344d-43a2-8504-13ed687dd77a",
"signInUrl": "https://operationsservice.truenorthtest.com/api/users/sign-in-with-token?token=adb1a12a-fda3-4957-bf89-389fb46decf0",
"signInUrlExpiresAt": "2020-01-23T21:37:14.3430665+00:00"
}
The create-sign-in-token endpoint creates a single-use link that a user can click to automatically log in, bypassing the login form.
The link expires after 5 minutes.
curl -H 'Authorization: Bearer {api-key}' \
-H 'Content-Type: application/json' \
-d '{"uniqueIdentifier": "a006d339-4ad0-4679-a37e-0fa36f069301"}' \
-X POST https://api.truenorthtest.com/2020q1/create-sign-in-token/
On success, the response contains the signInUrl that a user can use to bypass the login form. The link is single-use and expires after 5 minutes as indicated by the expiresAt value.
If the user could not be found, a 204 status code will be returned.
A 400 response with an array of errors is returned in the response body when the request is invalid.
{
"signInUrl": "https://operationsservice.truenorthtest.com/api/users/sign-in-with-token?token=6c42c316-9ba6-4abc-b92e-3b887b35b9a0",
"expiresAt": "2020-01-17T21:58:33.8677872+00:00"
}
The score endpoint retrieves the data for all assessments and scores assigned to the specified user.
curl -H 'Authorization: Bearer {api-key}' \
-H 'Content-Type: application/json' \
-d '{"uniqueIdentifier": "a006d339-4ad0-4679-a37e-0fa36f069301"}' \
-X POST https://api.truenorthtest.com/2020q1/score/
On success, each item in the scoreReports array specifies an assessment assigned to the user, identified by userAssessmentId.
It includes the status of the assessment and the score (if the assessment was completed).
The possible status values are:
NotStarted - when the assessment has been assigned but the user has not started itInProgress - the user has started, but not yet completed the assessmentScorePending - the user finished the assessment, but it has not yet been scoredCompleted - the assessment has been finished and scoredNeedsReview - an error occurred during the assessment which our team is investigating
For TrueNorth assessments, the score will be a value from 0 to 10, with .1 increments.
WebCAPE scores range from 0 to 1000, with whole number increments.
WebCAPE assessment may also show a placement field based on the score.
These placement values and their cutpoints are customizable for an account from the admin dashboard.
Many of the fields returned may be null or empty depending on the assessmentType (whether it was a TrueNorth or WebCAPE assessment) as you can see in the example response below.
If the user could not be found, a 204 status code will be returned.
A 400 response with an array of errors is returned in the response body when the request was invalid.
{
"userId": "615ba72f-f8a6-462a-b2b2-19d1952d1372",
"givenName": "John",
"surname": "Smith",
"username": "john-smith",
"email": "john-smith@example.com",
"studentId": "1234567890",
"uniqueIdentifier": "5799134",
"scoreReports": [
{
"userAssessmentId": "79fb94aa-344d-43a2-8504-13ed687dd77a",
"assessmentType": "WebCAPE",
"assessmentName": "English Grammar",
"status": "Completed",
"started": "2019-09-10T16:29:29.9074258+00:00",
"completed": "2019-09-10T16:30:13.7087307+00:00",
"duration": "00:00:43.8013049",
"score": 825.00,
"placement": "Semester 4",
"proficiencyLevelDescription": null,
"actflSpeakingLevel": null,
"actflDescription": null,
"cefrSpeakingLevel": null,
"cefrDescription": null,
"toeflSpeakingLevel": null,
"ieltsSpeakingLevel": null,
"toeicSpeakingLevel": null,
"diagnosticInfo": [],
"openResponses": [],
"surveyItems": [
{
"question": "What is the highest level of education that you have completed?",
"answer": "graduate degree"
},
{
"question": "Please list any additional languages you speak",
"answer": ""
},
{
"question": "What is your native language?",
"answer": "Spanish"
},
{
"question": "How many years have you been learning English? (in years)",
"answer": "2"
}
],
"subScores": {
"reading": {
"correct": 1,
"total": 2
},
"grammar": {
"correct": 14,
"total": 16
},
"listening": {
"correct": 0,
"total": 0
},
"vocabulary": {
"correct": 1,
"total": 1
}
},
"assessmentVersion": "A.20.01"
},
{
"userAssessmentId": "f8f04710-c569-4afa-9f28-f71cef73f7eb",
"assessmentType": "TrueNorth",
"assessmentName": "English Speaking",
"status": "Completed",
"started": "2019-07-29T18:01:08.8605745+00:00",
"completed": "2019-07-29T18:03:58.5438205+00:00",
"duration": "00:02:49.6832460",
"score": 8.00,
"placement": null,
"proficiencyLevelDescription": "Individuals at this level can express themselves freely and spontaneously, and for the most part accurately, on concrete topics and on most complex issues. They can usually support their opinion and develop hypotheses on topics of particular interest or personal expertise.",
"actflSpeakingLevel": "Advanced Mid - Advanced High",
"actflDescription": "ACTFL Overall Speaking Guideline: Speakers at the Advanced High sublevel perform all Advanced-level tasks with linguistic ease, confidence, and competence. They are consistently able to explain in detail and narrate fully and accurately in all time frames.",
"cefrSpeakingLevel": "B2-C1",
"cefrDescription": "CEFR Overall Production Description: Can give clear, detailed descriptions and presentations on complex subjects, integrating sub-themes, developing particular points and rounding off with an appropriate conclusion.",
"toeflSpeakingLevel": "25-27",
"ieltsSpeakingLevel": "7 - 7.5",
"toeicSpeakingLevel": "170-180",
"diagnosticInfo": [
"Focus on learning and using phrasal verbs (verb + preposition pairs that together form new meaning, ex. \"it just came up\")",
"Listen to native speakers for examples of idioms (ex. \"piece of cake\"). Practice intentionally using idioms in your speech.",
"Consider asking a language-learning partner to occasionally, unexpectedly confront you with unanticipated situations for practice.",
"Search for opportunities to listen to native speakers talk about divisive, hypothetical, or abstract topics.",
"Read as much as you can. Re-read complex passages to ensure you understand all of the words through context."
],
"openResponses": [
{
"question": "What is your favorite book and why?",
"responseAudioUrl": "2020q1/response-audio/50c76e88-11a8-486e-b283-cf0952651eef/fd1b0881-4506-4436-b5b0-d0e1215b8410"
},
{
"question": "Describe an experience when you got hurt. How did it happen and what did you do afterwards?",
"responseAudioUrl": "2020q1/response-audio/50c76e88-11a8-486e-b283-cf0952651eef/2d892090-adff-46fc-ae5c-b2689b158dc3"
},
{
"question": "How did you meet your best friend? What were the circumstances?",
"responseAudioUrl": "2020q1/response-audio/50c76e88-11a8-486e-b283-cf0952651eef/b85f78f8-4d06-4db8-9198-cfea34d41049"
}
],
"surveyItems": [],
"subScores": null,
"assessmentVersion": "C.19.04"
},
{
"userAssessmentId": "bdcceba8-14f1-4fe4-b8db-c98e2f2e4202",
"assessmentType": "TrueNorth",
"assessmentName": "Spanish Speaking",
"status": "NotStarted",
"started": null,
"completed": null,
"duration": null,
"score": 0.0,
"placement": null,
"proficiencyLevelDescription": null,
"actflSpeakingLevel": null,
"actflDescription": null,
"cefrSpeakingLevel": null,
"cefrDescription": null,
"toeflSpeakingLevel": null,
"ieltsSpeakingLevel": null,
"toeicSpeakingLevel": null,
"diagnosticInfo": [],
"openResponses": [],
"surveyItems": [],
"subScores": null,
"assessmentVersion": null
}
]
}
The scores endpoint retrieves the data for all assessments and scores for the account.
groupId values; only scores for users in the specified groups will be returned. If empty, scores for all users will be returned.
curl -H 'Authorization: Bearer {api-key}' \
-H 'Content-Type: application/json' \
-d '{"startedOnOrAfter": "2019-11-14T00:00:00Z"}' \
-X POST https://api.truenorthtest.com/2020q1/scores/
On success, the response body will contain a userScores array, where each item is identical to the format returned by the user scores endpoint.
It will also include an appliedFilters object that reflects the request filters that were provided.
{
"appliedFilters": {
"includeIncompleteAssessments": false,
"groupIds": null,
"startedOnOrAfter": "2019-11-14T00:00:00+00:00",
"startedOnOrBefore": null
},
"userScores": [
{
"userId": "615ba72f-f8a6-462a-b2b2-19d1952d1372",
"givenName": "John",
"surname": "Smith",
"username": "john-smith",
"email": "john-smith@example.com",
"studentId": "1234567890",
"uniqueIdentifier": "5799134",
"scoreReports": [
{
"userAssessmentId": "99807cea-1225-41e6-a271-eb7e8a732d1b",
"assessmentType": "WebCAPE",
"assessmentName": "English Grammar",
"status": "Completed",
"started": "2019-09-10T16:29:29.9074258+00:00",
"completed": "2019-09-10T16:30:13.7087307+00:00",
"duration": "00:00:43.8013049",
"score": 825.00,
"placement": "Semester 4",
"proficiencyLevelDescription": null,
"actflSpeakingLevel": null,
"actflDescription": null,
"cefrSpeakingLevel": null,
"cefrDescription": null,
"toeflSpeakingLevel": null,
"ieltsSpeakingLevel": null,
"toeicSpeakingLevel": null,
"diagnosticInfo": [],
"openResponses": [],
"surveyItems": [
{
"question": "What is the highest level of education that you have completed?",
"answer": "graduate degree"
},
{
"question": "Please list any additional languages you speak",
"answer": ""
},
{
"question": "What is your native language?",
"answer": "Spanish"
},
{
"question": "How many years have you been learning English? (in years)",
"answer": "2"
}
],
"subScores": {
"reading": {
"correct": 1,
"total": 2
},
"grammar": {
"correct": 14,
"total": 16
},
"listening": {
"correct": 0,
"total": 0
},
"vocabulary": {
"correct": 1,
"total": 1
}
},
"assessmentVersion": "A.20.01"
}
]
},
{
"userId": "e19d106d-22c5-458a-bb0a-957393453084",
"givenName": "Jenny",
"surname": "Doe",
"username": "jenny-doe",
"email": "jenny-doe@example.com",
"studentId": "8675309",
"uniqueIdentifier": "5412349",
"scoreReports": [
{
"userAssessmentId": "8e61a04f-29c4-4d9e-a103-a559362455de",
"assessmentType": "TrueNorth",
"assessmentName": "English Speaking",
"status": "Completed",
"started": "2019-07-29T18:01:08.8605745+00:00",
"completed": "2019-07-29T18:03:58.5438205+00:00",
"duration": "00:02:49.6832460",
"score": 8.00,
"placement": null,
"proficiencyLevelDescription": "Individuals at this level can express themselves freely and spontaneously, and for the most part accurately, on concrete topics and on most complex issues. They can usually support their opinion and develop hypotheses on topics of particular interest or personal expertise.",
"actflSpeakingLevel": "Advanced Mid - Advanced High",
"actflDescription": "ACTFL Overall Speaking Guideline: Speakers at the Advanced High sublevel perform all Advanced-level tasks with linguistic ease, confidence, and competence. They are consistently able to explain in detail and narrate fully and accurately in all time frames.",
"cefrSpeakingLevel": "B2-C1",
"cefrDescription": "CEFR Overall Production Description: Can give clear, detailed descriptions and presentations on complex subjects, integrating sub-themes, developing particular points and rounding off with an appropriate conclusion.",
"toeflSpeakingLevel": "25-27",
"ieltsSpeakingLevel": "7 - 7.5",
"toeicSpeakingLevel": "170-180",
"diagnosticInfo": [
"Focus on learning and using phrasal verbs (verb + preposition pairs that together form new meaning, ex. \"it just came up\")",
"Listen to native speakers for examples of idioms (ex. \"piece of cake\"). Practice intentionally using idioms in your speech.",
"Consider asking a language-learning partner to occasionally, unexpectedly confront you with unanticipated situations for practice.",
"Search for opportunities to listen to native speakers talk about divisive, hypothetical, or abstract topics.",
"Read as much as you can. Re-read complex passages to ensure you understand all of the words through context."
],
"openResponses": [
{
"question": "What is your favorite book and why?",
"responseAudioUrl": "2020q1/response-audio/50c76e88-11a8-486e-b283-cf0952651eef/fd1b0881-4506-4436-b5b0-d0e1215b8410"
},
{
"question": "Describe an experience when you got hurt. How did it happen and what did you do afterwards?",
"responseAudioUrl": "2020q1/response-audio/50c76e88-11a8-486e-b283-cf0952651eef/2d892090-adff-46fc-ae5c-b2689b158dc3"
},
{
"question": "How did you meet your best friend? What were the circumstances?",
"responseAudioUrl": "2020q1/response-audio/50c76e88-11a8-486e-b283-cf0952651eef/b85f78f8-4d06-4db8-9198-cfea34d41049"
}
],
"surveyItems": [],
"subScores": null,
"assessmentVersion": "C.19.04"
},
{
"userAssessmentId": "99a17dd0-dc41-47a1-8c7e-400734800c0f",
"assessmentType": "TrueNorth",
"assessmentName": "Spanish Speaking",
"status": "NotStarted",
"started": null,
"completed": null,
"duration": null,
"score": 0.0,
"placement": null,
"proficiencyLevelDescription": null,
"actflSpeakingLevel": null,
"actflDescription": null,
"cefrSpeakingLevel": null,
"cefrDescription": null,
"toeflSpeakingLevel": null,
"ieltsSpeakingLevel": null,
"toeicSpeakingLevel": null,
"diagnosticInfo": [],
"openResponses": [],
"surveyItems": [],
"subScores": null,
"assessmentVersion": null
}
]
}
]
}
The response-audio endpoint returns the audio file for an open response item, as specified from the user scores endpoint.
Open response items provide you examples of the user speaking the language.
responseAudioUrl links provided from the user scores endpoint.
curl -H 'Authorization: Bearer {api-key}' \
https://api.truenorthtest.com/2020q1/response-audio/3f4eda6e-1a64-4c3d-9724-360ce7f8e549/7005c513-55cb-4aac-94e6-7d3bc0b992e4
Content-Type: audio/wav).
The POST webhook endpoint allows you to register a webhook URL which the TrueNorth
system will POST to whenever a relevant event occurs in the system
(e.g. when a user assessment is scored).
Only one webhook may be registered; calling this endpoint will overwrite previous values.
curl -H 'Authorization: Bearer {api-key}' \
-H 'Content-Type: application/json' \
-d '{"url": "https://example.com/webhook/truenorth"}' \
-X POST https://api.truenorthtest.com/2020q1/webhook
200 status code with no response body on success,
or a 400 status code if the provided URL is not a properly formed, absolute http/https url.
The GET webhook endpoint returns the currently registered webhook url.
curl -H 'Authorization: Bearer {api-key}' \
https://api.truenorthtest.com/2020q1/webhook
url along with the createdAt timestamp
if a webhook is currently registered.
Otherwise it will return a 204 status code.
{
"url": "https://example.com/webhook/truenorth",
"createdAt": "2020-01-22T16:30:13.7087307+00:00"
}
The DELETE webhook endpoint allows you to unregister your webhook.
No further events will be sent until you register a new one.
curl -H 'Authorization: Bearer {api-key}' \
-X DELETE https://api.truenorthtest.com/2020q1/webhook
204 status code on success.
The webhook/example endpoint allows you to trigger an example event which will cause your webhook to be called.
You may use this to test that your webhook URL is configured correctly
and that your server can process the POST request.
Note that the example event will be triggered no more frequently than once per second.
curl -H 'Authorization: Bearer {api-key}' \
-X POST https://api.truenorthtest.com/2020q1/webhook/example
200 status code with no response body when the event was triggered successfully.
However, this does not mean that the webhook was called successfully.
This event is triggered when a user assessment is scored.
The data has the same format as the get user scores endpoint,
except it will only return a single item in the scoreReports array for the user assessment that was just scored.
Here is an example of the event data:
{
"event": "user-assessment-scored",
"data": {
"userId": "615ba72f-f8a6-462a-b2b2-19d1952d1372",
"givenName": "John",
"surname": "Smith",
"username": "john-smith",
"email": "john-smith@example.com",
"studentId": "1234567890",
"uniqueIdentifier": "5799134",
"scoreReports": [
{
"userAssessmentId": "79fb94aa-344d-43a2-8504-13ed687dd77a",
"assessmentType": "WebCAPE",
"assessmentName": "English Grammar",
"status": "Completed",
"started": "2019-09-10T16:29:29.9074258+00:00",
"completed": "2019-09-10T16:30:13.7087307+00:00",
"duration": "00:00:43.8013049",
"score": 825.00,
"placement": "Semester 4",
"proficiencyLevelDescription": null,
"actflSpeakingLevel": null,
"actflDescription": null,
"cefrSpeakingLevel": null,
"cefrDescription": null,
"toeflSpeakingLevel": null,
"ieltsSpeakingLevel": null,
"toeicSpeakingLevel": null,
"diagnosticInfo": [],
"openResponses": [],
"surveyItems": [
{
"question": "What is the highest level of education that you have completed?",
"answer": "graduate degree"
},
{
"question": "Please list any additional languages you speak",
"answer": ""
},
{
"question": "What is your native language?",
"answer": "Spanish"
},
{
"question": "How many years have you been learning English? (in years)",
"answer": "2"
}
],
"subScores": {
"reading": {
"correct": 1,
"total": 2
},
"grammar": {
"correct": 14,
"total": 16
},
"listening": {
"correct": 0,
"total": 0
},
"vocabulary": {
"correct": 1,
"total": 1
}
},
"assessmentVersion": "A.20.01"
}
]
}
}
This event is triggered by calling the example webhook event endpoint.
The example event data will always contain the same JSON:
{
"event":"webhook-example",
"data":{
"userId":"00000000-0000-0000-0000-000000000000",
"givenName":"John",
"surname":"Smith",
"username":"john-smith",
"email":"john-smith@example.com",
"studentId":"",
"uniqueIdentifier":"",
"scoreReports":[]
}
}
No. For security reasons, we do not store the raw API key values in our system. Instead, we store a hashed value which allows us to verify an API key without knowing the original value (similar to password storage practices).
If you have lost your API key or believe it may have been compromised, log into the administrative dashboard and use the API Keys settings page to replace it. After creating a new key, revoke the old one to maintain security on your account.
The uniqueIdentifier field is the value that the system uses to identify the user.
While this field may be a student id, it may also be a number of other types of identifiers.
There are two separate fields to cover the following scenarios:
First, in some instances, you may want to use something other than a student id as the unique identifier, but you also want to associate a student id to a user to make associations with the scoring data easier.
In this case, uniqueIdentifier and studentId may be different values.
Second, you may want to use student id as both the uniqueIdentifier and studentId.
If you were to just enter the student id as the uniqueIdentifier, we would have no way of knowing that this value is also the student id.
This means that we can't make that association in the administrative dashboard and in the scoring endpoints.