Skip to content

Create Address Lookup integration

This article will show how to create an address lookup integration using ArcGIS

ArcGIS allows us to search for addresses for free, but once we save an address into our database, we need to consume a credit, which is a paid-for service.

Description

ArcGIS exposes several REST baseAPIs. We will be configuring two integrations, one to search for the address and one for fetching the address and consuming a credit.

1: The search API

The suggest api provided by ArcGIS allows us to search for an address:

https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/suggest

The Integration Record

From within the ProcessFactorial Portal, browse to the Integrations Tab and click New Integration

Fill in the following details

Field Purpose Example Value
Name A friendly name to identify this integration Digital Journey Address Lookup - Search Addresses
Description A one paragraph description on this integration Look up addresses via ArcGIS
Triggered By Whether this integration will be triggered by Factorial Form, Factorial Flow or an external system ProcessFactorial Forms
Message Exchange Pattern Because we want to call an API and receive data back, set this to Two Way Two Way
Outbound Integration Business Object Not used for Factorial Form, so leave blank
Integration Verb GET, PUT, POST, DELETE, etc GET
Integration Type Because this is a synchronous integration that expects a response: UnqueuedSync
Base URL Fixed Value and "https://geocode.arcgis.com"
Path Fixed Value and "/arcgis/rest/services/World/GeocodeServer/suggest"
Headers No headers are needed for this specific integration
Query Parameters Some of these parameters are pre-configured (Type = Value) and others are dynamic (Type = Digital Journey Form) see #Query Parameters for Search API

Query Parameters for Search API

Name Data Type Type Value Comments
f String Fixed Value pjson Default value required by ArcGIS
category String Fixed Value Address Default value required by ArcGIS
maxSuggestions String Fixed Value 10 Default value required by ArcGIS. Specifies how many addresses to return during the search. 10 is an optimal number
text String Form search This field will be dynamically updated on the Digital Journey form. The label 'search' is the name of the parameter that we will use on the [[NPO Public Wiki/Terminology/Form Event]]
sourceCountry String Form country This field will be dynamically updated on the Digital Journey form The label 'country' is the name of the parameter that we will use on the [[NPO Public Wiki/Terminology/Form Event]]

Alt text

Inbound Mapping

The inbound mapping will determine what we do with the response that comes back from the ArcGIS services. The mapping record is how we tell the system where to find the data in the response ^44acd6

After creating the Integration record above, go to the Mapping tab and click New Mapping and fill in the following details:

Field Purpose Example Value
Name A friendly name to identify this integration Inbound mapping for ArcGIS Address Integration - Search Addresses
Description A one paragraph description on this integration Inbound mapping for ArcGIS Address Integration - Search Addresses
Direction Whether this is the inbound (from external service, such as ArcGIS into your website) or outbound mapping (from your website out to the external service) Inbound

Tree View

Click on the created mapping to open up the tree view. The tree structure allows you to map data from the API response to the corresponding attributes in the integration. Click on Add Child Table to define the hierarchical mapping based on the response structure.

Fill in the following details:

Field Description Example Value
Name Name used to reference the Child Table Object Suggestions Property
Description A short description of the Child Table Suggestions Property
Data Table Name The array within the api response containing the suggested address data suggestions
Integration Object Name The Integration object that represents the api response responses
Create Node on Data Availability toggle Enable to create a nested array only if valid data exists disabled
JSON Type Whether the root JSON object is an array or an object Array

Alt text

Once the Child Table has been created, click on the + button next to Fields to add fields to the table. Primarily we are interested in mapping the text and the magicKey attributes of the response for which we'll create two fields.

Fill in the following details for the each of the respective fields:

Field Description Example values
Integration Property Name The name of the integration property to map the attribute to 1. value
2. key
Condition on Data Availability Enable the toggle to create the field only when valid data is present enabled
Value Type Denotes the type of field value. Choose from Form, Form PlaceHolder and Fixed Value Form
Value The respective key of the value in the data table 1. text
2. magicKey

Alt text

Outbound Mapping

The outbound mapping will determine what we send to the ArcGIS services. In this particular example, we're not sending anything in the request, but the mapping record is still required, even though it doesn't have any mappings ^2da4ac

After creating the Integration record above, go to the Mapping tab and click New Mapping and fill in the following details:

