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 data | Endpoint | Lookup type | Columns |
|---|---|---|---|
| Articles and customer-specific articles | POST /master-data/articles/imports | ARTICLE_LOOKUP | Description |
| Customers | POST /master-data/clients/imports | CLIENT_LOOKUP | Description |
| Customer contacts | POST /master-data/contacts/imports | CONTACT_LOOKUP | Description |
| Delivery and invoice recipients | POST /master-data/addresses/imports | ADDRESS_LOOKUP | Description |
| Unit conversion | POST /master-data/conversion-factors/imports | CONVERSION_FACTOR_LOOKUP | Description |
| Framework agreements | POST /master-data/framework-contracts/imports | FRAMEWORK_CONTRACT_LOOKUP | Description |
| Orders to be matched | POST /master-data/order-matching/imports | ORDER_MATCHING_LOOKUP | Description |
| Quotes | POST /master-data/offer-matching/imports | OFFER_MATCHING_LOOKUP | Description |
In addition there are general endpoints for all types:
| Method | Path | Purpose |
|---|---|---|
GET | /master-data/imports | List imports (paginated, up to 1000 per page) |
POST | /master-data/imports | Create 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}/data | Append a data batch to a batched import |
POST | /master-data/imports/{import_id}/start | Start 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.
| Field | Content |
|---|---|
lookup_definition_id | ID of the lookup definition (required). |
batched | true: create a batched import that accepts more data batches. Default: false (import starts at once). |
file | CSV file (extension .csv), at most 10 MB. |
file_url | Publicly reachable http/https link to a CSV file. The path ends in .csv, the file has at most 10 MB. |
data | List 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:
| Field | Content |
|---|---|
import_id | Import ID. |
customer_id | ID of your organisation. |
lookup_type | Master data type, e.g. ARTICLE_LOOKUP. |
lookup_definition | ID of the lookup definition. |
ingestion_file_url | Location of the merged import file. |
ingestion_file_num_rows | Number of imported rows. |
error_type | Error type if the import failed. |
error_message | Error message if the import failed. |
trigger | Trigger, e.g. PUBLIC_API, SFTP_FILE_UPLOAD or WORKBENCH_FILE_UPLOAD. |
created_at | Created at. |
updated_at | Last changed at. |
started_at | Processing started at. |
finished_at | Processing finished at. |
status | Status, see below. |
input_file_url | Location of the first submitted file or data batch. |
input_file_num_rows | Rows in that file. |
status | Meaning |
|---|---|
PENDING | Created, not started yet (a batched import is waiting for data or the start call). |
RUNNING | Being processed. |
SUCCESS | Finished successfully. |
FAILED | Failed, see error_type and error_message. |
CANCELED | Canceled. |
You also see all imports, including those via the API, in the Master Data Hub of the Workbench.
Limits
- Per request:
datawith at most 10,000 rows,fileandfile_urlwith 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: onlyhttpandhttps. 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:
- Create a batched import with
"batched": true, e.g. viaPOST /master-data/articles/imports. The response contains theimport_id. - Append data batches with
POST /master-data/imports/{import_id}/data, as often as needed. CSV batches all need the same header row. - 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 status | Cause | Response |
|---|---|---|
400 | Invalid 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>"] |
401 | API key missing | {"detail": "Authentication credentials were not provided or invalid."} |
503 | The 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