Skip to main content

Upload SCM Data (ASYNC)


This document covers the process of uploading SCM data to the Scantrust API to be processed asynchronously. To upload data synchronously, see section Upload SCM Data (SYNC)

UAT token permissions

The UAT token needs to have access to the following permissions:

  • codes_view
  • scm_bulk_edit
  • scm_code_edit
  • product_view

The UAT token must be set in the header fields of all requests as described in Authentication & Tokens.


  • Upload handler: Formats, pre validates and uploads the data.
  • Endpoint: on the server, that accepts a batch of records.
  • Status check: Check the job status


There are 3 main prerequisites:

  1. Brand owner/SCM User account on the Scantrust portal: Scantrust will provide a developer test-account as well as a production account.

  2. A campaign that is setup to include the desired SCM fields:

  • Example of SCM fields: production_date, intended_market, rfid, case_number..
  • Please note: SCM fields not included in the campaign will be discarded by the system.
  1. Valid codes: for testing; from a work order for a product that is included in the campaign, which has valid codes.


In order to upload information for codes, constraints must be chosen to select the desired codes to upload data for.

There are 3 ways to determine constraints:

  1. The constraint could be extended_id (the unique message each code holds).

  2. The constraint can also be set to serial_number if they are set on the codes.

  3. SCM data can also be used as constraints:

    • Codes with RFID tags can be uploaded by key ‘rfid’ and value of each tag.
    • Codes with a Logistic Unit can be updated based on the unit.

Multiple constraints can be set for one upload.

Date Format

The date format for SCM fields of type “Date” should be be YYYY-MM-DD.

Other formats will be accepted and saved as-provided. However, this will result in issues displaying the data in the portal, and using the online data editor.

If you wish to store date data in other formats, please use the text format

Upload Handler

The upload handler will communicate with the API endpoint, handle the data to be uploaded, and processes the response from the server. The workflow is split up in the below steps:

  1. Pre-validate data to be uploaded
  2. Format data to be uploaded to the specified JSON structure
  3. Upload JSON data to the API
  4. Process the response
  5. Check the job status

Pre-Validation of uploaded file

It is recommended to pre-validate the data to be uploaded. This prevents unnecessary calls to the API.

Following pre-validation should be done:

  1. Format Checking:

    • Verify the data constraints to be either 'extended_id' and/or the desired SCM key.
  2. Preliminary Error Checking:

    • Verify that no constraint value is duplicated.
    • Verify that no constraint value is blank.

Format data to be uploaded

Data must be uploaded using JSON as the format. The API will accept a maximum of 5 constraints, with a maximum of 1K values. Data must be split into batches of items that contain the same SCM data. It is recommended to keep a log file containing the keys/batch # of previously uploaded items so they can be skipped when uploading. This prevents items from getting uploaded twice if the API intercepts a defective item in a specific batch.

General flow

  1. Process the data and create an array of JSON objects
  2. Create batches based on SCM data to upload
  3. Ignore previously uploaded rows
  4. Convert all values to strings
  5. Send request
  6. Send a request and save the constraint values as 'uploaded' in a logfile:
    • Subsequent runs should ignore all keys that are in the 'uploaded' file
  7. Check the status based on the returned transaction ID

API Design /api/v2/scm/upload/async/

Posting data to this endpoint will create an ASYNC server job that can edit any code in your company to contain the desired SCM data. The endpoint will return a task_id which can be used to check the status of the job.

constraintsrequiredjsonDefine the constraints which are used to lookup the codes. Constraints must be present in the code as field/SCM field. Match will be CASE SENSITIVE and EXACT.

Example uses:
- Use the rfid SCM field as a constraint
- Use the extended_id as a constraint

Maximum 5 different constraints allowed, containing 1K items

Disallowed constraints:
- message (must be passed as extended_id)
- product/product_id (not allowed)
- campaign/campaign_id (optional outside constraints)
scm_datarequiredjsonList of scm data in key/value pairs, to upload to individual codes. Each key needs to reference the key of the SCM field as defined the campaign. The names of the keys can be confirmed by downloading the template.csv file from the SCM T&T tab for the campaign.

Special keys:
-product (specify a product SKU/ID)
- activation_status (0=inactive, 1=active, 2=blacklisted)
- blacklist_reason

