1 Introduction

The Tracelink API allows you to access and modify data in Tracelink using webservice REST - HTTP and JSON/XML. The web based Tracelink application and the mobile App (iOS/Android) both use the API, hence it is highly tested and validated.

To access the API, an access token has to be generated within the Tracelink application. The access token are connected to a user account, has a access level (priviledges), and an expiration date.

If you have any questions to the API or need help, please contact us at api@tracelink.dk.

1.1 Service URL

The Tracelink API is accessed using the following base URL:
  https://tracelink.app/rest
Only secure HTTPS requests are allowed.

1.2 Request method

Requesting data, create objects and modify objects all use the POST request method.

Request REST Method Tracelink Method Comment
Create POST POST Create new object
Read GET POST Get list of objects - sorting/filtering in the body. See section 4 - Sorting and 5 - Filtering
Update PUT/PATCH POST Update existing object, as a PATCH command, including the object ID, and one or more key/values
Delete DELETE POST Delete existing object, by sending the object ID and the key xdelete with value 1

The above do not quite go with the REST standard, but it actually makes things more simple. Especially all filter, sorting, etc. is not handled by escaped query strings parameters but are handled as simple JSON order object in the body of the the POST call - see Sorting and Filtering below.

1.3 Response

Response from a request consist of a HTTP header followed by JSON response (content-type: application/json).

The JSON response consist of a basic Tracelink “header” with the following key/values:

  • status: will have a value of “ok” or “error”
  • code: same as the HTTP Header response code (e.g. 200 – OK, 404 – Not found, etc.)
  • query_millisec: the server time for handling the request
  • message: return message (e.g. error explained)
  • count: number of “objects” returned
  • total: total number of “objects” in request without limit (optional - depends on request)
Example of a response:
{
  "status":"ok",
  "code":200,
  "message":"TraceLink Orders for group 'all'",
  "count":4,
  "total":4,
  "order":[{...}, {...}, {...}, {...}]
}

After the Tracelink “header”, the object(s) (if any) is returned, depending on the function called. In the example above the “object” is “order”.

1.4 Idempotency

The API supports idempotency for safely retrying requests without accidentally performing the same operation twice. When creating or updating an object the client sends an idempotency key as part of the request. Then, if a network or connection error occurs, you can safely repeat the request without risk of creating an object twice.

The idempotency key is a unique key for each request, and is used to identify the request. The client is responsible to send a unique key for each request, if an error occurs, the client can safely send the request again, with the same key, and the API ensures that only one object is created or updated.

The key is sent in the HTTP header field Idempotency-Key with a unique value of maximum of 32 charaters. The server holds the response in minimum 2 hours, and will after that expire within one hour. To be safe, you should not reuse keys within 24 hours.

If a request with the same idempotency key is sent a second time and it has already been executed successfully, the API will return a cached response. You can identify these responses by the X-ResultFromCache header, which will be set to the idempotency key supplied in the request.

1.5 Tools

There is a lot of REST tools out there, like Advanced REST Client, Postman or just plain cURL. We use the first one with great success.

If you get an error - it might be because the body JSON object is not valid. To validate the JSON object, the online validator jsonlint.com is a good place to validate.

2 Authentication

To access a resource, an OAuth access token has to be provided in each request.

2.1 Generate access token

In the Tracelink application, an adminstrator can create access tokens to be used.

Go to the "Settings" menu, and then "External API key", and then create a new "key".

Please make an access token for each integration partner, it will then be easy to revoke the access for that partner if not needed anymore. Also provide a name of the token, which will indentify the token (e.g. what it is used for, which partner, etc.). The description can be used for further notes.

A token is hooked up on a user account. It would be a good idea to create a seperate user for integrations, since all objects created and modifies will have that user as source.

The token also includes an access level, which sets permissions to data:

  • No access
  • Read - access to read data
  • Read and create - further permission to create new objects
  • Read, create and write - further permission to update/write existing objects
  • Read, create, write and delete - further permission to delete existing objects
A third element in the token is an expiration date. After this date, the token is not valid.

The restrictions can be changed without generating a new token (the information is not included in the token) - i.e. it is not nessesary to generate a new token if the access level or the expiration is changed.

2.2 Request

When requesting the API, the access token has to be provided.