Field Purpose Example Value
Name A friendly name to identify this integration Outbound mapping for ArcGIS Address Integration - Search Addresses
Description A one paragraph description on this integration Outbound mapping for ArcGIS Address Integration - Search Addresses
Direction Whether this is the inbound (from external service, such as ArcGIS into your website) or outbound mapping (from your website out to the external service) Outbound
There is no additional tree structure needed for this mapping

2: The Save Address API

The findAddressCandidates api provided by ArcGIS returns the full address object in its parts, such as line 1, line 2 and city, and consumes a paid-for credit from ArcGIS

https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates

Creating the Integration record

From within the ProcessFactorial Portal, browse to the Integrations Tab and click New Integration

Fill in the following details

Field Purpose Example Value
Name A friendly name to identify this integration Digital Journey Address Lookup - Save Addresses
Description A one paragraph description on this integration Fetch single address details to save. Also consume quota
Triggered By Whether this integration will be triggered by Factorial Form, Factorial Flow or an external system ProcessFactorial Forms
Message Exchange Pattern Because we want to call an API and receive data back, set this to Two Way Two Way
Outbound Integration Business Object Not used for Factorial Form, so leave blank
Integration Verb GET, PUT, POST, DELETE, etc GET
Integration Type Because this is a synchronous integration that expects a response: UnqueuedSync
Base URL Fixed Value and "https://geocode.arcgis.com"
Path Fixed Value and "/arcgis/rest/services/World/GeocodeServer/findAddressCandidates"
Headers No headers are needed for this specific integration
Query Parameters Some of these parameters are pre-configured (Type = Value) and others are dynamic (Type = Digital Journey Form) see #Query Parameters for Save Address API
#### Query Parameters for Save Address API
Name Data Type Type Value Comments
f String Value pjson Default value required by ArcGIS
outFields String Value Address,District,City,SubRegion,Region,Postal,Country List of fields to be returned in the repsonse
maxLocations String Value 1 Maximum number of locations to be returned in the response
langCode String Value EN Language for the returned results
magicKey String DigitalJourneyForm key This field will be dynamically updated on the Digital Journey form. The label 'key' is the name of the parameter that we will use on the [[NPO Public Wiki/Terminology/Form Event]]

Alt text

Inbound Mapping

After creating the Integration record above, go to the Mapping tab and click New Mapping and fill in the following details:

Field Purpose Example Value
Name A friendly name to identify this integration ArcGIS response to Digital Journey form mapping for ArcGIS Address Integration
Description A one paragraph description on this integration Inbound (into NPO) mapping for ArcGIS Address Integration
Direction Whether this is the inbound (from external service, such as ArcGIS into your website) or outbound mapping (from your website out to the external service) Inbound

Tree View

Click on Add Child Table to map the tree structure of the response from the API

Fill in the following details:

Field Description Example Value
Name Name used to reference the Child Table Object Candidates Property
Description A short description of the Child Table Candidates Property
Data Table Name The array within the api response containing the suggested address data candidates
Integration Object Name The Integration object that represents the api response responses
Create Node on Data Availability toggle Enable to create a nested array only if valid data exists disabled
JSON Type Whether the root JSON object is an array or an object Array

Once the Child Table has been created. click on the + button next to Fields to add fields to the table.

Fill in the following details to add the address field:

Field Description Example values
Integration Property Name The name of the integration property to map the attribute to address
Condition on Data Availability Enable the toggle to create the field only when valid data is present enabled
Value Type Denotes the type of field value. Choose from Form, Form PlaceHolder and Fixed Value Form
Value The respective key of the value in the data table address

Alt text

Create a nested Child Table within the Candidates Property table to store the attributes properties

Fill in the following details:

Field Description Example Value
Name Name used to reference the Child Table Object Attributes Property
Description A short description of the Child Table Attributes Property
Data Table Name The array within the api response containing the suggested address data attributes
Integration Object Name The Integration object that represents the api response blank
Create Node on Data Availability toggle Enable to create a nested array only if valid data exists disabled
JSON Type Whether the root JSON object is an array or an object Object

Alt text

Create fields in the Attributes Property child table

Fill in the following details for each of the 7 respective fields to be created.

