🤝 Create products from your distributor's catalog
In a nutshell
This job allows a supplier account, on a table shared by its distributor, to create products from a list of EANs: the distributor's catalog is queried for those EANs, and the products are created on the supplier's side with the cleaned result - for each product, the EAN (its identifier), the description and the category, nothing else.
The shared job is built exclusively with data-* tasks and JSON payloads - two tasks, no key to adapt. The private export job adds two small scripts to parse the EAN list and shape the result into an import-ready JSON file.
📥 Download the shared job (supplier side) and 📥 the export job (distributor side).
⌛ Time to setup: 15 minutes.
📋 Prerequisites: Two Product-Live accounts with access to the Data Factory platform, and a single-level table shared between them.
The current version is (last updated on 2026-09-03).
Generic job reference: .
TIP
data-job-execution-create and the data-* tasks used here are in alpha phase. You can contact the Product-Live team at contact@product-live.com if you want more details and get an early access.
Result
Once set up, the supplier account (the account that receives the shared table) has a job in its Data Factory jobs list. When executing it, the user enters the EANs of the products to create, one per line.
The job then:
- Triggers a private export job on the distributor account - the account that owns the table and the catalog - and waits for its completion. That job finds the products in the distributor's catalog and returns a ready-to-use request file: for each product, only three fields - the EAN, the description and the category - along with the id of the partition holding it.
- Creates the products on the supplier's side of the shared table, by using that file as its own request body.
The same shared job works for every supplier without modification: everything that runs on the supplier's side uses the running account's context, and the distributor-side calls carry an API key of the distributor stored in a protected variable.
Requirement
To deploy this job, you need:
- A distributor account and at least one supplier account, with a single-level table shared between them. The table of this example holds an
EAN_13field (IDENTIFIER), aDESCRIPTIONfield and aCATEGORYfield - Two Data Factory pipelines, one for each job - see One job per pipeline
If you don't have access to the Data Factory module, please contact our support team.
Setup
- On the distributor account, import the export job, available here. Adapt its table key (
PRODUCTS), partition key (ACTIVES) and field keys (EAN_13,DESCRIPTION,CATEGORY) to your catalog - On the distributor account, import the shared job, available here, and share it with the supplier accounts. It carries no table or field key at all: everything it needs comes from the export job's output
- On the distributor account, create a protected global variable
api_keyholding an API key of the distributor account. Variables of a shared job are resolved on the job owner's account, so a supplier running the job gets the distributor's value - see Variables and the Variables and secrets tutorial - Attach the two jobs to two different pipelines
- From the supplier account, run the shared job and enter the EANs of the products to create, one per line
Further information
Job design
The shared job (supplier side) is composed of 2 tasks:
mermaid
flowchart TD
start["🏁 Job Start"]
end_["🟢 Job is complete"]
run_export["Run the export job on the distributor and wait [1]"]
create_products["Create the products with the returned operations [2]"]
start --> run_export
run_export --> create_products
create_products --> end_- [1]: The Data Factory task used is
data-job-execution-create - [2]: The Data Factory task used is
data-item-create-or-update
The export job (distributor side) is composed of 3 tasks:
mermaid
flowchart TD
start["🏁 Job Start"]
end_["🟢 Job is complete"]
parse_eans["Parse the EAN list [1]"]
find_products["Find the products by EAN, cleaned [2]"]
build_operations["Shape the result into a ready-to-use request file [3]"]
start --> parse_eans
parse_eans --> find_products
find_products --> build_operations
build_operations --> end_- [1]: The Data Factory task used is
code-execute-javascript - [2]: The Data Factory task used is
data-item-find - [3]: The Data Factory task used is
code-execute-javascript
The chaining mechanism - trigger, wait, read the terminal execution - is described in depth in the Trigger a job from another job and use its result use case. This job is its data-*, all-JSON counterpart: no XML, all the shaping confined to the private job, and the result travelling between the two accounts as a JSON file.
Detailed parameters
Job input parameter
The shared job asks the user for a single value:
| Parameter | Type | Required | Description |
|---|---|---|---|
eans | TEXT | yes | EANs of the products to create (one per line) |
[1] Run the export job on the distributor and wait
The export job is resolved from its job key by a lookup, executed on the distributor account thanks to the api_key variable, and awaited with wait: true - the task returns the terminal execution, including its output. The EAN list travels as the raw text typed by the user; parsing it is the export job's business:
json
{
"apiKey": "${workflow.globalVariables.api_key}",
"request": {
"method": "INLINE",
"contentType": "application/json",
"model": "default",
"json": {
"operations": [
{
"key": "a",
"lookups": [
{
"taskName": "data-job-find",
"assign": "element.jobId",
"entityKey": "export-products-by-ean"
}
],
"element": {
"info": {
"title": "Export products by EAN (triggered by a shared job)"
},
"input": {
"eans": "${workflow.input.eans}"
}
}
}
]
}
},
"wait": true,
"waitOptions": {
"pollingIntervalSeconds": 10,
"timeoutSeconds": 600
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
[2] Create the products with the returned file
The export job returns a complete request file - one operation per product found, each carrying the cleaned fields and the id of the partition holding the product. The task uses it directly as its request body, with request.method: ATTACHMENT:
json
{
"request": {
"method": "ATTACHMENT",
"contentType": "application/json",
"model": "default",
"file": "${run_export_on_distributor.output.result.json[0].response.output.operations_file}"
}
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
In the expression, run_export_on_distributor is the taskReferenceName of task [1], result.json[0].response is the terminal execution of the export job, and output.operations_file is the key the export job declares in its own outputParameters - see the User outputs tutorial.
The export job (distributor side)
[1] Parse the EAN list. A small script turns the raw text into a deduplicated array (one EAN per line, commas accepted):
json
{
"expressionFile": "file://assets/parse-eans.js",
"data": {
"eans": "${workflow.input.eans}"
}
}1
2
3
4
5
6
2
3
4
5
6
[2] Find the products. A single data-item-find task finds the products with an in criteria on the parsed array, and writes them to a file rather than inline (outputs[].outputMode: ATTACHMENT), so the result size never weighs on the workflow payloads. The cleaning happens here: includedFieldKeys whitelists the three fields to keep, and everything else is stripped from the response - the items' metadata, including the partition ids the caller needs, is always preserved:
json
{
"findMode": "REQUEST",
"request": {
"method": "INLINE",
"contentType": "application/json",
"model": "default",
"json": {
"context": {
"tableKey": "PRODUCTS",
"partitionKey": "ACTIVES"
},
"criteria": {
"type": "in",
"caseSensitive": true,
"field": {
"target": "item.fields",
"key": "EAN_13"
},
"value": "${parse_eans.output.result.eans}"
},
"options": {
"includedFieldKeys": ["EAN_13", "DESCRIPTION", "CATEGORY"]
}
}
},
"outputs": [
{
"mediaType": "application/json",
"outputMode": "ATTACHMENT",
"outputKey": "json"
}
]
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
With ATTACHMENT, result.json is no longer the items array but a file reference holding it.
[3] Shape the request file. A second script loads the exported file (resources, loadAs: JSON), maps each item to a data-item-create-or-update operation - the fields arrays already have the expected {key, type, value.data} shape, so they are carried over verbatim - and writes the result to a file of its own (response: FILE), which is exactly the request body the caller needs:
json
{
"expressionFile": "file://assets/build-operations.js",
"resources": [
{
"key": "items",
"file": "${find_products.output.result.json}",
"loadAs": "JSON"
}
],
"response": "FILE",
"outputFileName": "operations.json"
}1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
The job then exposes the result in its outputParameters, which is the only part of an execution readable by its caller:
json
{
"outputParameters": {
"requested": "${parse_eans.output.result.count}",
"found": "${find_products.output.totalElements}",
"operations_file": "${build_operations.output.result}"
}
}1
2
3
4
5
6
7
2
3
4
5
6
7
Which account each task runs on
- Tasks with no
apiKeyrun in the context of the account running the job, here the supplier. This is the case of the creation - which is why the products land on the supplier's side of the shared table, and why the same shared job works for every supplier. - Tasks carrying an
apiKeyrun in the context of the key's account, here the distributor. This is the case of the trigger, which is why the export job - private to the distributor - can be found and executed at all. - The receiving side addresses the shared table by ids, not by keys. A table shared to an account is not returned by the key-based finds run on that account: on the supplier,
data-table-findon the table key anddata-partition-findon the table id both come back empty. Reading and writing items with an explicitpartitionIdworks. This is why each operation returned by the export job carries itspartitionId, and why the shared job holds no table or partition key at all. - The returned file is designated by a URL that is sufficient on its own to download it. That is what lets the creation task read, from the supplier's context, a file produced on the distributor account - and also why such URLs must be treated as confidential.
- The table being the same shared table on both sides, the ids and the fields returned by the distributor (partition ids, field keys, types, and selection values such as the category) are valid as-is on the supplier's side.
Things to watch out for
One job per pipeline
A pipeline runs a single job at a time. The export job must run on a different pipeline than the job that waits for it, otherwise the waiting job blocks its own trigger until the wait times out. See Pipelines.
- Single-level tables only. This use case does not handle tables with several levels: the products are created without any parent or children, and the hierarchy of the distributor's catalog is not carried over
- EANs unknown to the distributor are simply absent from the result: the job creates the products that were found, and its output reports
requestedvsfoundso the difference is visible at a glance. If none of the EANs is found, the export job fails with an explicit error and so does the calling job - Re-running the job is safe. As the task name says,
data-item-create-or-updateupserts: anitem_createoperation whose identifier already exists on the supplier's side updates the product in place (the same item id is returned) instead of failing. The job can therefore also be used to refresh existing products with the distributor's latest data - Volume. The result travels as a file, so its size never weighs on the workflow payloads; the remaining bounds are the EAN list typed as a single text input and the creation happening in a single request. This job is designed for reasonable lists (up to a few hundred EANs per execution), not for full-catalog synchronization - for that, see the
table-export-items/table-import-itemsflow of the Trigger a job from another job and use its result use case waitOptions.failOnErrordefaults totrue: any terminal status of the export job other thanCOMPLETEDfails the calling job- This job intends to illustrate the mechanism and can be enhanced to suit your needs: the table key, partition key and field keys - all carried by the export job only - are specific to the demonstration table and must be adapted. To keep more fields than the description and the category, extend
includedFieldKeys- the operations travel in the same shape the creation step already consumes