This can be provided in a HTTP header field:

  x-access-token: <token>
- where <token> is the access token.

Or it can be specified as a query string parameter:

 https://tracelink.app/rest/<endpoint>?token=<token>
- where <endpoint> is the endpoint requested (see endpoints) and <token> is the access token.

2.3 Test the connection

To verify a connection to the API, you can perform a test by requesting information associated with the user linked to the <token> user account, using the cURL command line tool:
curl -X POST https://tracelink.app/rest/user -H 'x-access-token: <token>'

3 Formats

The request body and return data, can be in either JSON or XML.

3.1 JSON

The JSON format is the default, but you can add a HTTP header
accept: application/json
to specify it explicit.

Example of a JSON request body object:
{
  "object": {
    "user_id": 12345,
    "name": "Mr. Example"
  }
}

3.2 XML

If you would like to use XML instead of JSON as the transfer format you can do that.

In the HTTP header specify:

accept: application/xml
By specifying the application/xml header, the POST body should be in XML, and wraped by a <request> keyword. The result will be wraped in a <response> keyword.

Example of a XML request body object:
<request>
  <object>
    <user_id>12345</user_id>
    <name>Mr. Example</name>
  </object>
</request>

3.3 Character set

Default character set used in requests and replies is UTF-8 - e.g. all requests must be in UTF-8 format.

To make it easier for old Microsoft systems to integrate to Tracelink, it's possibe to send data in code page 850 (or Latin-1) and let Tracelink convert it to UTF-8. This is done by adding a HTTP header:

X-Charset: CP850
Note that conversion is only on requests, replies are still in UTF-8.

4 Sorting

If more that one object is returned, it is possible to specify which sorting should be used. In the body you can specify sort and reverse keys inside an order object.

Example of sorting by create date in reverse (descenting):
{
  "order": {
    "sort": "create_date",
    "reverse": 1
  }
}
The default sorting is by "name" in acending order.

It is possible to add more sort keys. Say you would like to sort by create date and - if two object has same create_date - then by name.

{
  "order": {
    "sort": "create_date,name"
  }
}

5 Filtering

To filter the objects returned, it is possible to add a filter object inside an order object. Within this object you specify the filter fields/columns.

Example of filter all objects which is not locked and is created after january 1st, 2020:
{
  "order": {
    "filter": {
      "create_date": ">2020-01-01",
      "locked": "=0"
    }
  }
}

Example with multiple operands on same key:
{
  "order": {
    "filter": {
      "order_id": [">1000", "!=2000"],
      "locked": "=0"
    }
  }
}

Default is to "AND" the fields/columns, if an "OR" option is needed (e.g. for searching in more columns), you can add a filter_or key.

Example with "OR" instead the default "AND":
{
  "order": {
    "filter_or": true,
    "filter": {
      "create_date": ">2020-01-01",
      "locked": "=0"
    }
  }
}

Advanced example with "OR" and "AND":
{
  "order": {
    "filter_or": true,
    "filter": {
      "create_date": ">2020-01-01",
      "update_date": "OR >2020-01-01",
      "locked": "AND =0"
    }
  }
}

5.1 Field operands

In the examples above, both "=" and ">" is used. The operands can be used as follows:

  (empty) default operant - if no one specified - "LIKE" is used