Field Description Example values
Integration Property Name The name of the integration property to map the attribute to 1. line1
2. city
3. country
4. district
5. postcode
6. subregion
7. region
Condition on Data Availability Enable the toggle to create the field only when valid data is present enabled (for all fields)
Value Type Denotes the type of field value. Choose from Form, Form PlaceHolder and Fixed Value Form (for all fields)
Value The respective key of the value in the data table 1. Address
2. City
3. Country
4. District
5. Postal
6. SubRegion
7. Region
Alt text

Add another child table nested in the Candidates Property table for storing lat/long property. Fill in the following details:

Field Description Example Value
Name Name used to reference the Child Table Object Lat/Long Property
Description A short description of the Child Table Lat/Long Property
Data Table Name The array within the api response containing the suggested address data location
Integration Object Name The Integration object representing the api response blank
Create Node on Data Availability toggle Enable to create a nested array only if valid data exists disabled
JSON Type Whether the root JSON object is an array or an object Object

Alt text

Add longitude and latitude fields to the Lat/Long Property table. Fill in the following details for the respective fields:

Field Description Example values
Integration Property Name The name of the integration property to map the attribute to 1. longitude
2. latitude
Condition on Data Availability Enable the toggle to create the field only when valid data is present enabled (for both)
Value Type Denotes the type of field value. Choose from Form, Form PlaceHolder and Fixed Value Form (for both)
Value The respective key of the value in the data table 1. x
2. y

Alt text

We have successfully mapped the tree structure for the integration.

Outbound Mapping

The outbound mapping will determine what we send to the ArcGIS services. In this particular example, we're not sending anything in the request, but the mapping record is still required, even though it doesn't have any mappings

After creating the Integration record above, go to the Mapping tab and click New Mapping and fill in the following details:

Field Purpose Example Value
Name A friendly name to identify this integration Website request to ArcGIS mapping for ArcGIS Address Integration
Description A one paragraph description on this integration Outbound (out of NPO) mapping for ArcGIS Address Integration
Direction Whether this is the inbound (from external service, such as ArcGIS into your website) or outbound mapping (from your website out to the external service) Outbound
There is no additional tree structure needed for this mapping

3. Raw JSON

Below are the actual request and responses sent and received at each stage of the examples above. These are here for reference only

1. The search API

This example shows the details of the #1 The search API

Step 1: Calling the ProcessFactorial Integration Engine

The first step is an external service, such as the ProcessFactorial Forms, calling the ProcessFactorial Integration Engine API. While this is typically called from another ProcessFactorial component, such as Forms or Flows, it can be called from other external services as well

cURL

Import the following into Postman to get the full request. Note that the Authorization header would have expired, so a fresh one will be needed

curl 'http://localhost:7231/api/dem/integrate' \
  -H 'Accept: */*' \
  -H 'Accept-Language: en-GB,en;q=0.9,en-US;q=0.8' \
  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IkhTMjNiN0RvN1RjYVUxUm9MSHdwSXEyNFZZZyJ9.eyJhdWQiOiIxYzllMzlhYS04ZWEwLTQxYTAtOWRlZC04YmI3ODA3MDU4MjEiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vMDYzZmY2YjYtODQ0Yy00ZGRmLThlNDUtYjcyYjNmYjk3MTRixxxxxxxx' \
  -H 'Cache-Control: no-cache' \
  -H 'Connection: keep-alive' \
  -H 'Content-Type: application/json' \
  -H 'Origin: http://localhost:5173' \
  -H 'Pragma: no-cache' \
  -H 'Referer: http://localhost:5173/' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Site: same-site' \
  -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0' \
  -H 'demToken: Qs3WogQhBCS5dbTtPRFngm1pUbi158ktFHffTksf3ZspZI96X0vV0YKc2C8tSzCRGSn4GtBPrXefmJMtntR/voAr4IvK8GLvGhxtBgrStnLlHQEdCMPT6vUZMN+waXebYontG4dWzB7YgCyH/8R+6nlfAv1ZPiKxz3xMwbv7yRJ9JhaSIrYpILZ29NrfxdrJgA9DsI/tgD23fKLXJ36gMDcLowemYgB7EKp4loor8egiXFgK5zMvDzFUsffd6MCKacJqjQzFnVsYweJiFdOKXGRAit6aur3F8pFT8bUrC49x0fyxGO0GtIKuUyB5PiHSchS7hXRCgtKnQvCF9Ai3fbUiVb4UxyEm6PYTMqJV+GIEpaZeHPoTIk0+jNnrv8RDj9r+Vp6Cbr7RAtLYbScZocRMOONTTG3gycKP8umGzqy5+dsHyTJ5mglYywXPE0Y44QG/VwHYhS6uqjrF0TcXNc8oJLIb8Wkc+AEn5+I+Yqz0aWXN31y9bOyNcCPti8K4lvVQf0VNf0uhye21uvd0ug==' \
  -H 'sec-ch-ua: "Chromium";v="140", "Not=A?Brand";v="24", "Microsoft Edge";v="140"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "Windows"' \
  --data-raw '{"integrationId":"aaaa2a43-bcac-49ca-96e2-2a1ccbac9004_aaaa2a43-bcac-49ca-96e2-2a1ccbac9005_aaaa2a43-bcac-49ca-96e2-2a1ccbac9006","data":{"OutputAction":"DataSet","IntegrationCategory":"Integrate","QueryStringValues":[{"Key":"search","SourceId":"50000000-1000-0000-0000-000000000002","DataType":"String","Value":"main"},{"Key":"country","SourceId":"50000000-1000-0000-0000-000000000001.npo_iso2code","DataType":"String","Value":"NZ"}]}}'
