Introduction

Overview

The Emmersion Enterprise API allows customers to integrate with the TrueNorth and WebCAPE 2.0 platform.

All usage examples are given as curl commands.

This page details the individual endpoints. For more information about common patterns and use cases for the API, please see our API Integration Guide.

API Versioning

The API uses a url-based versioning scheme which indicates when it was released, such as /2020q3 for quarter 3 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 latest version of the API is: https://api.emmersion.ai/2020q3

Documentation for other versions of the API can be found here.

Authentication

An API key is required with every request to the API. It must be sent in an Authorization header as a Bearer token (never as a query string parameter). 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.

Revoking an API key immediately cuts off access to the Enterprise API and that key is no longer usable (though a new one can be generated).

Emmersion reserves the right to revoke an API key if we observe suspicious, abusive, malicious, or excessive behavior. Whenever possible, we will reach out before taking this drastic action.

API Keys can also be revoked from the administrative dashboard. Please revoke and replace any API key you have reason to believe is compromised. Doing so helps keep your account secure.

Rate Limiting

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.

Security

All requests to our API must be secure (HTTPS) connections using TLS 1.2 or higher. Also, please note that our certificate may change unexpectedly; we do not support certificate pinning.

We do not provide a list of IP addresses for our API or webhook functionality because of how our system is hosted and the potential for spoofing IPs. Calling the API should always be done by the URL, not directly by IP address, and the default Host header should be present.

Webhook

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.

When a webhook is registered, a signing key will be returned that can be used to verify the authenticity of the request. This signing key cannot be retrieved after webhook registration.

We provide a signature in the X-Signature HTTP header. The signature is calculated using the signing key which is provided when registering a webhook. To calculate the signature concatenate the SHA-256 of the content (provided in the X-Content-SHA256 header) and the timestamp (provided in the X-Request-Timestamp header) separated by a semicolon.

For example, for a webhook with a signing key of AIFzHU25nf6XKz97ecmeH+IcRY5pR2AYEcUmp3kC9jg=, if you receive a request with the following headers:

    X-Content-SHA256: aZ4ZT4GuK02F89ShnhQzEcxHlvx0HCADngDcCGsgjCI=
    X-Request-Timestamp: 2021-11-10T17:34:16.1622931+00:00
    X-Signature: Algorithm=HMAC-SHA256; Signature=ZhUstTlHnebfK6sId90HEfXEDQP/Z3f9dCEDFgEyLTU=

Since the X-Content-SHA256 header value is aZ4ZT4GuK02F89ShnhQzEcxHlvx0HCADngDcCGsgjCI=, the X-Request-Timestamp header value is 2021-11-10T17:34:16.1622931+00:00, and the signing key returned when registering the webhook is AIFzHU25nf6XKz97ecmeH+IcRY5pR2AYEcUmp3kC9jg=, then computing the HMAC-SHA256 of aZ4ZT4GuK02F89ShnhQzEcxHlvx0HCADngDcCGsgjCI=;2021-11-10T17:34:16.1622931+00:00 should give a result of ZhUstTlHnebfK6sId90HEfXEDQP/Z3f9dCEDFgEyLTU=. That value should match the signature value in the X-Signature header. You should also validate that the SHA-256 hash of the body matches to prevent replay attacks.

For webhooks generated before November 2021 no signature will be provided. If you wish to begin validating webhook requests, regenerate your webhook by calling the register webhook endpoint again with the same url.

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.

Endpoints

Get List of Assessments

The assessments endpoint returns the list of assessments available to your account.

Endpoint
GET https://api.emmersion.ai/2020q3/assessments
Example Request
curl -H 'Authorization: Bearer api-key' \
     https://api.emmersion.ai/2020q3/assessments
Response
The response body will contain the name and assessmentId for each assessment. The assessmentId values may be required to use other endpoints.
Example Response
{
    "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"
        },
    ]
}
Get List of Groups

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.

Endpoint
GET https://api.emmersion.ai/2020q3/groups
Example Request
curl -H 'Authorization: Bearer api-key' \
     https://api.emmersion.ai/2020q3/groups
Response
The response body will contain the name and groupId for each group associated with your account.
Example Response
                            {
    "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"
        }
    ]
}

                            
Create Group

The POST groups endpoint creates a new group on the account.

Endpoint
POST https://api.emmersion.ai/2020q3/groups
Request Body
name
The name of the new group
Example Request
curl -H 'Authorization: Bearer api-key' \
     -H 'Content-Type: application/json' \
     -d '{"name": "English speaking"}' \
     -X POST https://api.emmersion.ai/2020q3/groups
