1. Getting started
The Fieldly Public API gives integrators and third-party applications the possibility to read and interact with the data in Fieldly.
The API is based on REST and supports three different methods
GET – Fetch data from Fieldly
POST – Create data in Fieldly
PATCH – Update data in Fieldly
Note that not all methods are available for all endpoints.
Endpoints and available methods can be found in the complete API documentation here:
1.1 Authentication
The Fieldly API uses OAuth 2.0 authentication with grant-type Client Credentials.
Use your ClientID and ClientSecret towards the token endpoint to obtain the access token.
Curl example:
curl -X POST -u 'client_id:client_secret' -d 'grant_type=client_credentials' https://api.fieldly.com/api/public/v1/oauth/token
Response:
{'access_token':'token', 'token_type':'Bearer', 'expires_in':3600, 'scope':'public', 'created_at':123123123}
Postman example:
Received access token must be included as Bearer in Authorization Header with each API request. Each access token is valid for one hour, then it needs to be requested once more.
1.2 Credentials
Contact Fieldly at support@fieldly.com to activate the Public API for your account. When activated the credentials can be found in integration settings under Fieldly API.
1.3 Documentation
The complete Fieldly API Swagger documentation can be found here: https://api.fieldly.com/api-docs/index.html
2. Query Customization
2.1 Pagination
All Get endpoints are paginated. This means a maximum of 50 records can be returned in each request.
If the request returns multiple pages you need to paginate across the different pages to access all records. This is done using the parameters “page” and “per_page”. If not provided, “per_page” is set to the maximum value of 50.
The number of pages, current page, and total records can be found in metadata which is returned in each get request.
Example of paginating across all pages (Python)
import requests
def fetch_all_pages(api_url, per_page=50):
page = 1
has_more_pages = True
while has_more_pages:
params = {'page': page, 'per_page': per_page}
response = requests.get(api_url, params=params)
if response.status_code == 200:
data = response.json()
# Process the data as needed
process_data(data)
# Check if there are more pages
has_more_pages = len(data) == per_page
page += 1
else:
# Handle the error if needed
print(f"Error: {response.status_code}")
def process_data(data):
# Do something with the fetched data
print(data)
# Example usage
api_url = 'https://example.com/api/data'
fetch_all_pages(api_url, per_page=50)
2.2 Filter parameters
For most of the GET endpoints, you have several filter parameters to help you find the relevant data. These can be strings to define the type of record or timestamps to only get created or updated records since a certain time.
The filter parameters are just added to the request and you can combine several filters in the same query.
Examples:
GET https://api.fieldly.com/api/public/v1/time_reports?reported_from=2023-06-01&reported_to=2023-12-31
Time reports with reported date between 2023-06-01 and 2023-12-31
GET https://api.fieldly.com/api/public/v1/work_items?type=workorder&created_at=2023-01-01
Work items of type “Work order” created after 2023-01-01
Filtering can in certain cases also be done in the URL path. Eg. if you want to fetch all time reports that are connected to a certain work item you can use the endpoint:
GET https://api.fieldly.com/api/public/v1/work_items/<work_item_id>/time_reports
In the API documentation, you can see the filter parameters that are available for each endpoint
3. Good to know
3.1 Metadata
In each get request for multiple records you get the metadata of the records together with your response. In the metadata object you can see:
Total (Number of records in response)
Total count (Total number of records from all pages)
Total pages
Page
Per page
3.2 Formats
3.2.1 Date and time parameters
All date and time fields in the API are in ISO 8601 format.
All timestamps are in the UTC time zone, which means that you as an integrator need to convert the times to your local time zone.
The conversion between time zones needs to be done both when fetching data and when creating or using timestamps in filters.
3.2.2 Monetary fields and special quantities
All monetary fields such as prices and totals are stored in “cents”. So to get the monetary value you should divide by 100.
Certain quantities are also stored in their smallest form to reduce the risk of the API doing incorrect rounding.
On time reports the internal_total_time and billable_total_time are stored in seconds. So you need to divide by 3600 to convert it to hours.
On travel reports the internal_distance and billable_distance are stored in meters.
3.3 Serial numbers
When creating clients or work items in Fieldly you as an integrator can choose if you want to provide the serial number or to let Fieldly generate the serial number.
If you choose to provide the serial number, this is done in two parameters
Serial number prefix (string)
Serial number sequence (integer)
These two parameters are concatenated into the read-only parameter “serial_number” which is shown in Get calls and successful responses from Post calls.
If the serial number is purely numerical, the serial number prefix is not needed. But if you provide a prefix, the sequence is mandatory.
The API has validation preventing you from creating records with serial numbers that already exist.
3.4 Relations and Fieldly ID
To set a relation to another object when doing Post or Patch calls you need to provide the Fieldly ID. The Fieldly ID for a record can be found in all GET calls and in the response of a successful post or patch call.
The relations are displayed as sub-records in the JSON of the response. For Get calls you will get a couple of parameters from the related object but in Post calls you should only provide the ID.
Example of relations “owner” and “client” in GET work_items response:
"work_items": [
{
"id": 1,
"title": "Test Work Item",
"starts_at": "2020-11-08T23:00:00.000Z",
"ends_at": "2020-11-09T23:00:00.000Z",
"serial_number": "1111",
"state": "pending",
"type": "Workorder",
"owner": {
"id": 1,
"employee_number": "06",
"firstname": "John",
"lastname": "Example"
},
"client": {
"id": 1,
"serial_number": "13",
"title": "Test Client"
},
Example of relations “owner” and “client” in POST work_items call
{
"title": "Test Work Item 2",
"starts_at": "2020-11-08T23:00:00.000Z",
"ends_at": "2020-11-09T23:00:00.000Z",
"serial_number": "1112",
"state": "pending",
"type": "Workorder",
"owner": {
"id": 1
},
"client": {
"id": 1
},
3.5 Special endpoints
3.5.1 Patch work item and client based on serial number
Clients and Work items have an addition to the PATCH endpoints making it possible to update records based on serial number instead of Fieldly ID.
The normal patch endpoint URL looks like this:
PATCH https://api.fieldly.com/api/public/v1/clients/<client_id>
By providing the serial number as a parameter, the call can also look like this:
PATCH https://api.fieldly.com/api/public/v1/clients?serial_number=<client_serial_number>
The logic also works for work_items endpoint. The only difference here is that you need to provide the “type” parameter as well. This is due to the possibility of work orders and projects having the same serial number.
PATCH https://api.fieldly.com/api/public/v1/work_items?serial_number=<work_item_serial_number>&type=project
3.5.2 Post supplier invoice
The endpoint to post supplier invoices into Fieldly is simplified and the integrator does not need to provide the Fieldly ID of the work item or calculate the markup.
The integrator is only asked to provide the parameters needed by Fieldly and the logic of how to connect to a work item, calculate markup, etc is however done within Fieldly.
4. Status codes and error handling
The Fieldly API will respond with HTTP statuses for each call
HTTP Code | Message | Description |
200 | OK | Successful GET or PATCH call |
201 | Created | Successful POST call |
401 | Unauthorized | Invalid or expired token |
404 | Not found | The requested resource could not be found |
422 | Unprocessable Entity | Validation of parameters failed |
If validation of parameters fails the response body will contain an array of errors regarding your call. Eg:
{
"errors": {
"title": [
"is missing"
],
"serial_number_sequence": [
"client with such serial number already exists"
]
}
}