Request Path
/api/dem/integrate
Request Query String
none
Request Headers
authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IkhTMjNiN0RvN1RjYVUxUm9MSHdwSXEyNFZZZyJ9.eyJhdWQiOiIxYzllMzlhYS04ZWEwLTQxYTAtOWRlZC04YmI3ODA3MDU4MjEiLCJpc3MiOiJodHRwczovLxxxxxxxxx
Request Body
{
    "data": {
        "IntegrationCategory": "Integrate",
        "OutputAction": "DataSet",
        "QueryStringValues": [
            {
                "DataType": "String",
                "Key": "search",
                "SourceId": "50000000-1000-0000-0000-000000000002",
                "Value": "main"
            },
            {
                "DataType": "String",
                "Key": "country",
                "SourceId": "50000000-1000-0000-0000-000000000001.npo_iso2code",
                "Value": "NZ"
            }
        ]
    },
    "integrationId": "aaaa2a43-bcac-49ca-96e2-2a1ccbac9004_aaaa2a43-bcac-49ca-96e2-2a1ccbac9005_aaaa2a43-bcac-49ca-96e2-2a1ccbac9006"
}
Response Body

The response body is returned after the Integration Engine has completed all its internal integration calls, which can be either a single integration to an external API or a series of integrations with an Integration Workflow In other words, this is the very final response of the entire sequence of integrations and is the actual response returned back to the original sender.

{
    "content": {
        "id": "aaaa2a43-bcac-49ca-96e2-2a1ccbac9004_aaaa2a43-bcac-49ca-96e2-2a1ccbac9005_aaaa2a43-bcac-49ca-96e2-2a1ccbac9006_1.0.0.0",
        "isActive": true,
        "jsonPropertyName": "responses",
        "keyFieldName": "key",
        "referenceRecordsJSON": "{\"responses\":[{\"value\":\"Main Drain Road, Glen Oroua, Manawatu-Wanganui, 4473, NZL\",\"key\":\"dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NzY4NjAjbG5nPTQxI2xicz0xMDk6OTEzNjA5NzUjbG49V29ybGQ=\"},{\"value\":\"Main Drain Road, Glen Oroua, Manawatu-Wanganui, 4477, NZL\",\"key\":\"dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NzY4NzAjbG5nPTQxI2xicz0xMDk6OTEzNjA5NzUjbG49V29ybGQ=\"},{\"value\":\"Main Drain Road, Rangiotu, Manawatu-Wanganui, 4477, NZL\",\"key\":\"dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NzczMzAjbG5nPTQxI2xicz0xMDk6OTEzNjA5NzUjbG49V29ybGQ=\"},{\"value\":\"Main Drive, Massey University, Palmerston North, Manawatu-Wanganui, 4472, NZL\",\"key\":\"dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3Nzg0NTIjbG5nPTQxI2xicz0xMDk6OTEzNjY3NjAjbG49V29ybGQ=\"},{\"value\":\"Main Highway Entry, Ōtaki, Wellington, 5512, NZL\",\"key\":\"dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE4MDcwMTEjbG5nPTQxI2xicz0xMDk6OTEzNjExMjAjbG49V29ybGQ=\"},{\"value\":\"Main Highway Exit, Ōtaki, Wellington, 5512, NZL\",\"key\":\"dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE4MDY5MzIjbG5nPTQxI2xicz0xMDk6OTEzNjExMjEjbG49V29ybGQ=\"},{\"value\":\"Main Highway, Ellerslie, Auckland, 1051, NZL\",\"key\":\"dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NDQ5ODQjbG5nPTQxI2xicz0xMDk6OTEzNjY3ODAjbG49V29ybGQ=\"},{\"value\":\"Main Highway, Ellerslie, Auckland, 1060, NZL\",\"key\":\"dHA9NCN0dj04NmU1NWE1MSNubT1NYWluIEhpZ2h3YXksIEVsbGVyc2xpZSwgQXVja2xhbmQsIDEwNjAsIE5aTCNzYz1OWiNsbmc9NDEjbG49V29ybGQ=\"},{\"value\":\"Main Highway, Ellerslie, Auckland, 1061, NZL\",\"key\":\"dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NDUwNjAjbG5nPTQxI2xicz0xMDk6OTEzNjY3ODAjbG49V29ybGQ=\"},{\"value\":\"Main Highway, Mount Wellington, Auckland, 1060, NZL\",\"key\":\"dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NTA4NTkjbG5nPTQxI2xicz0xMDk6OTEzNjY3ODAjbG49V29ybGQ=\"}]}",
        "valueFieldName": "value"
    },
    "errors": [
    ],
    "message": "Ok",
    "warnings": [
    ]
}