Response
The response body will contain the name and groupId of the newly created group.
Example Response
                            {
    "name": "English speaking",
    "groupId": "80843e92-5be1-46aa-9472-2862d11413b3"
}

                            
Create User/Assign Assessment to User

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.

Endpoint
POST https://api.emmersion.ai/2020q3/assign
Request Body
assessmentId
The assessmentId for the assessment you are assigning (see the assessments endpoint)
givenName
The given name of the user to whom you are assigning the assessment
surName
The surname of the user to whom you are assigning the assessment
emailAddress
The email address of the user to whom you are assigning the assessment. Either 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).
uniqueIdentifier
Your unique identifier to associate with the user to whom you are assigning the assessment, such as a student or employee id. This value may not exceed 200 characters. Either emailAddress or uniqueIdentifier is required.
studentId
An optional string specifying a student id when creating a user (the value is not updated on subsequent assignment calls). This value is returned in the scoring endpoints and in certain admin dashboard reports. If you are using student id as the uniqueIdentifier above, you will also need to provide it here in order to have this value returned as studentId in the scoring endpoints.
assignedGroups
An array of the groupId values matching the groups that you want the user to be added to. These values can be obtained from the groups endpoint.
returnUrl
An optional absolute url where the user will be directed when they complete the assessment. When the user visits this url, that is a signal that you can request the user's score from the user scores endpoint.
Example Request
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.emmersion.ai/2020q3/assign/
Response

On success, the response contains the Emmersion userId of the user for whom the assessment was assigned and the userAssessmentId which is the unique id of that assessment. It will include a signInUrl as described in the generate auto sign in link endpoint. Additionally a singleAssessmentSignInUrl will be returned. This url allows the test taker to sign in exclusively to this assessment, and can be used multiple times. It also has a much longer expiration time than the signInUrl.

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.

Example Response
{
    "userId": "a3a0ff2d-6817-47b9-b9db-fc6674bced8a",
    "userAssessmentId": "79fb94aa-344d-43a2-8504-13ed687dd77a",
    "signInUrl": "https://app-api.emmersion.ai/api/users/sign-in-with-token?token=adb1a12a-fda3-4957-bf89-389fb46decf0",
    "signInUrlExpiresAt": "2020-01-23T21:37:14.3430665+00:00",
    "singleAssessmentSignInUrl": "https://localhost:44357/api/users/sign-in-with-token?token=pN9mngpPoic1%2fUe87yWvu411xEcDUYx8AoZ8GPosRLgIjxEgGVG8GIEZOjrfsu6VMQlfgKTm13Xg7%2bwJpTVTNQ%3d%3d",
    "singleAssessmentSignInUrlExpiresAt": "2021-06-23T21:37:14.3430665+00:00"
}
Generate auto sign in link

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 for security compliance.

Endpoint
POST https://api.emmersion.ai/2020q3/create-sign-in-token
Request Body
At least one of userId, emailAddress, or uniqueIdentifier is required
userId
The Emmersion identifier for the user
emailAddress
The email address of the user
uniqueIdentifier
Your unique identifier for the user (if you provided one via the assign endpoint)
userAssessmentId
The id of the assessment for the user to be taken to upon sign-in (value obtained from the assign endpoint). If omitted, the user will be taken to their dashboard.
Example Request
curl -H 'Authorization: Bearer api-key' \
     -H 'Content-Type: application/json' \
     -d '{"uniqueIdentifier": "a006d339-4ad0-4679-a37e-0fa36f069301"}' \
     -X POST https://api.emmersion.ai/2020q3/create-sign-in-token/
Response

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.

Example Response
{
    "signInUrl": "https://app-api.emmersion.ai/api/users/sign-in-with-token?token=6c42c316-9ba6-4abc-b92e-3b887b35b9a0",
    "expiresAt": "2020-01-17T21:58:33.8677872+00:00"
}
Get Assignments

The assignments endpoint returns a list of assignments from a specified assigned on date, optionally filtered by a list of assessment statuses.

Endpoint
POST https://api.emmersion.ai/2020q3/assignments
Request Body
assignedOnOrAfter
This is required. Only return assessments started on or after the given date (ISO-8601 format is recommended)
assignedOnOrBefore
Only return assessments started on or before the given date (ISO-8601 format is recommended)
statuses
A list of assesment statuses to include (everything will be included by default).

Valid values are:

  • NotStarted
  • InProgress
  • Completed
