Linx Main Linx Help

Tutorial: Consuming REST APIs

Tutorial: Consuming REST APIs :mortar_board:

In the following tutorial I’ll be covering some of the basics of consuming REST APIs with Linx.

A number of different types of requests will be made as well as tip and tricks on how to handle the various types of responses and general REST integration advice.

The following sections are covered:


You can download a copy of the sample Solution used in this Tutorial below.

Solution.lsoz (18.5 KB)

Need help?

Feel free to contact and we'll assist.

Sending a basic request

A GET request is going to be made which makes a request to this endpoint :

The response will contain a JSON object in the form of a string which contains joke related information.

  1. Create a new Solution.
  2. Rename the default Process to GetRandomJoke.
  3. Add a CallRESTEndpointFNC to GetRandomJoke .
  4. Set the URL to the below:
  5. Right-click on the CallRESTEndpointFNC in GetRandomJoke and click Enable Logging.
  6. Select the GetRandomJoke Process in the Solution Explorer and start the Debugger.
  7. When the GetRandomJoke Process executes, you should see the request being made and the subsequent response being returned in the Debug Output panel like below:
CallRESTEndpoint: URL Constructed
CallRESTEndpoint: HTTP client created
CallRESTEndpoint: Sending GET request
CallRESTEndpoint: Request Headers: None
CallRESTEndpoint: Response received
CallRESTEndpoint: -----------------
CallRESTEndpoint: Response code: 200 (OK)
CallRESTEndpoint: Response Body:
CallRESTEndpoint: { "type": "success", "value": { "id": 141, "joke": "The original draft of The Lord of the Rings featured Chuck Norris instead of Frodo Baggins. It was only 5 pages long, as Chuck roundhouse-kicked Sauron's ass halfway through the first chapter.", "categories": [] } }
CallRESTEndpoint: -----------------
CallRESTEndpoint: Response Headers:
CallRESTEndpoint:  Transfer-Encoding = chunked
CallRESTEndpoint:  Connection = keep-alive
CallRESTEndpoint:  access-control-allow-origin = *
CallRESTEndpoint:  access-control-allow-methods = GET
CallRESTEndpoint:  vary = User-Agent
CallRESTEndpoint:  CF-Cache-Status = DYNAMIC
CallRESTEndpoint:  cf-request-id = 0677ef244c0000070ae7b33000000001
CallRESTEndpoint:  Report-To = {"endpoints":[{"url":"https:\/\/\/report?s=WyMy3iOfmuxMb4lUn%2FswmxyOBKEVyX%2B5EYSg9j9YxcoR4SuShpxBPjs6kxMRhATZXXJ4Wu2j3XLe%2Fk5mUJJmpbrSpF8TohMg%2F%2B6RbYlu"}],"group":"cf-nel","max_age":604800}
CallRESTEndpoint:  NEL = {"report_to":"cf-nel","max_age":604800}
CallRESTEndpoint:  CF-RAY = 5f39b4807d5e070a-LHR
CallRESTEndpoint:  Cache-Control = must-revalidate, no-cache
CallRESTEndpoint:  Date = Tue, 17 Nov 2020 13:12:44 GMT
CallRESTEndpoint:  Set-Cookie = __cfduid=dfba9c643a6d6f89c89e89de426e00aa31605618764; expires=Thu, 17-Dec-20 13:12:44 GMT; path=/;; HttpOnly; SameSite=Lax
CallRESTEndpoint:  Server = cloudflare
CallRESTEndpoint:  Content-Type = application/json
CallRESTEndpoint:  Expires = Sat, 26 Jul 1997 05:00:00 GMT
CallRESTEndpoint:  Content-Length = 267
Process end reached.

The CallRESTEndpointFNC has the following output values:

  • ResponseHeaders: Header list in the format key:value pairs which contain metadata associated with the response.
  • ResponseBody: The Response Body of the object. This will deserialized into the structure set as the Output type.
  • StatusCode: The HTTP Status Code of the request i.e. 200 , 404.

Working with the response body

By default, the CallRESTEndpointFNC has its Output type set to a StringTYP . This means that no deserialization is performed on the data and it is returned in the ResponseBody as a single string, as you can see in the Debug Values panel on the right in the above graphic.

 { "type": "success", "value": { "id": 141, "joke": "The original draft of The Lord of the Rings featured Chuck Norris instead of Frodo Baggins. It was only 5 pages long, as Chuck roundhouse-kicked Sauron's ass halfway through the first chapter.", "categories": [] } }