The data in the referenceRecordsJSON property can then be parsed and consumed:

{
    "responses": [
        {
            "key": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NzY4NjAjbG5nPTQxI2xicz0xMDk6OTEzNjA5NzUjbG49V29ybGQ=",
            "value": "Main Drain Road, Glen Oroua, Manawatu-Wanganui, 4473, NZL"
        },
        {
            "key": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NzY4NzAjbG5nPTQxI2xicz0xMDk6OTEzNjA5NzUjbG49V29ybGQ=",
            "value": "Main Drain Road, Glen Oroua, Manawatu-Wanganui, 4477, NZL"
        },
        {
            "key": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NzczMzAjbG5nPTQxI2xicz0xMDk6OTEzNjA5NzUjbG49V29ybGQ=",
            "value": "Main Drain Road, Rangiotu, Manawatu-Wanganui, 4477, NZL"
        },
        {
            "key": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3Nzg0NTIjbG5nPTQxI2xicz0xMDk6OTEzNjY3NjAjbG49V29ybGQ=",
            "value": "Main Drive, Massey University, Palmerston North, Manawatu-Wanganui, 4472, NZL"
        },
        {
            "key": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE4MDcwMTEjbG5nPTQxI2xicz0xMDk6OTEzNjExMjAjbG49V29ybGQ=",
            "value": "Main Highway Entry, Ōtaki, Wellington, 5512, NZL"
        },
        {
            "key": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE4MDY5MzIjbG5nPTQxI2xicz0xMDk6OTEzNjExMjEjbG49V29ybGQ=",
            "value": "Main Highway Exit, Ōtaki, Wellington, 5512, NZL"
        },
        {
            "key": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NDQ5ODQjbG5nPTQxI2xicz0xMDk6OTEzNjY3ODAjbG49V29ybGQ=",
            "value": "Main Highway, Ellerslie, Auckland, 1051, NZL"
        },
        {
            "key": "dHA9NCN0dj04NmU1NWE1MSNubT1NYWluIEhpZ2h3YXksIEVsbGVyc2xpZSwgQXVja2xhbmQsIDEwNjAsIE5aTCNzYz1OWiNsbmc9NDEjbG49V29ybGQ=",
            "value": "Main Highway, Ellerslie, Auckland, 1060, NZL"
        },
        {
            "key": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NDUwNjAjbG5nPTQxI2xicz0xMDk6OTEzNjY3ODAjbG49V29ybGQ=",
            "value": "Main Highway, Ellerslie, Auckland, 1061, NZL"
        },
        {
            "key": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NTA4NTkjbG5nPTQxI2xicz0xMDk6OTEzNjY3ODAjbG49V29ybGQ=",
            "value": "Main Highway, Mount Wellington, Auckland, 1060, NZL"
        }
    ]
}