Example Request
curl -H 'Authorization: Bearer api-key' \
     -H 'Content-Type: application/json' \
     -d '{"assignedOnOrAfter": "2023-03-28T00:00:00Z", "statuses": ["NotStarted", "InProgress"], "assignedOnOrBefore": "2023-03-28T12:45:00Z"}' \
     -X POST https://api.emmersion.ai/2020q3/assignments/ 
            
Response

On success, the response contains the assignments that were made during the specified date range. If statuses were specified, only assignments that are currently in the specified status will be included.

A 400 response with a problem detail object describing the error is returned if the request is invalid.

Example Response

{
  "assignments": [
    {
      "userId": "b13b45fe-4fb8-4667-a2cf-61401f259c69",
      "uniqueIdentifier": null,
      "email": "user@example.com",
      "username": "user@example.com",
      "givenName": "First",
      "surName": "Last",
      "assessmentName": "English Speaking",
      "userAssessmentId": "f61835eb-a8e1-4fb7-b86e-d57e1b1fc4eb",
      "userAssessmentStatus": "NotStarted",
      "assignedAt": "2023-03-01T21:51:00.4925066+00:00",
      "expiresAt": "2023-03-31T21:51:00.4925066+00:00",
      "startedAt": null,
      "completedAt": null
    }]
}
Get User Scores

The score endpoint retrieves the data for all assessments and scores assigned to the specified user.

Endpoint
POST https://api.emmersion.ai/2020q3/score
Request Body
At least one of the following is required
userId
The Emmersion identifier for the user
emailAddress
The email address of the user
uniqueIdentifier
Your unique identifier for the user (if you provided one via the assign endpoint)
Example Request
curl -H 'Authorization: Bearer api-key' \
     -H 'Content-Type: application/json' \
     -d '{"uniqueIdentifier": "a006d339-4ad0-4679-a37e-0fa36f069301"}' \
     -X POST https://api.emmersion.ai/2020q3/score/
Response

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 it
  • InProgress - the user has started, but not yet completed the assessment
  • ScorePending - the user finished the assessment, but it has not yet been scored
  • Completed - the assessment has been finished and scored
  • NeedsReview - 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.

Example Response
{
    "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": [],
            "writingOpenResponses": [],
            "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",
            "certificateUrl": null
        },
        {
            "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": "2020q3/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": "2020q3/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": "2020q3/response-audio/50c76e88-11a8-486e-b283-cf0952651eef/b85f78f8-4d06-4db8-9198-cfea34d41049"
                }
            ],
            "writingOpenResponses": [],
            "surveyItems": [],
            "subScores": null,
            "assessmentVersion": "C.19.04",
            "certificateUrl": "2020q3/certificate/50c76e88-11a8-486e-b283-cf0952651eef"
        },
        {
            "userAssessmentId": "0e414961-4317-4458-814c-b04ab2b50e55",
            "assessmentType": "TrueNorth",
            "assessmentName": "English Writing",
            "status": "Completed",
            "started": "2021-12-14T18:01:08.8605745+00:00",
            "completed": "2021-12-14T18:03:58.5438205+00:00",
            "duration": "00:02:49.6832460",
            "score": 7.20,
            "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": [],
            "writingOpenResponses": [
                {
                    "question": "Write about a time when you went to dinner at a restaurant and received poor service or food from the restaurant staff.",
                    "responseTextUrl": "2020q3/response-text/0e414961-4317-4458-814c-b04ab2b50e55/item/e09ad147-b01c-425c-a226-399f56c2ccf4"
                }
            ],
            "surveyItems": [],
            "subScores": null,
            "assessmentVersion": "C.19.04",
            "certificateUrl": "2020q3/certificate/0e414961-4317-4458-814c-b04ab2b50e55"
        },
        {
            "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": [],
            "writingOpenResponses": [],
            "surveyItems": [],
            "subScores": null,
            "assessmentVersion": null,
            "certificateUrl": null,
        }
    ]
}
Get All Scores

The scores endpoint retrieves the data for all assessments and scores for the account.

Endpoint
POST https://api.emmersion.ai/2020q3/scores
Request Body
All parameters in the request body are optional, and are used to filter the result set
groupIds
A JSON array of groupId values; only scores for users in the specified groups will be returned. If empty, scores for all users will be returned.
startedOnOrAfter
Only return assessments started on or after the given date (ISO-8601 format is recommended)
startedOnOrBefore
Only return assessments started on or before the given date (ISO-8601 format is recommended)
completedOnOrAfter
Only return assessments completed on or after the given date (ISO-8601 format is recommended)
completedOnOrBefore
Only return assessments completed on or before the given date (ISO-8601 format is recommended)
includeIncompleteAssessments
Whether incomplete assessments will be returned. If completedOnOrAfter or completedOnOrBefore are provided, this parameter is ignored.
Example Request
curl -H 'Authorization: Bearer api-key' \
     -H 'Content-Type: application/json' \
     -d '{"startedOnOrAfter": "2019-11-14T00:00:00Z"}' \
     -X POST https://api.emmersion.ai/2020q3/scores/