Even though the above is a JSON string, Linx is configured by default to interpret this as a single StringTYP .

In order to work with the data as individual objects, you are able to assign the output as a complex object.

Create a Custom Type object

To do this you need to create a CustomTYP which will map the fields from the response onto data objects within Linx.

You are able to import the initial ResponseBody string that is returned from the CallRESTEndpointFNC.

To do this:

  1. Repeat the steps in the section above and debug the GetRandomJoke process.
  2. Copy Response Body string from the Debug Output.
  3. Right-click on a Project in the Solution Explorer.
  4. Click Import Custom Type.
  5. Paste the copied text into the editor and change the Name to JokeResponse.
  6. Click Create.

This will create a JokeResponseTYP in the Solution Explorer. This object can then be referenced as a structure throughout the Solution.

Reference the Custom Type object as the output structure

Now that you have created the JokeResponseTYP which maps to the Response Body, you are able to map the response of the CallRESTEndpointFNC to this object.

To do this:

  1. In the Output type field , select your new JokeResponseTYP under Project > JokeResponse
  2. Debug the GetRandomJoke process.
  3. Take a look at the Debug Values panel and notice how the JSON string has now been deserialized into the JokeResponseTYP.

In subsequent functions in your Process, you will now have access to the individual fields contained in the Response Body.

Returning the data from the Process

To make the GetRandomJoke process re-usable, we are now going to configure the GetRandomJoke process to have a single $.Output which will be a StringTYP and will return the value of CallRESTEndpoint.ResponseBody.value.joke.

When the GetRandomJoke process is called from another process or event, a single string containing the joke will be returned.

To configure the $.Output:

  1. Select the GetRandomJoke process in the Solution Explorer
  2. Expand the Output editor.
  3. Add an $.Output with the Name of joke and leave the Type as String.
  4. Drag a SetValueFNC onto the GetRandomJoke process
  5. Set the Target as $.Output.joke.
  6. For the Source, reference CallRESTEndpoint.ResponseBody.value.joke.

To test out the re-usability of the GetRandomJoke process, create a new Process in the Solution Explorer.

Drag the GetRandomJoke process from the Solution Explorer into this new Process.

Debug the new Process with a Breakpoint added to the GetRandomJoke process.

Step into the GetRandomJoke process and take note of how the values are assigned to the output. When you return to the main Process, you will see the joke being returned from the GetRandomJoke process call.

Dynamic URLs

In the below example, a specific joke resources is retrieved by including the id of the joke in the request URL:{id}

It will return a specific joke in the same format of the GetRandomJoke.

In this case both the endpoints and{id} share the Base URL as well as returning the same single joke JSON structure.

We are able to copy the GetRandomJoke process out and tweak it slightly to account for the slight difference.

Before we do that, we are going to make our Base URL a $.Setting :gear: so that we can reference it throughout the Solution. This allows you to alter the Base URL in a single place and it will have Solution wide effects, this can be things such as changing environments, version changes or plain URL changes. After this, for each request we can just add the suffix of the specific path i.e. /random or /{id}.


It is advised that you use expressions based on $.Settings to build up URLs in cases where API versions and resource location may change.

To create a Base URL to reference:

  1. Open up the $.Settings :gear: in the top menu.
  2. Add a new setting with the Name of chuckNorrisBaseUrl
  3. As the Value, set it as
  4. Go back to the GetRandomJoke process and into the CallRESTEndpoint Properties.
  5. In the URL, open the expression editor (EX).
  6. Add the following expression:
    = $.Settings.chuckNorrisBaseUrl +   "/random"
  7. Debug the GetRandomJoke process, notice how the URL will be built up at runtime.

Fetching a specific resource

Often when working with REST APIs, specific resources are retrieved by indicating the specific resource with a parametrized URL request. This involves building up dynamic URLs which will contain identifiers for certain resources.

In this part of the tutorial, we are going to be making a request for a specific joke using an id as a parameter in the URL.

A GET request will be made to the endpoint{id}.

It was mentioned earlier how the first request we made and the one we are going to make share a similar URL as well as the same response structure.