Step 2: ProcessFactorial Integration Engine calling the ArcGIS Search API

This step is the actual internal call made by the Integration Engine to ArcGIS after any request mapping has taken place to convert the ProcessFactorial formats into the ArcGIS formats.

Notice how the response mapping from Step 1 above maps to the response mapping below.

cURL

Import the following into Postman to get the full request. Note that the Authorization header would have expired, so a fresh one will be needed

curl --location 'https://geocode.arcgis.com:443/arcgis/rest/services/World/GeocodeServer/suggest?f=pjson&category=Address&maxSuggestions=10&text=main&sourceCountry=NZ'
Request Path
https://geocode.arcgis.com:443/arcgis/rest/services/World/GeocodeServer/suggest?f=pjson&category=Address&maxSuggestions=10&text=main&sourceCountry=NZ
Request Query String
f=pjson
category=Address
maxSuggestions=10
text=main
sourceCountry=NZ
Request Headers
none
Request Body
none
Response Body

The raw response body is returned by the ArcGIS Search API, prior to being converted into the #Response Body that is consumed by the original sender.

{
    "suggestions": [
        {
            "isCollection": false,
            "magicKey": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NzY4NjAjbG5nPTQxI2xicz0xMDk6OTEzNjA5NzUjbG49V29ybGQ=",
            "text": "Main Drain Road, Glen Oroua, Manawatu-Wanganui, 4473, NZL"
        },
        {
            "isCollection": false,
            "magicKey": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NzY4NzAjbG5nPTQxI2xicz0xMDk6OTEzNjA5NzUjbG49V29ybGQ=",
            "text": "Main Drain Road, Glen Oroua, Manawatu-Wanganui, 4477, NZL"
        },
        {
            "isCollection": false,
            "magicKey": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NzczMzAjbG5nPTQxI2xicz0xMDk6OTEzNjA5NzUjbG49V29ybGQ=",
            "text": "Main Drain Road, Rangiotu, Manawatu-Wanganui, 4477, NZL"
        },
        {
            "isCollection": false,
            "magicKey": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3Nzg0NTIjbG5nPTQxI2xicz0xMDk6OTEzNjY3NjAjbG49V29ybGQ=",
            "text": "Main Drive, Massey University, Palmerston North, Manawatu-Wanganui, 4472, NZL"
        },
        {
            "isCollection": false,
            "magicKey": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE4MDcwMTEjbG5nPTQxI2xicz0xMDk6OTEzNjExMjAjbG49V29ybGQ=",
            "text": "Main Highway Entry, Ōtaki, Wellington, 5512, NZL"
        },
        {
            "isCollection": false,
            "magicKey": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE4MDY5MzIjbG5nPTQxI2xicz0xMDk6OTEzNjExMjEjbG49V29ybGQ=",
            "text": "Main Highway Exit, Ōtaki, Wellington, 5512, NZL"
        },
        {
            "isCollection": false,
            "magicKey": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NDQ5ODQjbG5nPTQxI2xicz0xMDk6OTEzNjY3ODAjbG49V29ybGQ=",
            "text": "Main Highway, Ellerslie, Auckland, 1051, NZL"
        },
        {
            "isCollection": false,
            "magicKey": "dHA9NCN0dj04NmU1NWE1MSNubT1NYWluIEhpZ2h3YXksIEVsbGVyc2xpZSwgQXVja2xhbmQsIDEwNjAsIE5aTCNzYz1OWiNsbmc9NDEjbG49V29ybGQ=",
            "text": "Main Highway, Ellerslie, Auckland, 1060, NZL"
        },
        {
            "isCollection": false,
            "magicKey": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NDUwNjAjbG5nPTQxI2xicz0xMDk6OTEzNjY3ODAjbG49V29ybGQ=",
            "text": "Main Highway, Ellerslie, Auckland, 1061, NZL"
        },
        {
            "isCollection": false,
            "magicKey": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NTA4NTkjbG5nPTQxI2xicz0xMDk6OTEzNjY3ODAjbG49V29ybGQ=",
            "text": "Main Highway, Mount Wellington, Auckland, 1060, NZL"
        }
    ]
}

2. The save address API

This example shows the details of the findAddressCandidates API

Step 1: Calling the ProcessFactorial Integration Engine