Example Request
curl -H 'Authorization: Bearer api-key' \
     -H 'Content-Type: application/json' \
     -d '{"startedOnOrBefore": "2019-11-14T00:00:00Z", "includeIncompleteAssessments": true, "groupIds": ["83ccbdeb-6fcf-46c8-a898-0530b4a59707", "79340353-f0ea-4ea7-9c89-ce86c411b3b6"]}' \
     -X POST https://api.emmersion.ai/2020q3/scores/
Response

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.

Example Response
{
    "appliedFilters": {
        "includeIncompleteAssessments": false,
        "groupIds": null,
        "startedOnOrAfter": "2019-11-14T00:00:00+00:00",
        "startedOnOrBefore": null,
        "completedOnOrAfter": null,
        "completedOnOrBefore": 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": [],
                    "writingOpenResponses": [],
                    "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",
                    "certificateUrl": null
                }
            ]
        },
        {
            "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": "2020q3/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": "2020q3/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": "2020q3/response-audio/50c76e88-11a8-486e-b283-cf0952651eef/b85f78f8-4d06-4db8-9198-cfea34d41049"
                        }
                    ],
                    "writingOpenResponses": [],
                    "surveyItems": [],
                    "subScores": null,
                    "assessmentVersion": "C.19.04",
                    "certificateUrl": "2020q3/certificate/50c76e88-11a8-486e-b283-cf0952651eef"
                },
                {
                    "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": [],
                    "writingOpenResponses": [],
                    "surveyItems": [],
                    "subScores": null,
                    "assessmentVersion": null,
                    "certificateUrl": null
                }
            ]
        }
    ]
}
Download Open Response Audio

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.

Endpoint
GET https://api.emmersion.ai/{responseAudioUrl}
URI Variables
When using this endpoint, use the responseAudioUrl links provided from the user scores endpoint.
Example Request
curl -H 'Authorization: Bearer api-key' \
     https://api.emmersion.ai/2020q3/response-audio/3f4eda6e-1a64-4c3d-9724-360ce7f8e549/7005c513-55cb-4aac-94e6-7d3bc0b992e4
Response
Returns the audio data that the user recorded for the open response question. Note that unlike the other endpoints, this endpoint returns raw binary data rather than JSON. The response headers will specify the format of the file (e.g. Content-Type: audio/wav).
Download Open Response Writing Sample

The response-text endpoint returns the text file for a writing open response item, as specified from the user scores endpoint. Writing open response items provide you examples of the user writing the language.

Endpoint
GET https://api.emmersion.ai/{responseTextUrl}
URI Variables
When using this endpoint, use the responseTextUrl links provided from the user scores endpoint.
Example Request
curl -H 'Authorization: Bearer api-key' \
     https://api.emmersion.ai/2020q3/response-text/3f4eda6e-1a64-4c3d-9724-360ce7f8e549/item/7005c513-55cb-4aac-94e6-7d3bc0b992e4
Response
Returns the submission that the user provided for the written open response question. Note that unlike the other endpoints, this endpoint returns raw text data rather than JSON. The response headers will specify the format of the file (e.g. Content-Type: text/plain; charset=utf-8).
Download Score Certificate

TrueNorth Speaking and Writing assessments include a pdf certificate for the user's score. The certificate endpoint allows you to download these certificates via the API. The user scores endpoint will provide a link to the certificate for a given user assessment.

Endpoint
GET https://api.emmersion.ai/{certificateUrl}
URI Variables
When using this endpoint, use the certificateUrl links provided from the user scores endpoint.
Example Request
curl -H 'Authorization: Bearer api-key' \
     https://api.emmersion.ai/2020q3/certificate/3f4eda6e-1a64-4c3d-9724-360ce7f8e549
Response
Returns the PDF certificate of ability for the user. Note that unlike the other endpoints, this endpoint returns raw binary data rather than JSON. The response headers will specify the format of the file (e.g. Content-Type: application/pdf).
Register Webhook

The POST webhook endpoint allows you to register a webhook URL which the Emmersion 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. The signing key cannot be retrieved after webhook registration.

