Home » Poimapper Now Available on Microsoft AppSource
Espoo, Finland — January 5th, 2024 Pajat Solutions Ltd, today announced the availability of Poimapper on Microsoft AppSource, an online cloud marketplace providing tailored line-of-business solutions.
Poimapper offers mobile data collection and reporting solutions based on an advanced form builder combined with task tracking and mapping capabilities. With Poimapper, data can be collected and analyzed, for instance, when doing comprehensive supplier audits, pre-delivery inspections of complex products, or mapping various assets in an industrial production site. Poimapper enables effective and user-friendly collection of comprehensive, high-quality data, automated summary reports, and generation of customized documents, 20-40% of time spent during the collection and reporting process.
Pertti Lounamaa, CEO of Pajat Solutions, said, ”We are seeing a revolution in the need to collect and process on-site data and to improve performance by using advanced visualization tools such as Microsoft Power BI and feeding into AI engines. Poimapper addresses this need with the flexibility in forming exactly the kind of mobile data collection and processing needed by each company.”
Giovanni Mezgec, Vice President of Modern Work + Business Applications Field & Partner Marketing, Microsoft Corp., said, “We welcome Poimapper to AppSource, where global customers can find thousands of line-of-business partner solutions that work with the Microsoft products they already use. Thanks to trusted partners like Pajat Solutions Ltd, AppSource is part of a cloud marketplace landscape predicted to grow revenue 500% from 2022 to 2025.”
Our mission is to help organizations provide high-quality products and services to their clients based on comprehensive and reliable on-site data collected effectively. We offer the Poimapper cloud services with the main components being an advanced form builder, a data viewer for viewing and analyzing the data, a mobile app for on-site personnel to collect and update the data, a Teams app for updating tasks assigned to users, and an API to enable smooth integration with other IT systems. The main customers are companies needing on-site site data to achieve their service and quality targets.
For more information:
Joonas Lounamaa, Pajat Solutions Ltd, +358207705120, joonas.lounamaa@poimapper.com
You can read more here!
Follow us on Facebook, Twitter, LinkedIn, Instagram and Youtube!
Copyright 2026 © Pajat Solutions, Ltd.
This technical specification describes the Poimapper Portal REST API, which can be used to fetch and write data from the Poimapper database.
Authenticate the user with the system and obtain the auth_token JSON object
| Method | URL |
| POST | https://portal.poimapper.com/json/auth/login |
These are in JSON:
| Type | Params | Values |
| POST
POST POST |
userName
password instance |
string
string string |
| Status | Response |
| 200 | { “auth_token”: <auth_token> } auth_token (Object) |
| 400 | {“error”:”Please provide username.”} |
| 400 | {“error”:”Please provide password.”} |
| 400 | {“error”:”Please provide account name.”} |
| 401 | {“error”:”Invalid account name.”} |
| 401 | {“error”:”Incorrect username or password.”} |
| 500 | {“error”:”Something went wrong. Please try again later.”} |
The auth_token is an object that contains the username, user_id, and the session key.
The cookies returned in response need to be present in all further requests.
key must be sent with all client requests after logging in. The key helps the server to validate the request source when using the API further.
Sample server response:
{
“userName”: “simon”,
“key”: “7CDE412E756D7967EA2BC0D02BF44416”,
“id”: “29”,
“groupId”: 0,
“parentGroup”: 0,
“editOwn”: false,
“readOwn”: false,
“canDelete”: true,
“assignedLocationOnly”: false,
“canDeleteall”: true,
“markerPreference”: “form”,
“locations”: “159,180,181”,
“forms”: “362273 ,470001”,
“users”: “undefined”,
“dates”: “null;null”,
“loadSession”: “false”,
“loadDataAutomatically”: “true”,
“clusterMap”: “true”,
“lang”: “en”
}
Fetch forms and the questions
| Method | URL |
| POST | https://portal.poimapper.com/json/formlists/user/<user_id> |
Header Parameters in JSON
| Type | Params | Values |
| HEAD
HEAD |
key
userId |
string
string |
The key that was given in response to /JSON/auth/login
userId is the username that you use to login to Poimapper
user_id is the integer value given in the response after login request above e.g. “id”: “29”
| Status | Response |
| 200 | { “questionnaireList”: {
“questionnaire”: [], “id”: “Survey6804861558685259111”, “name”: “Form list name”, “language”: “en”, “surveyID”: “27344”, “version”: “1785” }} |
| 500 | {“error”:”Something went wrong. Please try again later.”} |
Sample response:
{ “questionnaireList”: {
“questionnaire”: [
],
“id”: “Survey6804861558685259111”,
“name”: “Form list name”,
“language”: “en”,
“surveyID”: “27344”,
“version”: “1785”
}}
The response gives the details of the forms (identifier), number of POIs by the count, The details of the questions, The location labels of the Location hierarchy, if any, etc
The following is an outline of the question attributes:
| Attribute | Description |
| ID | This is a unique alphanumeric string for a given question |
| Type | This refers to the type of the question defined and can either be (IntQuestion for integers, StringQuestion for alphanumeric text questions, FloatQuestion for real numbers questions, SingleSelect for radio button questions, etc) |
| Text | This is the text displayed to the user as the question text e.g. What is your name? |
| Invisible | This is a Boolean attribute that determines if the question is to be shown to the user (either on Portal or devices) and is still valid. Questions hidden in the Form Builder will have Invisible set to true |
| Optional | This attribute determines if a question must be answered or not. If optional is false, the question is mandatory and must be answered before the data is saved. |
| Regexp | This attribute has the regular expression of a given question. Regular expressions are a great way of writing custom rules |
| Maxlen | This attribute stores the maximum length of the answer value to be filled in by the user. Default is empty meaning no limit |
| Minlen | This attribute stores the minimum length of the answer value expected from the answer filled in. |
| Default | This attribute holds the default value of the question that will be pre-filled for the question in the form. |
| UseLastSavedValue | This is a Boolean attribute that if true indicates that the last saved value of the question should be pre-filled in the form for the next data point to be added |
| AttachImage | This is a Boolean attribute that if true indicates that the question supports images to be attached |
| accept | used with File question to specify the accepted mime types for the question |
| validatefield | Boolean attribute that indicates if the field has a validation list which should be used to validate input from the user |
| validationlist | This is an attribute that stores the validation list values for a given question, usually text questions. The validation list is usually values separated with a semi-colon. |
| hideInDevice | This is a boolean attribute that determines if the question is displayed on the mobile device. If true, the question is not shown |
| hideInPortal | This is a boolean attribute that determines if the question is displayed on the Data viewer. If true, the question is not shown |
| hideInPopup | This is a boolean attribute that determines if the question is displayed on the map pop up. If true, the question is not shown |
| SPSSVariable | This is a unique user-defined identifier (reference name) for a given question that is used to reference a given question in logical conditions and also used as an SPSS export variable for the question |
| Script | This stores the script that has the condition to be executed in case of calculated value questions or skip logic questions. |
| Evaluate | This stores the question ID to be evaluated in the case of skip logic or the calculated value questions |
| Operation | Operations for numeric columns in tables values can be SUM, AVERAGE |
| readOnlyInDevice | A Boolean attribute which determines if a question is read-only on the device or editable. |
| includeFile | Boolean attribute that determines if the question supports attaching files. True value means file attachment is supported |
| edit | Specifies the user roles that can edit the question. For example, one may want to limit the enumerators from editing some specific questions |
| view | Specifies the user roles that can view the question. For example, one may want to limit the enumerators from viewing some specific questions |
| RunOnCreate | If true, the calculated value question will only be executed once. any other changes to the form won’t affect this question |
| AlertText | This is the custom warning text to be shown to the user if there is a problem with the values filled in. Particularly used with numeric questions |
| SalesForceId | A Boolean attribute that indicates if a question is a salesforce ID field |
| EnableBarCodeScan | A Boolean attribute that enables barcode scanning for a given question if true, usually text questions |
| PreserveValue | This is used in scheduling functionality, if true the question value will be preserved when a POI that has been scheduled, if false the value will be reset on the device. |
Fetch a list of locations for a location hierarchy associated with a group
| Method | URL |
| POST | https://portal.poimapper.com/json/app/locations/list/<user_id> |
Header Parameters in JSON
| Type | Params | Values |
| HEAD
HEAD |
key
userId |
string
string |
The key that was given in response to /JSON/auth/login
userId is the username that you use to login to Poimapper
user_id is the integer value given in the response after login request above e.g. “id”: “29”
| Status | Response |
| 200 | [] |
| 500 | {“error”:”Something went wrong. Please try again later.”} |
A sample response from the server of the Object array of locations:
[
{
“key”: “21120”,
“title”: “Province A”,
“zoom”: “0”,
“parent”: “-1”,
“level”: “0”,
“isFolder”: false,
“isLazy”: true,
“loaded”: false,
“lowerPostalCode”: [
1234
],
“upperPostalCode”: [
5678
]
},
{
“key”: “21121”,
“title”: “County 1”,
“zoom”: “0”,
“parent”: “21120”,
“level”: “1”,
“isFolder”: false,
“isLazy”: true,
“loaded”: false,
“lowerPostalCode”: [
1111
],
“upperPostalCode”: [
2222
]
},
{
“key”: “21122”,
“title”: “Sub-County 1”,
“zoom”: “0”,
“parent”: “21121”,
“level”: “2”,
“isFolder”: false,
“isLazy”: true,
“loaded”: false,
“lowerPostalCode”: [
333
],
“upperPostalCode”: [
444
]
},
{
“key”: “21126”,
“title”: “Sub-County 2”,
“zoom”: “0”,
“parent”: “21121”,
“level”: “2”,
“isFolder”: false,
“isLazy”: true,
“loaded”: false,
“lowerPostalCode”: [
567
],
“upperPostalCode”: [
789
]
},
{
“key”: “21123”,
“title”: “Village 1”,
“zoom”: “0”,
“parent”: “21122”,
“level”: “3”,
“isFolder”: false,
“isLazy”: true,
“loaded”: false,
“lowerPostalCode”: [
555
],
“upperPostalCode”: [
666
]
},
{
“key”: “21124”,
“title”: “Village 2”,
“zoom”: “0”,
“parent”: “21122”,
“level”: “3”,
“isFolder”: false,
“isLazy”: true,
“loaded”: false,
“lowerPostalCode”: [
777
],
“upperPostalCode”: [
888
]
},
{
“key”: “21125”,
“title”: “Village 3”,
“zoom”: “0”,
“parent”: “21122”,
“level”: “3”,
“isFolder”: false,
“isLazy”: true,
“loaded”: false,
“lowerPostalCode”: [
678
],
“upperPostalCode”: [
876
]
},
{
“key”: “21127”,
“title”: “Village 4”,
“zoom”: “0”,
“parent”: “21126”,
“level”: “3”,
“isFolder”: false,
“isLazy”: true,
“loaded”: false,
“lowerPostalCode”: [
123
],
“upperPostalCode”: [
345
]
},
{
“key”: “21128”,
“title”: “Village 5”,
“zoom”: “0”,
“parent”: “21126”,
“level”: “3”,
“isFolder”: false,
“isLazy”: true,
“loaded”: false,
“lowerPostalCode”: [
444,
456
],
“upperPostalCode”: [
556,
789
]
}
]
Fetch data of a given form
Request
| Method | URL |
| POST | https://portal.poimapper.com/json/app/user/<user_id> |
Header Parameters in JSON
| Type | Params | Values |
| HEAD
HEAD |
key
userId |
string
string |
The key that was returned in the response of the /json/auth/login request
userId is the username that you use to login to Poimapper
user_id is the integer value given in the response after login request above e.g. “id”: “29”
Response
| Status | Response |
| 200 | [] |
| 500 | {“error”:”Something went wrong. Please try again later.”} |
An example follows:
A sample response from the server of the Object array of users
[
{
“id”: 894,
“name”: “user-admin”,
“groupId”: 0,
“active”: true,
“roles”: null,
“email”: null,
“otp”: null,
“accessSharedDataOnly”: false,
“samlUser”: false,
“firstLogin”: false
}
]
The user object has some attributes which can be elaborated as follows:
Fetch data of a given questionnaire/form
Request
| Method | URL |
| GET | https://portal.poimapper.com/json/app/answer/<questionnaire_id>?version=<version_number> |
Header Parameters in JSON
| Type | Params | Values |
| HEAD
HEAD |
key
userId |
string
string |
The key that was given in response to /json/auth/login
userId is the username that you use to login to Poimapper
version is the integer value for the version number of the format of the answers. The most recent version recommended is 5.
Response
| Status | Response |
| 200 | [{}] |
| 500 | {“error”:”Something went wrong. Please try again later.”} |
Example requests
The request below returns answers where userid is 2 and needs editing true
/answer/Form79693315?version=2&query={“user_id”: 2, “needs_editing”: true}
This example returns answers that contain the user_id and questionnaire_id fields (+ row_id which is a unique number assigned to each data point)
/answer/Form79693315?version=2&fields=user_id,questionnaire_id
Here the request returns answers in given locations, NOTE: locations are treated as inclusive (OR), not exclusive (AND) like other fields in the query
/answer/Form79693315?version=2&query={“location1”: [1,2], “location2”: 6}
This request returns 1000 answers with row_id> 1224
/answer/Form79693315?version=2&offset=1224&limit=1000
Parameters
| property | value |
| condition | This can be any of this
CONTAINS, DOES_NOT_CONTAIN, STARTS_WITH, ENDS_WITH (For String). EQUAL, NOT_EQUAL (All field types) GREATER_THAN, LESS_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN_OR_EQUAL (Numeric fields) |
| field | The name of the field |
| value | The value of the filter |
| operator | 0 – AND 1 – OR |
| condition2 | This is a JSON object with a second condition to apply with the above operator. |
| property | value |
| sortdatafield | The field name to apply the sort |
| sortorder | The order of the sort. For ascending order, use asc and descending order use desc |
NB: field corresponds to the ID of a given question. Maybe one would like to get answers only for a given question or set of questions
Example response
[
{
“id”: “91bba030-3eff-4722-91d2-94de7ec0bc93”,
“name”: ” new query this one”,
“questionnaire_id”: “F423B0628A3A120A”,
“user_id”: 11,
“needs_editing”: false,
“modified”: 1405588263205,
“f1E1FF6292D1C316”: null,
“entryTime”: null,
“phoneEditTime”: 0,
“portalEditTime”: 15595,
“portalEditEntry”: 1405588263000,
“countQuestion”: 1,
“row_id”: 3002,
“comments”:[
{
“username”: “dda”,
“date”: “2015-02-02 10:53:49.62295”,
“comment”: “foo”
}
],
“files”: [
{
“id”: 27,
“rowId”: 3002,
“questionId”: “”,
“mimeType”: “image/png”,
“fileSize”: 69102,
“fileName”: “Screenshot 2014-07-16 17.13.54.png”,
“url”: “https://poimapper-uploads.s3.amazonaws.com/localhost-testing.poimapper%2F27?Expires=1405611267&AWSAccessKeyId=AKIAISUY2IXT4QFICOZQ&Signature=101DUwi%2BkduI34%2FPfqzV4yQ4FEM%3D”
},
{
“id”: 28,
“rowId”: 3002,
“questionId”: “”,
“mimeType”: “image/png”,
“fileSize”: 1417039,
“fileName”: “Screenshot 2014-07-16 17.13.48.png”,
“url”: “https://poimapper-uploads.s3.amazonaws.com/localhost-testing.poimapper%2F28?Expires=1405611267&AWSAccessKeyId=AKIAISUY2IXT4QFICOZQ&Signature=pdNxxRt9PVl30eNSFv6tOlKnRvc%3D”
},
{
“id”: 29,
“rowId”: 3002,
“questionId”: “”,
“mimeType”: “image/png”,
“fileSize”: 194961,
“fileName”: “Screenshot 2014-07-16 17.13.47.png”,
“url”: “https://poimapper-uploads.s3.amazonaws.com/localhost-testing.poimapper%2F29?Expires=1405611267&AWSAccessKeyId=AKIAISUY2IXT4QFICOZQ&Signature=MUSMR6xdCEk8cQBMNpQbfGhg8dI%3D”
},
{
“id”: 30,
“rowId”: 3002,
“questionId”: “”,
“mimeType”: “image/png”,
“fileSize”: 73281,
“fileName”: “Screenshot 2014-07-16 14.11.12.png”,
“url”: “https://poimapper-uploads.s3.amazonaws.com/localhost-testing.poimapper%2F30?Expires=1405611267&AWSAccessKeyId=AKIAISUY2IXT4QFICOZQ&Signature=SOzKh6nvKE7BncD9Tyf5g7ASo9c%3D”
}
]
}
]
This has the answer values for each question and the media files associated with the data
Below are some of the additional attributes that may be returned when the data fetch request is given:
Additional attributes that may be returned and are not specified in the request:
| Attribute | Description |
| needs_editing | Boolean attribute that indicates if the data points has been marked as the one that needs editing |
| rowId | This is a unique numerical value that is automatically assigned to each data point. This is different even for the same data point in a given history trace. |
| id | This is a unique GUID for a given data point and it is the same for the history trace of a given data point. i.e. this does not change when a data point is edited |
| gps_accuracy | The accuracy of the GPS coordinates, if any, in meters. This depends on the device used |
| url | The unique URL to access a file or image. This link expires after some time. |
| mimeType | This refers to the media type of the object. For example, image/png refers to an image of PNG format |
| fileSize | This is a numerical value that indicates the size of the file/image object in bytes |
| fileName | This is the name, if any, for the file/image object |
| modified | This is the timestamp of the last time this data point was modified |
| comments | This has the comments of a given data point, if any, and has the comment text itself, timestamp and username that commented |
| entryTime | This is the timestamp when this data point was added using the device. It is null if this data point was added using the Data Viewer portal |
| phoneEditTime | This is a numerical value that has the number of milliseconds used to add or edit the data point on the mobile application |
| portalEditTime | This is a numerical value that has the number of milliseconds used to add or edit the data point on the Data viewer |
| portalEditEntry | This is the timestamp when this data point was added using the Data Viewer. It is null if this data point was added using the Mobile application. |
Saving data for a form requires sending a JSON structure of the data. The keys for the JSON object will be the question identifiers and the values will be the responses. The structure of the JSON is dependent on the questionnaire and specific questions.
Request
| Method | URL |
| POST | https://portal.poimapper.com/json/app/answer/<form_id> |
The <form_id> parameter above is the alphanumeric ID of the form.
There are core fields in the definition of any form for the inner workings of Poimapper which have the following IDs:
NB: For selection options, please use the option ID value as the answer value for the corresponding ListItem option. For multiple select options, separate the option ID answers with a comma.
Below is an example of the JSON payload of a request to the server request URL https://portal.poimapper.com/json/app/answer/F28FC59F89A2C79F to save data for the form above:
{
“Coordinates”:”4.214943141390651 33.04687500000001″,
“Name”:”Sample Write API Test Data”,
“f4F8BD60D0F969E4”:28,
“f9EC852C3998B2F8″:”Opt9CA27100DA7833A”
}
The API returns a JSON with the status as OK or Error.
Below is a sample successful request response:
{
“status”: “OK”,
“message”: “Data Saved”,
“_id”: “689a45018f61571a0ce5f9e1”,
“id”: “cf801983-7d4c-4a06-ade9-01d535ccdd25”,
“dataPoint”: <json>
}
The _id is the unique numeric identifier for the data in the database. This value changes if the row is updated.
The id is the alphanumeric unique identifier for the data that does not change across all versions of a data point. This is required if this data is to be updated in future.
The dataPoint key contains the JSON of the datapoint that has been saved together with the generated alphanumeric id and the row id of the specific datapoint.
The _id value is a string string.
NB: If the form has a location hierarchy associated with it, the location values can be updated by specifying the location IDs, in the JSON payload, of the respective locations of the location hierarchy as below. You can get the location ID values by referring to section 3 of this document. The keys for the location levels starting from the topmost parent are location1, location2, location3, and finally location4 which is the lowest location level if your location level goes up to 4 levels.
{
“Coordinates”:”4.214943141390651 33.04687500000001″,
“Name”:”Sample Write API Test Data”,
“f4F8BD60D0F969E4”:28,
“f9EC852C3998B2F8″:”Opt9CA27100DA7833A”,
“location1”: 95,
“location2”: 96,
“location3”:97,
“location4”:98
}
6.1 Update Answer values for a given Form
Existing data can be updated via the API too. To update an existing data point, the unique identifier of the data point is required (UUID). To get the UUIDs of your data, you can export data for the form in Excel or CSV format in the portal and tick the option ‘Include unique data identifier’. The uuid is also returned with each data point saved as described earlier in section 6 of this document.
Request
| Method | URL |
| PUT | https://portal.poimapper.com/json/app/answer/<form_id>/<uuid> |
For example, to update the data we posted earlier, we just send the request below. Note the form ID and the UUID values are for the form and data point respectively:
Request URL:
https://portal.poimapper.com/json/app/answer/F28FC59F89A2C79F/cf801983-7d4c-4a06-ade9-01d535ccdd25
Request payload:
{
“Coordinates”:”4.214943141390651 33.04687500000001″,
“Name”:”Sample Write API Test Data Updated”,
“f4F8BD60D0F969E4”:32,
“f9EC852C3998B2F8″:”Opt9CA27100DA7833A”
}
6.1 Delete data for a given Form
You can delete data for a given form by specifying the specific UUIDs of the data in the request payload separating the UUIDs with a comma. The <form_id> parameter is the alphanumeric Questionnaire ID as in the previous sections above. The questionnaire ID can easily be read in the Questionnaire ID tag of the form’s XML
Request
| Method | URL |
| POST | https://portal.poimapper.com/json/app/delete/multiple/<form_id> |
Below is a sample request JSON payload. the argument is the key for the JSON array of uuids of the data to be deleted. As highlighted earlier in this document, the UUID of the data can be obtained by exporting the data of the form in the Data Viewer and checking the option to include the unique identifier of the data:
{
“arguments”: [“0d25c826-328f-4fcf-a091-cc43566f04ab”, “308a0d04-c4d8-4845-81c0-3d05582ecce4”]
}
On successful deletion, the API returns the message below:
{
“status”: “OK”,
“message”: “POIs Deleted successfully”,
“row_id”: 0
}
If the status is “fail”, the request could be having issues with the payload. Check the arguments are a JSON array