Disallowed keys:
- extended_id/serial_number/message (can not be changed)
- product_id (must be passed as product)
- status (must be passed as activation_status)
campaignoptionalintID of a campaign. If passed, system checks if all constraints’ scm-keys exist in the campaign.
referenceoptionalstringHuman readable name for task grouping. Tasks can be grouped using this field.

Body Parameters POST (application/json)

"constraints": {
"rfid": ["rfid1", "rfid2", "rfid3"],
"scm_data": {
"client_custom_field": "some_val",
"campaign": 11,
"reference": "SCM upload 11202020-10"

In this example all codes containing the SCM field rfid with value rfid1, rfid2 or rfid3 will be updated to have the SCM data "client_custom_field": "some_val". The API will check if client_custom_field is a valid field for campaign ID 11

Response (200): Status OK

If the post is succesfull, the API will return a task_id which can be used to lookup the job status.

"task_id": "your_task_uuid"

Response (400) : Invalid Data Format

An exception will be raised (with an appropriate error message) if the posted format/values are not valid:


"campaign": ["Incorrect type. Expected pk value, received str."],
"scm_data": {
"extended_id": "Invalid key name",
"status": "Invalid key name, use 'activation_status' instead"
"constraints": {
"message": "Invalid constraint name, please use 'extended_id' instead"

Special Cases

Special SCM fields can be used to alter the code and internal functions (assign a product, activation status, LU assignment, ...)

See docs: Special SCM Fields

Task Status Checks

When posting an async SCM upload, the task will be processed in the background. You will need to check back later to see the status of the task based on the returned task_id. Checks might need to happen multiple times if the status of the task is still pending. Jobs will be processed as soon as possible but might experience delay in busy periods.

API Design /api/v2/scm/tasks/

Task states

A task can have 4 different states:

  • pending (The task is in the queue and awaits processing)
  • in-progress (The task is currently being processed)
  • complete (The task has been completed, values can now be interpreted)
  • failed (The task has failed, the errors can be interpreted)

GET: /api/v2/scm/tasks/{id}/

Gets information for a specific task.

Response (200): Status OK

"id": "efe7dcd5-aa25-4fc1-b1d3-38640b86e593",
"reference": "",
"state": "complete",
"codes_affected": 322,
"created_by": 1638,
"created_at": "2019-08-22T16:00:11.449543Z",
"started_at": "2019-08-22T16:00:11.514456Z",
"completed_at": "2019-08-22T16:00:11.526948Z",
"details": {
"constraints": {
"rfid": "test_rfid"
"scm_data": {
"intended_market": "test"

It is advised to compare the codes_affected with the number of items that is expected to be updated.

GET: /api/v2/scm/tasks/

List of all created tasks by user

Filters may be added by appending the path ?filter_name=value e.g. /api/v2/scm/tasks/?state=pending

Filter Fields:

  • state: pending, in-progress, complete, failed
  • created_at: datetime
  • reference: string value

Response (200): Status OK

Example response (paginated result):

"count": 2,
"next": null,
"previous": null,
"results": [
"id": "6913d938-d6c3-4139-97d1-27c59c113ef0",
"state": "complete",
"reference": "",
"codes_affected": 777,
"created_by": 1638,
"created_at": "2019-08-22T16:00:12.996409Z",
"started_at": "2019-08-22T16:00:13.057840Z",
"completed_at": "2019-08-22T16:00:13.070875Z"
"id": "ef183d35-cc7c-4925-a95a-906c02e291ef",
"state": "complete",
"reference": "",
"codes_affected": 228,
"created_by": 1638,
"created_at": "2019-08-22T16:00:12.218396Z",
"started_at": "2019-08-22T16:00:12.277734Z",
"completed_at": "2019-08-22T16:00:12.289489Z"

POST: /api/v2/scm/tasks/

task_idsrequiredlist(string)List of task_ids to retrieve from the API.

['taskID1', 'taskID2']

(For Example Response See List view)

GET: /api/v2/scm/task-groups/{reference}/

Get a group of tasks based on reference ref1

Response (200): Status OK

"reference": "ref1",
"tasks_count": 3,
"codes_affected": 6,
"completed": true,
"state_stats": {
"pending": 0,
"in-progress": 0,
"complete": 3,
"failed": 0
"started_at": "2019-08-22T16:00:12.277734Z",
"completed_at": "2019-08-22T16:00:12.289489Z"