Because of these similarities we can copy the whole of the GetRandomJoke process and create a new one from it. We can then alter the process to account for the variations of the request.

To achieve this:

  1. Right-click on the GetRandomJoke process in the Solution Explorer.

  2. Click Copy.

  3. Right-click on the Project folder in the Solution Explorer.

  4. Click Paste.

  5. Rename the GetRandomJoke2 process to GetSpecificJoke.

  6. Add an $.Input field to the GetSpecificJoke process with the Name of id

  7. Alter the request URL to use the $ with the below expression:

    = $.Settings.chuckNorrisBaseUrl +   "/"  + $
  8. Debug the process, you will notice there is an available input field in the Debug Values panel. This allows you to simulate the process being called. Try the process out with several numbers [1-5].

    At runtime the URL will be built from the base URL as a $.Setting, and the id passed in to the GetSpecificJoke process.

    URL Constructed

As both of the requests return the same type of object, there is no need to do any further mapping.

Now to test out the re-usability of the GetSpecificJoke process, we are going to create a new process GetSeveralSpecificJokes which will call the GetSpecificJoke process and pass in different id values contained in a list. We are then going to add the joke returned from each call to the GetSpecificJoke process to a list containing the jokes of all the joke ids in the list.

To achieve the above:

  1. Create a new Process in the Solution Explorer.

  2. Rename it to GetSeveralSpecificJokes.

  3. Add a ListTYP to the process and rename it to ListOfJokeIDs. This will create an empty instance of a list []

  4. Expand the ListOfJokeIDs item editor and add several items containing the items:

  5. Add another ListTYP to the process and rename it to ListOfJokes [].

  6. Add a ForEachFNC below the ListOfJokeIDs and rename it to ForEach_JokeID.

  7. Set the List of ForEach_JokeID as ListOfJokeIDs.

  8. Drag the GetSpecificJoke process from the Solution Explorer, onto the GetSeveralSpecificJokes process, inside the execution path of the ForEach_JokeID. This means that for each item in the ListOfJokeIDs, the GetSpecificJoke process will execute and return a single joke.

  9. An id field will appear in the properties of the GetSpecificJoke process call on the canvas. This is because the GetSpecificJoke process takes in an $

  10. Each time the GetSpecificJoke process is called, we are going to pass in the current value of the ForEach_JokeID which will be a number from 1 - 5.

    To do this, reference ForEach_JokeID.Loop as the id parameter of the GetSpecificJoke process call.

  11. After the the GetSpecificJoke process is called, it will return a string containing a joke. We are going to add this returned value to the ListOfJokes.

    This is done by adding an AddToListFNC below the GetSpecificJoke process call but still within the execution path of the ForEach_JokeID.

  12. Set the List of the AddToList as ListOfJokes.

  13. Set the Value of the AddToList as GetSpecificJoke.joke.

  14. Debug the GetSeveralSpecificJokes process with breakpoints so that you can see the flow of data.

The result will be ListOfJokes containing strings like below:

   "Chuck Norris uses ......ets the pleasure.",
   "MacGyver can build an ai....rris can kill him and take it.",
   "Chuck Norris doesn't read books. He stares them down u... he wants.",
   "If you ask Chuck Norris w....o seconds till". After"..ks you in the face.",
   "Chuck his dad did."

Using Query parameters

Typically, you need to supply additional parameters in the query string of the request URL when retrieving data in order to limit the results.

In the below example, an escape parameter is included in the request.

This indicates to the API that it must return the data but not include JavaScript characters in the response.

Another example can be found below:[nerdy,explicit]

In order to add the query string to your request, expand the Query string property and add the above field from the first example like below.

When a request is made, the query values will be URL encoded and appended onto the request URL.

You will notice how the response joke does not contain any HTML characters.

Varying response formats

Occasionally, responses are returned and the exact type of object is not known until the response is returned, in cases like these Linx will not be able to implicitly deserialized the response body. Therefore you must implement custom logic like below to handle such requests.

To demonstrate:

  1. Expand the ListOfJokeIDs item editor and add 2 additional id values like below:

  2. Debug GetSeveralSpecificJokes

  3. You will notice that an error is thrown like below:

