About integration with fmcgProducts and fmcgProductsIntegrator
Methods
fmcgProducts supports the integration of product data with other systems using a web services API (JSON/XML), FTP, and mail-in.
File types
In addition to JSON/XML, fmcgProducts can process text files (comma-separated or column-formatted) and Excel files.
Field types
fmcgProducts can send and receive the following field types.
- GDSN 3.1 fields "Dxxxx", e.g. EAN/GTIN (D8165), Product name (D8258) etc.
- Own fields "Exxxx", e.g. assortment, product category fields etc. that you want to "control" in fmcgProducts, e.g. in relation to assortment overviews, product category overviews, Excel extracts, integration with other systems, etc.
- System fields "Xxxxx", e.g. X9000 "Ready for GS1" which makes it possible to control the synchronisation of product data with GS1 (should the product be synchronised with GS1 if it is "GS1 valid" or not).
- Other fields that are "mapped" to known fields in fmcgProducts.
History
Regardless of the method used to integrate and update fmcgProducts, all transactions and changes will be recorded on the individual product unit. The specific history for the individual product unit can be viewed by selecting "Show product history" from the user interface on the individual product.
Mail-In
fmcgProducts can receive text files (comma-separated or column-formatted) as well as Excel files via mail-in. fmcgProducts can be configured so that only specific sender addresses are allowed to email files to fmcgProducts for updating.
Integration without "mapping"
fmcgProducts can import a Microsoft Excel spreadsheet directly (without mapping) provided the Excel import syntax is followed. Correct syntax is field type/number in the first row and that the GDSN 3.1 standard is used in relation to keywords - example:
If the product unit already exists in fmcgProducts (the unique key is "EAN/GTIN + target market (country code)), the product unit is updated in fmcgProducts. If "EAN/GTIN + target market" is not found in fmcgProducts, a new product unit is created in fmcgProducts.
If the syntax is not respected, e.g. in case of missing Ean/GTIN in column A, the field indicated in the first row does not exist in fmcgProducts, use of an invalid keyword etc., the relevant row is skipped (product) and an attempt is made to load the next row (product).
For every loading of product data into fmcgProducts, a loading report is generated which shows exactly which rows (products) have been loaded correctly and which rows (products) have not been loaded due to syntax errors. The exact cause of syntax errors is indicated in the loading report (field does not exist, invalid keyword etc.).
It is possible to set up fmcgProducts so that the loading report is emailed to one or more email addresses following a loading to fmcgProducts.
Integration with "mapping"
fmcgProducts contains a "mapping module" which makes it possible to import and export files (comma-separated or column-formatted text file) to/from fmcgProducts.
Provided that "EAN/GTIN + target market" is specified correctly anywhere in the import file, it is possible to map all fields from the import file, i.e. position in the load file, to the corresponding fields in fmcgProducts.
If mapping, a number of functions can be performed at the same time - examples:
- Conversion (e.g. from KG to GRAM)
- Default fields (e.g. units of measurement, country codes, fixed values in fields, etc.)
"one to several units" e.g. can one row be loaded from a text file, which subsequently forms the basis for updating/creating several product units (base-box-pallet)
Web services API (JSON)
The API has support for the following calls/endpoints:
General:
GET /api/: returns system status on fmcgProducts.
GET /api/openapi: returns documentation in OpenAPI format.
GET /api/openapi.json: returns documentation in OpenAPI format as JSON.
One product/GTIN:
GET /api/status/<product id>: returns the status of the product where the product id is GTIN.TargetMarket. Example: https://<customer instance>.fmcgproducts.dk/api/status/04005514026085.752
GET /api/details/<product id>?fields=D8256,D8258,D8245: returns status and specific fields (the example returns the supplier's product number, the supplier's product name and GPC code).
GET /api/details/<product id>/<export profile>: returns status and specific fields defined in the export profile.
GET /api/details/<product id>/allfields: returns status and all fields.
Additional parameters:
- ?displayValues=true: Displays keyword value as translated value rather than as "technical" value.
Note: when using the export profile, this is determined based on the settings on the export profile itself.
POST /api/: creates/updates a product. The key is GTIN via field D8165 and target market via field D8255. Returns response corresponds to /api/status/<product id>. In this way validation errors (GDSN and specific rules for the individual target markets) are returned.
With the field "test" set to true, testing can be done without creating/updating products, and the correct response will still be returned.
You can send in data that you want to be returned in the response in the field called "customRequestId". This can be used for tracking in your internal systems.
Input is case sensitive, so Dxxxx fields must be entered in uppercase letters.
Date/time fields accept the following formats:
- dd-MM-yyyy
- dd-MM-yyyy HH:mm
- yyyy-MM-dd'T'HH:mm:ss
- yyyy-MM-dd'T'HH:mm:ss.SSS
You can update multiple products in one post to the API by sending the products in a JSON array.
If you want to remove/clear a field value, then you should send an empty string or a null value (example: so either “D8256”: “” or “D8256”: null).
If you don’t have any updates to the field and want to keep the current value, then you do not need to send the value again (but it’s ok if you do).
If you want to clear a grid then you need to set the first row to blank/null for all fields in that grid. All rows will then be cleared.
Alternatively you can use the "deleteGrids" array and add the name of the grid that you want to delete. The name of the grid can be found in the field definition for any field in that grid.
If you have 5 rows in a grid and now want to only have 1 row, then you only need to send the values for the first row. The rest of the rows will then be cleared.
Multiple products/GTINs.
GET /api/products/status: returns the status of all products with the option to limit the number of products with fromdate, limit and offset.
POST /api/products/status: returns the status of selected products with the option to limit the number of products with fromdate, limit and offset.
GET /api/products/status?fromdate=01-01-2022: returns the status of all products sent to GS1 since 1/1-2022.
GET /api/products/status?fromdate=01-01-2022&offset=25&limit=25: returns the status of all products sent to GS1 since 1/1-2022, but use offset and limit to retrieve a subset (paging).
Status codes.
The API returns the status of a product hierarchy in fmcgProductsStatus and gs1Status.
fmcgProductsStatus can have the following possible values that are directly mapped to the current value in X9004:
SENT
PENDING
OK
FAILED
The purpose of gs1Status is to return the latest status from GS1 if the product has been sent to GS1 before.
If the product has never been sent to GS1, then the returned status is NEVER_SENT.
If the product is expired or withdrawn, then this status is returned (as either EXPIRED or WITHDRAWN).
If the product has recently been submitted (so that fmcgProductsStatus is PENDING), then gs1Status will reflect the latest status from GS1.
So gs1Status can therefore have the following possible values:
SENT
OK
FAILED
NEVER_SENT
EXPIRED
WITHDRAWN
A selection of multiple products/GTINs.
One or more selections can be defined based on certain criteria. The selection is saved in the customer instance under a "viewname", which is specified in the web API call. The API returns all the products that meet the given criteria. This allows you to define a number of selections, e.g. on selected suppliers (GLN = ??? OR GLN = ??? etc.), on GPC code and so on, which returns exactly the product data that is needed.
Examples:
GET /api/view/<view id>: Returns all products from the specified selection/view in JSON format.
GET /api/view/<view id>/xml: Returns all products from the specified selection/view in XML format.
GET /api/view/excel/<view id>/<export profile>: Returns an Excel file with products from the specified view with fields as specified in the export profile.
Additional parameters:
- &fieldnames: "gs1" can be specified, which returns gs1 field names, or other field names by agreement (corresponding to the field names used by the receiving system)
- &gridsToArray=true: Collects fields from the same grid in one JSON array rather than displaying the fields in a flat structure
- &allergensToBold=true: Indicates allergens in ingredient description D8179 in bold (with <b> and </b>) based on the allergen filter for the language in question for the product's target market
- &displayValues=true: Displays keyword value as translated value rather than as "technical" value
- &limit=<number>&offset<start from number>: Returns a number of products from the specified "offset" (paging)
- &modifiedsince=<minutes>: Returns the products in the relevant view/selection that have been modified within XXX minutes. It requires that the first column in the corresponding overview is either D8260 ("Last modified" date for GS1 fields), X9101 ("Last modified" date for GS1 and own fields) or last modified dateTime @Modified. Otherwise D8260 ("Last modified" date for GS1 fields) is automatically used.
PDF.
GET /api/pdf/<product id>: retrieves product sheet as PDF for the product where product id is GTIN.TargetMarket. The default PDF template for the unit type in question is used.
GET /api/pdf/<product id>/<PDF template>: retrieves product sheet as PDF for the product where the product id is GTIN.TargetMarket.
GET /api/pdf/<item id>/<country>/<PDF template>: retrieves product sheet as PDF for the product with the specified item number (item id) from the specified target market.
GET /api/web/<product id>/<PDF template>: retrieves the product sheet as HTML for display directly in the browser for the product where the product id is GTIN.TargetMarket.
GET /api/web/<item id>/<country>/<PDF template>: retrieves the product sheet as HTML for display directly in the browser for the product with the specified item number (item id) from the specified target market.
In all cases "PDF template" is the name of the template or the ID of the template. If the name does not match, the PDF template which is the default for the unit type in question is used.
Security.
The API is accessed with basic authentication.
Furthermore, it is possible to use an API key which must be sent in a HTTP header called X-Api-Key in order to access the API.
fmcgProducts and fmcgProductsIntegrator are run in a duplicated server environment consisting of a cluster with servers distributed over 2 physical locations.
Nginx is used for distribution of HTTPS traffic and redirection in the event of a server failure.
As an alternative to basic authentication, all services can be locked to one or more IP addresses, and thus only the specified IP addresses have access to call the API.
The API can also be secured with OIDC.
Caching.
All calls to /api/ return an ETag HTTP header. The value in the ETag HTTP header must be sent back in subsequent calls to the API on the same request in an If-None-Match HTTP header in order to utilise caching and thus get faster responses if the data has not changed since the last call (conditional GET).
Limits/throttling.
The API has a limit of 90 requests/minute to limit the load on the backend servers. If the limit is exceeded, the API returns HTTP 429 "Too Many Requests".
HTTP responses.
The API use the HTTP response code to indicate whether the request was accepted or not.
If the request content is correct and for instance a requested product can be processed (whether valid or not) then the HTTP response code is OK (200).
HTTP Bad request (400) means that the request contains invalid content so that for instance a product can not be processed and validated (such as incorrect/unknown field names).
If authentication is unsuccesful then the HTTP response code is Unauthorized (401).