The first step is an external service, such as the ProcessFactorial Forms, calling the ProcessFactorial Integration Engine API. While this is typically called from another ProcessFactorial component, such as Forms or Flows, it can be called from other external services as well

cURL

Import the following into Postman to get the full request. Note that the Authorization header would have expired, so a fresh one will be needed

curl 'http://localhost:7231/api/dem/integrate' \
  -H 'Accept: */*' \
  -H 'Accept-Language: en-GB,en;q=0.9,en-US;q=0.8' \
  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IkhTMjNiN0RvN1RjYVUxUm9MSHdwSXEyNFZZZyJ9.eyJhdWQiOiIxYzllMzlhYS04ZWEwLTQxYTAtOWRlZC04YmI3ODA3MDU4MjEiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vMDYzZmY2YjYtODQ0Yy00ZGRmLThlNDUtYjcyYjNmYjk3MTRixxxxxxxx' \
  -H 'Cache-Control: no-cache' \
  -H 'Connection: keep-alive' \
  -H 'Content-Type: application/json' \
  -H 'Origin: http://localhost:5173' \
  -H 'Pragma: no-cache' \
  -H 'Referer: http://localhost:5173/' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Site: same-site' \
  -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0' \
  -H 'demToken: Qs3WogQhBCS5dbTtPRFngm1pUbi158ktFHffTksf3ZspZI96X0vV0YKc2C8tSzCRGSn4GtBPrXefmJMtntR/voAr4IvK8GLvGhxtBgrStnLlHQEdCMPT6vUZMN+waXebYontG4dWzB7YgCyH/8R+6nlfAv1ZPiKxz3xMwbv7yRJ9JhaSIrYpILZ29NrfxdrJgA9DsI/tgD23fKLXJ36gMDcLowemYgB7EKp4loor8egiXFgK5zMvDzFUsffd6MCKacJqjQzFnVsYweJiFdOKXGRAit6aur3F8pFT8bUrC49x0fyxGO0GtIKuUyB5PiHSchS7hXRCgtKnQvCF9Ai3fbUiVb4UxyEm6PYTMqJV+GIEpaZeHPoTIk0+jNnrv8RDj9r+Vp6Cbr7RAtLYbScZocRMOONTTG3gycKP8umGzqy5+dsHyTJ5mglYywXPE0Y44QG/VwHYhS6uqjrF0TcXNc8oJLIb8Wkc+AEn5+I+Yqz0aWXN31y9bOyNcCPti8K4lvVQf0VNf0uhye21uvd0ug==' \
  -H 'sec-ch-ua: "Chromium";v="140", "Not=A?Brand";v="24", "Microsoft Edge";v="140"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "Windows"' \
  --data-raw '{"integrationId":"aaaa2a43-bcac-49ca-96e2-2a1ccbac9007_aaaa2a43-bcac-49ca-96e2-2a1ccbac9008_aaaa2a43-bcac-49ca-96e2-2a1ccbac9009","data":{"OutputAction":"PopulateFormFields","IntegrationCategory":"Integrate","QueryStringValues":[{"Key":"key","SourceId":"50000000-1000-0000-0000-000000000002.key","DataType":"String","Value":"dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NzY4NzAjbG5nPTQxI2xicz0xMDk6OTEzNjA5NzUjbG49V29ybGQ="}]}}'
Request Path
/api/dem/integrate
Request Query String
none
Request Headers
authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IkhTMjNiN0RvN1RjYVUxUm9MSHdwSXEyNFZZZyJ9.eyJhdWQiOiIxYzllMzlhYS04ZWEwLTQxYTAtOWRlZC04YmI3ODA3MDU4MjEiLCJpc3MiOiJodHRwczovLxxxxxxxxx
Request Body
{
    "data": {
        "IntegrationCategory": "Integrate",
        "OutputAction": "PopulateFormFields",
        "QueryStringValues": [
            {
                "DataType": "String",
                "Key": "key",
                "SourceId": "50000000-1000-0000-0000-000000000002.key",
                "Value": "dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NzY4NzAjbG5nPTQxI2xicz0xMDk6OTEzNjA5NzUjbG49V29ybGQ="
            }
        ]
    },
    "integrationId": "aaaa2a43-bcac-49ca-96e2-2a1ccbac9007_aaaa2a43-bcac-49ca-96e2-2a1ccbac9008_aaaa2a43-bcac-49ca-96e2-2a1ccbac9009"
}
Response Body