Exception at GetSpecificJoke :
GetSeveralSpecificJokes.GetSpecificJoke: GetSpecificJoke.CallRESTEndpoint: Error converting value "No quote with id=7." to type 'CustomTypes_5a956d5dfa3f45a391e2e6f6497bf31f._4c5174890ed7419bb42546f15d9b7f3f'. Path 'value', line 1, position 64.
Could not cast or convert from System.String to CustomTypes_5a956d5dfa3f45a391e2e6f6497bf31f._4c5174890ed7419bb42546f15d9b7f3f.

GetSpecificJoke Trace Log:
URL Constructed
HTTP client created
Sending GET request
Request Headers: None
Response received
Response code: 200 (OK)
Response Body:
{ "type": "NoSuchQuoteException", "value": "No quote with id=7." }

If you look at the stack trace of the error, you will see that a successful request was made and a 200 (OK) response code was returned. However, even though the response was successful, an error was thrown because the object returned in the Response Body cannot correctly map to the configured Output type.

If you compare the returned Response Body:

   "value":"No quote with id=7."

With the JokeResponseTYP configured as the Output type:


The JokeResponseTYP contains two fields (type,value). The value field contains a nested object containing fields for the id, joke and categories field.

In the “error” response, the field value is a StringTYP , and therefore cannot map to the CustomTYP object JokeResponse_valueTYP.

This often happens when working with APIs whereby the possible structure of the objects returned varies from response to response.

In order to handle such scenarios, you need to add additional logic to deserialized the Response Body into the correct object.

We are now going to add logic which will return the Response Body as a StringTYP , we will then add decision making logic to parse the response for the success field for the text “NoSuchQuoteException”.

This is done by resetting the Output type to String. This will then return any Response Body as a StringTYP .

Using an IfElseFNC , the text returned from the request is searched for the text “NoSuchQuoteException”.

If the above text is detected, then the $.Output.joke is set to a default value, if not then the ResponseBody is deserialized into the JokeResponseTYP $.Output.joke is set to the JokeResponse.value.joke.

To demonstrate,

  1. Go back to the GetSpecificJoke process from earlier.

  2. Alter the Output type of the CallRESTEndpointFNC to be String.

  3. Add an IfElseFNC below the CallRESTEndpointFNC .

  4. Add a condition to the IfElseFNC with the the name of JokeExists and with the value containing the below expression:

    = !CallRESTEndpoint.ResponseBody.Contains("NoSuchQuoteException")

    At runtime the above expression will evaluate if the text returned from the response does not (!) contain the text “NoSuchQuoteException”.

  5. We can assume if it the text doesn’t contain the text “NoSuchQuoteException”, then it will map correctly to the JokeResponseTYP.

    With Linx, you are able to explicitly assign a StringTYP to a CustomTYP and it will deserialize the text into the object if it can.

    In order to do this, drag the JokeResponseTYP from the Solution Explorer into the JokeExists execution path. This will create a local instance of the JokeResponseTYP which can be used to work with data in this structure locally.

  6. For the Value, reference the CallRESTEndpoint.ResponseBody.

    Now you are able to access the individual fields of the Response Body by referencing the local instance JokeResponse.#fieldname#.

  7. You would have noticed a validation error appear for the GetSpecificJoke.SetValue. This is because the CallRESTEndpoint.ResponseBody.value.joke value no longer exist as we set it to a string.

    You now need to alter the SetValue to reference the local instance of the JokeResponseTYP as the Source. In order to access the local JokeResponseTYP, you need to be within its scope, which is currently the JokeExists execution path.

    Drag the SetValue from the bottom of the process, into the JokeExists execution path, below the the local instance of the JokeResponseTYP.

    For the Source, update the reference to the below:

    = JokeResponse.value.joke

  8. Now, select the Show else property to create an alternate execution flow.

  9. In the Else execution flow, add a SetValueFNC and give it the Name of SetValue_NoJoke.

  10. For the Target reference the $.Output.joke.

  11. For the Source, we are going to return a default message with the ID of the joke.
    This is done with the below expression:

    ="No joke for ID :" + $

If you debug the GetSeveralSpecificJokes process again, step into the GetSpecificJoke process per id and take note of how the Response Body is assigned to the CustomTYP structure.

When the id of 7 is encountered, the response is handled and no explicit error is thrown.