~ not "LIKE" (tilde)
= is equal
!= not equal
< is less than
<= is less than or equal
> is greather than
>= is greather than or equal
IN(x,y,z) "IN" list of values (e.g. list of id's)
!IN(x,y,z) not "IN" list of values (e.g. list of id's)
Bx,y Between x and y (e.g. between two dates)

5.2 Paging

Default page size in Tracelink is 1.000. If you need more that 1.000 elements you can use paging.

You can specify two keys in the order object: limit and page for paging.

The limit specifies the page size (which by default is 1000, and can not be higher), and the page is which page you would like to retrieve.

Say you have a resource with 10.000 object, then the first response will return the first 1.000, sending the request again, with page: 1 will return the next 1.000 (ie. the first page with element 0 to 1.000 is 0)

Example of limiting objects to 100 and fetch page 2
{
  "order": {
    "limit": 100,
    "page": 2
  }
}
Please use a low limit (e.g. 100), and then use filtering to get the needed objects. That's much more efficient that transfer large amount of data.

5.3 Filtering and sorting

Sorting, filtering and paging can be combined into the order object.

Example finding first 25 objects which is not locked and sorted by name
{
  "order": {
    "sort": "name",
    "limit": 25,
    "filter": {
      "locked": "=0"
    }
  }
}

5.3.1 Example request

A complete cURL example for getting a list of maximum 25 Tracelink orders, sort by the name of the orders, and where the orders is not locked - would be:
curl -X POST https://tracelink.app/rest/tracelink/order/list -H 'x-access-token: <token>' \
  -d '{"order": {"sort": "name", "limit": 25, "filter": {"locked": "=0"}}}'

6 Types

The columns returned by a request, will have a type naming convension, this will makes it easy to convert to display, and ensures a uniform way.

In general, the last part of the column name determines the type. Say that a column ends with _dt it tells you, that the type is time and date - eg. 2020-02-31 10:23:10. All dates are in CET (ajusted by day light savings time). All decimals has a maximum length of 16, where 10 goes before the decimal point and 6 after.

Ends withType
_cyCurrency (decimal)
_pctPercent % (decimal)
_scSeconds (duration)
_iIntegrer
_fDecimal
_boolBoolean
_byteBytes
_dt
date_time
create_date
update_date
Date and time
_da
date
Date
_tiTime of day

7 Modules

Tracelink are built in modules, and there are more than 50 of them. Each module adds functionality to Tracelink. Some customers only have a handfull, other have 15 or even more.

The most important modules for the API is:

NameInternal nameDescriptionAccess by
Custom listscustlistCustom lists - used for extra fields
TimeRegtimeregTime registrationOrder
CustomercustomerTracelink Customers
TasktaskHandling of tasks, routes, etc.Order
GenObjgenobjGeneric object type - stock, bookings, etc.Direct/Order
Batchbatch_genobjBatch portions for the stockGenobj
DocsdocsGuidelines, procedures, documents, etc.
CRMcrmCRM and sales qoutes
PurchasepurchasePurchase orders
SuppliersupplierPurchasing suppliers
Stock locationstocklocStock locations for Genobj/Batch

Some endpoints will have a module_id in the URL, this should be replaced with the "Internal name" column above.

Example of a URL with module id
https://tracelink.app/rest/tracelink/order/list/module/timereg/74295

This call will return the time registrations for order 74295.

For modules where "Access by" is "Order" see section 8.4.

8 Endpoints

The endpoints or request URL's, are grouped into different usages.

8.1 Core Tracelink endpoints

8.1.1 Company

Get master data of the current company:

/company

8.1.2 Departments

Get all departments:

/company/dept/list

8.1.3 Users

Get current login user:

/user
Get all users:

/user/list

8.1.4 User groups

Get all user groups:

/user/group/list

8.2 Tracelink modules

Create, read, update or delete module objects in Tracelink.

8.2.1 Create

Create endpoints will have the create and module-name keyword in the URL.

Example of a URL with create for an object in the purchase module (the internal name)
https://tracelink.app/rest/object/create/purchase

With a payload of:

{
  "object": {
    "number": "523",
    "name": "Icecream",
    "description": "",
    "exp_delivery_dt": "2020-09-25 10:00:00",
  }
}
Response from the request is
{
  "status": "ok",
  "code": 201,
  "message": "Item '156' for module 'Purchase' created",
  "count": 1,
  "object": {
    "purchase_id": 156
  }
}
The purchase_id is the internal Tracelink ID for the purchase. This ID is used to update the purchase.

8.2.2 Read

Read endpoints will have the module-name and id keyword in the URL.

Example of a URL with read for an object in the purchase module
https://tracelink.app/rest/object/list/module/purchase/156

- where 156 in this example, is the purchase_id. The response is:

{
  "status": "ok",
  "code": 200,
  "message": "Object 156 to module Purchase returned",
  "count": 0,
  "object": {
    "purchase_id": "156",
    "number": "523",
    "name": "Icecream",
    "description": "",
    "module_id": "51",
    "supplier_id": "8",
    "supplier_invoice": "",
    "total_purchase_price_f": "0.000000",
    "due_dt": "0000-00-00 00:00:00",
    "invoice_dt": "0000-00-00 00:00:00",
    "invoice_extra_cy": "0.000000",
    "assigned_user_id": "1",
    "assigned_group_id": "0",
    "order_id": "0",
    "order_sub_id": "0",
    "item": "0",
    "locked": "0",
    "placed": "0",
    "placed_dt": "0000-00-00 00:00:00",
    "state": "Under opbygning",
    "extra_dt": "0000-00-00 00:00:00",
    "exp_delivery_dt": "2020-09-25 10:00:00",
    "foreigndata_1": null,
    "foreigndata_2": "",
    "foreigndata_3": "",
    "metadata_1": "",
    "metadata_2": "",
    "metadata_3": "",
    "metadata_4": "",
    "metadata_5": "",
    "order_metadata_1": "",
    "order_metadata_2": "",
    "order_metadata_3": "",
    "order_metadata_4": "",
    "order_metadata_5": "",
    "create_date": "2020-09-28 13:39:17",
    "create_user": "1",
    "update_date": "2020-09-28 13:39:17",
    "update_user": "1",
    "create_user_name": "Claus Bo",
    "update_user_name": "Claus Bo",
    "doc": [],
  }
}

8.2.3 List

List endpoints will have the list and module-name keyword in the URL.

Example of a URL with list for objects in the purchase module
https://tracelink.app/rest/object/list/module/purchase

The response is:

{
  "status": "ok",
  "code": 200,
  "message": "Object 156 to module Purchase returned",
  "count": 0,
  "object": [{
        <object>
      }, {
        <object>
      }, {
        <object>
      }, ...
  ]
}
- where <object> is a purchase object (like the one in the read endpoint).

Note that Tracelink will enforce a limit of 1.000 objects - please read the Paging section for more infomation.

8.2.4 Update

Update endpoints will have the update and module-name keyword in the request.

Example of a URL with update for an object in the purchase module (the internal name)
https://tracelink.app/rest/object/update/purchase

The payload should include the purchase_id of the object that should be updated, and the fields to update:

{
  "object": {
    "purchase_id": "156",
    "name": "Icecream new name",
  }
}
Response from the request is
{
  "status": "ok",
  "code": 201,
  "message": "Object '156' for module 'Purchase' updated"
}
The purchase_id is the internal Tracelink ID for the purchase.

8.2.5 Delete

To delete an object the update endpoint is called with module-name keyword in the URL.

Example of delete an object in the purchase module (the internal name)
https://tracelink.app/rest/object/update/purchase

The payload should include the purchase_id of the object that should be deleted and the xdelete keyword equal to '1':

{
  "object": {
    "purchase_id": "156",
    "xdelete": "1",
  }
}
Response from the request is
{
  "status": "ok",
  "code": 201,
  "message": "Object '156' for module 'Purchase' deleted"
}
Please note that Tracelink API will not check if a delete is posible or not, and will not update other objects that has a reference to the deleted object. In many modules a disabled field should be used, which just disables the object, hence relations will be intact (this way prober traceability will be keept).

8.2.6 List documents

As the endpoint /object/list/module will not list documents (only if asked for a specific 'id'), this endpoint list documents to a module. The endpoint could be used in cases where you would like to list new documents or changed documents within a specific time.

Example of listing documents in the genobj module (the internal name)
https://tracelink.app/rest/util/doc/list/module/genobj

The payload can include filter and sorting, see Filtering and Sorting for more information.

So if I need documents changed/created since 2024-01-01, the payload could be:

{
  "order": {
    "filter": {
      "update_date": ">2024-01-01"
  }
}
The response is:
{
  "status": "ok"					
  "code": 201
  "count": 3
  "message": "Documents from module 'purchase' listed"
  "object": [{...}, {...}, {...}]
}

8.2.7 Upload document

To upload a document to a module the update call should be used.

Example of update an object in the purchase module (the internal name)
https://tracelink.app/rest/object/update/purchase

The payload should include the purchase_id of the object that should be updated, and the fields to update:

{
  "object": {
    "purchase_id": "1040",
    "image_data_encoded": "...base64 encoded data...",
    "image_description": "document.png",
    "image_type": "png"
  }
}
- where purchase_id is the id of the parent object (e.g. if the module is CRM it should be crm_id), image_data_encoded is the base64 encoded data of the document, image_description is the name of the document and image_description is the type/extension if the file (e.g. jpg, png, pdf, etc.) - if not set the extention is taken from the description.

8.3 Order/suborder

Create, read, update or delete Tracelink orders and suborders

8.2.1 Create order

Create a Tracelink order:
/tracelink/order/create

Example payload
{
  "object": {
    "number": "912",
    "name": "Make a car for Ford",
    "description": "Make it a black Ford T"
  }
}
Response from the request is
{
  "status": "ok",
  "code": 201,
  "message": "TraceLink order number '2020219' created",
  "order_id": 1040,
  }
}
The order_id is the internal Tracelink ID for the order.

If the order should be automatically numbered, number should not be included, and three fields should be added to the object payload:

{
  "object": {
    "name": "Make a car for Ford",
    "description": "Make it a black Ford T",
    "use_numbering": 1,
    "number_begin": 1000,
    "number_offset": 1
  }
}
use_numbering equal to 1, means use auto numbering, number_begin is the start number (if no order has been created before) and number_offset is the delta between numbers (if 10, then the orders will be 1000, 1010, 1020 if begin starts at 1000).

8.3.2.1 Create suborder

Create a suborder is similar to an order, exept that the order (under which the suborder should live), should be included in the request as parent_order_id:
/tracelink/suborder/create

Example payload
{
  "object": {
    "parent_order_id": "1040",
    "number": "912 - 1",
    "name": "Make wheels"
  }
}

8.3.2 Read order

Read a Tracelink order:
/tracelink/order/<order_id>

- where <order_id> is the internal Tracelink order id (in the example above 1040.

Example response on request /tracelink/order/1040
{
  "status": "ok",
  "code": 200,
  "message": "TraceLink Order with id 10140",
  "count": 1,
  "order": {
    "order_id": "1040",
    "number": "1010",
    "name": "Make a car for Ford",
    "description": "Make it a black Ford T",
    "dept_id": "0",
    "locked": "0",
    "paused": "0",
    "state": "",
    "start_date": "2020-09-28 00:00:00",
    "deadline_date": "2020-10-01 16:17:00",
    "budget_hours": "0",
    "budget_minutes": "0",
    "units": "1.000000",
    "assigned_user_id": "0",
    "order_group_id": "0",
    "parent_order_id": "0",
    "order_src_data": "",
    "customer_id": "0",
    "delivery_address_id": "0",
    "customer_contact_id": "0",
    "bpm_id": "0",
    "stockloc_id": "0",
    "tmpl_id": "0",
    "metadata_1": "",
    "metadata_2": "",
    "metadata_3": "",
    "metadata_4": "",
    "metadata_5": "",
    "metadata_form": "",
    "metadata_values": "",
    "foreigndata_1": "",
    "foreigndata_2": "",
    "foreigndata_3": "",
    "create_date": "2020-09-28 16:17:18",
    "update_date": "2020-09-28 16:17:41.780",
    "create_user": "1",
    "update_user": "1",
    "create_user_name": "Claus Bo",
    "update_user_name": "Claus Bo",
    "sub_order": []
    }
}

8.3.2.1 Read suborder

Read a suborder is similar to an order
/tracelink/suborder/<order_sub_id>

8.3.3 List orders

Get a list of Tracelink orders:
/tracelink/order/list

Example respons
{
    "status": "ok",
    "code": 200,
    "message": "TraceLink Orders for group 'all'",
    "count": 25,
    "total": 230,
    "order": [{
        <order>
      }, {
        <order>
      }, {
        <order>
      }, ...
  ]
}
- where <order> is a order object (like the one in the read endpoint).

Note that Tracelink will enforce a limit of 1.000 orders - please read the Paging section for more infomation

8.3.3.1 List suborder

List of suborders is similar to list of orders
/tracelink/suborder/list

8.3.4 Order update

Update a Tracelink order:
/tracelink/order/update

The payload should include the order_id of the order that should be updated, and the fields to update:

{
  "object": {
    "order_id": "1040",
    "name": "Make a electric car for Ford",
  }
}

8.3.4.1 Suborder update

Update of suborder is similar to order
/tracelink/suborder/update

8.3.5 Delete

To delete a Tracelink order, the update endpoint is called.

The payload should include the order_id of the order that should be deleted and the xdelete keyword equal to '1':

{
  "object": {
    "order_id": "1040",
    "xdelete": "1",
  }
}
Please note that Tracelink API will not check if a delete is posible or not, and will not update other objects that has a reference to the deleted order or suborder. Make sure that there is no reference to the deleted order, else inconsistence will be introduced.

8.3.6 Upload document

To upload a document to an order the update call should be used.
/tracelink/order/update

The payload should include the order_id of the order that the document should be added to:

{
  "object": {
    "order_id": "1040",
    "image_data_encoded": "...base64 encoded data...",
    "image_description": "document.png",
    "image_type": "png"
  }
}
- where image_data_encoded is the base64 encoded data of the document, image_description is the name of the document and image_description is the type/extension if the file (e.g. jpg, png, pdf, etc.) - if not set the extention is taken from the description.

Add a document to a suborder is similar to the above order e.g. update a suborder

8.4 Module to order/suborder

Create, read, update or delete modules to Tracelink orders and suborders. These endpoints are used to add module objects to a Tracelink order (or suborder). An example is adding a time registration to an order.

8.4.1 Create add module to order

Create a module entry to a Tracelink order:
/tracelink/order/add/object/module/<module-name>

Example payload for a time registration - /tracelink/order/add/object/module/timereg
{
  "object": {
    "order_id": "10134",
    "order_sub_id": "0",
    "timerstart": 1601306570,
  }
}
Response from the request is
{
  "status": "ok",
  "code": 201,
  "message": "Object 1186 for module 'TimeReg' added to order 1040",
  "count": 1,
  "object": {
    "timereg_id": 1186
  }
}
The order_id is the internal Tracelink ID for the order.

8.4.2 List module to order

Get a list of modules entries to a Tracelink order:
/tracelink/order/list/module/<module-name>/<order_id>

Example respons from /tracelink/order/list/module/timereg/1040
{
  "status": "ok",
  "code": 200,
  "message": "List to module 'timereg' returned (5/5)",
  "count": 5,
  "total": 5,
  "objects": [
    {
      "timereg_id": "1181",
      "dept_id": "0",
      "order_id": "1040",
      "order_sub_id": "0",
      "item": "0",
      "order_name": "1010 - Make a car for Ford",
      "multi_order": "[]",
      "task_id": "0",
      "task_name": "",
      "timerstart": "0",
      "timerpause": "0",
      "stop_date": "2020-09-08 16:30:00",
      "hours": "0",
      "minutes": "12",
      "profiletime_id": "9",
      "wage_type": "3200",
      "operation": "20",
      "locked": "0",
      "approved": "0",
      "econ_approved": "0",
      "latitude": "0.0000000000",
      "longitude": "0.0000000000",
      "altitude": "0",
      "accuracy": "0",
      "origin_address": "",
      "dest_address": "",
      "distance": "0",
      "distance_text": "",
      "drive_time": "0",
      "drive_time_text": "",
      "metadata_1": "",
      "metadata_2": "",
      "metadata_3": "",
      "metadata_4": "",
      "metadata_5": "",
      "foreign_key": "0",
      "create_date": "2020-09-08 16:18:00",
      "create_user": "1",
      "create_platform": "MacIntel Safari 13.0.5",
      "update_date": "2020-09-09 13:43:51",
      "update_user": "1",
      "create_user_name": "Claus Bo",
      "update_user_name": "Claus Bo"
    }, ...
  ]
}
To get alle timeregistrations (or other modules items to order) - the endpoint can be called without the order number - e.g.
/tracelink/order/list/module/<module-name>
Here you would proberly setup some filtering - e.g. for getting all registrations for a certain use. See the Filtering section.

8.4.3 update module to order

Update a module entry to a Tracelink order:
/tracelink/order/update/object/module/<module-name>

8.4.4 delete module to order

Delete a module entry to a Tracelink order:
/tracelink/order/update/object/module/<module-name>
- whith the xdelete set to '1'

8.5 Module to module

Create, read, update or delete modules to modules. These endpoints are used to relate one module objects to a different module. An example is adding a genobj (stock goods) to a CRM activity.

8.5.1 Create module to module relation

Create a module entry related to a different module:
object/module/create/<from-module>/to/<to-module>

Example payload a genobj (stock goods) to a CRM activity - object/module/list/genobj/to/crm
{
    "object": {
        "genobj_id": "546271"
        "crm_id": "16126",
        "unit_order_count_f": 1
     }
}
Response from the request is
{
    "status": "ok",
    "code": 201,
    "message": "Object 45150 for module 'genobj_crm' added",
    "count": 1,
    "object": {
        "genobj_crm_id": 45150
    }
}

8.5.2 List module to module

Get a list of one module entries related to different module:
object/module/list/<from-module>/to/<to-module>/<to-module_id>

- where <to-module_id> is optional. See See section 4 - Sorting and 5 - Filtering for ways to get desired list

Example respons from object/module/list/genobj/to/crm/12345
{
    "status": "ok",
    "code": 200,
    "message": "Module2module 'genobj_crm' returned (32/32)",
    "count": 32,
    "total": 32,
    "objects": [
        {
            "object_id": "2250394",
            "tag_id": "2GGCQLOAHS",
            "barcode": "",
            "module_id": "21",
            "dept_id": "0",
            "name": "301001",
            "create_date": "2021-10-08 11:08:22",
            "update_date": "2021-10-08 11:08:22",
            "create_user": "1",
            "update_user": "1",
            "obj_group_id": "0",
            "genobj_type_id": "1",
            "name2": "A name",
            "description": "Testing description",
            "state": "",
            "unit": "stk",
            "unit_total_f": "0.000000",
            "unit_used_f": "0.000000",
            "unit_back_f": "0.000000",
            "unit_left_pct": "0.000000",
            "unit_reserved_f": "31.000000",
            "unit_in_production_f": "0.000000",
            "unit_available_f": "-31.000000",
            "unit_available_min_f": "0.000000",
            "unit_available_max_f": "0.000000",
            "unit_available_for_pick_f": "-31.000000",
            "unit_expired_f": "0.000000",
            "total_value_f": "0.000000",
            "avg_cost_price_f": "0.000000",
            "brutto_price_cy": "0.000000",
            "decom": "0",
            "stockloc_id": "0",
            "expire": "0000-00-00",
            "expire_2": "0000-00-00",
            "check_days": "0",
            "check_days_2": "0",
            "checked": "0",
            "borrow_user_id": "0",
            "metadata_1": "",
            "metadata_2": "",
            "metadata_3": "",
            "metadata_4": "",
            "metadata_5": "",
            "metadata_form": "",
            "metadata_values": "",
            "genobj_crm_id": "12587",
            "genobj_id": "2298394",
            "unit_order_count_f": "1.000000",
            "crm_id": "14936",
            "order_metadata_1": "",
            "order_metadata_2": "",
            "order_metadata_3": "",
            "order_metadata_4": "",
            "order_metadata_5": ""
    }, ...
  ]
}

8.5.3 update module to module

Update module entry relateded to a different module:
object/module/update/<from-module>/to/<to-module>

8.5.4 delete module to module

Delete module entry relateded to a different module:
object/module/update/<from-module>/to/<to-module>
- whith the xdelete set to '1'

9 Metadata and Foreigndata

All objects in the Tracelink database has five 'metadata' fields. These fields can be used for any purpose, but are often used for storing extra information about the object. The metadata fields are named metadata_1, metadata_2, metadata_3, metadata_4 and metadata_5. In some cases the these fields are prefixed with a module name, e.g. order_metadata_1.

The metadata fields are stored as strings, and can contain any information. The fields are not used by the Tracelink system - i.e. there is no build in logic, and are only for the users to store extra information. An example of this is a stock product that may need information about the packing dimentions, here the metadata can store information about height, width and depth

The metadata fields is configured in the Tracelink system - e.g. a checkbox, a input field, a select drop down, etc. It is possibe to extend each of the five fields into a "table" with multiple rows - e.g. the above example of the packing dimentions, can be stored in one metadata field, and not three. In this case the value of the metadata field, will be an JSON array of values - e.g. for the dimention where height = 3, width = 8 and depth = 2, the metadata field will be a JSON string: ["3","8","2"].

Some modules has three 'foreigndata' fields. These fields can hold external information - e.g. an id from an external system. The three fields are named foreigndata_1, foreigndata_2 and foreigndata_3. The fieds are not displayed in the Tracelink system, and are only for the use to store extra external information. An integration partner can use it to store information about an external object, that is not part of the Tracelink system.