Skip to main content
Markdown

Using the Master Data API

Workist requires the master data from your ERP system. Via the API you submit it:

  • as a CSV file,
  • as a link to a publicly reachable CSV file,
  • as a list of objects in JSON format, in several batches for large volumes.

Every import replaces the entire data set of the lookup definition: Workist deletes rows that are missing from the new import. So always send the complete data set. Delta imports can be set up by Workist on request.

API Documentation (Swagger): https://api.workist.com/v1/swagger/

Basics​

  • Base URL: https://api.workist.com/v1/master-data
  • Authentication: the same API key as for the Document API, in the header Authorization: Bearer <API key> (see Quickstart).
  • Lookup definition: Every import belongs to exactly one lookup definition, given as lookup_definition_id. Where to find the ID is described under Lookup Definition IDs.
  • No trailing slash on paths.

Endpoints​

Each master data type has its own endpoint that creates an import. The lookup definition must match the type of the endpoint. Each path links to the endpoint in Swagger.

Master dataEndpointLookup typeColumns
Articles and customer-specific articlesPOST /master-data/articles/importsARTICLE_LOOKUPDescription
CustomersPOST /master-data/clients/importsCLIENT_LOOKUPDescription
Customer contactsPOST /master-data/contacts/importsCONTACT_LOOKUPDescription
Delivery and invoice recipientsPOST /master-data/addresses/importsADDRESS_LOOKUPDescription
Unit conversionPOST /master-data/conversion-factors/importsCONVERSION_FACTOR_LOOKUPDescription
Framework agreementsPOST /master-data/framework-contracts/importsFRAMEWORK_CONTRACT_LOOKUPDescription
Orders to be matchedPOST /master-data/order-matching/importsORDER_MATCHING_LOOKUPDescription
QuotesPOST /master-data/offer-matching/importsOFFER_MATCHING_LOOKUPDescription

In addition there are general endpoints for all types:

MethodPathPurpose
GET/master-data/importsList imports (paginated, up to 1000 per page)
POST/master-data/importsCreate an import, for any master data type
GET/master-data/imports/{import_id}Get the status of an import
POST/master-data/imports/{import_id}/dataAppend a data batch to a batched import
POST/master-data/imports/{import_id}/startStart a batched import

Request fields​

An import contains exactly one of the fields file, file_url or data. Send the request as multipart/form-data or as JSON. With multipart/form-data, pass data as JSON text.

FieldContent
lookup_definition_idID of the lookup definition (required).
batchedtrue: create a batched import that accepts more data batches. Default: false (import starts at once).
fileCSV file (extension .csv), at most 10 MB.
file_urlPublicly reachable http/https link to a CSV file. The path ends in .csv, the file has at most 10 MB.
dataList of objects (JSON), at most 10,000 rows. All objects need the same fields.

The field names of the objects and CSV columns are the column names on the master data page of each type ("Columns" above). Workist converts JSON data into a comma-separated CSV file. If you have set up a transformer configuration for the lookup definition, e.g. column mappings or a different delimiter, it also applies to imports via the API.

Response and import status​

Workist processes imports in the background. Every call that creates an import, appends data or starts it answers 202 with the import ID:

{"import_id": "0b7c6a52-5d0e-4f43-9a8e-3c2b1d0e9f11"}

The Location header holds the address of the status. Request it with GET /master-data/imports/{import_id} until status is SUCCESS, FAILED or CANCELED:

import time

url = f"{base_url}/imports/{import_id}"
while True:
run = requests.request("GET", url, headers=headers).json()
if run["status"] in ("SUCCESS", "FAILED", "CANCELED"):
break
time.sleep(60)
# e.g. {"import_id": "...", "status": "SUCCESS", "lookup_type": "ARTICLE_LOOKUP", ...}

The response contains:

FieldContent
import_idImport ID.
customer_idID of your organisation.
lookup_typeMaster data type, e.g. ARTICLE_LOOKUP.
lookup_definitionID of the lookup definition.
ingestion_file_urlLocation of the merged import file.
ingestion_file_num_rowsNumber of imported rows.
error_typeError type if the import failed.
error_messageError message if the import failed.
triggerTrigger, e.g. PUBLIC_API, SFTP_FILE_UPLOAD or WORKBENCH_FILE_UPLOAD.
created_atCreated at.
updated_atLast changed at.
started_atProcessing started at.
finished_atProcessing finished at.
statusStatus, see below.
input_file_urlLocation of the first submitted file or data batch.
input_file_num_rowsRows in that file.
statusMeaning
PENDINGCreated, not started yet (a batched import is waiting for data or the start call).
RUNNINGBeing processed.
SUCCESSFinished successfully.
FAILEDFailed, see error_type and error_message.
CANCELEDCanceled.