Responses as Lists

Typically, responses contain richer information that just a basic type. Often, lists of objects are returned containing basic types as well as nested objects. This could be something like a list of orders being retrieved, where each order consists of an id, date, customer, total cost and a list of items.


When you import a response which is a list of child objects, only the child object will be imported. This is to say, if you import a list of orders , Linx will create a single order CustomTYP.

Similar to setting a List<basic type>, using the type editor, set the List<TYPE> by referencing your imported custom type as List<your Custom Type>.

To create a list of these items to use as the output structure of the response, in the Output type property, for example set the Output type as List<order>.

To demonstrate , a request is made to the CoinGecko Cryptocurrency market API.

In the below example, a GET request is made to the URL:

The response contains a list of coin objects which contains a id, symbol and name field containing the information related to the cryptocurrency coin/token like below:



            "id": "01coin",

            "symbol": "zoc",

            "name": "01coin"



            "id": "02-token",

            "symbol": "o2t",

            "name": "O2 Token"



            "id": "0cash",

            "symbol": "zch",

            "name": "0cash"



When you import a response which is a list of child objects, only the child object will be imported. This is to say, if you import a list of orders , Linx will create a single order CustomTYP.

In order to access these objects, the response body needs to be imported as a CustomTYP. The returned list then needed to be looped through.

To demonstrate, a new process is going to be created which makes a request to retrieve all the coin objects. These objects are then looped through at added to a list containing the name of each coin:

  1. Create a new Process and name it GetAllCoins

  2. Add a CallRESTEndpointFNC to the process.

  3. Set the URL to

  4. Import the Response Body and give it the name of coin.

    You will notice that only a single CustomTYP is created and not a list. This object is now a type so it can be referenced liked any basic type with List<CustomType>.

  5. Set the Output type of the CallRESTEndpointFNC to List.

  6. Using the field editor set the List<type> to List<Project.coin>.

  7. Debug the GetAllCoins process and notice how the response body is now deserialized into a a list containing coins objects.

In the Debug Values panel you are able to see all the items in the list.


In order to access individual objects in the list, you need to use a ForEachFNC and loop through the list of objects. In each loop you will then have access to that particular object.


See more about accessing individual list items.

To demonstrate, the list of coins returned in the response is going to be looped through. The name of each coin item will then be added to a list:

  1. Add ForEachFNC to the GetAllCoins process and rename it ForEach_coin.

  2. Reference the CallRESTEndpoint.ResponseBody as the List to loop through.

  3. Add a ListTYP to the beginning of the GetAllCoins process and rename it ListOfCoins.

    This will store the name of each coin object.

  4. Within the execution path of the Loop , add an AddToListFNC .

  5. For the List , reference the ListOfCoins.

  6. For the Value , reference the current loop name field value i.e.

  7. Debug the GetAllCoins process and take note of the ListOfCoins list being built up.

Nested list objects

Often, resources are returned in a list, and within each item in the list, there is another list.

That is to say there is a List present inside your Response Body, whether its a List<string>, List<object> or List<List<>> . You will need to first loop through the higher level list, and then for each item, you will have to loop through the nested list to access those nested objects and fields.

Take the example of the below Response Body which contains a list of episode objects. Within each episode, there is a list of characters.

         "Jimmy McGill",
         "Mike Erhmantraut",
         "Kim Wexler",
         "Howard Hamlin",
         "Chuck McGill",
         "Nacho Varga"

In order to access the nested list i.e. characters, a loop needs to be performed on the list of episode , and then for each episode , an additional iteration must be performed on the characters list of that particular episode.

To demonstrate the approach, an example request is made to the Breaking Bad API.

In the below example, a GET request is made to the endpoint.

This will return a list of episode objects like in the sample above. Within each episode, there is a List<string> containing the names of the characters present in that attitude.

The names of all the characters will be added to a ListTYP one by one.

To challenge yourself:

  1. Create a new Process and name it GetAllBreakingBadCharacters

  2. Add a ListTYP and rename it to CharacterList.

  3. Add a CallRESTEndpointFNC to the process.

  4. Set the URL to

  5. Import the Response Body and give it the name of episode.

  6. Set the Output type to List<Project.episode>.

  7. Add a ForEachFNC and loop through the Response Body returned from the request.

  8. For each episode, add another ForEachFNC and loop through the characters list of that iteration.

  9. Add each character to the CharacterList.