Endpoint
POST https://api.emmersion.ai/2020q3/webhook
Request Body
url
The fully qualified url for your webhook; the location where event data will be sent. We strongly recommend this be a secure (HTTPS) endpoint.
Example Request
curl -H 'Authorization: Bearer api-key' \
     -H 'Content-Type: application/json' \
     -d '{"url": "https://example.com/webhook/emmersion"}' \
     -X POST https://api.emmersion.ai/2020q3/webhook
Response
Returns a 200 status code with the signing key that will be needed for request verification, or a 400 status code if the provided URL is not a properly formed, absolute http/https url.
Example Response
{
    "signingKey": "IQAjTiRFweYusQZL8GSOE+2KiA3si4Rk/kQbTBbXS6k="
}
Get Webhook

The GET webhook endpoint returns the currently registered webhook url.

Endpoint
GET https://api.emmersion.ai/2020q3/webhook
Example Request
curl -H 'Authorization: Bearer api-key' \
     https://api.emmersion.ai/2020q3/webhook
Response
Returns the registered url along with the createdAt timestamp if a webhook is currently registered. Otherwise it will return a 204 status code.
Example Response
{
  "url": "https://example.com/webhook/emmersion",
  "createdAt": "2020-01-22T16:30:13.7087307+00:00"
}
Unregister Webhook

The DELETE webhook endpoint allows you to unregister your webhook. No further events will be sent until you register a new one.

Endpoint
DELETE https://api.emmersion.ai/2020q3/webhook
Example Request
curl -H 'Authorization: Bearer api-key' \
     -X DELETE https://api.emmersion.ai/2020q3/webhook
Response
Returns a 204 status code on success.
Example Webhook Event

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.

Endpoint
POST https://api.emmersion.ai/2020q3/webhook/example
Example Request
curl -H 'Authorization: Bearer api-key' \
     -X POST -d '' https://api.emmersion.ai/2020q3/webhook/example
Response
Returns a 200 status code with no response body when the event was triggered successfully. However, this does not mean that the webhook was called successfully.

Webhook Events

User Assessment Scored Event

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": [],
                "writingOpenResponses": [],
                "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",
                "certificateUrl": null
            }
        ]
    }
}
Example Event

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

Misc

FAQ
I lost my API key. Can you send it to me?

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.

Why is there both a uniqueIdentifier field and a studentId field when creating a user and assigning an assessment?

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.

Can I access the API from a web browser? What do I do about CORS errors?

We do not support calling the Enterprise API from JavaScript in a web browser because doing so exposes the API key. If someone were to inspect your page, they could take the API key and then make their own calls indistinguishable from legitimate traffic. Therefore, it does not make sense for us to configure CORS to allow this.

Instead, we recommend that you make all calls to our API from your web servers or other non-web systems.

I tried a curl example and nothing happened. What's going on?

By default, curl only shows the HTTP response body as output. But in some cases, such as an invalid API key, our API may not return a response body. You can add the -i option to a curl command to also view the HTTP status code and response headers. For example:

curl -i -H 'Authorization: Bearer fake-api-key' \
     https://api.emmersion.ai/2020q3/assessments

The -i option is not listed in the examples because the additional output can be confused with the response body.

What do I do if I get an error status code?

When successfully calling the API, you should get mostly 200 OK responses (or possibly some others in the 200-299 range). Here are some of the more common error codes you may encounter:

  • 400 Bad Request - occurs when there is a problem with the formatting of your request. The response body may give you some guidance; otherwise, double check the documentation.
  • 401 Unauthorized - your API key was not provided correctly, is incorrect, or has been revoked. Make sure that you are correctly sending the Authorization header with the Bearer keyword
  • 403 Forbidden - your request specified resources you are not allowed to access.
  • 404 Not Found - the URL for the request was incorrect. Double check it against the endpoint documentation above.
  • 405 Method Not Allowed - make sure you are sending the correct HTTP method (e.g. GET, POST, PUT, or DELETE).
  • 409 Conflict - occurs when you attempt to assign an assessment to an non-eligible test taker, such as administrator on your account.
  • 415 Unsupported Media Type - make sure you have included the correct Content-Type header (i.e. Content-Type: application/json).
  • 429 Too Many Requests - your account has exceeded our rate limits. You may need to throttle your requests.

Any errors in the 500+ range indicate a problem on our end and you should retry your request later.

What format should I use for request bodies? Can I send parameters via query strings?

We recommend all POST request bodies be formatted as JSON and sent with the Content-Type: application/json header as per all of the examples. None of our endpoints accept query string parameters at this time.

Do you have a non-production environment for us to test against?

No, we do not provide a non-production environment (such as staging or UAT) for testing at this time.