You also see all imports, including those via the API, in the Master Data Hub of the Workbench.

Limits​

  • Per request: data with at most 10,000 rows, file and file_url with at most 10 MB. Transfer larger data sets as a batched import.
  • Per hour: If more than 12 imports were created for a lookup definition in the last hour, the API rejects further ones with 400 (Too many imports scheduled for this lookup definition recently). Imports from all sources count, including SFTP uploads. An SFTP upload over the limit is skipped without notice.
  • file_url: only http and https. The API rejects addresses that point to internal or private networks. Workist downloads the file during the request.

Batched imports​

For data sets over 10,000 rows or 10 MB, create a batched import and transfer the data in batches:

  1. Create a batched import with "batched": true, e.g. via POST /master-data/articles/imports. The response contains the import_id.
  2. Append data batches with POST /master-data/imports/{import_id}/data, as often as needed. CSV batches all need the same header row.
  3. Start the import with POST /master-data/imports/{import_id}/start. After that the import accepts no more data.
import requests
import json

def chunk(it, size):
from itertools import islice
it = iter(it)
return iter(lambda: tuple(islice(it, size)), ())

base_url = "https://api.workist.com/v1/master-data"
lookup_definition_id = "<Article Lookup Definition ID>"
token = "<Your Auth Token>"
headers = {"Authorization": f"Bearer {token}"}

articles = [
{"article_id1": "123", "description": "abc", "order_units": ["PCS", "KG"]},
{"article_id1": "456", "description": "def", "order_units": ["KG"]},
{"article_id1": "789", "description": "def", "order_units": ["M"]}
]
articles_chunked = list(chunk(articles, 10000))

url = f"{base_url}/articles/imports"
response = requests.request("POST", url, headers=headers, data={
"lookup_definition_id": lookup_definition_id,
"batched": True,
})
import_id = response.json().get("import_id")

for articles_batch in articles_chunked:
url = f"{base_url}/imports/{import_id}/data"
response = requests.request("POST", url, headers=headers, data={"data": json.dumps(articles_batch)})

url = f"{base_url}/imports/{import_id}/start"
response = requests.request("POST", url, headers=headers)

Customers​

clients = [
{"client_id1": "C-001", "company_name": "Test SE", "address1": "Test street 1", ...},
{"client_id1": "C-002", "company_name": "Muster GmbH&Co. KG", ...}
]
url = f"{base_url}/clients/imports"
payload = {"lookup_definition_id": "<your lookup definition>", "data": json.dumps(clients)}
response = requests.request("POST", url, headers=headers, data=payload)

Delivery Addresses​

Linked to customers via partition_id. The delivery address field should contain company names only.

delivery_addresses = [
{"partition_id": "C-001", "address_id1": "L-001", "name": "Tester 2 GmbH", "address1": "Test street 2", ...}
]
url = f"{base_url}/addresses/imports"
payload = {"lookup_definition_id": "<your lookup definition>", "data": json.dumps(delivery_addresses)}
response = requests.request("POST", url, headers=headers, data=payload)

Articles​

order_units must be submitted as an array (e.g. ["KG", "STK"]).

articles = [
{"article_id1": "ART-001", "description": "Sensor Module", "order_units": ["PCE", "KG"]},
]
url = f"{base_url}/articles/imports"
payload = {"lookup_definition_id": "<your lookup definition>", "data": json.dumps(articles)}
response = requests.request("POST", url, headers=headers, data=payload)

Customer-Specific Articles​

Each entry requires partition_id (customer reference) and article_id1 (internal article). article_id2 contains the customer article number.

client_articles = [
{"partition_id": "C-001", "article_id1": "ART-001", "article_id2": "CUST-ART-555"},
]
url = f"{base_url}/articles/imports"
payload = {"lookup_definition_id": "<your client-specific lookup definition>", "data": json.dumps(client_articles)}
response = requests.request("POST", url, headers=headers, data=payload)

Errors​

HTTP statusCauseResponse
400Invalid request, e.g. missing lookup_definition_id, file is not a CSV file, too many rows, lookup definition doesn't match the endpoint, import no longer in status PENDING, too many imports per hour{"detail": "<message>"} or ["<message>"]
401API key missing{"detail": "Authentication credentials were not provided or invalid."}
503The request took longer than 30 seconds{"detail": "Please try again later"}

Postman Collection​

A Postman collection for the master data API is available on request. Contact your Workist representative or email support@workist.com.

Lookup Definition IDs​

Users with the Manager, IT or Admin role create lookup definitions in the Master Data Hub. You find the ID in two places:

  • in the Master Data Hub: in the overview in the ID column and on the detail page of the lookup definition,
  • in the channel under Manage channel → Master Data, below the selected lookup definition.

For more details: Retrieve Lookup IDs