Sending content

So far, we’ve only dealt with how to make varying requests (GET) and receive the varying responses. What we haven’t touched on is sending content such is the case with POST, PUT and PATCH.


The below section describes how to send an `application/json` request body with a request.

Typically, request bodies require data to be submitted in some structured form, most often this is JSON. Examples of these are typically provided on the target APIs reference documentation.

In order to send a JSON (or XML) request body, you must configure the correct Body format respectively.

For the Body, you need to reference a data object which will be serialized appropriately.

In order to send the correct data structure, you must create a CustomTYP which maps to the same fields and types of the expected request body structure.

Just like when working with response bodies, you are able to import the sample request body from the documentation site into Linx.

You are then able to work with this data structure locally.

To give you an idea, we are going to make a request to the Unit Timestamp Converter API (* this API was built and is hosted using Linx).

The API returns date related information in the form of a Unix Timestamp.

To demonstrate using POST functionality, we are going to submit a response body to the endpoint below:

The Request Body will contain a field with the name DateTime and a string value containing a timestamp:

   "Datetime":"2019/02/11 13:38:00"

If successful, a 200 (OK) response will be returned with the below Response Body:


To implement the above functionality in Linx:

  1. Create a new Process and rename it PostCurrentTimestamp.

  2. Create or Import a new CustomTYP with the name of CurrentTimestamp.

  3. Add a field with the Name of DateTime and leave the Type as String.

  4. Drag the CurrentTimestampTYP onto the PostCurrentTimestamp process.

  5. Expand the local isntance’s of the CurrentTimestampTYP Value.

  6. For the Value of DateTime, we are going to create an expression to format the current timestamp into the correct time format.

    This is done with the below expression using the .ToString() method:

    =$.System.CurrentDateTime.ToString("yyyy/MM/dd HH:mm:ss")

  7. Now that we’ve created and set the local instance of our request body, we need to configure the
    CallRESTEndpointFNC to send the correct content.

    Add a a CallRESTEndpointFNC to the PostCurrentTimestamp process.

  8. Set the URL as:
  9. Alter the Method to be POST.

  10. Set the Body format as JSON.

    This will automatically serialize the data into the correct format and include the application/json Content-Type header.

  11. For the Body , this will be the payload we want to submit, in our case it is the local instance of the CurrentTimestampTYP.

    Reference the CurrentTimestamp as the Body.

Debug the process and note how the Request Body is submitted with the current date stamp.

Re-using data structures

The Response Body from the request above contains a single field with the name UnixTimeStamp and is of the type String. In order to parse the response body text for this field, we need to assign it to a CustomTYP. Our CurrentTimestampTYP is of the same structure , however the field names don’t match i.e. “DateTime” does not map to “UnixTimeStamp”, therefore if we used this it would not map correctly.

We could create a new CustomTYP and reference that, however that will just add more clutter to the Solution Explorer. Instead, we are going to map the fields returned in the response to the use the CurrentTimestampTYP

In Linx, you are able to map the Response Body to a CustomTYP using custom mapping.

This is done using a JSONReaderFNC .

A JSONReaderFNC takes in a StringTYP and has an Output of a CustomTYP. You are able to map fields that appear in the string to the CustomTYP.

In our case, we are going to read the Response Body string.

The field “UnixTimestamp” will be parsed and its value mapped to the CurrentTimestampTYP.

  1. Add the JSONPLG .

  2. Add a JSONReaderFNC to the PostCurrentTimestamp process.

  3. Set the Json string as the CallRESTEndpoint.ResponseBody.

  4. For the Output type, reference Project.CurrentTimestamp.

    If you debug the process, you will see there is an output from the JsonReader, however the DateTime field is empty.

    This is because we still need to manually map the fields in the Json string to the CurrentTimestampTYP.

  5. Expand the Property map editor.

  6. The Name is the field in the text that the value will be extrated from , in this case UnixTimestamp.

  7. The corresponding Property Name will be DateTime.

When you debug the process now, note how the JsonReader correctly maps the field:


To use this parsed value, you just need to reference the output of the JsonReader in subsequent functions like:

= "The current Unix timestamp is " +  JsonReader.DateTime