This page explains how to use the managed platform REST API to get digital assets such as videos, images, and NER corpus documents into the Alegion platform, create annotation tasks, and retrieve results.
This tutorial explains how to use the API during the lifecycle of a labeling project. If you're already familiar, visit the endpoint documentation for details about each call's parameters, return types, error codes, etc.
Command examples here are for the cURL
command line utility.
Terminology
An "asset" is the video, image, or NER corpus document you want annotated. Most annotation tasks involve an asset, though this is not necessarily the case (see "compound/general tasks").
A "workflow" in the Alegion platform contains all the steps and settings used to annotate your source data. It includes task designs, classification lists, and quality control configurations associated with a project. (For more detail, see the tailored workflows section.)
"Batches" are arbitrary collections of input records, as well as the annotations that get attached. Batches belong to one (and only one) workflow. Our customer success team can provide guidance on batching strategy to optimize for traceability, quality control and delivery.
An "input record" tracks the journey of an asset, in a batch, through a workflow, to produce an annotation result.
Getting Started
After setup, the lifecycle of a project is:
- You upload assets.
- You create a batch within your workflow.
- You create input records in the batch for those assets.
- Labelers work the resulting tasks.
- You download results using various optional criteria, including batch ID.
All of these steps can go on continuously, in parallel. For instance, results can be retrieved while labeling is ongoing, and new input records can be added at any time.
The first section below covers the common API operations performed in that lifecycle. The second section covers some useful but less frequent operations.
A full round trip
Note
Your API key needs to be sent in the x-api-key
header for every request, including /login
.
Authentication
Authenticate by sending a POST request to the /login
endpoint. Retrieve the access_token
from the response body for use in an Authorization
header in all subsequent requests.
Example request
curl -X POST 'https://api.alegion.com/v1/login' \
-H 'x-api-key: {your-api-key}' \
-H 'Content-Type: application/json' \
-H 'cache-control: no-cache' \
--data-raw '{
"username": "{your-username}",
"password": "{your-password}"
}'
Example response
{
"access_token": "access_token",
"expires_in": 3600,
"token_type": "bearer"
}
Token expiration
Access tokens have a defined lifespan, and requests made using an expired token will fail with an HTTP 401
error. Simply make the authentication request again and use the new access token in all subsequent requests.
Tip
Reusing a token is optional. You can make an authorization request for every new transaction in order to avoid dealing with expiration.
Uploading Assets
Because assets tend to be large, part of the upload work has been outsourced directly to our cloud storage provider. Therefore, each asset upload requires several API calls. From a high level, the steps to getting an asset into the Alegion platform are as follows:
-
Register asset
-
Open upload session
-
Upload image or video file
-
Close upload session
Register the asset
First, provide some metadata about your asset
Example request
curl -X POST 'https://api.alegion.com/v1/assets' \
-H 'Content-Type: application/json' \
-H 'x-api-key: {your-api-key}' \
-H 'authorization: Bearer {access_token}' \
--data-raw '{
"name": "cars-1900 from api",
"fileName": "cars-1900.mp4",
"fps": 25,
"frameCount": 1500,
"type": "video"
}'
Example response
{
"id": "c226197c-17c5-4cc6-9529-0098ae771148",
"name": "cars-1900 from api",
"fileName": "cars-1900.mp4",
"status": "uploading",
"source": "file",
"type": "video",
"createdAt": "2021-08-27T21:44:49.866238252Z",
}
The response contains the asset id
, which you will use in subsequent calls related to this asset. Note that the current status of the asset is uploading
.
Create an asset upload session
Example request
curl -X POST 'https://api.alegion.com/v1/assets/{assetId}/upload' \
-H 'x-api-key: {your-api-key}' \
-H 'authorization: Bearer {access_token}''
}'
Example response
{
"url": "https://cdn.app.alegion.com/tenant-assets/vandelay-industries/c226197c-17c5-4cc6-9529-0098ae771148?Policy=eyJTdGF0ZW1lbnQiOiBbeyJSZXNvdXJjZSI6Imh0dHBzOi8vY2RuLmFwcC5hbGVnaW9uLmNvbS90ZW5hbnQtYXNzZXRzL3ZhbmRlbGF5LWluZHVzdHJpZXMvYzIyNjE5N2MtMTdjNS00Y2M2LTk1MjktMDA5OGFlNzcxMTQ4IiwiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNjMwMTA0NjkyfX19XX0_&Signature=DpfMk3Vs~rJ5GLYOR4k3doaWCC5ajuFb1NbzADDazYlDPYcE9FvluZQoYkW6heWvNWJjHmHMVCFrvonTvSCRFBNJASmu37AwFk-rNkmSfRoro7nNlSrwPVlT9pgAQAMckds0pOIhNUQNibS5Jk-UDSxl8KZ8cfAIyr3jwtYVyd8R9ncHNc7w9PyOZlI8VpMmwe6YpKxfb4-8vTNTF8qzxVHTUPyAIsiS3dbIwzdx0gaRie8QN5EYYaXyGOkOd6wGQTeprka2Rmm~BC8zetWCSNudD1fzQ1sg~9-Nd9DYJQ6zgwSbSM1TrIETUMe2X9ZiwHLJZzfqSGcvCVTXHFlzJQ__&Key-Pair-Id=APKAJDMX44Y7WWY2FGYQ"
}
Note
The response contains a signed url
. This a secure, private, pre-authorized url directly into our cloud storage provider, where you can upload the asset file. The signed url is also temporary - it expires after 60 minutes.
Upload the asset
Upload the asset file to the signed url using PUT
. Note that because the signed url is pre-authorized, you don't need to include the x-api-key
nor authorization
headers in your request.
Example request
curl -v --upload-file cars-1900.mp4 'https://cdn.app.alegion.com/tenant-assets/vandelay-industries/c226197c-17c5-4cc6-9529-0098ae771148?Policy=eyJTdGF0ZW1lbnQiOiBbeyJSZXNvdXJjZSI6Imh0dHBzOi8vY2RuLmFwcC5hbGVnaW9uLmNvbS90ZW5hbnQtYXNzZXRzL3ZhbmRlbGF5LWluZHVzdHJpZXMvYzIyNjE5N2MtMTdjNS00Y2M2LTk1MjktMDA5OGFlNzcxMTQ4IiwiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNjMwMTA0NjkyfX19XX0_&Signature=DpfMk3Vs~rJ5GLYOR4k3doaWCC5ajuFb1NbzADDazYlDPYcE9FvluZQoYkW6heWvNWJjHmHMVCFrvonTvSCRFBNJASmu37AwFk-rNkmSfRoro7nNlSrwPVlT9pgAQAMckds0pOIhNUQNibS5Jk-UDSxl8KZ8cfAIyr3jwtYVyd8R9ncHNc7w9PyOZlI8VpMmwe6YpKxfb4-8vTNTF8qzxVHTUPyAIsiS3dbIwzdx0gaRie8QN5EYYaXyGOkOd6wGQTeprka2Rmm~BC8zetWCSNudD1fzQ1sg~9-Nd9DYJQ6zgwSbSM1TrIETUMe2X9ZiwHLJZzfqSGcvCVTXHFlzJQ__&Key-Pair-Id=APKAJDMX44Y7WWY2FGYQ'
Example response
< HTTP/2 200
< content-length: 0
< date: Fri, 27 Aug 2021 22:03:47 GMT
< etag: "d1dc268ff709a0b47b21cea0a38a59b4"
< server: AmazonS3
< x-cache: Miss from cloudfront
< via: 1.1 7f5e0d3b9ea85d0d75063a66c0ebc841.cloudfront.net (CloudFront)
< x-amz-cf-pop: HIO50-C1
< x-amz-cf-id: b2OAQzlfPTynZca9wV2I6uXnoJCCNlilSNYiTUmNZE3q3YDT3kKpvA==
HTTP 200
response code indicates success.
Close the upload session
Example request
curl -X DELETE 'https://api.alegion.com/v1/assets/{assetId}/upload' \
-H 'x-api-key: {your-api-key}' \
-H 'authorization: Bearer {access_token}'
HTTP 204
response code indicates success.
Creating a batch
You can create a batch using the /workflows/{workflowId}/batches
endpoint.
Example request
curl -X POST \
https://api.alegion.com/v1/workflows/{workflowId}/batches \
-H 'x-api-key: {your-api-key}' \
-H 'authorization: Bearer {access_token}' \
-H 'content-type: application/json' \
-H 'accept: application/json' \
--data-raw '{
"name": "Batch Name",
"isEnabled": false
}'
Note
The appropriate value for isEnabled
varies by use case. Please contact your Alegion customer success manager for guidance.
Example response
{
"id": "739b1978-cb5b-4188-9d1d-37a394d67f5a",
"name": "Batch Name",
"workflowId": "dac402db-b594-4f44-a2c7-87a535cf26f9",
"priority": "normal",
"isEnabled": false,
"createdAt": "2019-03-25T19:45:47.275Z"
}
Note the batch id
for use in subsequent calls
Creating input records for assets
Once your assets have been uploaded and your batch is created, you can create input records to send those assets through your annotation workflow.
Example request
curl -X POST 'https://api.alegion.com/v1/batches/{batchId}/records/assets' \
-H 'x-api-key: {your-api-key}' \
-H 'authorization: Bearer {access_token}' \
-H 'Content-Type: application/json' \
--data-raw '{
"assetIds": [
"{assetId}"
]
}'
Upload limit
This endpoint has a limit of 1,000 asset ids per request. Attempting to send more than 1,000 asset ids in a single request will result in an HTTP 422 Unprocessable Entity
error.
Example response
{
"created": [
{
"id": "f56e9c6c-5058-4c89-b150-b997530823ee",
"assetId": "c226197c-17c5-4cc6-9529-0098ae771148"
}
],
"assetValidationErrors": []
}
If you get a HTTP 201 Created
success response as shown above, your tasks are in the batch and are ready to be worked. You do not need to query the batch.
Retrieving results
Some details of retrieving results vary by use case. Please contact your Alegion customer success manager for guidance.
Selecting results to export
Use the /exports/workflows/{workflowId}/results
endpoint to list results for a workflow. Results will be paginated.
Example request
curl -X GET \
https://api.alegion.com/v1/exports/workflows/{workflowId}/results?batchIds={batchIds} \
-H 'x-api-key: {your-api-key}' \
-H 'authorization: Bearer {access_token}'
Example response
[{
"id": "3fad5acd-3466-49f5-baec-6fe45eb845c3",
"workflowId": "4cf60bf4-7092-4cfe-b7b8-e17f6674663d",
"batchId": "e8a530d4-9490-424c-99ee-8cf1cc79cd54",
"inputRecordId": "7ab3632c-7007-4a37-8821-873ecb474484",
"createdAt": "2021-01-22T15:49:10.722Z",
"iteration": 0
}]
Create an export
Use the /exports/record-result-exports
endpoint to kick off export generation.
There are two export formats to choose from: zip and json. We recommend using the ZIP format.
ZIP Using zip filetype generates a zip file containing a directory per record result named <record-result-id>
. In each record result directory, a json named <asset-name>.json
containing the single record result and the asset named <asset-name>.<extension>
. Example POST body:
{
"fileType": "zip",
"filename": "export-example.zip",
"workflowId": "4cf60bf4-7092-4cfe-b7b8-e17f6674663d"
}
JSON Using json fileType generates a json file containing array of results. We recommend naming the file with a .gz suffix to generate a gzipped export. Example POST body:
{
"fileType": "json",
"filename": "export-example.json.gz",
"workflowId": "4cf60bf4-7092-4cfe-b7b8-e17f6674663d"
}
Example request
curl -X POST \
https://api.alegion.com/v1/exports/record-result-exports \
-H 'x-api-key: {your-api-key}' \
-H 'authorization: Bearer {access_token}' \
-H 'Content-Type: application/json' \
--data-raw '{
"fileType": "zip",
"filename": "export-example.zip",
"workflowId": "4cf60bf4-7092-4cfe-b7b8-e17f6674663d",
"minCreatedAt": "2021-01-01T00:00:00Z"
}'
Note the use of minCreatedAt
to filter the results to be included in the new export. Using the createdAt
value for your previous export in conjunction with the minCreatedAt
field in the POST body when creating a new export, you can build an export containing only the results that have been finalized since your last generated export. See the full endpoint documentation for more parameters that can be used for filtering the desired results for your export.
Example response
{
"id": "ec02f767-66cb-4115-b530-82b9aa624217",
"status": "in-progress",
"filename": "export-example.zip",
"fileType": "zip",
"recordResultCount": 1,
"workflowId": "4cf60bf4-7092-4cfe-b7b8-e17f6674663d",
"createdAt": "2021-08-27T21:43:01.708946361Z",
"createdBy": "e01fbbea-6cdd-4b25-9e4e-8e0cfda75b5f",
"s3Path": "s3://app-dev-secure-media/domain-object/record-result-export/ec02f767-66cb-4115-b530-82b9aa624217/export-example.zip"
}
Wait for the export to assume a ‘ready’ status
Use the /exports/record-result-exports/{exportId}
endpoint to get the export. It will be ready to download once it has assumed the ‘ready’ status.
Example request
curl -X GET https://api.alegion.com/v1/exports/record-result-exports/{exportId} \
-H 'x-api-key: {your-api-key}' \
-H 'authorization: Bearer {access_token}'
Example response
{
"id": "ec02f767-66cb-4115-b530-82b9aa624217",
"status": "ready",
"filename": "export-example.zip",
"fileType": "zip",
"recordResultCount": 1,
"workflowId": "4cf60bf4-7092-4cfe-b7b8-e17f6674663d",
"createdAt": "2021-08-27T21:43:01.708946Z",
"createdBy": "e01fbbea-6cdd-4b25-9e4e-8e0cfda75b5f",
"s3Path": "s3://app-dev-secure-media/domain-object/record-result-export/ec02f767-66cb-4115-b530-82b9aa624217/export-example.zip"
}
Use the /exports/record-result-exports/{exportId}/download
endpoint to get the export. When the export is in the ‘ready’ (or ‘downloaded’), get the signed url for the export.
Example request
curl -i
-X GET https://api.alegion.com/v1/exports/record-result-exports/{exportId}/download \
-H 'x-api-key: {your-api-key}' \
-H 'authorization: Bearer {access_token}' | sed -En 's/^location: (.*)\r$/\1/p'
The signed url will live in the location
header of the response and will expire after 10 seconds. Get the export using the signed url. The -i
parameter to curl makes it display the response headers. The sed
command extracts the location header value.
Example request
curl -o export-example.zip "{signed-url}"
It is important to put the signed url in quotes, because it contains characters that will be interpreted by the shell otherwise.
About pagination
Some API responses are large enough that it makes sense to paginate them. Any paginated response will provide a Link
header and a X-Total-Count
header and will accept pagination related paramaters in the query string.
Pagination request parameters
page
: Which page number to returnpageSize
: How many records per pagesort
:-createdAt
or+createdAt
, to sort bycreatedAt
descending or ascending, respectively
Example pagination response headers: Link
and X-Total-Count
Link: <https://api.alegion.com/v1/batches/{batchId}/records?page=1&pageSize=20&sort=-createdAt>;rel="first",
<https://api.alegion.com/v1/batches/{batchId}/records?page=1&pageSize=20&sort=-createdAt>;rel="prev",
<https://api.alegion.com/v1/batches/{batchId}/records?page=3&pageSize=20&sort=-createdAt>;rel="next",
<https://api.alegion.com/v1/batches/{batchId}/records?page=3&pageSize=20&sort=-createdAt>;rel="last"
X-Total-Count: 42
Checking for doneness
Alegion does not have a "callback" mechanism for notifications when a batch is "ready for pickup". This is for two reasons:
- Batches don't have a defined end as explained above.
- Alegion is platform-agnostic with respect to the client calling our API, and any single mechanism (e.g. webhooks) would not in practice work for a substantial portion of our customers.
However, it is trivial to call the results endpoint with pagination parameters of page=1
and pageSize=1
, then read the X-Total-Count
response header to see how many results are available. Provided your system keeps track of how many records were sent into the batch, you'll know when it's complete.
But: There are two other task states that are considered "final" but are not returned by the results endpoint: exception and canceled. These need to be counted separately. Read on for the explanation of these exception state, and the way to retrieve the exception count.
Other calls and concepts
Filtering results
You can filter results using the following parameters.
minCreatedAt
: to exclude results finalized before this datetimemaxCreatedAt
: to exclude results finalized after this datetime
Note, these might live in the POST body or as query parameters. Please check the API documentation for the endpoint you are using.
Example
Suppose your system knows the last time it requested results from a batch. To query for only new results that became final after that, use minCreatedAt
:
curl -X GET \
https://api.alegion.com/v1/batches/{batchId}/results?minCreatedAt=2020-01-01T10:00:00.000Z \
-H 'x-api-key: {your-api-key}' \
-H 'authorization: Bearer {access_token}'
Common errors
Malformed Batch ID
Sending a seriously malformed batch ID will return an HTTP 422
with the following body:
{
"message": "Failed to convert value of type 'java.lang.String' to required type 'java.util.UUID'; nested exception is java.lang.IllegalArgumentException: Invalid UUID string: {batch_id}"
}
Missing, Incorrect, or Expired Token
Any sort of problem with your access token will return an HTTP 401
error with an empty body.
Missing or Incorrect API key
If the x-api-key header is not sent properly, HTTP 403
will be returned.
Uploading input records for non-Asset-based workflows
This section shows how to encode an input record using JSON.
Each input record has this structure:
- a
data
member containing- a list of key-value pairs where
- the key is a fieldname determined by the task design
- the value is displayed to the labeler
- a list of key-value pairs where
metadata
(optional): any string:When used,metadata
will be associated with that input record throughout its lifetime. Use it to attach context to a record to track it as it moves through the Alegion platform. For instance, you can use it to store the record's corresponding unique ID in your database.
Warning
metadata
is a reserved word and must be a sibling to the input record data
field, not a child of data
Valid:
[
{
"data": {
"input_fieldname": "this is my value"
},
"metadata": "external_ID"
}
]
Invalid:
[
{
"data": {
"input_fieldname": "this is my value",
"metadata": "external_ID"
}
}
]
Use the /batches/{batchId}/records/import
endpoint to bulk load JSON input records into your batch. The request body is an array of single input records.
Example request
curl -X POST https://api.alegion.com/v1/batches/{batchId}/records/import \
-H 'x-api-key: {your-api-key}' \
-H 'authorization: Bearer {access_token}' \
-H 'content-type: application/json' \
--data-raw '[
{
"data": {
"input_fieldname_1": "this is my value on record 1",
"input_fieldname_2": "another field value on record 1"
},
"metadata": "sample_metadata"
},
{
"data": {
"input_fieldname_1": "this is my value on record 2",
"input_fieldname_2": "another field value on record 2"
},
"metadata": "more_sample_metadata"
}
]'
Example response
[
{
"id": "309ec5c5-6589-47fc-bd3d-c5b4edeb5d57",
"data": {
"input_fieldname_1": "this is my value on record 1",
"input_fieldname_2": "another field value on record 1"
},
"metadata": "sample_metadata"
"createdAt": "2019-11-15T14:26:17.661Z",
"workflowStageId": "string",
"status": "queued"
},
{
"id": "83224129-b65f-4533-8f06-d25333a21759",
"data": {
"input_fieldname_1": "this is my value on record 2",
"input_fieldname_2": "another field value on record 2"
},
"metadata": "more_sample_metadata"
"createdAt": "2019-11-15T14:26:17.661Z",
"workflowStageId": "string",
"status": "queued"
}
]
If you get a success response as shown above, your tasks are in the batch and are ready to be worked. You do not need to query the batch.
Upload limit
The import endpoints currently limit imports to 1,000 records per request. Attempting to send more than 1,000 records in a single request will result in an HTTP 422 Unprocessable Entity
error.
Listing your workflows
To retrieve an array of all workflows in your account, use the /workflows
endpoint. Results will be paginated.
Example request
curl -X GET https://api.alegion.com/v1/workflows \
-H 'x-api-key: {your-api-key}' \
-H 'Authorization: Bearer {access_token}'
Example response
[
{
"id": "dac402db-b594-4f44-a2c7-87a535cf26f9",
"name": "Workflow name",
"description": "Workflow description",
"isActive": true,
"isVisible": true,
"isArchived": false,
"createdAt": "2018-09-26T18:35:38.188Z",
"isLimitWorkerToOncePerInputRecord": false
}
]
Listing batches within a workflow
To retrieve an array of all batches for a given workflow, use the /workflows/{workflowId}/batches
endpoint. Results will be paginated. Input record counts by status will also be rolled up in the response. In the example below, there are 2 complete input records and none in any other status.
Example request
curl -X GET \
https://api.alegion.com/v1/workflows/{workflowId}/batches \
-H 'x-api-key: {your-api-key}' \
-H 'Authorization: Bearer {access_token}'
Example response
[
{
"id": "6ca34705-239c-424c-9b8e-1fd44ad0f0e8",
"name": "Batch Name",
"workflowId": "dadc6d1e-9fb3-4e74-9285-0ad01a27b373",
"priority": "normal",
"isEnabled": true,
"createdAt": "2021-07-13 22:12:49.504323+00",
"complete": 2,
"inProgress": 0,
"queued": 0,
"archived": 0,
"archiving": 0,
"adminReview": 0,
"content": 0,
"exceptions": 0,
"canceled": 0,
"publishedForReview": false,
"status": "Active"
}
]
Get metadata about a batch
Use a GET
to the /batches/{batchId}
endpoint to retrieve metadata about a batch. Note that this returns the properties of a batch as a container object, and does not return information about the input records, batch status, or results.
Example request
curl -X GET https://api.alegion.com/v1/batches/{batchId} \
-H 'x-api-key: {your-api-key}' \
-H 'Authorization: Bearer {access_token}'
Example response
{
"id": "3c9fa471-882b-4d92-82d4-ece202606ba6",
"name": "Batch Name",
"workflowId": "dac402db-b594-4f44-a2c7-87a535cf26f9",
"isEnabled": true,
"createdAt": "2019-03-26T17:47:03.399Z"
}
List a batch's input records
Use the /batches/{batchId}/records
endpoint to retrieve input records belonging to a batch. Results will be paginated.
Example request
curl -X GET \
https://api.alegion.com/v1/batches/{batchId}/records \
-H 'x-api-key: {your-api-key}' \
-H 'authorization: Bearer {access_token}'
Example response
[
{
"id": "046b6c7f-0b8a-43b9-b35d-6489e6daee91",
"createdAt": "2017-11-14T21:02:36.491Z",
"metadata": "aeiou",
"data": "aeiou",
"workflowStageId": "046b6c7f-0b8a-43b9-b35d-6489e6daee91",
"status": "in-progress"
}
]
Task exceptions
"Exception" has a special meaning in Alegion, specifically with regard to tasks. (Consider it an overloaded term, unrelated to how programmers normally use the word.)
Labelers report a task exception when for whatever reason a task cannot be worked, for instance when an image fails to render. Task exceptions go into a special queue for review. If the situation was temporary (e.g. permissions that expire on an S3 bucket, "internet weather"), those tasks can be restarted and proceed normally, eventually appearing in the final results.
However, if the situation was not temporary (e.g. a bad filename in the input data), the tasks can be canceled, in which case they will not appear in the final results. (Tasks can be canceled for other administrative reasons as well.)
This is an intentional and constructive task design pattern, and depending on your use case, there are other ways to employ exceptions usefully. (Alegion's customer success team will guide you in this.)
Counting exceptions and canceled tasks
To complete the picture of batch status described above, combine the count from the results endpoint with the count of exception
and canceled
tasks from the records endpoint with these specific query parameters:
status=exception,canceled
page=1
pageSize=1