The response body is returned after the Integration Engine has completed all its internal integration calls, which can be either a single integration to an external API or a series of integrations with an Integration Workflow In other words, this is the very final response of the entire sequence of integrations and is the actual response returned back to the original sender.

{
    "content": {
        "id": "aaaa2a43-bcac-49ca-96e2-2a1ccbac9007_aaaa2a43-bcac-49ca-96e2-2a1ccbac9008_aaaa2a43-bcac-49ca-96e2-2a1ccbac9009_1.0.0.0",
        "isActive": true,
        "referenceRecordsJSON": "{\"address\":\"Main Drain Road, Glen Oroua, Manawatu-Wanganui, 4477\",\"line1\":\"Main Drain Road\",\"city\":\"Glen Oroua\",\"country\":\"NZL\",\"district\":\"\",\"postcode\":\"4477\",\"subregion\":\"Manawatu\",\"region\":\"Manawatu-Wanganui\",\"longitude\":175.425557901815,\"latitude\":-40.364695750347}"
    },
    "errors": [
    ],
    "message": "Ok",
    "warnings": [
    ]
}

The data in the referenceRecordsJSON property can then be parsed and consumed:

{
    "address": "Main Drain Road, Glen Oroua, Manawatu-Wanganui, 4477",
    "city": "Glen Oroua",
    "country": "NZL",
    "district": "",
    "latitude": -40.364695750347,
    "line1": "Main Drain Road",
    "longitude": 175.425557901815,
    "postcode": "4477",
    "region": "Manawatu-Wanganui",
    "subregion": "Manawatu"
}

Step 2: ProcessFactorial Integration Engine calling the ArcGIS Save Address API

This step is the actual internal call made by the Integration Engine to ArcGIS after any request mapping has taken place to convert the ProcessFactorial formats into the ArcGIS formats.

Notice how the response mapping from Step 1 above maps to the response mapping below.

cURL

Import the following into Postman to get the full request.

curl --location 'https://geocode.arcgis.com:443/arcgis/rest/services/World/GeocodeServer/findAddressCandidates?f=pjson&outFields=Address%2cDistrict%2cCity%2cSubRegion%2cRegion%2cPostal%2cCountry&maxLocations=1&langCode=EN&magicKey=dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NzY4NzAjbG5nPTQxI2xicz0xMDk6OTEzNjA5NzUjbG49V29ybGQ%3D%3D%3D'
Request Path
https://geocode.arcgis.com:443/arcgis/rest/services/World/GeocodeServer/findAddressCandidates?f=pjson&outFields=Address%2cDistrict%2cCity%2cSubRegion%2cRegion%2cPostal%2cCountry&maxLocations=1&langCode=EN&magicKey=dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NzY4NzAjbG5nPTQxI2xicz0xMDk6OTEzNjA5NzUjbG49V29ybGQ===
Request Query String
f=pjson
outFields=Address%2cDistrict%2cCity%2cSubRegion%2cRegion%2cPostal%2cCountry&maxLocations=1
langCode=EN
magicKey=dHA9MCN0dj04NmU1NWE1MSNsb2M9NzE3NzY4NzAjbG5nPTQxI2xicz0xMDk6OTEzNjA5NzUjbG49V29ybGQ===
Request Headers
none
Request Body
none
Response Body

The raw response body is returned by the ArcGIS Search API, prior to being converted into the #Response Body that is consumed by the original sender.

{
    "candidates": [
        {
            "address": "Main Drain Road, Glen Oroua, Manawatu-Wanganui, 4477",
            "attributes": {
                "Address": "Main Drain Road",
                "City": "Glen Oroua",
                "Country": "NZL",
                "District": "",
                "Postal": "4477",
                "Region": "Manawatu-Wanganui",
                "SubRegion": "Manawatu"
            },
            "extent": {
                "xmax": 175.426557901815,
                "xmin": 175.424557901815,
                "ymax": -40.363695750347,
                "ymin": -40.365695750347
            },
            "location": {
                "x": 175.425557901815,
                "y": -40.364695750347
            },
            "score": 100
        }
    ],
    "spatialReference": {
        "latestWkid": 4326,
        "wkid": 4326
    }
}