> This is part 1 of 2 of the full documentation (pages 1–100 of 142).
> The content is paginated: fetch every part to see all of it.
> Next part: https://docs.movesdk.com/move-platform/llms-full.txt/1
> Page index: https://docs.movesdk.com/move-platform/llms.txt

# Introduction

## Using this documentation with AI tools

This documentation is optimized for AI-assisted development.

* MCP Server: `https://docs.movesdk.com/move-platform/~gitbook/mcp` → [How to configure MCP in your AI tool](https://gitbook.com/docs/ai-and-search/mcp-servers-for-published-docs)
* **Full documentation as plain text (llms.txt):** <https://docs.movesdk.com/move-platform/llms-full.txt>

## About the MOVE SDK

The MOVE SDK enables you to collect **location, motion, and other sensor data from your smartphone users**. This data is then transmitted to our backend, where it is evaluated, enriched with industry-leading machine learning algorithms, and applied to a comprehensive **24/7 timeline**.&#x20;

This timeline gives you insights into where your users move and how they get there, whether in the past, present, or future (via our prediction algorithms).&#x20;

With our MOVE SDK, you will gain a deep understanding of your users’ personas and service them in a whole new way, completely transforming how you interact with them.

![](https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FBl4F3hnPOQ8CojCJQT8d%2Fmove-diagram-docs.png?alt=media\&token=45700846-624b-449a-86b7-c6ad55e23865)

## Why MOVE SDK?

### Available for iOS and Android

Available for iOS and Android, the MOVE SDK is always up-to-date, using the latest technologies and adapting ahead to new OS features and updates.&#x20;

We also provide wrappers, sample source code, and documentation for implementing the SDK in React Native and Flutter apps.

### Easy integration

Simple SDK setup, clear documentation, sample apps, and development support will guarantee a fast and smooth integration of the SDK in any iOS or Android app.

### Fully autonomous and self-launched

After the SDK is set up and its services are launched, it will handle automatically waking up in the background and collecting the required data in a fully autonomous way, without any user interactions, even if the app is closed.

### Battery efficient&#x20;

Each SDK instance running on a user’s phone learns about its user’s activity, which is then used to personalize its life cycle in the background. This optimizes the SDK for each user based on his/her daily routines and accurately collects data in a battery-efficient manner.

### Accurate analysis

The SDK collects GPS and IMU data in high frequencies to accurately analyze the user’s mode of transportation and driving behavior, based on different driving events like phone usage while driving, speeding, acceleration, cornering, and braking.&#x20;

### Optimized bandwidth usage

The SDK uses lightweight intelligent algorithms to process the data on the device before sending it to the server to optimize bandwidth usage.

### Cost-sensitive

You can tune the SDK to your requirements and will only be charged for the services required by your app.


# MOVE Services

Driving Services

The MOVE SDK offers various features that recognise when, where and how users are moving through their days. This allows app developers to e.g. establish context-based communication (e.g. location-based marketing), to raise awareness about movement patterns, or to offer assistance when needed.

## Timeline

One of our key features is a user timeline about when, where and how users move through their days. The timeline can be more or less detailed, depending on the features active in the [MOVE configuration](https://dashboard.movesdk.com/admin/sdkConfig).

All of this is running in the background using OS-specific functions, to ensure that the battery footprint is as low as possible. Of course, the more features you activate, the more battery will be required to run MOVE.

Please note that the following timeline components are prioritised in how they are registered into the timeline: CAR trips are registered in the timeline before PUBLIC TRANSPORT and WALKING. So while a CAR trip may be there merely a few minutes after you finished your trip, you may have to wait a bit for other timeline items. We do this to ensure that (a) the timeline never changes retrospectively, (b) the timeline looks clean and compact (e.g. a 2 hours walk should be a 2 hours walk in the timeline, rather than numerous 5-15 minute walk segments), and (c) we only transfer the minimum amount of data in the minimum frequency needed to provide quality of service.

## CAR trips

Even in the background, MOVE will wake up on a location change and check whether the user is moving at a considerable speed. For CAR trips, this is a linear speed of 20 km/h for at least 2 minutes or more. As soon as a trip is detected, MOVE will record GPS points of the trip and only stop when the user stops moving.

Please note that real world data impurities may lead MOVE into thinking it is a trip, while it actually isn’t (e.g. GPS jumps), and vice versa (e.g. initial linear speed is too slow because car takes multiple turns in pedestrian zone). But overall, trip detection works in most situations and bad results may indicate other problems (e.g. wrong setup, bad battery settings kill app on Android phones).

In addition to merely collecting GPS points, MOVE may score DFD, DBE and Speed during the trip.

### Speed

GPS positions during a trip are matched to the closest street. At this point, we can compare the actual speed with the legally allowed speed for that street segment according to our source data in Open Street Map (OSM). Please note that the coverage of OSM-data may vary between countries, although we found OSM to be one of the most up-to-date sources for map data.

### DFD - Distraction-Free Driving

Phone usage is currently the most frequent and fatal cause of car accidents around the globe. Therefore, MOVE recognises any type of phone usage during a car trip: each event of voice or swipe-and-type is indicated in the trip details. The technology of detecting DFD events is very different between Android and iOS; we took great care, however, that the events are detected with largely similar fidelity.

MOVE also offers a standard DFD score for each CAR trip, which basically scores the minutes used vs overall minutes of the trip into a score value of 0-100. However, based on the phone usage events, you may also implement a different scoring algorithm. Please note that events of hands-free phone usage generate different DFD events; yet, since both cause mental distraction, we recommend that both are scored negatively.

### DBE - Driving Behavior Events

MOVE platform profiles driving behavior for acceleration, braking and cornering from sensor data recorded during a trip. We are particularly proud about our algorithms for normalising the direction of driving, which works even without user interaction. The algorithm recovers if the phone is relocated during phone usage. However, it is impossible to detect DBE if the phone is unstable and e.g. slides in the storage console with every turn, or the driver put the phone in the shirt pocket. Also for iOS, DBE and DFD cannot be detected at the same time.

### BDD - Bluetooth Device Discovery

If you're aiming to identify specific vehicles, one method to do this is by assigning a specific Bluetooth device that can be used when in proximity, for example a car's hands-free kit.

MOVE supports two types of such devices:

* Bluetooth audio devices
* Bluetooth beacons that support the iBeacon protocol

A host application can register a collection of Bluetooth devices (multiple devices are supported) with the SDK. The SDK will scan for all registered devices during a trip and will add discovered devices to the trip's metadata.

## CYCLING

MOVE detects CYCLING like CAR trips, although CYCLING trips can be slower at about 12 km/h. Later, we distinguish between CAR and CYCLING based on speed and movement. Configuring CYCLING has a couple of impacts on MOVE:

* Due to the reduced initial speed from 20 km/h to 12 km/h, MOVE is recording trips more often. This increases the likelihood of a fake trip in the timeline (i.e. a trip which actually was no real trip but due to GPS inaccuracies it seems like a trip).
* Since MOVE is awake and recording trips more often, you may see an increase in battery usage.
* We usually detect CYCLING trips in a city quite well, but there are various contexts that may make it hard for us: e.g. cycling up a steep hill may be too slow and classified as WALKING; mountain biking may be not detected at all or classified as UNKNOWN; fast e-bikes may be confused with CAR.

## Mode of Transport

MOVE needs to deal with messy data, with regards to both, technical noise in the data (e.g. GPS accuracy is low) as well as unexpected user behavior (e.g. a car trip following exactly a tram line). We use machine learning algorithms and huge training data sets to classify trip data in the MOVE backend to the correct mode of transport:

* **Fake trips** are recognised based on speed and GPS validations (e.g. GPS jumps around a location rather than following a route)
* if the movement patterns of the majority of the trip time points to walking/running, we re-classify the trip as WALKING
* slow maximum speed plus movement patterns for cycling and walking may indicate CYCLING
* GPS positions close to a train, tram or metro track indicate a PUBLICTRANSPORT (rather than CAR)
* trips that are for the most part too far away from a public road will be classified as UNKNOWN (this includes e.g. skiing, boat trips, drone flights)

If you know from user interaction that we classified a specific trip to the wrong mode of transport, you are invited to report this back to us through the API. This may also change the data provided for the timeline item (e.g. if you re-classify from PUBLICTRANSPORT to CAR within 2 weeks after the trip occurred, you receive the DBE, DFD and Speed scores).

## PUBLIC TRANSPORT

While we can detect some PUBLICTRANSPORT trips based on GPS, it is insufficient for a full coverage. There are multiple reasons for this: metro lines by definition have no GPS underground, even trains sometimes have bad GPS reception (perhaps of the overhead contact lines for electric power), and in a city the high frequency of stops at stations may confuse the MOVE trip detection. For this reason, we also developed a second detection mechanism for PUBLICTRANSPORT which is based on the stations and how quickly you move between public transport stations. Overall, our detection of rail-based public transit is more than 85% (according to our manual tests in central Europe). However, we cannot at this point distinguish public buses or taxi from CAR merely based on GPS and other phone sensors. Depending on the user app, you may want to use bluetooth or any other available context signals to ensure the user is actually using her car.

## WALKING

Last in line for timeline items, we evaluate all times outside of a trip as to whether or not they were walking/running. You can also walk in a train, and sometimes cycling seems like walking from a sensor movement perspective, so therefore it is important to evaluate WALKING timeline items as last in line.

Sensor-based movement evaluation is performed in quite different ways by operating systems and manufacturers. So therefore, a Samsung with Android 10 could yield quite different results compared to a Pixel with Android 13 and compared to iOS 15. We took great efforts to ensure that those differences are reduced to a minimum (counting timeline minutes). So that apps, which award points for each walking minute, can be fair across platforms/manufacturers/OS versions. Part of this implies that WALKING items should be at least 3 minutes long; shorter walks (such as switching rooms indoors) are ignored by MOVE.

## Points of Interest

MOVE offers to register geographical locations that will trigger an immediate event notification (called point of interest, POI). For example, you can register all airports and train stations, tag them accordingly, and whenever a user enters an airport or train station send a dedicated message to the user. Because the message is suited to the user context at that time, you can create significant touch points.

POIs can be triggered on-enter or on-exit, and they can be triggered outside or within a trip. Please note that the OS functions provided by Android and iOS are not fully reliable. So some events may be triggered a bit late or may be inaccurate. But we measured in our tests that those events are about 85% reliable (see also the section on PUBLICTRANSPORT).

Uploading your POIs and definition of the webhook for the event notification is done in the [MOVE dashboard](https://dashboard.movesdk.com/admin/poi).

## ASSISTANCE

This set of services is particularly targeted at organisations that offer (human) assistance in emergency situations. Users can either call for help manually (i.e. bCall = breakdown call, road-side assistance), or when phone sensors indicate an accident, help is sent automatically to the location of the accident.

If your organisation seeks support for providing emergency response services, please [get in touch](mailto:info@dolph.in?subject=MOVE%20SDK).

### Assistance Call

The manual assistance call can be manually triggered by a user and merely sends the current GPS location plus metadata to the MOVE backend. The MOVE backend then forwards to e.g. a call robot or a 24/7 on-duty human phone service to send help if needed. For this, the MOVE backend needs “receivers” (= web hooks) to be defined in the MOVE dashboard.

### Automated Impact Detection

We automatically detect high impacts on the smartphone sensors. An impact of more than 3.5g during a trip will trigger recording of a potential accident, and apply a series of filters (based on GPS and sensors) in a period of 60 seconds. Only if none of the filters has triggered after that evaluation time, the impact will be forwarded to the receiver (as defined in the [MOVE backend](https://dashboard.movesdk.com/admin/sdkConfig/receiver?selected=3)).

Note that for every recorded impact we calculate the acceleration severity index (ASI). The ASI is an internationally acknowledged method for calculating the risk of bodily injury in car accidents. It is most notably based on the impact strength (measured in g) and the impact angle. This can be the last filter before forwarding the impact to a human-operated call-center to consider sending an ambulance to the location: only impacts with an ASI > x are forwarded to the receiver. We recommend using an ASI > 0.5 for FNOL (first notification of loss, data available in backend for e.g. insurance report) and ASI > 1.0 for human assistance in case of car accident.

### Setup of assistance services

The following steps are required to setup your assistance services:

1. Configure "assistance call" and/or "AID" in the [MOVE configuration](https://dashboard.movesdk.com/admin/sdkConfig)
2. Activate them in the [setup of the mobile frontend](https://docs.movesdk.com/move-platform/sdk/models/moveconfig) as well
3. Validate that you receive assistance requests in the [MOVE dashboard](https://dashboard.movesdk.com/admin/impact)
4. Specify the target for real-time events in MOVE Dashboard > Configuration > [Receiver/Assistance](https://dashboard.movesdk.com/admin/sdkConfig/receiver?selected=3). Make sure to specify the ASI threshold as to your required level of sensitivity - we recommend an ASI of 1.0, but if you like to receive more events set the ASI lower, e.g. to 0.5

## HEALTH

Collecting health and fitness related data.

### Steps

If this feature is enabled, and corresponding permissions are given, steps data is queried by the system regularly and uploaded to our backend. Due to restrictions for each platform and synchronization between different input devices this data cannot be collected in real time.

Our SDK provides the option to read step data from fitness apps like Google Fit (on Android via Health Connect) and HealthKit (on iOS). Please note that accessing this data always requires the explicit consent of the end user. The application integrating the SDK must request the appropriate permissions from the respective platform before the SDK is able to use any fitness information. Without these permissions being granted by the user, the SDK will not be able to access step data.

{% hint style="info" %}
Developmental feature.

This feature is in ongoing development and we are working on stability.
{% endhint %}

## Battery vs. background services

In order to provide quality service, we need to make sure that MOVE is initialized in the background all the time, all permissions are granted, and - on Android - the battery settings allow operations in the background. In other words, to provide quality service we need the cooperation of the user. We aim to achieve this with transparency and data minimalism on the one hand, and foremost with our focus on battery optimization.

The more MOVE is active (in the background or foreground), the higher the battery consumption. Therefore, MOVE has various OS-specific mechanisms that allow the app to sleep without any battery consumption (e.g. when the smartphone is idle at home or at any fixed location), yet wake up whenever MOVE needs to work (e.g. when the user moves to a different location or in a POI).

It is a tough balance to make sure that the app is awake as much as needed to provide quality of service, yet asleep as much as possible to ensure low battery impact. You can help to improve this balance to your advantage by only activating the MOVE features in the [MOVE configuration](https://dashboard.movesdk.com/admin/sdkConfig) that you really need.

\ <br>


# Getting Started

Your shortcut through the MOVE platform into a runnable app is:

1. Register and create a project in the [MOVE Dashboard](/move-platform/sdk/getting-started/move-dashboard)
2. Obtain the projectId and an API key from the [MOVE configuration page](https://dashboard.movesdk.com/admin/sdkConfig) of your new MOVE project
3. Clone the code sample app ([Android](/move-platform/sdk/getting-started/android) / [iOS](/move-platform/sdk/getting-started/ios) / [React](https://github.com/dolphin-technologies/MOVE-sample-React) / [Flutter](https://pub.dev/packages/movesdk/example)), adapt the projectId and API key to your project
4. Install the app on your mobile phone, take the phone everywhere you go for a couple of days
5. Check the results in the [MOVE timeline](https://dashboard.movesdk.com/admin/appUsers)

{% hint style="warning" %}
If you have any problems during setup, please check the OS specific **Troubleshooting** section. ([iOS](/move-platform/sdk/troubleshooting/ios))
{% endhint %}

{% hint style="warning" %}
You can check out our sample code on [Github](https://github.com/dolphin-technologies?tab=repositories)!

* Our **code sample app** ([Android](https://github.com/dolphin-technologies/MOVE-sample-Android) / [iOS](https://github.com/dolphin-technologies/MOVE-sample-iOS) / [React](https://github.com/dolphin-technologies/MOVE-sample-React) / [Flutter](https://pub.dev/packages/movesdk/example)) is a very lean app that exemplifies how to initialise and run the MOVE SDK. It contains no display of timeline elements or other fancy stuff, but with your projectId and API key you can get this up and running in no time.
* The **MOVE App** is more comprehensive, with display of timeline elements and scoring. You will be able to find open source code ([Android](https://github.com/dolphin-technologies/MOVE-App-Android) / [iOS](https://github.com/dolphin-technologies/MOVE-App-iOS) / [React](https://github.com/dolphin-technologies/MOVE-App-React)); the incarnation of the React code is also available from the stores ([Android](https://play.google.com/store/apps/details?id=in.dolph.move) / [iOS](https://apps.apple.com/tt/app/dolphin-move/id1600878778)).
* The **sample backend** illustrates how to consume the MOVE APIs in [node.js](https://github.com/dolphin-technologies/MOVE-demo-backend). You can use it to run your own version of the MOVE App e.g. on Firebase or on a local machine.
  {% endhint %}

{% hint style="info" %}
After installing and running MOVE on your mobile phone, make sure that the OS allows MOVE to operate:

* all [permissions for Android](/move-platform/sdk/appendix/android/permission-handling) / [permissions for iOS](/move-platform/sdk/appendix/ios/permission-handling) are given
* for Android: all battery settings are set to allow MOVE to work in the background
* check in the [timeline of the MOVE Dashboard,](https://dashboard.movesdk.com/admin/appUsers) whether there is a basic connection, by searching for your contract ID (defined in the registration after installing on the phone)
* take the phone everywhere you go for a couple of days\
  (MOVE needs some minimum activity outdoors before it starts recording, so you have to actually walk, make a car trip, take the subway, or do whatever MOVE feature you are interested in for 5 minutes or longer)
  {% endhint %}


# MOVE Dashboard

Getting Started

The MOVE Dashboard at [https://dashboard.movesdk.com](https://dashboard.movesdk.com/) is (a) the console where you can set up and configure your MOVE projects, and (b) the initial place for inspecting and troubleshooting your MOVE apps.&#x20;

If you already created your project in the MOVE Dashboard, and obtained a product ID and API key, you can skip this chapter and explore first steps for [Android](/move-platform/sdk/getting-started/android), [iOS](/move-platform/sdk/getting-started/ios), [React](/move-platform/sdk/getting-started/react-native) and [Flutter](/move-platform/sdk/getting-started/flutter).

## Registration and first project

On first opening the page, please register and enter your details. Note that your first couple of users are free, so you can experiment with the MOVE SDK.

After your first login, you will see a pretty empty space. You can create your first MOVE project, using the <img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FxxkZL1ruUWKb35gvUZaW%2Fimage.png?alt=media&amp;token=3d89eb23-a7c4-4a9a-9cc2-71a5f3dc46f5" alt="" data-size="line"> in the bottom of the navigation bar. If you created multiple projects, you can select your project in the drop-down list in the top of the navigation bar.

* **key** - copy the key from here
* **name** - you can set this to whatever roles or rights segmentation you like to use in your systems; not relevant for MOVE
* **write-only** - two different key types are available: write only (write-only=true; for all SDK functions that send and process data), and read-write (write-only=false; for all SDK functions / APIs you may use for reading data)


# Access Control

## Manage developer rights

This page allows you to add developer colleagues to this project in the MOVE Dashboard. Make sure that your colleague has registered with the MOVE Dashboard previously. Then enter her/his email address and role in order to add her/him to the project. Next time your colleague loads the MOVE Dashboard, s/he will be able to select the project in the drop-down list located on top of the navigation bar.

You can choose between an "admin" and a "reader" role. An admin has rights to change the configuration of the project, which has direct implications on monthly cost. A reader is mainly able to view user contracts in the "Timeline" section. We recommend you use the "reader" role for e.g. frontend developers or testers.

## Delete Project

On this page you are also able to delete the project.

{% hint style="warning" %}
**Attention!** **If you delete the project, you no longer have access to the data.**
{% endhint %}


# Configuration

## Add MOVE features

The configuration of your MOVE project is split into 3 parts. Please make sure to select the right project in the drop-down menu of the navigation bar before you proceed. Also, please note that configuration changes may have an impact on your cost.

### 1. FEATURES

With these settings you can activate or deactivate [MOVE features](https://dashboard.movesdk.com/admin/sdkConfig) like Walking, Driving, or Public Transport. You will find a short syllabus of each feature in the MOVE Dashboard, and more detailed technical specifications in the chapter [API Interface](/move-platform/sdk/api-interface) in these docs.

### 2. API KEYS & PROJECT CODES

Create an API key that allows secure access to the MOVE APIs.

Using the API key in the **backend** for:

* Fetching data from the Timeline API or the Notifier API (see [Timeline/authentication](/move-platform/backend/move-backend/move-timeline-api#gettingstartedwiththedolphinmovetimelineservice-authentication))
* Creating tokens that are user-specific, and forward these tokens e.g. to your users' smartphones to setup the MOVE SDK properly (see [Android](/move-platform/sdk/api-interface/android/initialization#setup), [iOS](/move-platform/sdk/api-interface/ios/setup#setup-auth-config)).

Using the API key in the **frontend**:

* To authenticate your mobile MOVE SDK (see our code sample on [Github](https://github.com/dolphin-technologies?tab=repositories)). For security reasons, we recommend to use write-only keys for this scenario, or preferably the next option:

You can create, expire and delete as many API keys as you want on this page. The following parameters pertain to each API key:

* **key** - copy the key from here
* **name** - you can set this to whatever roles or rights segmentation you like to use in your systems; not relevant for MOVE
* **write-only** - two different key types are available: write only (write-only=true; for all SDK functions that send and process data), and read-write (write-only=false; for all SDK functions / APIs you may use for reading data)

### 3. RECEIVER

The [MOVE Generic Notifier](/move-platform/backend/move-generic-notifier-api) pushes important events to your backend. This contains real-time events like POIs (Points of Interest), as well as more administrative data about user devices, that you may want to use to allow more targeted communication with your users.&#x20;

Notifier events are pushed to your backend via a web hook: Set up a service, that is capable of receiving [notifier events](/move-platform/backend/move-generic-notifier-api). Enter the URL of your service into this configuration page, as well as a token to be used for signing the event.

#### Timeline

The [MOVE Timeline](/move-platform/backend/move-backend/move-timeline-api) contains all the key results of MOVE compiled into a chronological timeline. Whenever a new timeline item is created for a user, MOVE pushes update notifications to your backend. Timeline items are not created in real-time; MOVE tries to clean up the timeline as much as possible from the raw data we receive from the devices, and is also enhancing the basic data with additional added value data - this may take some time. Note that we strictly avoid to change the timeline retrospectively, to simplify processing for your backend.

Timeline events are pushed to your backend via a web hook: Set up a service, that is capable of receiving [timeline events](/move-platform/backend/move-backend/move-timeline-api). Enter the URL of your service into this configuration page, as well as a token to be used for signing the event.

#### Generic

Generic notifier sends all notification that are not related to timeline events. This contains multiple type of data:

* Points-of-Interest: In case you activated the Points-of-Interest feature in your configuration, you will receive POI events here. These events can then be passed on to e.g. your CRM resp. Marketing Automation system for communicating with your user. This interface is almost real-time.
* Device settings: User phones need to have a series of permissions granted. Permission profiles are forwarded through this interface, to enable communication with your users (e.g. please grant the Location Access "Always", otherwise we are unable to detect trips in the background).
* may be extended in the future for new features

#### Assistance

Assistance notifier receives **user alarms** in emergency situations (both manual and automatic). At the specified URL you will receive the current GPS location and other details about the alarm, so you can adequately react to it. In order to react on user alarms, companies will usually set up a call service that is staffed 24/7 with human call operators.

* manual - triggered in the mobile app whenever e.g. a user pushes an ALARM-button which calls the “initiate assistance call” service in the MOVE SDK
* automatic - an Automatic Impact Detection can be configured as part of the [MOVE features](https://dashboard.movesdk.com/admin/sdkConfig). Whenever a serious impact is detected during a car trip, the MOVE SDK sends an automatic alarm with some additional data to put the [impact](https://dashboard.movesdk.com/admin/impact) into context. The threshold helps to filter false positives. We recommend setting it to 1.0 in order to forward only serious impacts with an acceleration severity index>= 1.0.


# Timeline

## Explore user contracts

The [timeline](https://dashboard.movesdk.com/admin/appUsers) offers you details about individual users - in terms of (a) their timeline on a day-per-day basis, (b) their device and (c) some more detailed logs for debugging (in cooperation with the MOVE community).

### Timeline - List of user

You can also filter individual users by their contract ID. In the timeline, you can select a specific day and inspect each individual timeline item on that day.

### **Timeline - Details**

On top of the detailed user timeline page, there are some details of the user device:

* user id
* plattform
* device name
* OS version
* MOVE SDK version
* A link to the last timeline item
* A list of the permission states of the device

Also on the detailed timeline (above the map) you can filter for specific transport types and also (in case of CAR transport types) display event types like Speed, DBE (= Driving Behaviour Events) like Acceleration, Braking and Cornering.

### Timeline - Logs

Alternatively you are also able to look into the SDK User Logs. Please note that we currently do not offer a manual of how to interpret the logs. In case you have problems e.g. initializing your MOVE SDK or receiving all transport types, please get in touch and we will analyse the logs together.


# Points of Interest

## Get notified when user is close by

In addition to detecting user movements as timeline items, the MOVE SDK also offers to detect real-time-activities whenever a user is close to a specific location. You can define such a location as a "Point of Interest" by either right-clicking on the map, using the "add Point of Interest"-button beneath the map or by importing a CSV-list.

A Point of Interest is defined by the following **mandatory** characteristics:

* **Name** - any string you choose for your PoI
* **Latitude/Longitude** - GPS location on the map

Trigger **optional** properties:

* **In Trip** - trigger a POI notification even if a user is in a trip (e.g. CAR, CYCLING, PUBLIC TRANSPORT). Please note that the frontend (iOS, Android) may bouncing back and forth between trip detection, whenever the user is moving outside with some speed or due to GPS jumps. Those wrong data will be filtered.
* **On Enter** - a POI event is triggered when entering the POI
* **On Exit** - a POI event is triggered when leaving the POI
* **Active** - the POI is active (or not)
* **Tags** - you may want to add tags to the POI for your convenience. These tags will be forwarded to you in the [POI event](/move-platform/backend/move-generic-notifier-api#poi-event-notifications) that is sent through the [Generic Notifier](/move-platform/backend/move-generic-notifier-api).


# Android

Getting Started

{% hint style="warning" %}

## Prerequisites&#x20;

* Android 9.0+ / API 28+ (it is possible that the MOVE SDK is also useable with previous Android OS versions but it is not tested on our side)
* Kotlin 2.0.21+
* Android Studio >= Narwhal (2025.1.1) (earlier versions may work but are not officially tested or supported)

Apps hosting MOVE SDK should always be built using the latest released Android and Android Studio versions.
{% endhint %}

For a quick start, you can download and build our public [MOVE Sample](https://github.com/dolphin-technologies/MOVE-sample-Android) app or the more comprehensive [MOVE App](https://github.com/dolphin-technologies/MOVE-App-Android).


# Installation

Getting Started / Android

## Adding the MOVE SDK to your app

There are two possible ways to integrate the MOVE SDK:

1. Include from an Artifactory
2. Include binaries directly into your app&#x20;

### Include from Artifactory

Include the maven repository to your gradle build script where the MOVE SDK package is located.

```bash
maven { 
    url "https://dolphin.jfrog.io/artifactory/move-sdk-libs-release" 
}
```

{% hint style="info" %}
Add this to your project-level `build.gradle` inside `allprojects { repositories { } }`, or to `settings.gradle` inside `dependencyResolutionManagement { repositories { } }` if your project uses AGP 7+.
{% endhint %}

Add the dependency for the MOVE SDK Android library to your module (app-level) Gradle file (usually app/build.gradle).

{% hint style="info" %}
You can check for latest releases here:\
<https://dolphin.jfrog.io/ui/native/move-sdk-libs-release/io/dolphin/move/move-sdk>
{% endhint %}

```bash
// Include the latest version number of our artifactory e.g. 2...
// Latest releases: https://dolphin.jfrog.io/ui/native/move-sdk-libs-release/io/dolphin/move/move-sdk
implementation "io.dolphin.move:move-sdk:w.x.y.zzz"
```

{% hint style="info" %}
**Note:** The snippets above use Groovy DSL syntax. If your project uses Kotlin DSL (`build.gradle.kts`), replace single quotes with double quotes and adjust the syntax accordingly.
{% endhint %}

{% hint style="info" %}
**Note:** ProGuard/R8 consumer rules are bundled with the SDK. No additional configuration required.
{% endhint %}

### Include SDK binary directly

The SDK may be shipped as an AAR library directly. Place the library in a "libs" folder of your application module.  If there is no libs folder, you must create it first.

Once the library is placed in the correct folder, the app build file needs to be adapted as shown below. After a Gradle sync, the MOVE SDK should be ready to use.

{% code title="app build.gradle" %}

```bash
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
    ...
}
```

{% endcode %}

{% hint style="info" %}
You may also include the binaries directly into your own Artifactory. Then you are able to use the Artifactory solution from above.
{% endhint %}

More information about AAR libraries can be found here: <https://developer.android.com/studio/projects/android-library>


# Quick Start

Getting Started / Android

## Setup the MOVE SDK

The Android MOVE SDK must be initialized by adding MoveSdk.[init](/move-platform/sdk/api-interface/android/initialization#init)() at the first line in your Android Application class (onCreate). This instance can then be used to control MOVE SDK services (check [API Interface](/move-platform/sdk/api-interface) for more [details](/move-platform/sdk/api-interface/android/initialization)).

After the MOVE SDK has been initialized you also want to add notifications, listeners or activate additional features.

Also, you have to configure the MOVE SDK before you can call .[setup](/move-platform/sdk/api-interface/android/initialization#setup)(...).

{% hint style="warning" %}
To successfully initialize and run the MOVE SDK, the user's [MoveAuth ](/move-platform/sdk/models/moveauth)must already be fetched with the [MOVE Admin API](/move-platform/backend/move-backend/move-admin-api) and the required permissions must be granted ([Permission Handling](/move-platform/sdk/appendix/android/permission-handling)).

If the provided [MoveAuth ](/move-platform/sdk/models/moveauth)is invalid, the MOVE SDK will not initialize.

If the required permissions are missing, the MOVE SDK State will change to READY. Additionally, MoveServiceFailure and/or MoveServiceWarning will present the missing permission.
{% endhint %}

The initialization of the MOVE SDK is asynchronous and you will be notified regarding state changes with the [MoveStateListener](/move-platform/sdk/models/listeners-callbacks). On successful initialization the [MoveSdkState](/move-platform/sdk/models/movesdkstate) changes to `READY`.&#x20;

To be able to use the MOVE SDK, several permissions need to be granted. This is described in [Permission Handling](/move-platform/sdk/appendix/android/permission-handling).

Now that there is an instance of the MOVE SDK, the detection may be started with [startAutomaticDetection()](/move-platform/sdk/api-interface/android/services#start-automatic-detection), which should lead to the state `RUNNING` of the MOVE SDK.

{% hint style="warning" %}
If the MOVE SDK trip detection was started with [startAutomaticDetection()](/move-platform/sdk/api-interface/android/services#start-automatic-detection) then it is not possible to manual start a trip with [startTrip(...)](/move-platform/sdk/api-interface/android/services#manual-start-trip).
{% endhint %}

{% hint style="warning" %}
The MOVE SDK is collecting data only when in`RUNNING`state.
{% endhint %}

### Code example

```kotlin
package com.example.movesdkandroid

import android.app.Application
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.util.Log
import androidx.annotation.MainThread
import androidx.core.app.NotificationCompat
import io.dolphin.move.DrivingService
import io.dolphin.move.MoveAuthResult
import io.dolphin.move.MoveAuthState
import io.dolphin.move.MoveConfig
import io.dolphin.move.MoveConfigurationError
import io.dolphin.move.MoveDetectionService
import io.dolphin.move.MoveNotification
import io.dolphin.move.MoveSdk
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class MoveSDKTest : Application() {

    private val authCallback = object : MoveSdk.MoveAuthCallback {
        override fun onResult(result: MoveAuthResult) {
            // Handle result here. See full example:
            // https://docs.movesdk.com/move-platform/sdk/api-interface/android/initialization#with-authcode
            Log.d("MoveAuthCallback", "onResult: $result")
        }
    }

    override fun onCreate() {
        // MoveSdk.init() must be the first line in onCreate()
        MoveSdk.init(this)
        super.onCreate()
        setupSdk()
    }

    private fun setupSdk() {
        CoroutineScope(Dispatchers.IO).launch {
            // Fetch authCode from your backend.
            // Your backend calls the MOVE Admin API:
            // GET /v20/user/authcode?userId={userId}
            // https://docs.movesdk.com/move-platform/backend/move-backend/move-admin-api
            // Returns: { "authCode": "string" }
            val authCode: String? = "YOUR_AUTH_CODE" // Replace this with your actual backend call

            if (authCode != null) {
                withContext(Dispatchers.Main) {
                    prepareAndConfigSdk(authCode)
                }
            } else {
                Log.e("MoveSDKTest", "Failed to fetch authCode from backend")
            }
        }
    }

    @MainThread
    private fun prepareAndConfigSdk(authCode: String) {

        val channelId = "channel-sdk"
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        val sdkChannel = NotificationChannel(channelId, "Dolphin SDK", NotificationManager.IMPORTANCE_DEFAULT)
        notificationManager.createNotificationChannel(sdkChannel)

        MoveSdk.get()?.recognitionNotification(
            NotificationCompat.Builder(this, channelId)
                .setSmallIcon(R.drawable.ic_notification) // Replace with your own drawable resource
                .setContentTitle(getString(R.string.app_name)) // Replace with your own app nameame))
                .setContentText("Active")
                .setShowWhen(false)
                .setSilent(true)
        )

        MoveSdk.get()?.tripNotification(
            NotificationCompat.Builder(this, channelId)
                .setSmallIcon(R.drawable.ic_notification) // Replace with your own drawable resource
                .setContentTitle(getString(R.string.app_name)) // Replace with your own app nameame)ame))
                .setContentText("Driving")
                .setShowWhen(true)
                .setSilent(true)
        )

        // To customize notification texts only (without replacing the full notification):
        /*
        MoveSdk.get()?.setNotificationText(
            MoveNotification(
                recognitionTitle = getString(R.string.app_name),
                recognitionText = "Active",
                drivingTitle = getString(R.string.app_name),
                drivingText = "Driving",
            )
        )
        */

        val initListener = object : MoveSdk.InitializeListener {
            override fun onError(error: MoveConfigurationError) {
                Log.d("MoveConfigurationError", "onError: $error")
            }
        }

        val authStateListener = object : MoveSdk.AuthStateUpdateListener {
            override fun onAuthStateUpdate(state: MoveAuthState) {
                when (state) {
                    is MoveAuthState.INVALID -> {
                        // User session invalid -> log out and shut down
                        MoveSdk.get()?.shutdown(force = true)
                    }
                    else -> {}
                }
            }
        }

        MoveSdk.get()?.apply {
            authStateUpdateListener(authStateListener)
            initializationListener(initListener)

            // MORE INFORMATION ABOUT LISTENERS:
            // https://docs.movesdk.com/move-platform/sdk/models/listeners-callbacks

            // sdkStateListener(sdkStateListener)
            // tripStateListener(tripStateListener)

            consoleLogging(true)
        }

        val moveConfig = MoveConfig(
            moveDetectionServices = listOf(
                MoveDetectionService.Driving(
                    drivingServices = listOf(
                        DrivingService.DrivingBehaviour,
                        DrivingService.DistractionFreeDriving,
                        DrivingService.DeviceDiscovery,
                    )
                ),
                MoveDetectionService.Walking(),
                MoveDetectionService.Cycling,
                MoveDetectionService.AutomaticImpactDetection,
                MoveDetectionService.AssistanceCall,
            )
        )

        MoveSdk.get()?.setup(
            authCode = authCode,
            config = moveConfig,
            start = true, // true = startAutomaticDetection() is called automatically after setup
            callback = authCallback
        )
    }
}
```


# iOS

Getting Started

{% hint style="warning" %}

## Prerequisites&#x20;

* Xcode 10+
* iOS 11.0+

Apps hosting Move SDK should be always build using the latest released iOS and Xcode versions.&#x20;
{% endhint %}

For a quick start, you can download and build our public [MOVE sample](https://github.com/dolphin-technologies/MOVE-sample-iOS) app or the more comprehensive [MOVE App](https://github.com/dolphin-technologies/MOVE-App-iOS).


# Installation

Getting Started / iOS

## Adding the MOVE SDK

### Swift Package Manager

Add the package with the URL:

```
https://github.com/dolphin-technologies/MOVE-iOS-Packages
```

Add the frameworks to the project:

* Go to the **General** tab of your target settings
* Click the **+** button under the **Frameworks, Libraries, and Embedded Content** heading
* Click **Add Other** and then **Add Package Dependency**

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FuWtys1HUCprL3vIxoOKH%2FScreenshot%202024-01-16%20at%2016.18.27.png?alt=media&amp;token=2a561b95-505e-41ae-8774-c5606c7826d5" alt=""><figcaption><p><strong>DolphinMoveSDK</strong> added to <strong>Libraries</strong>.</p></figcaption></figure>

#### Health Kit Extension

If the MoveSDK Health service is needed add `DolphinMoveSDKHealth` to **Frameworks, Libraries, and Embedded Content**

{% hint style="warning" %}
Version 2.15 and above:

If you are using the steps feature with health kit synchronization, in order to sync data with your AppleWatch or other devices, you also need to embed *DolphinMoveSDKHealth.* This will use HealthKit, which must be supported by your app's provisioning and requires user permissions, see [Permission Handling](/move-platform/sdk/appendix/ios/permission-handling).
{% endhint %}

### Manual Installation&#x20;

{% hint style="info" %}
If you need to install the Framework manually you will have to extract the download link for the zip from the latest [Swift Package](https://github.com/dolphin-technologies/MOVE-iOS-Packages/blob/master/Package.swift). If you want to use a specific version refer to the [tags](https://github.com/dolphin-technologies/MOVE-iOS-Packages/tags) in the repository.
{% endhint %}

1. Download and extract the latest Move SDK XCFramework&#x20;
2. Add the frameworks to the project ()
   * Go to the **General** tab of your target settings
   * Click the **+** button under the **Frameworks, Libraries, and Embedded Content** heading
   * Click **Add Other** and then **Add Files**
   * Choose the **Move XCFramework** file and click **Open**
3. Change the **Embed** option next to the framework to **Do Not Embed**

### Important Notes

{% hint style="warning" %}
*For versions bellow 2.3:*

When exporting your application archive make sure the ***manageAppVersionAndBuildNumber*** option is set to false, otherwise the version numbers of all frameworks (including MoveSDK) included in your application will be overwritten. This can cause issues with migration code since the correct version number is lost.

When building with ***Fastlane*** this is done by adding export options to your ***gym*** export command, see following code snippet:
{% endhint %}

```ruby
gym(
	...
	export_options: {
		manageAppVersionAndBuildNumber: false,
		...
	}
	...
)
```

### ~~Using Cocoapods~~

{% hint style="danger" %}
Version 2.19.0 and above.

The public Cocoapods repository will be locked coming December 2026.

As of version 2.19.0 DolphinMoveSDK is available via SwiftPackageManager only.&#x20;
{% endhint %}

~~CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects. Check out their~~ [~~homepage~~](https://cocoapods.org/) ~~for more details.~~

~~If your project already uses CocoaPods, then add the dependency to your ***Podfile***:~~

```bash
pod 'DolphinMoveSDK'
```

~~Run the following command from the terminal:~~

```bash
$ pod install
```

*See also* [*Troubleshooting*](/move-platform/sdk/troubleshooting/ios#cocoapods)*.*

### ~~Health Kit Extension~~

{% hint style="warning" %}
Version 2.15 and above:

In order to allow the [Steps](/move-platform/move-services#health) service to collect HealthKit data an additional framework is needed.

Make sure to use the *DolphinMoveSDKHealth* framework with the same version number.
{% endhint %}

```bash
pod 'DolphinMoveSDKHealth'
```


# Quick Start

Getting Started / iOS

{% hint style="info" %}
Check our public [sample application](https://github.com/dolphin-technologies/MOVE-sample-iOS) for an actual implementation of the snippets below and how they can be utilized.&#x20;
{% endhint %}

## Overall Code

A quick start snippet will look something like this in your app's [`willFinishLaunchWithOptions`](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623032-application):

```swift
import DolphinMoveSDK
#if canImport(DolphinMoveSDKHealth)
import DolphinMoveSDKHealth
#endif

func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
#if canImport(DolphinMoveSDKHealth)
		sdk.enable(healthKit: MoveSDKHealth.shared)
#endif
    MoveSDK.shared.setSDKStateListener { sdkState in
            switch state {
            case .uninitialized:
                print("/* SDK uninitialized*/")
                break
            case .ready:
                print("/* SDK initialised and ready to start the service*/")
                break
            case .running:
                print("/* SDK Started Detection*/")
                break
            }
    }
    
    MoveSDK.shared.setAuthStateUpdateListener { authState in  ... }    
    MoveSDK.shared.setTripStateListener       { tripState in ... }
    MoveSDK.shared.setServiceFailureListener  { failures in ... }
    MoveSDK.shared.setServiceWarningListener  { warnings in ... }

    MoveSDK.shared.initialize(launchOptions: launchOptions)
}
```

{% hint style="warning" %}
This snippet assumes that the required configurations and permissions are already setup to work. Check the [permissions handling](/move-platform/sdk/appendix/ios/permission-handling#required-permissions) section for more details.
{% endhint %}

### SDK Authentication

Users will need to be authenticated. This authentication will persist until shutdown is called. It will persist over the termination of the app. The configuration to enable functionality is passed here. `startAutomaticDetection` will start the services. This too will persist and services will automatically start when launching the app from the background.

{% hint style="info" %}
The authentication object is constructed with tokens that need to be acquired from the backend (either from the SDK backend directly, or via your product backend). See [MOVE Backend](/move-platform/backend/move-backend/move-admin-api#gettingstartedwiththedolphinmovetimelineservice-authentication).
{% endhint %}

{% tabs %}
{% tab title="Swift 5" %}

<pre class="language-swift"><code class="lang-swift"><strong>import DolphinMoveSDK
</strong>
// Response from the API Request.
// {
//  "authCode": "string"
// }

func authenticateUser(authCode: String) {

	let config = MoveConfig(
		detectionService: [
			.driving([.drivingBehavior, .distractionFreeDriving, .deviceDiscovery]),
			.walking([.location]), .cycling, .places,
			.publicTransport,
			.pointsOfInterest,
			.assistanceCall,
			.automaticImpactDetection
		])

	MoveSDK.shared.setup(authCode: authCode, config: config) { status in
		switch status {
		case .success:
			MoveSDK.shared.startAutomaticDetection()
		case let .invalidCode(code):
			print("Invalid auth code: \(code). Auth codes may only be used once")
		case let .networkError(error):
			print("There was an error contacting the server. Please try again later. \(error)"
		}
	}
}
</code></pre>

{% endtab %}

{% tab title="Swift 6" %}

<pre class="language-swift"><code class="lang-swift"><strong>import DolphinMoveSDK
</strong>
// Response from the API Request.
// {
//  "authCode": "string"
// }

func authenticateUser(authCode: String) async {

	let config = MoveConfig(
		detectionService: [
			.driving([.drivingBehavior, .distractionFreeDriving, .deviceDiscovery]),
			.walking([.location]), .cycling, .places,
			.publicTransport,
			.pointsOfInterest,
			.assistanceCall,
			.automaticImpactDetection
		])

	let status = await MoveSDK.shared.setup(authCode: authCode, config: config)
	switch status {
		case .success:
			await MoveSDK.shared.startAutomaticDetection()
			...
		case let .invalidCode(code):
			print("Invalid auth code: \(code). Auth codes may only be used once")
		case let .networkError(error):
			print("There was an error contacting the server. Please try again later. \(error)"
		}
}
</code></pre>

{% endtab %}
{% endtabs %}

### Authentication Invalidation

{% hint style="warning" %}
The host app is expected to monitor [MoveAuthState](/move-platform/sdk/models/moveauthstate) updates via`authStateChangeListener`([iOS](/move-platform/sdk/api-interface/ios/services#set-sdk-auth-state-listener)) API and handle those changes accordingly.

Check [Authentication updates and expiry](/move-platform/sdk/models/moveauthstate#authentication-updates-and-expiry) for more details about authentication expiry and renewal.
{% endhint %}

An auth state listener must be implemented to handle user invalidation, which can happen due to a user being blocked or having multiple conflicting installations with the same user.

<pre class="language-swift"><code class="lang-swift"><strong>import DolphinMoveSDK
</strong>
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {

    ...

    MoveSDK.shared.setAuthStateUpdateListener { state in
        switch state {
        case .invalid:
            MoveSDK.shared.shutdown()
        }
    }

    MoveSDK.shared.initialize(launchOptions: launchOptions)

...
</code></pre>

### SDK State

The host app is expected to set its [`SDKStateListener`](/move-platform/sdk/api-interface/ios/services#set-sdk-state-listener) **before** initializing the SDK to intercept the [MoveSDKState](/move-platform/sdk/models/movesdkstate) changes.

The provided block could then start the SDK when [MoveSDKState](/move-platform/sdk/models/movesdkstate) is `ready` or handle errors if occurred. The provided block could look something like this:&#x20;

```swift
MoveSDK.shared.setSDKStateListener { state in
    switch state {
    case .uninitialized:
        /* SDK uninitialized*/
        break
    case .ready:
        /* SDK initialised and ready to start the service*/
        break
    case .running:
        /* SDK Started Detection*/
        break
    }
}
```

### SDK Initialization&#x20;

{% hint style="warning" %}
The[`initialization`](/move-platform/sdk/api-interface/ios/intialization)API must be executed before[`didFinishLaunchingWithOptions`](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622921-application)returns. We recommend calling it in[`willFinishLaunchingWithOptions`](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623032-application).\
\
Exceptions might apply, where the SDK is not initialized on app launch.  First initialization is a good example, where the app would only initialize the SDK after onboarding the user and requesting permissions. \
\
Check[ Initialization Timing](/move-platform/sdk/api-interface/ios/intialization#timing) for more details about the importance of adequately initializing the SDK.
{% endhint %}

```swift
MoveSDK.shared.initialize(launchOptions: launchOptions)
```

### Warnings and Errors

When services are not running properly because they are missing permissions or are not authorized on the backend, warnings or errors will be reported in the corresponding listeners.

```swift
MoveSDK.shared.setServiceFailureListener { failures in
    for failure in failures {
        /* a list of MoveServiceFailure objects */
        switch failure.reason {
	case .unauthorized:
	    /* a service is not configured on the backend */
	    break
	case let .missingPermission(permissions):
	    /* a required permission is missing */
	    break
        }
    }
}

MoveSDK.shared.setServiceWarningListener { warnings in
    for warning in warnings {
        /* a list of MoveServiceWarning objects */
        switch warning.reason {
	case let .missingPermission(permissions):
	    /* an optional permission is not provided, data collection will be reduced */
	    break
        }
    }
}
```

## WORKING SAMPLE CODE

```swift
import UIKit
import CoreMotion
import CoreLocation
import DolphinMoveSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
    var locationManager = CLLocationManager()
    let activityManager = CMMotionActivityManager()
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // ACQUIRE PERMISSIONS
        setupPermissions()
        
        // INITIALIZE MOVE SDK
        initializeSDK()
        
        return true
    }

    /// INITIALIZE MOVE SDK
    func initializeSDK(launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
        setupSDKListeners()

        MoveSDK.shared.initialize(launchOptions: launchOptions)
        if MoveSDK.shared.getSDKState() == .uninitialised {
            self.setupUser()
        }    
    }
    
    /// SETUP LISTENERS
    func setupSDKListeners() {
        MoveSDK.shared.setSDKStateListener { state in
            switch state {
            case .uninitialized:
                print("SDK uninitialized")
                break
            case .ready:
                print("SDK initialised and ready to start the service")
                break
            case .running:
                print("SDK Started Detection")
                break
            }
        }
        
        MoveSDK.shared.setServiceFailureListener { failures in
            for failure in failures {
                /* a list of MoveServiceFailure objects */
                switch failure.reason {
                case .unauthorized:
                    /* a service is not configured on the backend */
                    print("unauthorized")
                case let .missingPermission(permission):
                    /* a required permission is missing */
                    print(permission)
                    break
                }
            }
        }
        
        MoveSDK.shared.setServiceWarningListener { warnings in
            for warning in warnings {
                /* a list of MoveServiceWarning objects */
                switch warning.reason {
                case let .missingPermission(permissions):
                    /* an optional permission is not provided, data collection will be reduced */
                    print(permissions)
                    break
                }
            }
        }
    }
    
    /// ACQUIRE PERMISSIONS
    func setupPermissions() {
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestAlwaysAuthorization()
        locationManager.startUpdatingLocation()
        
        switch CMMotionActivityManager.authorizationStatus() {
        case .restricted, .denied:
            print("UNAUTHORIZED")
        case .authorized:
            print("AUTHORIZED")
        case .notDetermined:
            let activityManager = CMMotionActivityManager()
            activityManager.queryActivityStarting(from: Date(), to: Date(), to: .main) { (activity, error) in
            }
        }
    }
    
    /// SETUP USER
    func setupUser() {
        // API REQUEST - Post Request for Auth Code: 
        // Example: https://stackoverflow.com/a/26365148
        let authCode = ... 
               
        // SDK CONFIGURATION WITH SERVICES
        let sdkConfig = MoveConfig(
            detectionService: [
                .driving([.drivingBehavior, .distractionFreeDriving]),
                .walking([]), 
                .cycling, 
                .places,
                .publicTransport,
                .pointsOfInterest,
                .assistanceCall,
                .automaticImpactDetection
            ])

        // SETUP THE SDK WITH AUTH AND SDK CONFIG OBJECTS
        MoveSDK.shared.setup(authCode: authCode, config: sdkConfig) { status in
        }
        
        // START THE SDK SERVICES
        MoveSDK.shared.startAutomaticDetection()
    }
}

```

##


# React Native

Getting Started

## Installation

```bash
npm install react-native-move-sdk --save
#or
yarn add react-native-move-sdk
```

Here is [**npm package documentation**](https://www.npmjs.com/package/react-native-move-sdk).

## Setup

### iOS

See also: [iOS/Troubleshooting](/move-platform/sdk/troubleshooting/ios).

#### Configuration

1. Using the **terminal**, access the **iOS folder** in your project
2. Run `$`<mark style="color:blue;">`pod install`</mark>&#x20;
3. Open the ***.xcworkspace*** folder using **Xcode**
4. Go to the **Capabilities** tab of your target settings
5. Turn on **Background Modes** and enable **Location updates**

![Location updates background mode capability](https://394612935-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXD5xlIFUYU8eK_kkLo%2F-Ma7-Qp0tvRtlszHh2aC%2F-MaWrFoEnyiReo8XoJL3%2Fimage.png?alt=media\&token=171c219f-f0e1-4d9a-9fe8-a0ccb47078a6)

#### Health Services&#x20;

*Since MoveSDK 2.15*:

For iOS, using the steps service requires the addition of the MoveSDKHealth framework.

This can be configured by adding an environment variable in the Podfile.

```
ENV['DOLPHIN_MOVE_SDK_HEALTH'] = '1'
```

### Android

Include the maven repository to your gradle build script, where the MOVE SDK package is located.

```bash
maven { 
    url "https://dolphin.jfrog.io/artifactory/move-sdk-libs-release" 
}
```

Add the dependency for the MOVE SDK Android library to your module (app-level) Gradle file (usually app/build.gradle).

{% hint style="info" %}
You can check for latest releases here:\
<https://dolphin.jfrog.io/ui/native/move-sdk-libs-release/io/dolphin/move/move-sdk>
{% endhint %}

Use the following SDK and Kotlin versions:

```javascript
minSdkVersion = 26
kotlinVersion = '1.7.10'
compileSdkVersion = 33
targetSdkVersion = 31
```

### Expo

If you use Expo, please take a look at our [**sample app**](https://github.com/dolphin-technologies/MOVE-sample-React) created with Expo. Note that it is simplified as much as possible and its main task is to show an example of integration with the MOVE SDK. The [**plugin**](https://github.com/dolphin-technologies/MOVE-sample-React/blob/main/plugins/move/index.js) is required to integrate with the MOVE SDK when using the Expo.

Contact us for assistance if you still have questions.

## Further Information

{% hint style="info" %}
See also the [Appendix](/move-platform/sdk/appendix/react-native/permission-handling) section to make sure you are not missing anything.
{% endhint %}


# Flutter

Getting Started

A wrapper for the MOVE SDK is available for Google's Flutter framework and published on pub.dev.

<https://pub.dev/packages/movesdk>

**Quick Start:** For a complete working example, see the [example project on pub.dev](https://pub.dev/packages/movesdk/example) and [MOVE SDK Flutter Example App](https://github.com/dolphin-technologies/MOVE-SDK-Flutter/tree/master/example) on GitHub.

## Installation

Add the Dolphin MOVE SDK package to your flutter app using:

```sh
flutter pub add movesdk
```

or, by adding it as a dependency to your *pubspec.yaml* file and run:

```bash
flutter pub get
```

{% hint style="warning" %}
Add the following section within the **root build.gradle**.

```
allprojects {
    repositories {
        google()
        mavenCentral()
        maven {
            url "https://dolphin.jfrog.io/artifactory/move-sdk-libs-release"
        }
    }
}
```

{% endhint %}

{% hint style="warning" %}
Also please check if the following values are set within the **app build.gradle**.

```
minSdkVersion 28 or higher
compileSdkVersion 35
targetSdkVersion flutter.targetSdkVersion // automatically set by the Flutter framework to the current recommended target SDK version.
```

```
android {
    compileSdkVersion 35
    // ...
    // ...
    defaultConfig {
        // ...
        // ...
        minSdkVersion 28
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
        // ...
        // ...
    }
    // ...
    // ...
}
```

{% endhint %}

See [Flutter - Using packages](https://docs.flutter.dev/packages-and-plugins/using-packages) for further information regarding package use.

Import the package in your code:

```dart
import 'package:movesdk/movesdk.dart';
```

See the included example ([move-sdk-flutter/example](https://pub.dev/packages/movesdk/example)) project in the package for reference on how to get started.

## iOS

### Initialization

The SDK will be automatically initialized and load its persisted state in the plugin's lifecycle through the`FlutterAppDelegate`.&#x20;

### Setting up Permissions

The MOVE SDK requires several permissions to function.

Make sure required [permissions](/move-platform/sdk/appendix/ios/permission-handling) are added in your iOS Runner.workspace and also the corresponding strings for requesting user permissions are set in the projects *Info.plist*.

![Location updates background mode capability](https://394612935-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXD5xlIFUYU8eK_kkLo%2F-Ma7-Qp0tvRtlszHh2aC%2F-MaWrFoEnyiReo8XoJL3%2Fimage.png?alt=media\&token=171c219f-f0e1-4d9a-9fe8-a0ccb47078a6)

If you are using the [**flutter-permission-handler**](https://github.com/Baseflow/flutter-permission-handler) package refer to [this guide](https://github.com/Baseflow/flutter-permission-handler/blob/main/permission_handler/README.md) (see also [here](https://github.com/Baseflow/flutter-permission-handler/blob/main/permission_handler/example/ios/Podfile)) to add the permissions in your iOS *Podspec* file.

## Android

### Initialization

The SDK needs to be initialized at the start of the app by calling *MoveSdk.init.* It is recommended to put this in the Application's `onCreate` method. This will load the persistent Move SDK state.

```kotlin
import io.dolphin.move.MoveSdk

class MainApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        val sdk = MoveSdk.init(this)
        ...
    }
    
    ...
}
```

### Setting up Permissions

Permission setup is inherited automatically.


# Move SDK CLI

MOVE SDK CLI is a command-line interface (CLI) for the MOVE SDK. It provides various commands to interact with the SDK, such as creating a project, listing projects, logging in and out, and more.

#### Installation

You can install MOVE SDK CLI via npm. Make sure you have Node.js and npm installed on your system before proceeding.

```bash
npm install movesdk-cli
```

#### Usage

Here are some of the commands you can use:

* **clone**: Clones the test projects.
* **login**: Logs in to the MOVE SDK CLI.
* **logout**: Logs out from the MOVE SDK CLI.
* **projects**: Lists the projects.
* **create-project**: Creates a new project.
* **delete-project**: Deletes a project.
* **services**: Lists the services.
* **help**: Opens the MOVE documentation.
* **open-project**: Opens the MOVE dashboard.
* **keys**: List move sdk project keys

For example, to create a new project, you would run:

```bash
movesdk create-project
```

***

This documentation provides an overview of the available commands and their usage. For detailed information on each command and additional examples, please refer to the MOVE SDK documentation.

This is a command-line interface (CLI) for the MOVE SDK. It provides various commands to interact with the SDK, such as creating a project, listing projects, logging in and out, and more.

<br>


# API Interface

On the following pages you can find some more information about initialization and setup of the MOVE SDK and MOVE SDK services for different operating systems.


# Android

API Interface


# Initialization

API Interface / Android

## Init

The Android MOVE SDK must be initialized by adding MoveSdk.init() at the first line in your Android Application class (onCreate). This instance can then be used to control MOVE SDK services.

After the MOVE SDK has been initialized you also want to add notifications, listeners or activate additional features.

Also you have to configure the MOVE SDK before you are able to call .setup(...).

```kotlin
// your application class

override fun onCreate() {
   // init the MOVE SDK
   val moveSdk = MoveSdk.init(this)   
   
   super.onCreate()

   // Example of adding some notifications, register listener
   // and activate MOVE SDK features.
   moveSdk.apply {
     recognitionNotification(recognitionNotification)
     tripNotification(drivingNotification)
     sdkStateListener(sdkStateListener)
     tripStateListener(tripStateListener)
     authStateUpdateListener(authStateListener)
     initializationListener(initListener)
     setServiceErrorListener(errorListener)
     setServiceWarningListener(warningListener)
     initiateAssistanceCall(assistanceListener)
     deviceDiscoveryListener(deviceDiscoveryListener)
     consoleLogging(true)
   }
   
   // ... continue with Config ...
}
```

{% hint style="info" %}
**Note:** `MoveSdk.get()` returns `null` if `MoveSdk.init()` has not been called yet. Always ensure `MoveSdk.init()` is called first in `Application.onCreate()` before accessing the SDK instance.
{% endhint %}

By clicking the links below you can find further information about the usage.

* [recognitionNotification](#dolphinsdk.builderv1.1-recognitionnotificationrecognitionnotifications)
* [tripNotification](#trip-notifications)
* [sdkStateListener](#dolphinsdk.builderv1.1-sdkstatelistenersdkstatelistener)
* [tripStateListener](#trip-state-listener)
* [authStateUpdateListener](#dolphinsdk.builderv1.1-initializationinitializationlistener-1)
* [initializationListener](#dolphinsdk.builderv1.1-initializationinitializationlistener)

Used Services in the example above and [more](/move-platform/sdk/api-interface/android/services):

* [setServiceErrorListener](/move-platform/sdk/api-interface/android/services#set-service-error-listener)
* [setServiceWarningListener](/move-platform/sdk/api-interface/android/services#set-service-warning-listener)
* [initiateAssistanceCall](/move-platform/sdk/api-interface/android/services#initiate-assistance-call)
* [consoleLogging](/move-platform/sdk/api-interface/android/services#console-logging)
* [deviceDiscoveryListener](/move-platform/sdk/api-interface/android/services#set-device-discovery-listener)

## Config <a href="#config" id="config"></a>

Whenever you are ready to start the Move SDK, setup() needs to be called with a proper configuration. The following code sample demonstrates a common configuration with driving, walking, cycling, automatic impact detection and assistance call.

```kotlin
   // ... Init ...
   
   // Example of a configuration of the MOVE SDK
    val moveConfig = MoveConfig(
        moveDetectionServices = listOf(
            MoveDetectionService.Driving(
                drivingServices = listOf(
                    DrivingService.DrivingBehaviour,
                    DrivingService.DistractionFreeDriving,
                    DrivingService.DeviceDiscovery,
                )
            ),
            MoveDetectionService.Walking(),
            MoveDetectionService.Cycling,
            MoveDetectionService.AutomaticImpactDetection,
            MoveDetectionService.AssistanceCall,
        )
    )
   // ... continue with Setup ...
```

## Setup

{% hint style="warning" %}
It is recommended to set up notifications before calling the setup() method.
{% endhint %}

{% hint style="warning" %}
It is recommended that .setup(...) is called **ONLY ONCE!**

If .shutdown() was called before then .setup(...) must be redone.
{% endhint %}

### With MoveAuth

{% hint style="warning" %}
Deprecated in the future. The new approach is by using an authCode. see [Setup with authCode](#with-authcode)
{% endhint %}

The data for the MoveAuth object must be fetched using the given project’s API Key (see [MOVE Backend - Example request](/move-platform/backend/example-requests#create-a-new-user)).

```kotlin
.setup(
    auth: MoveAuth, 
    config: MoveConfig,
    start: Boolean?,
    options: MoveOptions?
)
```

<table data-header-hidden><thead><tr><th width="263.3333333333333">Parameter</th><th width="220"></th><th>Description</th></tr></thead><tbody><tr><td>auth</td><td><a href="/move-platform/sdk/models/moveauth">MoveAuth</a></td><td>The user's Auth object. (see <a href="/move-platform/backend/example-requests#create-a-new-user">MOVE Backend - Create a new user</a>) </td></tr><tr><td>config</td><td><a href="/move-platform/sdk/models/moveconfig">MoveConfig</a></td><td>The move configuration</td></tr><tr><td>start</td><td>Boolean</td><td>optional:<br>Default: <strong>true</strong> ->  <a href="/move-platform/sdk/api-interface/android/services#start-automatic-detection">startAutomaticDetection()</a> is called automatically<br><br><strong>false</strong> -> you have to call <a href="/move-platform/sdk/api-interface/android/services#start-automatic-detection">startAutomaticDetection()</a> manually</td></tr><tr><td>options</td><td><a href="/move-platform/sdk/models/moveoptions">MoveOptions</a></td><td>optional: added with v2.3.+</td></tr></tbody></table>

{% hint style="warning" %}

### SDK Authentication

Passing the authentication config is **required** for each setup. The host app is also responsible for monitoring the [AuthState](/move-platform/sdk/models/moveauthstate) changes.
{% endhint %}

{% hint style="warning" %}
If you want to use startTrip(...) ([**Manual Start Trip**](/move-platform/sdk/api-interface/android/services#manual-start-trip)) you have to pass **false** to the parameter **start**.
{% endhint %}

### With authCode

The authCode must be fetched using the userId (see [MOVE Backend - Example request](/move-platform/backend/example-requests#create-a-new-user)).

```kotlin
.setup(
    authCode: String, 
    config: MoveConfig,
    start: Boolean?,
    options: MoveOptions?,
    callback: MoveAuthCallback
)
```

<table data-header-hidden><thead><tr><th width="263.3333333333333">Parameter</th><th width="220"></th><th>Description</th></tr></thead><tbody><tr><td>authCode</td><td>String</td><td>The authCode received from the backend. (see <a href="/move-platform/backend/example-requests#create-a-new-user">MOVE Backend - Create a new user</a>) </td></tr><tr><td>config</td><td><a href="/move-platform/sdk/models/moveconfig">MoveConfig</a></td><td>The move configuration</td></tr><tr><td>start</td><td>Boolean</td><td>optional:<br>Default: <strong>true</strong> ->  <a href="/move-platform/sdk/api-interface/android/services#start-automatic-detection">startAutomaticDetection()</a> is called automatically<br><br><strong>false</strong> -> you have to call <a href="/move-platform/sdk/api-interface/android/services#start-automatic-detection">startAutomaticDetection()</a> manually</td></tr><tr><td>options</td><td><a href="/move-platform/sdk/models/moveoptions">MoveOptions</a></td><td></td></tr><tr><td>callback</td><td>MoveAuthCallback</td><td>This listener will report the success or failure during the internal MOVE SDK authentication process. (see <a href="/move-platform/sdk/models/moveauthresult">MoveAuthResult</a>)</td></tr></tbody></table>

#### Example of implementing the MoveAuthCallback:

```kotlin
private val moveAuthCallback = object : MoveSdk.MoveAuthCallback {
    override fun onResult(result: MoveAuthResult) {
        when (result.status) {
            AuthSetupStatus.SUCCESS -> {
                // Do something if the result is SUCCESS.
            }
            AuthSetupStatus.INVALID_CODE -> {
                // Do something if the result is INVALID_CODE.
            }
            AuthSetupStatus.NETWORK_ERROR -> {
                // Do something if the result is NETWORK_ERROR.
            }
        }
    }
}
```

## Listeners

### Initialization listener <a href="#dolphinsdk.builderv1.1-initializationinitializationlistener" id="dolphinsdk.builderv1.1-initializationinitializationlistener"></a>

Block that gets invoked on initialization completion with error. On error, [MoveConfigurationError](/move-platform/sdk/models/moveconfigurationerror#android) is returned. On success, the [MoveSdkState](/move-platform/sdk/models/movesdkstate) will change accordingly.

```kotlin
fun initializationListener(callback: InitializeListener)
```

| Parameter |                                                                                         | Description                                                                                                                                                                                 |
| --------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| listener  | [InitializeListener](/move-platform/sdk/models/listeners-callbacks#initialize-listener) | <p>Block that gets invoked on initialization completion with error. On error, </p><p><a href="/move-platform/sdk/models/moveconfigurationerror">MoveConfigurationError</a> is returned.</p> |

### Auth state update listener <a href="#dolphinsdk.builderv1.1-initializationinitializationlistener" id="dolphinsdk.builderv1.1-initializationinitializationlistener"></a>

Provide a block to be invoked every time [MoveAuthState](/move-platform/sdk/models/moveauthstate) changes.

```kotlin
fun authStateUpdateListener(callback: AuthStateUpdateListener)
```

| **Callback**            |                                                                                                         |
| ----------------------- | ------------------------------------------------------------------------------------------------------- |
| AuthStateUpdateListener | Block that gets invoked every time [MoveAuthState](/move-platform/sdk/models/moveauthstate) is updated. |

{% hint style="warning" %}

### Authentication

Check [Authentication updates](/move-platform/sdk/models/moveauthstate#authentication-updates-and-expiry) for more details about authentication expiry and renewal.
{% endhint %}

### MOVE SDK State listener <a href="#dolphinsdk.builderv1.1-sdkstatelistenersdkstatelistener" id="dolphinsdk.builderv1.1-sdkstatelistenersdkstatelistener"></a>

&#x20;Provide a block to be invoked every time[ MoveSdkState](/move-platform/sdk/models/movesdkstate) changes.

{% hint style="warning" %}
The host app is expected to be monitoring [MoveSdkState](/move-platform/sdk/models/movesdkstate) changes so it can start the SDK services when [MoveSdkState](/move-platform/sdk/models/movesdkstate) is`.ready`or handle errors if occurred.
{% endhint %}

```kotlin
fun sdkStateListener(listener: StateListener)
```

| Parameter |                                                                                       | Description                                                                                    |
| --------- | ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| listener  | [StateListener](/move-platform/sdk/models/listeners-callbacks#movesdk-state-listener) | Block gets called whenever the [MoveSdkState](/move-platform/sdk/models/movesdkstate) changes. |

### Trip state listener

```kotlin
fun tripStateListener(listener: TripStateListener)
```

| Parameter |                                                                                        | Description                                                                                                                                                                                                                                                                              |
| --------- | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| listener  | [TripStateListener](/move-platform/sdk/models/listeners-callbacks#trip-state-listener) | A listener where [`onTripStateChanged`](https://docs.movesdk.com/move-platform/sdk/api-interface/android/pages/-MZIfp4AHvpUSOaycA60#DolphinSdk.Builderv1.1-tripstatelistenerTripstatelistener) gets called whenever the [MoveTripState](/move-platform/sdk/models/movetripstate) changes |

### Trip notifications

Passes a notification builder which is used to create a notification reaching places and walking paths. For more information on that please check[ notification management](/move-platform/sdk/appendix/android/notification-management).

```kotlin
fun tripNotification(notification: Notification)
fun tripNotification(notification: NotificationCompat.Builder)
```

| Parameter                  | Description                                                                     |
| -------------------------- | ------------------------------------------------------------------------------- |
| NotificationCompat.Builder | The notification builder to build the notification `package androidx.core.app`. |
| Notification               | A class that represents how a persistent notification `package android.app`.    |

### Recognition notifications <a href="#dolphinsdk.builderv1.1-recognitionnotificationrecognitionnotifications" id="dolphinsdk.builderv1.1-recognitionnotificationrecognitionnotifications"></a>

Passes a notification  builder which is used to create notification while detecting activities, trips and more. For more information on that, please check[ notification management](/move-platform/sdk/appendix/android/notification-management).

```kotlin
fun recognitionNotification(notification: Notification)
fun recognitionNotification(notification: NotificationCompat.Builder)
```

| Parameter                  | Description                                                                     |
| -------------------------- | ------------------------------------------------------------------------------- |
| NotificationCompat.Builder | The notification builder to build the notification `package androidx.core.app`. |
| Notification               | A class that represents how a persistent notification `package android.app`.    |

### Trip Metadata <a href="#dolphinsdk.builderv1.2-metadatametadata" id="dolphinsdk.builderv1.2-metadatametadata"></a>

Host apps can use this API to add any app-level information (for ex. bluetooth beacon detected, foreground/background time, etc) to append to a trip as metadata. This metadata will be forwarded back along with the trip when fetched by the client-server, so the host app can utilize it in its app. Note: The MOVE SDK will not use this metadata element in any way, it is just passed through to the project.

The block provides the trip's start and stop times. Make sure to only include metadata events that are collected inside the given start and end periods.

```kotlin
fun metadataProvider(provider: TripMetadataProvider)
```

| Parameter                                                                        | Description                                                                                                          |
| -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| [provider](/move-platform/sdk/models/listeners-callbacks#trip-metadata-provider) | Callback to provide a bundle of key-value pairs to a trip. The trip is represented with a given start and stop time. |

## Initialization

Tries to initialize the MOVE SDK. You can only have one initialized MOVE SDK at a time. If you have a MOVE SDK instance already, consider calling [`shutdown`](/move-platform/sdk/api-interface/android/services#shutdown-sdk)before.\
The initialization process is asynchronous and the host app is expected to register a [MoveSdkState](/move-platform/sdk/models/movesdkstate) [`listener`](https://docs.movesdk.com/move-platform/sdk/api-interface/android/pages/-MZIfp4AHvpUSOaycA60#DolphinSdk.Builderv1.1-sdkstatelistenerSdkstatelistener) to monitor successful initialization and start services when [MoveSdkState](/move-platform/sdk/models/movesdkstate) transits to`READY` . The host app should also monitor [`initialization listener`](https://docs.movesdk.com/move-platform/sdk/api-interface/android/pages/-MZIfp4AHvpUSOaycA60#DolphinSdk.Builderv1.1-initializationInitializationlistener) to handle potential [MoveConfigurationError](/move-platform/sdk/models/moveconfigurationerror).

{% hint style="warning" %}

### Application Context

Make sure to pass the application context
{% endhint %}

| Parameter   | Description                                                                                                                                                   |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| context     | Main application context.                                                                                                                                     |
| initOptions | **optional**: Configuration applied when the SDK is initialized, before setup() is called. (see [MoveInitOptions](/move-platform/sdk/models/moveinitoptions)) |

```kotlin
fun init(
    context: Context,
    initOptions: MoveInitOptions? = null,
): MoveSdk
```

| **Return** |                             |
| ---------- | --------------------------- |
| MoveSdk    | The instance of the MoveSdk |

{% hint style="info" %}
If you have already successfull initialized the MOVE SDK once, try to initialize the MOVE SDK next time in your application in [onCreate](https://developer.android.com/reference/android/app/Application#onCreate\(\)). This ensures that the MOVE SDK can do its work whenever the application is restarted after termination.
{% endhint %}


# Services

API Interface / Android

## **Configuration services**

### Update Config <a href="#update-authentication" id="update-authentication"></a>

Change the config originally passed in setup.

```kotlin
fun updateConfig(config: MoveConfig, options: MoveOptions? = null)
```

{% hint style="info" %}
**Note:** Calling `updateConfig()` will stop and restart the affected services that changed in the new configuration.
{% endhint %}

| **Parameters** |                                                      |                                                  |
| -------------- | ---------------------------------------------------- | ------------------------------------------------ |
| config         | [MoveConfig](/move-platform/sdk/models/moveconfig)   | Move services configuration.                     |
| options        | [MoveOptions](/move-platform/sdk/models/moveoptions) | Optional MoveOptions if they need to be changed. |

Occasionally this functionality is needed for deployed apps when a projects configuration is updated on the backend.

### Update authentication <a href="#update-authentication" id="update-authentication"></a>

{% hint style="warning" %}
**Deprecated:** Token expiry is no longer a valid auth state forwarded to the app and does not need to be handled.
{% endhint %}

Updates MOVE SDK [MoveAuth](/move-platform/sdk/models/moveauth#android). The host app was expected to fetch a new [MoveAuth](/move-platform/sdk/models/moveauth) using its project API key and pass it to the MoveSDK using the following API:

```kotlin
@Deprecated("Do not use manual token update, this will be handled internally by the Move SDK")
fun updateAuth(auth: MoveSdk.Auth, onError: (MoveAuthError) -> Unit)
```

### Get MOVE SDK Config

{% hint style="info" %}
Since MOVE SDK v2.16
{% endhint %}

Returns the active [MoveConfig](/move-platform/sdk/models/moveconfig#android) based on the current configuration source.

If `useBackendConfig` is enabled, the MOVE Dashboard configuration is returned. Otherwise, the local client configuration is returned.

```kotlin
fun getMoveConfig(): MoveConfig
```

### Get MOVE auth state

Returns the current [MoveAuthState](/move-platform/sdk/models/moveauthstate#android).

**Precondition**: Returns `UNKNOWN` if SDK is in `Uninitialised` state.

```kotlin
suspend fun getAuthState(): MoveAuthState
```

### **Set Remote Config Change Listener**&#x20;

{% hint style="info" %}
Since MOVE SDK v2.5
{% endhint %}

Provides a block to be invoked every time [MoveConfig](/move-platform/sdk/models/moveconfig) was successfully fetched from the server.

If the MoveConfig object couldn't be fetched from the server then a [MoveConfigurationError](/move-platform/sdk/models/moveconfigurationerror) ServiceUnreachable will be triggered.

{% hint style="warning" %}
This listener is only triggered if `useBackendConfig` is enabled.
{% endhint %}

```kotlin
fun setRemoteConfigChangeListener(listener: RemoteConfigChangeListener)
```

| **Parameters** |                                                                                                                   |
| -------------- | ----------------------------------------------------------------------------------------------------------------- |
| listener       | A callback returning a [MoveConfig](/move-platform/sdk/models/moveconfig) object after a successful server fetch. |

## Detection Services

### Start Automatic Detection

Starts the required detection services stated in the [MoveConfig](/move-platform/sdk/models/moveconfig) passed on initialization. Starting the service will set the [MoveSdkState](/move-platform/sdk/models/movesdkstate) to `Running`.

{% hint style="warning" %}
**Precondition**: MOVE SDK must be in`READY`[MoveSdkState](/move-platform/sdk/models/movesdkstate).
{% endhint %}

```kotlin
fun startAutomaticDetection()
```

### **Stop Automatic Detection**

Stops the automatic detection service, including all MOVE SDK services like driving detection, points of interest, walking and places. Stopping the service will set the [MoveSdkState](/move-platform/sdk/models/movesdkstate) back to `Ready`.&#x20;

{% hint style="warning" %}
**Precondition**: MOVE SDK must be in`Running`[MoveSdkState](/move-platform/sdk/models/movesdkstate).
{% endhint %}

```kotlin
fun stopAutomaticDetection()
```

## Trip Services

### **Force Trip Recognition**

Temporarily calibrates the MOVE SDK to the highest detection mode.

In order to optimize battery consumption, the MOVE SDK goes through different detection modes with different battery consumption levels, depending on the user's current behavior and activity. In general, the MOVE SDK is responsible for alternating between those different detection modes.&#x20;

The MOVE SDK also provides hosting apps this API to call if they have their own reasons (like buttons, sensors or beacons) to believe that the user is starting a trip. This will make sure the MOVE SDK is on the highest detection state to detect the trip faster.

{% hint style="warning" %}
&#x20;**Precondition**: SDK must be in`RUNNING` [MoveSdkState](/move-platform/sdk/models/movesdkstate).
{% endhint %}

```kotlin
fun forceTripRecognition()
```

```kotlin
fun forceTripRecognition(duration: Long)
```

| **Parameters** | **Type** |                                                                                                                                    |
| -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| duration       | Long     | Limit the high power detection to a certain amount of time in milliseconds, to not drain the battery. Default 60000ms (= 1 minute) |

### **Manual Start Trip**

Manually force the start of a trip, bypassing trip validation checks. This non-standard SDK usage may be feasible only in situations where active user input can be expected. Using the metadata parameter, self-defined information can be added to each trip which can be fetched from the [timeline](/move-platform/backend/move-backend/move-timeline-api#trip-metadata).

```kotlin
fun startTrip(metadata: Map<String, String>?)
```

{% hint style="danger" %}
Be sure that you set the **`start`** flag  to **`false`** during the MOVE SDK setup.

e.g.:\
\
`setup(`\
&#x20;      `authCode = authCode,`\
&#x20;      `config = moveConfig,`\
&#x20;     **`start = false,`**\
&#x20;      `callback = authCallback`\
`)`
{% endhint %}

{% hint style="warning" %}
**Precondition**: MOVE SDK must be in`.ready`[MoveSdkState](/move-platform/sdk/models/movesdkstate).

Manually starting a trip bypasses additional trip detection checks. It is strongly recommended to finish manually started trips with `finishCurrentTrip()`
{% endhint %}

{% hint style="warning" %}
Starting a trip with *startTrip(...)* prevents the execution of *startAutomaticDetection()*.
{% endhint %}

### **Finish Current Trip**

Ends the current ongoing trip.

This API will end the ongoing trip and set [MoveTripState](/move-platform/sdk/models/movetripstate) back to `.idle`. The MOVE SDK is responsible for detecting the trip start and end points. The MOVE SDK also provides hosting apps this API to call if they have their own reasons (like sensors or beacons) to believe that the user's trip has ended.

{% hint style="warning" %}
**Precondition**:[ MoveTripState](/move-platform/sdk/models/movetripstate) should be in an active trip.
{% endhint %}

```kotlin
fun finishCurrentTrip()
```

{% hint style="info" %}
If this API is called while the user is active on a driving trip, a new trip will start again right away. If the intention is to un-track the ongoing trip, call `ignoreCurrentTrip`API.

More information about trip states can be found in [MoveTripState](/move-platform/sdk/models/movetripstate).
{% endhint %}

{% hint style="info" %}
If the trip was started with [`startTrip(metadata:)`](#manual-start-trip)`finishCurrentTrip()` brings the SDK back to `.ready` state.
{% endhint %}

### **Ignore Current Trip**

Ignores the current ongoing trip.&#x20;

This API will set the ongoing [MoveTripState](/move-platform/sdk/models/movetripstate) to `.ignored`. Data of ignored trips is purged and not sent to the server.

{% hint style="warning" %}
**Precondition**: [MoveTripState](/move-platform/sdk/models/movetripstate) should be in an active trip.
{% endhint %}

```kotlin
fun ignoreCurrentTrip()
```

### **Set Trip Start Listener**&#x20;

Provides a block to be invoked when a trip actually begins.

In comparison to the tripStateListener (only state changes) the tripStartListener will provide you with the start time of the actual trip.

```kotlin
fun setTripStartListener(listener: TripStartListener)
```

## Processing Services

### **Keep in foreground**

When an Android application is in the background it may receive limited data (location, sensors, etc.). To improve this behavior, it is possible to put the application always in the foreground with a visible notification that cannot be discarded. Just because it's visible it doesn't mean that it is performing any data collection at all. So this should not have any significant battery impact at all.

{% hint style="info" %}
Disabled by default.
{% endhint %}

{% hint style="warning" %}
Since it may be annoying to the user, it should only be enabled in case of problems.
{% endhint %}

```kotlin
fun keepInForeground(enabled: Boolean)
```

### **Keep active**

To save battery consumption, the MOVE SDK is using several triggers to start its data listeners. In case of trouble, these triggers can be circumvented by allowing the MOVE SDK to stay active all the time. In that case the MOVE SDK is always monitoring required data and is therefore consuming more battery. Depending on the configuration, it may happen that the notification (see[ notification handling](/move-platform/sdk/appendix/android/notification-management)) is always visible to the user.

{% hint style="info" %}
Disabled by default.
{% endhint %}

{% hint style="warning" %}
Since this is consuming more battery, it should only be enabled in case of problems.
{% endhint %}

```kotlin
fun keepActive(enabled: Boolean)
```

### **Console logging**

Toggles whether the MOVE SDK is allowed to log into the console or not.&#x20;

{% hint style="info" %}
Enabled by default.
{% endhint %}

```kotlin
fun consoleLogging(enabled: Boolean)
```

| **Parameters** |                                                               |
| -------------- | ------------------------------------------------------------- |
| enabled        | Boolean that sets MOVE SDK console logging to enabled or not. |

### Mock locations <a href="#dolphinsdk.builderv1.1-allowmockmocklocations" id="dolphinsdk.builderv1.1-allowmockmocklocations"></a>

In Android it is possible to use simulated location by enabling it in the device developer mode.\
If you want the MOVE SDK to support those locations, you need to specify it. By default this is disabled to prevent wrong data.&#x20;

{% hint style="warning" %}
Points of Interests are not supported with mock locations.\
Keep in mind that mock locations may have negative impact on trip recognition afterwards.
{% endhint %}

{% hint style="info" %}
Rooted devices are still able to send mock locations without allowing mock locations.
{% endhint %}

```kotlin
fun allowMockLocations(allow: Boolean)
```

| **Parameters** |                                                                              |
| -------------- | ---------------------------------------------------------------------------- |
| allow          | Allows driving with mock locations. Should only be used in debug/test builds |

### **Get MOVE SDK State**

Gets the current[ MoveSdkState](/move-platform/sdk/models/movesdkstate).

```kotlin
suspend fun getSdkState(): MoveSdkState
```

| **Return**                                             |                                                                |
| ------------------------------------------------------ | -------------------------------------------------------------- |
| [MoveSdkState](/move-platform/sdk/models/movesdkstate) | Latest [MoveSdkState](/move-platform/sdk/models/movesdkstate). |

### **Get Trip State**

Gets the current [MoveTripState](/move-platform/sdk/models/movetripstate).

```kotlin
fun getTripState(): MoveTripState
```

| **Return**                                               |                                                                  |
| -------------------------------------------------------- | ---------------------------------------------------------------- |
| [MoveTripState](/move-platform/sdk/models/movetripstate) | Latest [MoveTripState](/move-platform/sdk/models/movetripstate). |

### Get Device Status

Gets the current [MoveDeviceStatus](/move-platform/sdk/models/movedevicestatus)*.*

```kotlin
fun getDeviceStatus(): MoveDeviceStatus
```

| **Return**                                                     |                                                                         |
| -------------------------------------------------------------- | ----------------------------------------------------------------------- |
| [MoveDeviceStatus](/move-platform/sdk/models/movedevicestatus) | Latest  [MoveDeviceStatus](/move-platform/sdk/models/movedevicestatus). |

### Get Service Failures

Gets the current [MoveServiceFailures](/move-platform/sdk/models/moveservicefailure#android).

```kotlin
suspend fun getServiceErrors(): List<MoveServiceFailure>
```

| **Return**                                                                         |                            |
| ---------------------------------------------------------------------------------- | -------------------------- |
| List of [MoveServiceFailure](/move-platform/sdk/models/moveservicefailure#android) | A list of failed services. |

### Set Service Error Listener

```kotlin
fun setServiceErrorListener(listener: MoveErrorListener)
```

Provide a block to be invoked every time [MoveServiceFailures ](/move-platform/sdk/models/moveservicefailure#android)will change.

| **Parameters**                                                                              |                                                             |
| ------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| [MoveErrorListener](/move-platform/sdk/models/listeners-callbacks#service-failure-callback) | Block that gets invoked when service failure state changes. |

### Get Service Warnings

Gets the current [MoveServiceWarnings](/move-platform/sdk/models/moveservicefailure).

```kotlin
fun getServiceWarnings(): List<MoveServiceWarning>
```

| **Return**                                                                          |                                       |
| ----------------------------------------------------------------------------------- | ------------------------------------- |
| List of [MoveServiceWarnings](/move-platform/sdk/models/moveservicewarning#android) | A list of partially working services. |

### Set Service Warning Listener

Provide a block to be invoked every time [MoveServiceWarnings ](/move-platform/sdk/models/moveservicewarning#android)will change.

```kotlin
fun setServiceWarningListener(listener: MoveWarningListener)
```

<table data-header-hidden><thead><tr><th width="256">Listener</th><th></th></tr></thead><tbody><tr><td><strong>Listener</strong></td><td></td></tr><tr><td><a href="/move-platform/sdk/models/listeners-callbacks#service-warning-callback">MoveWarningListener</a></td><td>Block that gets invoked when service warnings change.</td></tr></tbody></table>

### **Set Log Listener**

Provide a block to be invoked every time a new SDK log event occurs.

```kotlin
fun setLogListener(listener: MoveLogCallback)
```

### **Shutdown SDK**

Shutdown SDK shared instance.

Stops SDK services, send the queued user data, and de-initializes the MOVE SDK. After .shutdown() is executed, the [MoveSdkState](/move-platform/sdk/models/movesdkstate) will transit to `Uninitialised`.

{% hint style="warning" %}
**Precondition:** MOVE SDK must be initialized.
{% endhint %}

```kotlin
fun shutdown(
        force: Boolean = true,
        timeoutSeconds: Int = 0,
        callback: ((MoveShutdownResult) -> Unit)? = null,
)
```

<table data-header-hidden><thead><tr><th width="192.33333333333331"></th><th width="148"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td><strong>Default</strong></td><td></td></tr><tr><td>force</td><td>true</td><td>If true, <em>shutdown</em> executes immediately. Pending Data may be lost.</td></tr><tr><td>timeoutSeconds</td><td>null</td><td>If timeoutSeconds > 0, a graceful shutdown is performed regardless of force: the callback resolves immediately with SUCCESS, and the SDK keeps retrying to send pending data in the background until the queue is empty or the timeout expires, after which it shuts down and discards remaining data.</td></tr><tr><td>callback</td><td>null</td><td>Returns a <a href="/move-platform/sdk/models/moveshutdownresult#android">MoveShutdownResult</a> upon completion. May fail if not forced.</td></tr></tbody></table>

### Set Health Score Listener

Provide a block to be invoked every time MoveHealthScore[ ](/move-platform/sdk/models/moveservicewarning#android)will change.

```kotlin
fun setMoveHealthScoreListener(listener: MoveHealthScoreListener?)
```

<table data-header-hidden><thead><tr><th width="260.3333333333333"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td></td></tr><tr><td><a href="/move-platform/sdk/models/listeners-callbacks#sdk-health-listener">MoveHealthScoreListener</a></td><td>Block that get's invoked when the health score changes.</td></tr></tbody></table>

### Geocoding

Geo-coordinate address lookup.

```kotlin
fun geocode(latitude: Double, longitude: Double, result: (GeocodeResult) -> Unit)
```

<table data-header-hidden><thead><tr><th width="177"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td></td></tr><tr><td>latitude</td><td>Geo-coordinate latitude</td></tr><tr><td>longitude</td><td>Geo-coordinate longitude</td></tr><tr><td>completion</td><td>Callback that returns a <em>Result</em> with an address S<em>tring</em> or a <a href="/move-platform/sdk/models/movegeocodeerror#android">MoveGeocodeError</a></td></tr></tbody></table>

Geocode will try a *reverseGeocodeLocation* or fallback to contacting the MOVE backend to attempt a geo-lookup.

{% hint style="warning" %}
**Throttle:** Geocode requests are rate-limited. If the limit is exceeded, `MoveGeocodeError.thresholdReached` is returned.
{% endhint %}

### **Delete Local Data**

Deletes all the collected user MOVE SDK data stored on the device. This doesn't affect the [MoveSDKState](/move-platform/sdk/models/movesdkstate).

{% hint style="warning" %}
**Precondition:** [MoveSDKState](/move-platform/sdk/models/movesdkstate) should be initialized.
{% endhint %}

```kotlin
fun deleteLocalData()
```

{% hint style="info" %}
**Note:** Deletes all runtime properties and databases from all registered modules. Data that has not yet been synced to the backend will be lost.
{% endhint %}

### **Synchronize User Data**

Used to force synchronizing user data with the MOVE backend. Limited to once per 2 minutes.

```kotlin
fun synchronizeUserData(result: ((Boolean) -> Unit)?)
```

The result Returns FALSE in case there are Timeline-relevant packages in the queue that remain to be sent to the MOVE backend; and it returns TRUE in case the queue is empty.

<table data-header-hidden><thead><tr><th width="247"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td></td></tr><tr><td>result</td><td>Optional callback. Returns <code>true</code> if the queue is empty and all data has been sent to the backend. Returns <code>false</code> if there are still pending items in the queue.</td></tr></tbody></table>

## Other services

### Live Location TAG

{% hint style="info" %}
Deprecated in MOVE SDK 2.17.0
{% endhint %}

{% hint style="info" %}
New feature since MOVE SDK 2.8.0
{% endhint %}

Adds a Tag (=string value) to trip events. This Tag information is added to the timeline data.

To clear the Tag pass `null` as parameter.

After a `shutdown(...)` ([Android](/move-platform/sdk/api-interface/android/services#shutdown-sdk) / [iOS](#shutdown-sdk)) the Tag is also cleared.

```kotlin
@Deprecated("Please get in touch with the MOVE SDK team if you want to use this method.")
fun setLiveLocationTag(tag: String?): Boolean
```

<table data-header-hidden><thead><tr><th width="158"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td></td></tr><tr><td>tag</td><td>String <code>[a-z] [0-9]</code> and <code>null</code> to clear the Tag.</td></tr></tbody></table>

<table data-header-hidden><thead><tr><th width="160"></th><th></th></tr></thead><tbody><tr><td><strong>Return values</strong></td><td></td></tr><tr><td>true</td><td>Live Location Tag is applied.</td></tr><tr><td>true</td><td>Live Location Tag is cleared. (parameter <code>null</code>)</td></tr><tr><td>false</td><td>Live Location Tag exceeds the limit of 200 characters.</td></tr><tr><td>false</td><td>Live Location Tag is blank or empty.</td></tr><tr><td>false</td><td>If the passed chars are not one of these [a-z] [0-9].</td></tr></tbody></table>

### Initiate Assistance Call

{% hint style="info" %}
New feature in MOVE SDK 2.x; configuration in MOVE dashboard pending - please [get in touch](mailto:info@dolph.in?subject=MOVE%20SDK).
{% endhint %}

Initiate an assistance call to emergency services.

{% hint style="warning" %}
**Precondition:** The assistance call service needs to be configured. The MOVE SDK needs to be in *ready* or *running* state.
{% endhint %}

```kotlin
fun initiateAssistanceCall(assistanceListener: AssistanceStateListener)
```

| **Parameters**     |                                                                                                                |
| ------------------ | -------------------------------------------------------------------------------------------------------------- |
| assistanceListener | A callback returning a [MoveAssistanceCallStatus](/move-platform/sdk/models/moveassistancecallstatus#android). |

### Set Assistance MetaData

{% hint style="info" %}
New feature since MOVE SDK 2.1.
{% endhint %}

```kotlin
fun setAssistanceMetaData(assistanceMetadataValue: String?)
```

{% hint style="info" %}
**Before** SDK 2.4 Android returns null.
{% endhint %}

Get a unique qualifier to identify the individual device.

<table data-header-hidden><thead><tr><th width="283"></th><th width="174"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td></td><td></td></tr><tr><td>assistanceMetadataValue</td><td>String</td><td>A string to be sent with each assistance call or impact.</td></tr></tbody></table>

The metadata string is set once, and then sent to the server with each and every manual assistance call and with AID report. The contents of the string can be anything, e.g. JSON data. The assistance data is persisted once set.

### Get Device Qualifier

Returns the Android ID (`Settings.Secure.ANDROID_ID`) — a unique 64-bit hex string per app and device (app-scoped since Android 8.0).&#x20;

```kotlin
fun getDeviceQualifier(): String?
```

The device qualifier should be passed to the backend during user registration. See [Move backend](/move-platform/backend/move-backend/move-admin-api#gettingstartedwiththedolphinmovetimelineservice-authentication).

### Resolve Error

Forces a permission recheck. This is handled internally by the SDK. Manual calls are not required.

```kotlin
fun resolveError()
```

## Device Discovery

{% hint style="danger" %}
Due to limitations in Android’s Classic Bluetooth APIs, reliable connection status tracking may not always be possible. For more details and available workarounds, see [Forcing the Signal - Classic Bluetooth](/move-platform/sdk/appendix/android/forcing-the-signal-classic-bluetooth).
{% endhint %}

Device discovery for Bluetooth devices. Multiple devices can be registered.

The configuration of the scanning will be done with the object `DeviceDiscovery` in MoveOptions during MOVE SDK setup. From the start of a trip registered devices are scanned after a `startDelay` and are scanned for `duration`. This scan will repeat after an `interval`.

To scan for Bluetooth devices only once then the flag `stopScanOnFirstDiscovered` should be set.

Device scanning results are appended to the trip [metadata](https://docs.movesdk.com/move-platform/sdk/api-interface/android/pages/-MZIfp4AHvpUSOaycA60#dolphinsdk.builderv1.2-metadatametadata-1).

Registering/unregistering devices during a trip may result in undefined behavior.

{% hint style="warning" %}
Before the DeviceDiscovery configuration can be changed, a [shutdown](#shutdown-sdk) with a following [setup](/move-platform/sdk/api-interface/android/initialization#setup) must be executed.
{% endhint %}

### Set Device Discovery Listener

Set a device discovery listener to be fired when registered [MoveDevice](/move-platform/sdk/models/movedevice#android)'s are scanned.

{% hint style="warning" %}
If [stopScanOnFirstDiscovered](/move-platform/sdk/models/moveoptions/devicediscovery#android) of the [DeviceDiscovery](/move-platform/sdk/models/moveoptions/devicediscovery) object is set to true then the list of MoveScanResults may be incomplete.
{% endhint %}

```kotlin
fun deviceDiscoveryListener(listener: DeviceDiscoveryListener)
```

| **Parameters**                                                                                                 |                                                                                    |
| -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| listener -> [DeviceDiscoveryListener](/move-platform/sdk/models/listeners-callbacks#device-discovery-listener) | A callback returning a [MoveScanResult](/move-platform/sdk/models/movescanresult). |

### Set MoveDevice Connection State Listener

{% hint style="info" %}
Since MOVE SDK v2.10.0
{% endhint %}

Set a [MoveDevice](/move-platform/sdk/models/movedevice) connection state listener to be fired when the Bluetooth connection state of a previously registered [MoveDevice](/move-platform/sdk/models/movedevice#android) has changed.

```kotlin
fun setDeviceStateListener(listener: MoveDeviceStateListener?)
```

| **Parameters**                                                                                                        |                                                                                                                 |
| --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| listener -> [MoveDeviceStateListener](/move-platform/sdk/models/listeners-callbacks#movedevice-state-change-listener) | A callback returning the [MoveDevice](/move-platform/sdk/models/movedevice) which connection state was changed. |

### Register Device

{% hint style="warning" %}
Please note that MoveDevices can only be registered if the SDK has been configured with .setup()
{% endhint %}

Register [MoveDevice](/move-platform/sdk/models/movedevice#android)'s / add more [MoveDevice](/move-platform/sdk/models/movedevice#android)'s:

```kotlin
suspend fun registerDevices(devices: List<MoveDevice>): Boolean
```

<table data-header-hidden><thead><tr><th width="239.90234375"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td></td></tr><tr><td>devices</td><td>A list of <a href="/move-platform/sdk/models/movedevice#android">MoveDevice</a>'s to be scanned during a trip.</td></tr></tbody></table>

### Unregister Device

Unregister a [MoveDevice](/move-platform/sdk/models/movedevice#android):

```kotlin
suspend fun unregisterDevices(devices: List<MoveDevice>): Boolean
```

<table data-header-hidden><thead><tr><th width="240.12890625"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td></td></tr><tr><td>devices</td><td>A list of <a href="/move-platform/sdk/models/movedevice#android">MoveDevice</a>'s that should no longer be scanned during a trip.</td></tr><tr><td><strong>Return</strong></td><td></td></tr><tr><td>Boolean</td><td><p>true: </p><ul><li>If the unregistration of the MoveDevice on the backend was successful.</li></ul><p>false:</p><ul><li>If the MOVE SDK is not initialised.</li><li>If there is an error during the MoveDevice unregistration process. See <a href="/move-platform/sdk/models/listeners-callbacks#movedevice-state-listener-callback">MoveDeviceStateListener</a></li></ul></td></tr><tr><td><strong>Throws</strong></td><td></td></tr><tr><td>IllegalArgumentException</td><td><ul><li>If the beacon device Id is not a valid UUID.</li><li>If the length of device display name is longer than 1000 characters.</li></ul></td></tr></tbody></table>

### Get Registered Devices

Get current registered [MoveDevice](/move-platform/sdk/models/movedevice#android)'s.

```kotlin
suspend fun getRegisteredDevices(): List<MoveDevice>
```

Alternative it is possible to subscribe to registered devices changes.

```kotlin
fun getRegisteredDevicesFlow(): Flow<List<MoveDevice>>
```

### Additional device discovery methods

```kotlin
fun convertToMoveDevice(scanResult: ScanResult): MoveDevice
```

Converts [android.bluetooth.le.ScanResult](https://developer.android.com/reference/kotlin/android/bluetooth/le/ScanResult#) into a MOVE SDK specific [MoveDevice](/move-platform/sdk/models/movedevice).

```kotlin
fun convertToMoveDevice(bluetoothDevice: BluetoothDevice): MoveDevice
```

Converts [android.bluetooth.BluetoothDevice](https://developer.android.com/reference/android/bluetooth/BluetoothDevice) into a MOVE SDK specific [MoveDevice](/move-platform/sdk/models/movedevice).

## Step Counter (via Google Health Connect)

{% hint style="info" %}
Since MOVE SDK v2.14
{% endhint %}

Only available if this feature is enabled in the backend ([MOVE SDK Dashboard](https://dashboard.movesdk.com/admin/sdkConfig)) and the user grants the permission `android.permission.health.READ_STEPS` . To collect steps even the app is in background, the permission`android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND`  is required.

For more information regarding Health Connect please see [Android - Health Connect](https://developer.android.com/health-and-fitness/guides/health-connect/develop/get-started).

{% hint style="warning" %}
Please note that Health Connect requires an additional fitness app. These apps must be synced with Health Connect. Check the manual of the fitness app to see how to connect it to Health Connect.
{% endhint %}

Add the following permissions to your AndroidManifest.xml file :

```xml
<!--Permissions for the step counter feature (Health)-->
<uses-permission android:name="android.permission.health.READ_STEPS"/>
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND" />
```

Also you need to intent filter for  Health Connect permission handling:

```xml
<!--To use Health feature your app must handle health permissions-->
<intent-filter>
    <action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE"/>
    <category android:name="android.intent.category.HEALTH_PERMISSIONS"/>
</intent-filter>
<intent-filter>
    <action android:name="android.intent.action.VIEW_PERMISSION_USAGE" />
    <category android:name="android.intent.category.HEALTH_PERMISSIONS" />
</intent-filter>
```

See also [MoveServiceFailure](/move-platform/sdk/models/moveservicefailure) for permissions and Health Connect related errors.


# iOS

API Interface


# Initialization

API Interface / iOS

## Definition

Initialize the SDK `shared` instance and prepare the required services based on the passed [MoveConfig](/move-platform/sdk/models/moveconfig). SDK must be successfully initialized **once** before any of the SDK Services can be used. Call this API on the `shared` instance to initialize the SDK:

{% tabs %}
{% tab title="Swift 5" %}

```swift
func initialize(launchOptions: [UIApplication.LaunchOptionsKey: Any]?, options: MoveInitOptions? = nil)
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
@MainActor func initialize(options: MoveInitOptions? = nil) async
```

{% endtab %}
{% endtabs %}

| **Parameters** |                                                                                                              |                                                                                                                                                         |
| -------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| launchOptions  | \[[LaunchOptionsKey ](https://developer.apple.com/documentation/uikit/uiapplication/launchoptionskey): Any]? | The launch options passed in[`willFinishLaunchWithOptions`](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623032-application). |
| options        | [MoveInitOptions](/move-platform/sdk/models/moveinitoptions#ios)                                             | Options passed, see struct details.                                                                                                                     |

{% hint style="warning" %}
The[`initialization`](/move-platform/sdk/api-interface/ios/intialization)API must be executed before[`willFinishLaunchingWithOptions`](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623032-application)returns. We recommend calling it in [`didFinishLaunchingWithOptions`](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622921-application).
{% endhint %}

## Health Service

In order to use HealthKit synchronization to collect data, such as steps you need to enable this functionality before initialization

```swift
MoveSDK.shared.enable(healthKit: MoveSDKHealth.shared)
MoveSDK.shared.initialize(...)
```

## Timing

#### Why should the initialization be called before [`willFinishLaunchingWithOptions`](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623032-application) returns?

Once the MOVE SDK has been successfully initialized and started for the first time, the SDK will then set up its timers, tasks, and system triggers to be able to automatically wake up in the background and start its services, even if the app has been killed by the user.

When the app wakes up in the background because of the SDK triggers and tasks, the SDK must be already initialized and started before receiving those events in order to be to handle them.

Initializing the MOVE SDK before[`willFinishLaunchingWithOptions`](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623032-application)returns will guarantee that all the required SDK components are initialized and ready to handle the triggered system events.

{% hint style="info" %}
An exception is when it is the first time the SDK is initialized, as the host app might need to delay this step till the user is onboarded and system permission has been granted.
{% endhint %}

## Background-Fetch (recommended)

**How can you make sure that the app synchronises with the MOVE backend even if you have patches of offline operation ?**

For security reasons we cannot schedule background data upload tasks to upload data to the MOVE backend. Hence, the application must be running (at least) in the background. In order to guarantee that data is sent in a timely manner, we recommend setting up a BackgroundFetch-functionality in the app delegate of your host application.

Additionally: the background fetch is essential in case you only configure WALKING in your MOVE project. In this case, the background fetch is the only mechanism to wake up your app in the background and record WALKING data in the first place.

#### iOS 12 and below

For background fetches to work in iOS12 and below you need to implement the background fetch callback of the app delegate:

```swift
func application(_: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
   MoveSDK.shared.performBackgroundFetch(completionHandler)
}
```

and set the minimum background fetch interval for example in the app delegate's *didFinishLaunchingWithOptions()* with an interval of e.g. 4 hours:

```swift
application.setMinimumBackgroundFetchInterval(backgroundRefreshInterval)
```

#### iOS 13 and up

Follow the guide at the [Apple developer documentation.](https://developer.apple.com/documentation/uikit/app_and_environment/scenes/preparing_your_ui_to_run_in_the_background/using_background_tasks_to_update_your_app) The upload will start automatically as soon as the SDK switches into RUNNING state (SDK 1.6) respectively after initializing the SDK (SDK 2.x and higher).


# Setup

Before services can be started a user object must be setup to use the SDK and a services configuration must be provided (see [iOS Quick Start](/move-platform/sdk/getting-started/ios/quick-start)).

### Setup Auth/Config

Authenticates a user to be used with the SDK.

{% tabs %}
{% tab title="Swift 5" %}

```swift
func setup(authCode: String, config: MoveConfig, options: MoveOptions, callback: @escaping MoveAuthCallback)
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func setup(authCode: String, config: MoveConfig, options: MoveOptions) async -> MoveAuthResult
```

{% endtab %}
{% endtabs %}

| **Parameters** |                                                                          |                                 |
| -------------- | ------------------------------------------------------------------------ | ------------------------------- |
| authCode       | String                                                                   | Auth code.                      |
| config         | [MoveConfig](/move-platform/sdk/models/moveconfig#ios)                   | Move services configuration.    |
| options        | [MoveOptions](/move-platform/sdk/models/moveoptions#ios)                 | Move SDK service options dict.  |
| callback       | [MoveAuthCallback](/move-platform/sdk/models/listeners-callbacks#ios-12) | Called after setup with result. |

Setup with auth tokens:

```swift
func setup(auth: MoveAuth, config: MoveConfig, options: MoveOptions)
```

| **Parameters** |                                                          |                                |
| -------------- | -------------------------------------------------------- | ------------------------------ |
| auth           | [MoveAuth](/move-platform/sdk/models/moveauth#ios)       | User account object.           |
| config         | [MoveConfig](/move-platform/sdk/models/moveconfig#ios)   | Move services configuration.   |
| options        | [MoveOptions](/move-platform/sdk/models/moveoptions#ios) | Move SDK service options dict. |

{% hint style="warning" %}
Deprecated, use [setup(authCode: ...)](#setup-auth-config) instead
{% endhint %}

### Update Config

Change the config originally passed in setup.

```swift
func update(config: MoveConfig, options: MoveOptions? = nil)
```

| Parameters |                                                          |                                |
| ---------- | -------------------------------------------------------- | ------------------------------ |
| config     | [MoveConfig](/move-platform/sdk/models/moveconfig#ios)   | Move services configuration.   |
| options    | [MoveOptions](/move-platform/sdk/models/moveoptions#ios) | Move SDK service options dict. |

Occasionally this functionality is needed for deployed apps when a projects configuration is updated on the backend.

{% hint style="warning" %}
**Precondition:** SDK user/config should be setup.
{% endhint %}

### Update authentication

Updates SDK [MoveAuth](/move-platform/sdk/models/moveauth). The host app was expected to fetch a new [MoveAuth](/move-platform/sdk/models/moveauth) using its project API key and pass it to the MoveSDK using the following API:

```swift
func update(auth: MoveAuth, completion: ((MoveAuthError?) -> Void)? = nil)
```

{% hint style="danger" %}
**Deprecated:** Token expiry is no longer a valid auth state forwarded to the app and does not need to be handled.
{% endhint %}

### **Get SDK Auth State**

Gets the current [MoveAuthState](/move-platform/sdk/models/moveauthstate).

```swift
func getAuthState() -> MoveAuthState
```

| **Return**                                               |                  |
| -------------------------------------------------------- | ---------------- |
| [MoveAuthState](/move-platform/sdk/models/moveauthstate) | Latest SDK State |

### **Set SDK Auth State Listener**

Provide a block to be invoked every time [MoveAuthState](/move-platform/sdk/models/moveauthstate) changes.

{% tabs %}
{% tab title="Swift 5" %}

```swift
func setAuthStateUpdateListener(_ listener: @@escaping AuthStateCallback)
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func setAuthStateUpdateListener(_ listener: @escaping AsyncMoveAuthStateCallback)
```

{% endtab %}
{% endtabs %}

| **Callback**                                                                                  |                                                                                                         |
| --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| [AuthStateCallback](/move-platform/sdk/models/listeners-callbacks#auth-state-update-listener) | Block that gets invoked every time [MoveAuthState](/move-platform/sdk/models/moveauthstate) is updated. |

{% hint style="warning" %}

### Authentication Expiry

The host app is expected to monitor [MoveAuthState](/move-platform/sdk/models/moveauthstate) updates via`authStateUpdateListener`API and handle those changes accordingly.

Check [Authentication updates and expiry](/move-platform/sdk/models/moveauthstate#authentication-updates-and-expiry) for more details about authentication expiry and renewal.
{% endhint %}

### **Set SDK Initialization Listener**

Provide a block to be invoked when configuration fetch failed.

```swift
func setInitializationListener(_ listener: @escaping MoveInitializationCallback)
```

| **Callback** |                                                                                    |
| ------------ | ---------------------------------------------------------------------------------- |
|              | Block that gets invoked every time **configuration** fetch from the server failed. |

{% hint style="warning" %}
Deprecated. Not needed when setting up with an auth token.
{% endhint %}

### Shutdown

Shutdown SDK shared instance.

Stops SDK services, send the queued user data, and de-initializes the SDK. After that is executed,  the [MoveSDKState](/move-platform/sdk/models/movesdkstate) will transit to `.uninitialized`.

{% tabs %}
{% tab title="Swift 5" %}

```swift
func shutDown(force: Bool, timeout: TimeInterval = 0, _ callback: ((MoveShutdownResult) -> Void)?)
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func shutDown(force: Bool = true, timeout: TimeInterval = 0) async -> MoveShutdownResult
```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="139">Callback</th><th width="90"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td><strong>Default</strong></td><td></td></tr><tr><td>force</td><td>true</td><td>If true, <em>shutdown</em> executes immediately. Pending Data may be lost.</td></tr><tr><td>timeout</td><td>0</td><td>Ignored if <code>force == true</code>.<br>If <code>timeout > 0</code> unsuccessful shutdown will continue trying to send data until timeout expires, the app is terminated, or a call to <code>setup(authCode: ...)</code> are made.</td></tr><tr><td>callback</td><td>nil</td><td>Returns a <a href="/move-platform/sdk/models/moveshutdownresult#ios">MoveShutdownResult</a> upon completion. May fail if not forced. If timeout is set, pending shutdown will continue after the callback.</td></tr></tbody></table>

{% hint style="warning" %}
**Precondition:** SDK user/config should be setup.
{% endhint %}


# Services

API Interface / iOS

**Shared Instance**

Use the shared instance as your interface to the MOVE SDK.

```swift
static let shared: MoveSDK
```

## **Detection Services**

### **Start Automatic Detection**

Starts the required detection services stated in the [MoveConfig](/move-platform/sdk/models/moveconfig) passed on initialization. Starting the service will set the [MoveSDKState](/move-platform/sdk/models/movesdkstate) to `.running`.

{% hint style="warning" %}
**Precondition**: SDK must be in `.ready` [MoveSDKState](/move-platform/sdk/models/movesdkstate)
{% endhint %}

{% tabs %}
{% tab title="Swift 5" %}

```swift
func startAutomaticDetection() -> Bool
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func startAutomaticDetection() async -> Bool
```

{% endtab %}
{% endtabs %}

Returns false if the SDK is not in `.ready` state.

### **Stop Automatic Detection**

Stops the automatic detection service, including all SDK services like driving detection, points of interest, walking and places. Stopping the service will set the [MoveSDKState](/move-platform/sdk/models/movesdkstate) back to `.ready`.&#x20;

{% hint style="warning" %}
**Precondition**: SDK must be in `.running` [MoveSDKState](/move-platform/sdk/models/movesdkstate).
{% endhint %}

{% tabs %}
{% tab title="Swift 5" %}

```swift
func stopAutomaticDetection() -> Bool
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func stopAutomaticDetection() -> Bool async
```

{% endtab %}
{% endtabs %}

Returns false if the SDK is not in `.ready` state.

### **Force Trip Recognition**

Temporarily calibrates the SDK to the highest detection mode.

In order to optimize battery consumption, the SDK goes through different detection modes with different battery consumption levels, depending on the user's current behavior and activity. In general, the SDK is responsible for alternating between those different detection modes.&#x20;

The SDK also provides hosting apps this API to call if they have their own reasons (like buttons, sensors or beacons) to believe that the user is starting a trip. This will make sure the SDK is on the highest detection state to detect the trip faster.

{% hint style="warning" %}
&#x20;**Precondition**: SDK must be in `.running` [MoveSDKState](/move-platform/sdk/models/movesdkstate).
{% endhint %}

```swift
func forceTripRecognition()
```

### **Manual Start Trip**

Manually force the start of a trip, bypassing trip validation checks. This non-standard SDK usage may be feasible only in situations where active user input can be expected. Using the metadata parameter, self-defined information can be added to each trip which can be fetched from the [timeline](/move-platform/backend/move-backend/move-timeline-api#trip-metadata).

{% tabs %}
{% tab title="Swift 5" %}

```swift
func startTrip(metadata: [String: String] = [:]) -> Bool
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func startTrip(metadata: [String : String] = [:]) async -> Bool
```

{% endtab %}
{% endtabs %}

Returns false if the SDK is not in `.ready` state.

{% hint style="warning" %}
**Precondition**: MOVE SDK must be in `READY` [MoveSdkState](/move-platform/sdk/models/movesdkstate).

Manually starting a trip bypasses additional trip detection checks. Manually started trips must be ended with [`finishCurrentTrip()`](#finish-current-trip)

It is recommended not to use [MoveOptions](/move-platform/sdk/models/moveoptions#ios) `motionPermissionMandatory` or `backgroundLocationPermissionMandatory` with this API, as they will be ignored.
{% endhint %}

### **Finish Current Trip**

Ends the current ongoing trip.

This API will end the ongoing trip and set [MoveTripState](/move-platform/sdk/models/movetripstate) back to `.idle`. The SDK is responsible for detecting the trip start and end points. The SDK also provides hosting apps this API to call if they have their own reasons (like sensors or beacons) to believe that the user's trip has ended.

{% hint style="warning" %}
**Precondition**: [MoveTripState](/move-platform/sdk/models/movetripstate) should be in an active trip.
{% endhint %}

```swift
func finishCurrentTrip()
```

{% hint style="info" %}
If this API is called while the user is active on a driving trip, a new trip will start again right away. If the intention is to un-track the ongoing trip, call `ignoreCurrentTrip` API.

More information about trip states can be found in [MoveTripState](/move-platform/sdk/models/movetripstate).
{% endhint %}

{% hint style="info" %}
If the trip was started with [`startTrip(metadata:)`](#manual-start-trip) `finishCurrentTrip()` brings the SDK back to READY state.
{% endhint %}

### **Ignore Current Trip**

Ignores the current ongoing trip.&#x20;

This API will set the ongoing [MoveTripState](/move-platform/sdk/models/movetripstate) to `.ignored`. Data of ignored trips is purged and not sent to the server.

{% hint style="warning" %}
**Precondition**: [MoveTripState](/move-platform/sdk/models/movetripstate) should be in an active trip.
{% endhint %}

```swift
func ignoreCurrentTrip()
```

### **Set Trip Start Listener**&#x20;

Provides a block to be invoked when a trip actually begins.

In comparison to the tripStateListener (only state changes) the tripStartListener will provide you with the start time of the actual trip.

{% tabs %}
{% tab title="Swift 5" %}

<pre class="language-swift"><code class="lang-swift"><strong>func setTripStartListener(_ listener: @escaping MoveTripStartCallback)
</strong></code></pre>

{% endtab %}

{% tab title="Swift 6" %}

```swift
func setTripStartListener(_ listener: @escaping AsyncMoveTripStartCallback)
```

{% endtab %}
{% endtabs %}

## Processing Services

### **Get SDK State**

Gets the current [MoveSDKState](/move-platform/sdk/models/movesdkstate).

{% tabs %}
{% tab title="Swift 5" %}

```swift
func getSDKState() -> MoveSDKState
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func getSDKState() -> MoveSDKState async
```

{% endtab %}
{% endtabs %}

| **Return**                                             |                  |
| ------------------------------------------------------ | ---------------- |
| [MoveSDKState](/move-platform/sdk/models/movesdkstate) | Latest SDK State |

### **Set SDK State Listener**

Provide a block to be invoked every time [MoveSDKState](/move-platform/sdk/models/movesdkstate) changes.

{% hint style="info" %}
Set the [MoveSDKState](/move-platform/sdk/models/movesdkstate) listener before initializing the SDK to anticipate the SDK [State](/move-platform/sdk/models/movesdkstate) changes triggered by the initialization API. \
Here the host app can start the SDK services when [MoveSDKState](/move-platform/sdk/models/movesdkstate) is `.ready`.&#x20;
{% endhint %}

{% tabs %}
{% tab title="Swift 5" %}

```swift
func setSDKStateListener(_ listener: @escaping SDKStateCallback)
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func setSDKStateListener(_ listener: @escaping AsyncMoveSDKStateCallback)
```

{% endtab %}
{% endtabs %}

| **Callback**                                                                         |                                                                                                                                                                                        |
| ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [SDKStateCallback](/move-platform/sdk/models/listeners-callbacks#sdk-state-listener) | Block that gets invoked every time[ MoveSDKState](/move-platform/sdk/models/movesdkstate) is changed and provides the updated [ MoveSDKState](/move-platform/sdk/models/movesdkstate). |

### **Get Trip State**

&#x20;Gets the current [MoveTripState](/move-platform/sdk/models/movetripstate).

{% tabs %}
{% tab title="Swift 5" %}

```swift
func getTripState() -> MoveTripState
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func getTripState() async -> MoveTripState
```

{% endtab %}
{% endtabs %}

| **Return**                                               |                                                                  |
| -------------------------------------------------------- | ---------------------------------------------------------------- |
| [MoveTripState](/move-platform/sdk/models/movetripstate) | Current [MoveTripState](/move-platform/sdk/models/movetripstate) |

### **Set Trip State Listener**

Provide a block to be invoked every time [MoveTripState](/move-platform/sdk/models/movetripstate) changes.

{% tabs %}
{% tab title="Swift 5" %}

```swift
func setTripStateListener(_ listener: @escaping TripStateCallback)
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func setTripStateListener(_ listener: @escaping AsyncTripStateCallback)
```

{% endtab %}
{% endtabs %}

| Callback                                                                               |                                                                                                                                                                                             |
| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [TripStateCallback](/move-platform/sdk/models/listeners-callbacks#trip-state-listener) | Block that gets invoked every time  [MoveTripState](/move-platform/sdk/models/movetripstate) is changed and provides the updated  [MoveTripState](/move-platform/sdk/models/movetripstate). |

### Get Device Status

{% hint style="warning" %}
Deprecated since 2.17.
{% endhint %}

Gets the current [MoveDeviceStatus](/move-platform/sdk/models/movedevicestatus)*.*

```swift
func getDeviceStatus() -> MoveDeviceStatus
```

| Return                                                         |                                                                        |
| -------------------------------------------------------------- | ---------------------------------------------------------------------- |
| [MoveDeviceStatus](/move-platform/sdk/models/movedevicestatus) | Current [MoveDeviceStatus](/move-platform/sdk/models/movedevicestatus) |

### Get Service Failures

Gets the current [MoveServiceFailures](/move-platform/sdk/models/moveservicefailure#ios).

{% tabs %}
{% tab title="Swift 5" %}

```swift
func getServiceFailures() -> [MoveServiceFailure]
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func getServiceFailures() async -> [MoveServiceFailure]
```

{% endtab %}
{% endtabs %}

| Return                                                                         |                            |
| ------------------------------------------------------------------------------ | -------------------------- |
| List of [MoveServiceFailure](/move-platform/sdk/models/moveservicefailure#ios) | A list of failed services. |

### Set Service Failure Listener

{% tabs %}
{% tab title="Swift 5" %}

```swift
func setServiceFailureListener(_ listener: @escaping MoveServiceFailureCallback)
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func setServiceFailureListener(_ listener: @escaping AsyncMoveServiceFailureCallback)
```

{% endtab %}
{% endtabs %}

Provide a block to be invoked every time [MoveServiceFailures](/move-platform/sdk/models/moveservicefailure#ios) change.

| Callback                                                                          |                                                             |
| --------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| [MoveServiceFailureCallback](/move-platform/sdk/models/listeners-callbacks#ios-6) | Block that gets invoked when service failure state changes. |

### Get Service Warnings

Gets the current [MoveServiceWarnings](/move-platform/sdk/models/moveservicewarning#ios).

{% tabs %}
{% tab title="Swift 5" %}

```swift
func getServiceWarnings() -> [MoveServiceWarning]
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func getServiceWarnings() async -> [MoveServiceWarning]
```

{% endtab %}
{% endtabs %}

| Return                                                                           |                                       |
| -------------------------------------------------------------------------------- | ------------------------------------- |
| List of [MoveServiceWarnings](/move-platform/sdk/models/moveservicewarning#ios). | A list of partially working services. |

### Set Service Warning Listener

Provide a block to be invoked every time [MoveServiceWarnings](/move-platform/sdk/models/moveservicewarning#ios) change.

{% tabs %}
{% tab title="Swift 5" %}

```swift
func setServiceWarningListener(_ listener: @escaping MoveServiceWarningCallback)
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func setServiceWarningListener(_ listener: @escaping AsyncMoveServiceWarningCallback)
```

{% endtab %}
{% endtabs %}

| Callback                                                                          |                                                       |
| --------------------------------------------------------------------------------- | ----------------------------------------------------- |
| [MoveServiceWarningCallback](/move-platform/sdk/models/listeners-callbacks#ios-7) | Block that gets invoked when service warnings change. |

### **Set Metadata Listener**

Provide a block returning bundle of key-value pairs to be appended to the trip metadata before the trip finishes.

Host apps can use this API to add any app-level information (for ex. Bluetooth beacon detected, foreground/background time, etc) to append to a trip as metadata. This metadata will be forwarded back along with the trip when fetched by the client-server, so the host app can utilize it in its app. Note: The SDK will not use this metadata element in any way, it is just passed through to the project environment.

The block provides the trip's start and stop times. Make sure to only include metadata events that are relevant for the given start and end periods.

```swift
func setTripMetaDataListener(_ listener: @escaping MetaDataCallback)
```

| **Callback**                                                                             |                                                                                                   |
| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| [MetaDataCallback](/move-platform/sdk/models/listeners-callbacks#trip-metadata-provider) | Block that gets invoked on every trip finish. The block provides the trip's start and stop times. |

**Usage Example**

```swift
MoveSDK.shared.setMetadataListener { (tripStartTime, tripEndTime) in
    getCollectedMetadataForPeriod(start: tripStartTime, end: tripEndTime)
}
```

### **Set Log Listener**

Provide a block to be invoked every time a new SDK log event occurs.

```swift
func setLogListener(_ listener: LogCallback)
```

{% tabs %}
{% tab title="Swift 5" %}

```swift
func setLogListener(_ listener: @escaping LogCallback)
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func setLogListener(_ listener: @escaping AsyncLogCallback)
```

{% endtab %}
{% endtabs %}

### **Set Console Logging State** <a href="#set-log-listener" id="set-log-listener"></a>

Toggles console logging enabled state.

This doesn't affect recieving the logs via  `setLogListener(_ listener: MoveLogCallback)` API.

Enabled by default.

```swift
func setConsoleLogging(enabled: Bool) 
```

| **Parameter** |                                                          |
| ------------- | -------------------------------------------------------- |
| enabled       | Boolean that sets SDK console logging to enabled or not. |

### Set Health Score Listener

{% tabs %}
{% tab title="Swift 5" %}

```swift
func setHealthScoreListener(_ listener: @escaping MoveHealthScoreCallback)
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func setHealthScoreListener(_ listener: @escaping AsyncMoveHealthScoreCallback)
```

{% endtab %}
{% endtabs %}

| **Parameter**                                                                                |                                                         |
| -------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
| [MoveHealthScoreCallback](/move-platform/sdk/models/listeners-callbacks#sdk-health-listener) | Block that get's invoked when the health score changes. |

### Geocoding

Geo-coordinate address lookup.

{% tabs %}
{% tab title="Swift 5" %}

```swift
func geocode(latitude: Double, longitude: Double, completion: @escaping (Result<String, MoveGeocodeError>) -> Void)
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func geocode(latitude: Double, longitude: Double) async -> Result<String, MoveGeocodeError>
```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="177"></th><th></th></tr></thead><tbody><tr><td><strong>Parameter</strong></td><td></td></tr><tr><td>latitude</td><td>Geo-coordinate latitude</td></tr><tr><td>longitude</td><td>Geo-coordinate longitude</td></tr><tr><td>completion</td><td>Callback that returns a <em>Result</em> with an address S<em>tring</em> or a <a href="/move-platform/sdk/models/movegeocodeerror#ios">MoveGeocodeError</a></td></tr></tbody></table>

Geocode will use Apple's builtin *CLGeocoder.reverseGeocodeLocation* or fallback to contacting the MOVE backend to attempt a geo-lookup.

{% hint style="warning" %}
**Throttle:** *Geocode* is limited to a maximum of 100 lookups per hour.

*CLGeocoder.reverseGeocodeLocation* has its own throttling and maybe used up for the app calling this function.
{% endhint %}

### **Delete Local Data**

Deletes all the collected user SDK data stored on the device. This doesn't affect the [MoveSDKState](/move-platform/sdk/models/movesdkstate).

{% hint style="warning" %}
**Precondition:** [MoveSDKState](/move-platform/sdk/models/movesdkstate) should be initialized.
{% endhint %}

```swift
func deleteLocalData()
```

### **Synchronize User Data**

Used to force synchronizing user data with the SDK server. Limited to once per 2 minutes.

```swift
func synchronizeUserData()
```

Returns FALSE in case there are Timeline-relevant packages in the queue that remain to be sent to the SDK Backend; and it returns TRUE in case the queue is empty.

## Other Services

### Live Location TAG

{% hint style="warning" %}
Deprecated since MOVE SDK 2.17.0
{% endhint %}

Adds a Tag (=string value) to trip events. This tag information is added to the timeline data.

To clear the Tag pass `null` as parameter.

After a `shutdown(...)` ([Android](/move-platform/sdk/api-interface/android/services#shutdown-sdk) / [iOS](#shutdown-sdk)) the tag is also cleared.

```swift
func setLiveLocationTag(_ tag: String?) -> Bool
```

<table data-header-hidden><thead><tr><th width="158"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td></td></tr><tr><td>tag</td><td>String <code>[a-z] [0-9]</code> and <code>null</code> to clear the Tag.</td></tr></tbody></table>

<table data-header-hidden><thead><tr><th width="160"></th><th></th></tr></thead><tbody><tr><td><strong>Return values</strong></td><td></td></tr><tr><td>true</td><td>Live Location Tag is applied.</td></tr><tr><td>true</td><td>Live Location Tag is cleared. (parameter <code>null</code>)</td></tr><tr><td>false</td><td>Live Location Tag exceeds the limit of 200 characters.</td></tr><tr><td>false</td><td>Live Location Tag is blank or empty.</td></tr><tr><td>false</td><td>If the passed chars are not one of these [a-z] [0-9].</td></tr></tbody></table>

### Initiate Assistance Call

*New feature in MOVE SDK 2.x; configuration in MOVE dashboard pending - please* [*get in touch*](mailto:info@dolph.in?subject=MOVE%20SDK)*.*

Initiate an assistance call to emergency services.

```swift
func initiateAssistanceCall(_ completionHandler: @escaping (MoveAssistanceCallStatus) -> Void)
```

| **Parameters**    |                                                                                                            |
| ----------------- | ---------------------------------------------------------------------------------------------------------- |
| completionHandler | A callback returning a [MoveAssistanceCallStatus](/move-platform/sdk/models/moveassistancecallstatus#ios). |

The application should process the callback status and inform the user in case of failure.

{% hint style="warning" %}
**Precondition:** The assistance call service needs to be configured in the MOVE dashboard. The SDK needs to be in *ready* or *running* state.
{% endhint %}

### Set Assistance MetaData

*New feature in MOVE SDK 2.1*

```swift
func setAssistanceMetaData(_ metadata: String)
```

| **Parameters** |                                                         |
| -------------- | ------------------------------------------------------- |
| metadata       | A string to be sent with each assistance call or impact |

The metadata string is sent to the server with each manual assistance call and with each AID report. The contents of the string can be anything, e.g. JSON data. The assistance data is persisted once set.

### Get Device Qualifier

*New feature in MOVE SDK 2.2*

Get a unique qualifier to identify the individual device.

{% tabs %}
{% tab title="Swift 5" %}

```swift
func getDeviceQualifier() -> String
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func getDeviceQualifier() async -> String
```

{% endtab %}
{% endtabs %}

The device qualifier should be passed to the backend during user registration. See [Move backend](/move-platform/backend/move-backend/move-admin-api#gettingstartedwiththedolphinmovetimelineservice-authentication).

## Device Discovery

Device discovery for iBeacon and Audio devices. Multiple devices can be registered but limitations of `CLLocationManager` region API may apply.

From the start of a trip registered devices are scanned after a period `deviceDetectionDelay`, beacons are scanned for a duration `deviceDetectionDuration` repeated after an interval `deviceDetectionInterval`, see [`MoveOptions`](/move-platform/sdk/models/moveoptions#ios).

If `stopScanOnFirstDiscovered` is set the scan stops after any device is discovered.

Device scanning results are appended to the trip metadata.

Registering/unregistering devices during a trip may result in undefined behavior.

### Register Device

Register an additional device:

```swift
func register(devices: [MoveDevice]) throws
```

### Unregister Device

Unregister a device:

```swift
func unregister(devices: [MoveDevice])
```

{% hint style="info" %}
Since MOVE SDK v2.13: Devices are persisted after [shutdown](/move-platform/sdk/api-interface/ios/setup#shutdown).
{% endhint %}

### Get Registered Devices

Get current registered devices.

{% tabs %}
{% tab title="Swift 5" %}

```swift
func getRegisteredDevices() -> [MoveDevice]
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func getRegisteredDevices() async -> [MoveDevice]
```

{% endtab %}
{% endtabs %}

### **Set Device Discovery Listener**

Set a device discovery listener to be fired when registered [MoveDevice](/move-platform/sdk/models/movedevice#ios)s are scanned. It returns a list of the devices registered with `register(devices: [MoveDevice])`. If the option [`stopScanOnFirstDiscovered`](/move-platform/sdk/models/moveoptions/devicediscovery#ios) is set the list may be incomplete.

{% tabs %}
{% tab title="Swift 5" %}

```swift
func setDeviceDiscoveryListener(_ listener: @escaping MoveDeviceDiscoveryCallback)
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func setDeviceDiscoveryListener(_ listener: @escaping AsyncMoveDeviceDiscoveryCallback)
```

{% endtab %}
{% endtabs %}

| **Callback**                                                                       |                                                                           |
| ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| [MoveDeviceDiscoveryCallback](/move-platform/sdk/models/listeners-callbacks#ios-9) | Block that gets invoked whenever a scan for registered devices completes. |

### Set MoveDevice Connection State Listener

{% hint style="info" %}
Since MOVE SDK v2.10.0
{% endhint %}

Set a [MoveDevice](/move-platform/sdk/models/movedevice) connection state listener to be fired when the connection state of a previously registered [MoveDevice](/move-platform/sdk/models/movedevice#android) has changed. Only works with paired audio devices, not iBeacons.

```swift
func setDeviceStateListener(_ listener: @escaping MoveDeviceStateCallback)
```

{% tabs %}
{% tab title="Swift 5" %}

```swift
func setDeviceStateListener(_ listener: @escaping MoveDeviceStateCallback)
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func setDeviceStateListener(_ listener: @escaping AsyncMoveDeviceStateCallback)
```

{% endtab %}
{% endtabs %}

| **Parameters**                                                                  |                                                                                                                 |
| ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| [MoveDeviceStateCallback](/move-platform/sdk/models/listeners-callbacks#ios-13) | A callback returning the [MoveDevice](/move-platform/sdk/models/movedevice) which connection state was changed. |

### **Set Remote Config Change Listener**&#x20;

{% hint style="info" %}
Since MOVE SDK v2.5
{% endhint %}

Provide a block to be invoked every time [MoveConfig](/move-platform/sdk/models/moveconfig#ios) was successfully fetched from the server.

If the MoveConfig object couldn't be fetched from the server then a [MoveConfigurationError](/move-platform/sdk/models/moveconfigurationerror#ios) ServiceUnreachable will be triggered.

{% tabs %}
{% tab title="Swift 5" %}

```swift
func setRemoteConfigChangeListener(_ listener: @escaping MoveRemoteConfigChangeCallback)
```

{% endtab %}

{% tab title="Swift 6" %}

```swift
func setRemoteConfigChangeListener(_ listener: @escaping AsyncMoveRemoteConfigChangeCallback)
```

{% endtab %}
{% endtabs %}

| **Parameters** |                                                                           |
| -------------- | ------------------------------------------------------------------------- |
| listener       | A callback returning a MoveConfig object after a successful server fetch. |

### **Get Configuration**

Gets the current used Move configuration set in setup/update or configuration. If options flag `useBackendConfig` is set returns configuration set in dashboard.&#x20;

{% hint style="info" %}
Since MOVE SDK v2.16
{% endhint %}

```swift
func getMoveConfig() -> MoveConfig?
```

| **Return**                                         |                                                                                                        |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| [MoveConfig](/move-platform/sdk/models/moveconfig) | Move Configuration passed in setup/update or configuration from backend if *useBackendConfig* is set.. |

### **Step Counter (via HealthKit)**

{% hint style="info" %}
Since MOVE SDK v2.14
{% endhint %}

See section [Permissions Handling](/move-platform/sdk/appendix/ios/permission-handling#health-permissions) in Appendix.


# React Native

API Interface


# Components

### LazyMoveSdk

{% hint style="info" %}
Since MOVE SDK v2.7.0
{% endhint %}

```typescript
import { LazyMoveSdk } from 'react-native-move-sdk';
```

Due to the fact that the application using MOVE SDK will be launched in the background in case of trip detection, all components and all functionality of the application will start working in normal mode, this consumes the memory of the device. The device's operating system may close applications that are running in the background to save memory, and if this happens to the application that is recording the trip, it will negatively affect the result of the trip recording.

The **LazyMoveSdk** wrapper component is designed to minimise the memory usage of the device. This component monitors [AppState](https://reactnative.dev/docs/appstate) and [MoveTripState](https://docs.movesdk.com/move-platform/sdk/models/movetripstate). **LazyMoveSdk** will remove it's **children** in one of the cases:&#x20;

* the app was started in the background&#x20;
* the app is in the background and MoveTripState is `'DRIVING'`, after some delay (*delayToRemoveUiInBackgroundMs*)

When AppState changes back to *'active',* **LazyMoveSdk** will render it's children again, if they were removed.

<table><thead><tr><th width="312">Prop</th><th width="97">Default</th><th>Description</th></tr></thead><tbody><tr><td>delayToRemoveUiInBackgroundMs</td><td>30000</td><td>If the app was in the background and a trip is started - after this delay, the LazyMoveSdk children will be removed.</td></tr></tbody></table>

{% hint style="danger" %}
Please note, that LazyMoveSdk removes it's children. If you have some important logic (for example requests) inside of any child component, it will not be executed.
{% endhint %}

#### Usage example

{% code fullWidth="false" %}

```tsx
import { lazy, useEffect } from 'react';
import { LazyMoveSdk } from 'react-native-move-sdk';

const App = lazy(() => import('./App')); // actual app

const LazyApp = () => (
  <LazyMoveSdk delayToRemoveUiInBackgroundMs={20000}>
    <App />
  </LazyMoveSdk>
);

export default LazyApp;
```

{% endcode %}

{% hint style="info" %}
You can also wrap not the entire application code, but only the part that uses the most memory (like maps, charts, etc.).
{% endhint %}


# Initialization

API Interface / React Native

The MOVE SDK must be initialized natively. For the first init, the SDK expects to be setup after user onboarding using Javascript. In this case, Javascript passes the required auth code or [MoveAuth](/move-platform/sdk/models/moveauth), and [MoveConfig](/move-platform/sdk/models/moveconfig) objects.

In all future inits, the SDK expects to be initialized natively at app start points (In AppDelegate for iOS, and MainApplication for Android). This is to guarantee that the MOVE SDK is set up and active before the limited time provided by the OS in background wakeups is consumed.&#x20;

The native init will re-use the last authentication and configs objects passed to the SDK from the JS initialization.

### Expo

{% hint style="info" %}
Added in SDK 2.16.
{% endhint %}

When using *expo* the following iOS/Android sections can be skipped and replaced by adding the Move SDK as a plugin in your `app.config.js`:

```js
plugins: [
  ["react-native-move-sdk", {
    "extensions": [
      "Health", // optional
      "maxQueueSizeMB": 100 // optional
    ]
  }],
	...
]
```

Optional extensions

Pass `"extensions": []` otherwise.

<table><thead><tr><th width="137.1015625">Extension</th><th>Comment</th></tr></thead><tbody><tr><td><code>"Health"</code></td><td>Used for Health Steps service, enables HealthKit functionality. When using this, make sure the app is properly setup to use Health APIs for each platform. See <a href="/move-platform/sdk/appendix/react-native/permission-handling">Appendix</a>.</td></tr><tr><td><code>"maxQueueSizeMB"</code></td><td>Sets the maxQueueSizeMB for <a href="/move-platform/sdk/models/moveinitoptions#react-native">MoveInitOptions</a>.</td></tr></tbody></table>

### iOS

~~To initialize the SDK natively, in your AppDelegate:~~

{% hint style="danger" %}
Removed in SDK 2.14. Only for 2.13 and bellow.
{% endhint %}

```objectivec
#import <ReactMoveSDK/MoveSdk.h>
...
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  [RCTMoveSdk initIfPossibleWithLaunchOptions:launchOptions];
  return YES;
}
```

#### Info.plist

Additional configuration can be set via the App's Info.plist. When using Expo, this file is generated using the plugin.

<table><thead><tr><th>Key</th><th>Type</th><th data-type="number">Default</th><th>Description</th></tr></thead><tbody><tr><td>MoveSdkMaxQueueSizeMB</td><td>Number</td><td>0</td><td>Passed to <a href="/move-platform/sdk/models/moveinitoptions#react-native">MoveInitOptions</a>. Set by expo plugin.</td></tr></tbody></table>

### Android

To initialize the SDK natively, in your MainApplication:

```java
import com.movesdk.NativeMoveSdkWrapper;
import io.dolphin.move.MoveInitOptions // optional
...
public class MainApplication extends Application implements ReactApplication {
	private NativeMoveSdkWrapper sdkWrapper;
	...
	public void onCreate() {
		super.onCreate();
		sdkWrapper = NativeMoveSdkWrapper.getInstance(this);
		sdkWrapper.init(this);
		...
	}
}
```

or using Kotlin

```kotlin
package your.package.name
import com.movesdk.NativeMoveSdkWrapper
import io.dolphin.move.MoveInitOptions // optional
// ...

class MainApplication : Application(), ReactApplication {
    private lateinit var sdkWrapper: NativeMoveSdkWrapper
    // ...
    override fun onCreate() {
        super.onCreate()
    	sdkWrapper = NativeMoveSdkWrapper.getInstance(this)
    	sdkWrapper.init(this)
        // or optionally:
    	sdkWrapper.init(this, MoveInitOptions(maxQueueSizeMB = 100))
        // ...
    }
    // ...
}
```

When using the Health Service, you must register the permission handler in your activity:

```kotlin
package your.package.name
import com.movesdk.NativeMoveSdkWrapper
// ...

class MainActivity : ReactActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // ...
        NativeMoveSdkWrapper.getInstance(this.applicationContext).registerRequestPermissionLauncher(this)
        super.onCreate(null)
    }
}
```

### Javascript

To setup the SDK in React Native you have to provide and auth code (provided by the backend), [**MoveSdkConfig**](https://docs.movesdk.com/move-platform/sdk/models/moveconfig#react-native) and [**MoveSdkAndroidConfig**](https://docs.movesdk.com/move-platform/~/changes/1lLi1pFRKkteajbXv0hC/sdk/models/movesdkandroidconfig)**.** [**MoveSdkOptions**](/move-platform/sdk/models/moveoptions) is optional object with additional SDK configurations.

```javascript
MoveSdk.setupWithCode(
    code: string,
    config: MoveSdkConfig,
    android: MoveSdkAndroidConfig,
    options: MoveSdkOptions
) => Promise<void>
```

Setup will return with a promise or throw an error on failure, such as when the code is expired or there is no network available. These errors must be caught.

Previously setup was done using a [**MoveSdkAuth**](https://docs.movesdk.com/move-platform/sdk/models/moveauth#react-native) objec&#x74;**.**

```javascript
MoveSdk.setup(
    config: MoveSdkConfig,
    auth: MoveSdkAuth,
    android: MoveSdkAndroidConfig,
    options: MoveSdkOptions
) => Promise<void>
```

{% hint style="warning" %}
Will be removed in future versions, use `setupWithCode(...)` instead.
{% endhint %}

### Next steps

The SDK will provide all relevant information on its status and ability to recognise trips. In order to have up-to-date information about the status of the SDK you can add [listeners](https://docs.movesdk.com/move-platform/sdk/models/listeners-callbacks) (e.g. [addSdkStateListener](https://docs.movesdk.com/move-platform/sdk/models/listeners-callbacks#sdk-state-listener) to be aware of every [MoveSDKState](https://docs.movesdk.com/move-platform/sdk/models/movestate) change, [addTripStateListener](https://docs.movesdk.com/move-platform/sdk/models/listeners-callbacks#trip-state-listener) to be aware of every [MoveTripState](https://docs.movesdk.com/move-platform/sdk/models/movetripstate) change) or request this information directly (e.g. [getState](https://docs.movesdk.com/move-platform/sdk/api-interface/react-native/services#get-sdk-state) and [getTripState](https://docs.movesdk.com/move-platform/sdk/api-interface/react-native/services#get-trip-state)).

In addition, the SDK will report all possible [errors](https://docs.movesdk.com/move-platform/sdk/models/moveservicefailure) and [warnings](https://docs.movesdk.com/move-platform/sdk/models/moveservicewarning) that may prevent the SDK from functioning properly. Among these errors and warnings will be those that indicate a missing permission or incomplete guarantee of certain permission. This is useful for informing the user of certain problems in granting permissions to the host app. To keep track of these errors and warnings you can use listeners ([addErrorsListener](https://docs.movesdk.com/move-platform/sdk/api-interface/react-native/services#set-errors-listener) and [addWarningsListener](https://docs.movesdk.com/move-platform/sdk/api-interface/react-native/services#set-warnings-listener)) or request a list of errors or warnings directly ([getErrors](https://docs.movesdk.com/move-platform/sdk/api-interface/react-native/services#get-errors) and [getWarnings](https://docs.movesdk.com/move-platform/sdk/api-interface/react-native/services#get-warnings)).

{% hint style="info" %}
Also note that for better efficiency all listeners should be added before initialising the SDK. With this approach it's easier to track down and fix all errors and problems, that could be triggered by initialisation or occurred even before initialisation.
{% endhint %}


# Services

API Interface / React Native

```javascript
import MoveSdk from 'react-native-move-sdk';
```

## **Detection Services**

### **Start Automatic Detection**

Starts the required detection services stated in the [MoveConfig](/move-platform/sdk/models/moveconfig) passed on initialization. Starting the service will set the [MoveSDKState](/move-platform/sdk/models/movesdkstate) to `.running`.

```typescript
MoveSdk.startAutomaticDetection(): Promise<boolean>
```

Promise will be resolved with ***false*** if the SDK is not in `.ready` state.

### **Stop Automatic Detection**

Stops the automatic detection service, including all SDK services like driving detection, points of interest, walking and places. Stopping the service will set the [MoveSDKState](/move-platform/sdk/models/movesdkstate) back to `.ready`.&#x20;

```typescript
MoveSdk.stopAutomaticDetection(): Promise<boolean>
```

Promise will be resolved with ***false*** if the SDK is not in `.running` state.

### **Force Trip Recognition**

Temporarily calibrates the SDK to the highest detection mode.

In order to optimize battery consumption, the SDK goes through different detection modes with different battery consumption levels, depending on the user's current behavior and activity. In general, the SDK is responsible for alternating between those different detection modes.&#x20;

The SDK also provides hosting apps this API to call if they have their own reasons (like buttons, sensors or beacons) to believe that the user is starting a trip. This will make sure the SDK is on the highest detection state to detect the trip faster.

```javascript
MoveSdk.forceTripRecognition(): void
```

### **Finish Current Trip**

Ends the current ongoing trip.

This API will end the ongoing trip and set [MoveTripState](/move-platform/sdk/models/movetripstate) back to `.idle`. The SDK is responsible for detecting the trip start and end points. The SDK also provides hosting apps this API to call if they have their own reasons (like sensors or beacons) to believe that the user's trip has ended.

{% hint style="warning" %}
**Precondition**:[ MoveTripState](/move-platform/sdk/models/movetripstate) should be in an active trip.
{% endhint %}

```javascript
MoveSdk.finishCurrentTrip(): void
```

{% hint style="info" %}
If this API is called while the user is active on a driving trip, a new trip will start again right away. If the intention is to un-track the ongoing trip, call `ignoreCurrentTrip`API.

More information about trip states can be found in [MoveTripState](/move-platform/sdk/models/movetripstate).
{% endhint %}

### **Ignore Current Trip**

Ignores the current ongoing trip.&#x20;

This API will set the ongoing [MoveTripState](/move-platform/sdk/models/movetripstate) to `.ignored`. Data of ignored trips is purged and not sent to the server.

{% hint style="warning" %}
**Precondition**: [MoveTripState](/move-platform/sdk/models/movetripstate) should be in an active trip.
{% endhint %}

```javascript
MoveSdk.ignoreCurrentTrip(): void
```

### **Set Trip Metadata**

{% hint style="info" %}
Since MOVE SDK v2.8.0
{% endhint %}

Add key-value pairs to be appended to the trip metadata before the trip finishes.

Host apps can use this API to add any app-level information (for ex. Bluetooth beacon detected, foreground/background time, etc) to append to a trip as metadata (only for current trip, when the next trip starts old metadata is removed). This metadata will be forwarded back along with the trip when fetched by the client-server. Note: The SDK will not use this metadata element in any way, it is just passed through to the project environment.

```typescript
MoveSdk.setTripMetadata(metadata?: { [key: string]: string }): void
```

### **Manual Start Trip**

{% hint style="info" %}
Since MOVE SDK v2.8.0
{% endhint %}

Manually force the start of a trip, bypassing trip validation checks. This non-standard SDK usage may be feasible only in situations where active user input can be expected. Using the metadata parameter, self-defined information can be added to each trip which can be fetched from the [timeline](/move-platform/backend/move-backend/move-timeline-api#trip-metadata).

```typescript
startTrip(metadata?: { [key: string]: string} ): Promise<boolean>
```

Promise will be resolved with ***false*** if the SDK is not in `.ready` state.

{% hint style="warning" %}
**Precondition**: MOVE SDK must be in`READY`[MoveSdkState](/move-platform/sdk/models/movesdkstate).

Manually starting a trip bypasses additional trip detection checks. Manually started trips must be ended with [`finishCurrentTrip()`](#finish-current-trip)

It is recommended not to use [MoveOptions](/move-platform/sdk/models/moveoptions#ios) *`motionPermissionMandatory`* o&#x72;*`backgroundLocationPermissionMandatory`*`with` this API, as they will be ignored.
{% endhint %}

## Processing Services

### **Keep in foreground (Android only)**

When an Android application is in the background it may receive limited data (location, sensors, etc.). To improve this behaviour, it is possible to put the application always in the foreground with a visible notification that cannot be discarded. Just because it's visible it doesn't mean that it is performing any data collection at all. So this should not have any significant battery impact at all.

{% hint style="info" %}
Disabled by default. Since it may be annoying to the user, it should only be enabled in case of problems.
{% endhint %}

```javascript
MoveSdk.keepInForeground(enabled: boolean): void
```

### **Keep active (Android only)**

To save battery consumption, the SDK is using several triggers to start its data listeners. In case of trouble, these triggers can be circumvented by allowing the MoveSdk to stay active all the time. In that case the SDK is always monitoring required data and is therefore consuming more battery. Depending on the configuration, it may happen that the notification (see[ notification handling](/move-platform/sdk/appendix/android/notification-management)) is always visible to the user.

{% hint style="info" %}
Disabled by default. Since this is consuming more battery, it should only be enabled in case of problems.
{% endhint %}

```javascript
MoveSdk.keepActive(enabled: boolean): void
```

### **Get SDK State**

Gets the current[ MoveSDKState](/move-platform/sdk/models/movesdkstate).

```typescript
MoveSdk.getState(): Promise<SdkState>
```

### Get Trip State

Get the current [MoveTripState](/move-platform/sdk/models/movetripstate).

```typescript
MoveSdk.getTripState(): Promise<TripState>
```

### Get Auth State

Get the current [MoveAuthState](/move-platform/sdk/models/moveauthstate).

```typescript
MoveSdk.getAuthState(): Promise<AuthState>
```

### Get Errors

Get the current list of [MoveServiceFailure](/move-platform/sdk/models/moveservicefailure).

```typescript
MoveSdk.getErrors(): Promise<ErrorListType>
```

### Get Warnings

Get the current list of [MoveServiceFailure](/move-platform/sdk/models/moveservicefailure).

```typescript
MoveSdk.getWarnings(): Promise<WarningListType>
```

### **Set SDK State Listener**

Provide a block to be invoked every time [MoveSDKState](/move-platform/sdk/models/movesdkstate) changes.

{% hint style="info" %}
Set the [MoveSDKState](/move-platform/sdk/models/movesdkstate) listener before initializing the SDK to anticipate the SDK [State](/move-platform/sdk/models/movesdkstate) changes triggered by the initialization API. \
Here the host app can start the SDK services when [MoveSDKState](/move-platform/sdk/models/movesdkstate) is`.ready`or handle errors if occurred.
{% endhint %}

{% hint style="warning" %}
For android platform it is necessary to start listen explicitly by calling:

```typescript
if (Platform.OS === 'android') {
    MoveSdk.startNativeSdkStateListener();
}
```

{% endhint %}

```javascript
MoveSdk.addSdkStateListener(sdkStateChanged: (state: SdkState) => void): ListenerSubscription;
```

| **Callback**    |                                                                                                                                                                                        |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| sdkStateChanged | Block that gets invoked every time[ MoveSDKState](/move-platform/sdk/models/movesdkstate) is changed and provides the updated [ MoveSDKState](/move-platform/sdk/models/movesdkstate). |

### **Set SDK Auth State Listener**

Provide a block to be invoked every time [MoveAuthState](/move-platform/sdk/models/moveauthstate) changes.

```javascript
MoveSdk.addAuthStateListener(authStateChanged: (event: AuthStateEvent) => void): ListenerSubscription;
```

| **Callback**     |                                                                                                         |
| ---------------- | ------------------------------------------------------------------------------------------------------- |
| authStateChanged | Block that gets invoked every time [MoveAuthState](/move-platform/sdk/models/moveauthstate) is updated. |

{% hint style="warning" %}

### Authentication Expiry

The host app is expected to monitor [MoveAuthState](/move-platform/sdk/models/moveauthstate) updates via`authStateUpdateListene` API and handle those changes accordingly.

Check [Authentication updates and expiry](/move-platform/sdk/models/moveauthstate#authentication-updates-and-expiry) for more details about authentication expiry and renewal.
{% endhint %}

### **Set Trip State Listener**

Provide a block to be invoked every time [MoveTripState](/move-platform/sdk/models/movetripstate) changes.

```javascript
MoveSdk.addTripStateListener(tripStateChanged: (state: TripState) => void): ListenerSubscription;
```

| Callback         |                                                                                                                                                                                             |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| tripStateChanged | Block that gets invoked every time  [MoveTripState](/move-platform/sdk/models/movetripstate) is changed and provides the updated  [MoveTripState](/move-platform/sdk/models/movetripstate). |

### Set Errors Listener

Provide a block to be invoked every time [MoveServiceFailure](/move-platform/sdk/models/moveservicefailure) changes.

```javascript
MoveSdk.addErrorsListener(errorsReceived: (errors: ErrorListType) => void): ListenerSubscription;
```

### Set Warnings Listener

Provide a block to be invoked every time [MoveServiceWarning](/move-platform/sdk/models/moveservicewarning) changes.

```javascript
MoveSdk.addWarningsListener(warningsReceived: (warnings: ErrorListType) => void): ListenerSubscription;
```

### **Set Log Listener**

Add a log listener for debugging.

```typescript
static addLogListener(logReceived: (event: MoveSdkLog) => void): ListenerSubscription;
```

### **Shutdown SDK**

Shutdown SDK shared instance.

{% hint style="warning" %}
**Precondition:** SDK must be initialized.
{% endhint %}

Stops SDK services, send the queued user data, and de-initializes the SDK. After that is executed,  the [MoveSDKState](/move-platform/sdk/models/movesdkstate) will transit to `.uninitialized`.

{% hint style="info" %}
If it's necessary just to stop all SDK services you most likely need to use [stopAutomaticDetection](https://docs.movesdk.com/move-platform/sdk/api-interface/react-native/services#stop-automatic-detection) instead of shutdown. Use shutdown in case of user's logout, SDK auth error (in those cases where you know for sure that you will need to execute [MoveSdk.setup](https://docs.movesdk.com/move-platform/sdk/api-interface/react-native/initialization#javascript) with new [MoveAuth](https://docs.movesdk.com/move-platform/sdk/models/moveauth#react-native) object, for example).
{% endhint %}

```javascript
MoveSdk.shutdown(force:boolean = true, timeout?: number): Promise<ShutdownReturnType>
```

<table data-header-hidden><thead><tr><th width="196.66666666666669"></th><th width="137"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td><strong>Default</strong></td><td></td></tr><tr><td>force</td><td>true</td><td>If true, <em>shutdown</em> executes immediately. Pending Data may be lost and always returns with a success, see <a href="/move-platform/sdk/models/moveshutdownresult#react">ShutdownReturnType</a> otherwise.</td></tr><tr><td><code>timeoutSeconds</code></td><td></td><td>Ignored if <code>force == true</code>.<br>If <code>timeout > 0</code> unsuccessful shutdown will continue trying to send data until timeout expires, the app is terminated, or a call to <code>setup(authCode: ...)</code> are made.</td></tr><tr><td><strong>Returns</strong></td><td></td><td></td></tr><tr><td><a href="/move-platform/sdk/models/moveshutdownresult#react">MoveShutdownResult</a> </td><td></td><td></td></tr></tbody></table>

{% hint style="danger" %}
When `force: false` is specified the shutdown may fail when pending data cannot be uploaded and reject the promise (status code: `NETWORK_ERROR`) which needs to be handled.
{% endhint %}

### Resolve Error

```typescript
MoveSdk.resolveError(): void
```

### **Synchronize User Data**

Used to force synchronizing user data with the SDK server. Limited to once per 2 minutes.

```javascript
MoveSdk.synchronizeUserData(): void
```

## Other Services

### Initiate Assistance Call

*New feature in MOVE SDK 2.x; configuration in MOVE dashboard pending - please* [*get in touch*](mailto:info@dolph.in?subject=MOVE%20SDK)*.*

Initiate an assistance call to emergency services.

```typescript
MoveSdk.initiateAssistanceCall(): Promise<boolean>
```

Returns a promise with a [MoveAssistanceCallStatus](/move-platform/sdk/models/moveassistancecallstatus#android).

{% hint style="warning" %}
**Precondition:** The assistance call service needs to be configured in the MOVE dashboard. The SDK needs to be in *ready* or *running* state.
{% endhint %}

### Set Assistance MetaData

{% hint style="info" %}
Since MOVE SDK 2.1.0
{% endhint %}

```typescript
MoveSdk.setAssistanceMetaData(data: string): void
```

<table><thead><tr><th width="281.3333333333333"></th><th width="176"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td></td><td></td></tr><tr><td><pre><code>data
</code></pre></td><td>String</td><td>A string to be sent with each assistance call or impact</td></tr></tbody></table>

The metadata string is set once, and then sent to the server with each and every manual assistance call and with AID report. The contents of the string can be anything, e.g. JSON data. The assistance data is persisted once set.

### Set Timer (Android only)

{% hint style="info" %}
Since MOVE SDK v2.7.0
{% endhint %}

```typescript
MoveSdk.setTimer(callback: () => void, delay?: number): string
```

Usual setTimeout doesn't work if app is in the background on Android. The SDK provides **setTimer** that works in the same way as setTimeout, but also in the background. A call to `setTimer` returns a “timer identifier” that we can use to cancel the execution via [`cancelTimer`](#cancel-timer-android-only).

<table><thead><tr><th></th><th></th><th width="103"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td><strong>Default</strong></td><td></td><td></td></tr><tr><td>delay</td><td>60000</td><td>number</td><td>Delay in miliseconds.</td></tr><tr><td>callback</td><td></td><td>function</td><td>Callback that will be executed after delay.</td></tr></tbody></table>

### Cancel Timer (Android only)

{% hint style="info" %}
Since MOVE SDK 2.7.0
{% endhint %}

```typescript
MoveSdk.cancelTimer(key: string): void
```

This method removes timer that was added via [`setTimer`](#set-timer-android-only).

|                |        |                                                        |
| -------------- | ------ | ------------------------------------------------------ |
| **Parameters** |        |                                                        |
| key            | string | "Timer identifier" which was returned from `setTimer`. |

### Live Location TAG

{% hint style="info" %}
Since MOVE SDK 2.8.0
{% endhint %}

```typescript
MoveSdk.setLiveLocationTag(tag?: string): Promise<boolean>
```

Adds a Tag to trip events. This Tag information is added to the timeline data. To clear the Tag do not pass parameter.

After a `shutdown(...)` ([Android](/move-platform/sdk/api-interface/android/services#shutdown-sdk) / [iOS](#shutdown-sdk)) the Tag is also cleared.

<table><thead><tr><th width="160"></th><th width="549"></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td></td></tr><tr><td>tag</td><td>String <code>[a-z] [0-9]</code> and <code>null</code> to clear the Tag.</td></tr></tbody></table>

<table><thead><tr><th width="161"></th><th></th></tr></thead><tbody><tr><td><strong>Return values</strong></td><td></td></tr><tr><td>true</td><td>Live Location Tag is applied.</td></tr><tr><td>true</td><td>Live Location Tag is cleared (no parameter is passed).</td></tr><tr><td>false</td><td>Live Location Tag exceeds the limit of 200 characters.</td></tr><tr><td>false</td><td>Live Location Tag is blank or empty.</td></tr><tr><td>false</td><td>If the passed chars are not one of these [a-z] [0-9].</td></tr></tbody></table>

## Configuration services

### Update authentication

Updates SDK [MoveAuth](/move-platform/sdk/models/moveauth). On SDK auth expiry, the authStateListener will trigger expired state. The host app is expected to fetch a new [MoveAuth](/move-platform/sdk/models/moveauth) using its project API key and pass it to the MoveSDK using the following API:

```jsx
MoveSdk.updateAuth(auth: MoveSdkAuth): Promise<void>
```

<table><thead><tr><th width="186.4285714285714">Parameters</th><th width="150"> </th></tr></thead><tbody><tr><td>auth</td><td>The user's updated Auth object with the new token.</td></tr></tbody></table>

### Update config

{% hint style="info" %}
Since MOVE SDK v2.8.0
{% endhint %}

Change the [MoveConfig](/move-platform/sdk/models/moveconfig) originally passed in setup. Optionally update the [MoveOptions](/move-platform/sdk/models/moveoptions#react-native) passed in setup.

```typescript
MoveSdk.updateConfig(config: MoveSdkConfig, options?: MoveSdkOptions): Promise<boolean>
```

## Device Discovery

{% hint style="danger" %}
Due to limitations in Android’s Classic Bluetooth APIs, reliable connection status tracking may not always be possible. For more details and available workarounds, see [Forcing the Signal - Classic Bluetooth](/move-platform/sdk/appendix/android/forcing-the-signal-classic-bluetooth).
{% endhint %}

### Start Scanning Devices

Start scanning for devices which can be registered on the SDK for trip device discovery. A block will get invoked each time new devices are found.

```tsx
MoveSdk.startScanningDevices(sdkDevicesDetected: (state: Array<MoveSdkDevice>) => void, filter: MoveSdkDeviceFilter[], uuid?: string, manufacturerId?: number): ListenerSubscription;
```

<table><thead><tr><th width="208">Parameters</th><th width="194.33333333333334"></th><th></th></tr></thead><tbody><tr><td>sdkDevicesDetected</td><td>Listener</td><td>Block that gets invoked every time a new <a href="/move-platform/sdk/models/movedevice#react">MoveSdkDevice</a>  is detected.</td></tr><tr><td>filter</td><td>MoveSdkDeviceFilter</td><td>Filter devices by type.  See bellow.</td></tr><tr><td>uuid</td><td>string</td><td>UUID String required to scan beacons.</td></tr><tr><td>manufacturerId</td><td>number</td><td>Manufacturer ID needed to scan beacons.</td></tr></tbody></table>

Returns a subscription object. Scanning will stop automatically when the subscription is removed, otherwise the scan will continue and this will impact device battery usage.

A list of filters can be specified to filter which devices to scan for:

<table><thead><tr><th width="193">MoveDeviceFilter</th><th></th></tr></thead><tbody><tr><td>paired</td><td>Scan for paired devices. <strong>Default</strong></td></tr><tr><td>connected</td><td>Scan for connected devices. <em>New since version 2.10.4</em>.</td></tr><tr><td>beacon</td><td>Scan for beacon devices. <code>uuid</code> and <code>manufacturerId</code> required.</td></tr></tbody></table>

### Set MoveDevice Connection State Listener

{% hint style="info" %}
Since MOVE SDK v2.10.0
{% endhint %}

Set a [MoveDevice](/move-platform/sdk/models/movedevice#react-native) connection state listener to be fired when the Bluetooth connection state of a previously registered [MoveDevice](/move-platform/sdk/models/movedevice#react-native) has changed.

```typescript
MoveSdk.addDeviceStateListener(onScanResult: (results: Array<MoveSdkDevice>) => void): ListenerSubscription;
```

| **Parameters**                                                                                                          |                                                                                                                              |
| ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| listener -> [MoveDeviceStateListener](/move-platform/sdk/models/listeners-callbacks#movedevice-state-listener-callback) | A callback returning the [MoveDevice](/move-platform/sdk/models/movedevice#react-native) which connection state was changed. |

### Get Registered Devices

Get a list of devices ([MoveSdkDevice](/move-platform/sdk/models/movedevice#react)) registered to be discovered during trips.

```tsx
MoveSdk.getRegisteredDevices(): Promise<Array<MoveSdkDevice>>;
```

### Register Devices

Register devices ([MoveSdkDevice](/move-platform/sdk/models/movedevice#react)) to be discovered during trips.

```tsx
MoveSdk.registerDevices(devices: Array<MoveSdkDevice>): Promise<boolean>;
```

### Unregister Devices

Unregister devices (MoveSdkDevice) to be discovered during trips.

```tsx
MoveSdk.unregisterDevices(devices: Array<MoveSdkDevice>): Promise<boolean>;
```

{% hint style="info" %}
Since MOVE SDK v2.13: Devices are persisted after [shutdown](/move-platform/sdk/api-interface/react-native/services#shutdown-sdk).
{% endhint %}

### Discover Devices

```tsx
MoveSdk.addDeviceDiscoveryListener(onScanResult: (results: Array<MoveScanResult>) => void): ListenerSubscription;
```

Subscribe to updates for registered devices scanned during trips. See [MoveScanResult](/move-platform/sdk/models/movescanresult#react).

### Set Health Score Listener

Provide a block to be invoked every time MoveHealthScore[ ](/move-platform/sdk/models/moveservicewarning#android)will change.

```typescript
MoveSdk.addHealthListener(scoreReceived: (health: MoveHealthScore) => void): ListenerSubscription
```

<table data-header-hidden><thead><tr><th width="260.3333333333333"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td></td></tr><tr><td><a href="/move-platform/sdk/models/listeners-callbacks#react-native-11">MoveHealthScoreListener</a></td><td>Block that get's invoked when the health score changes.</td></tr></tbody></table>

### **Set Remote Config Change Listener**&#x20;

{% hint style="info" %}
Since MOVE SDK v2.5
{% endhint %}

Provide a block to be invoked every time [MoveConfig](/move-platform/sdk/models/moveconfig#react-native) was successfully fetched from the server.

```typescript
MoveSdk.addRemoteConfigChangeListener(configChangeReceived: (config: Array<IssueListService>) => void): ListenerSubscription
```

| **Parameters** |                                                                          |
| -------------- | ------------------------------------------------------------------------ |
| listener       | A callback returning a List of services after a successful server fetch. |

### **Get Configuration**

Gets the current used Move configuration set in setup/update or configuration. If options flag `useBackendConfig` is set returns configuration set in dashboard.&#x20;

{% hint style="info" %}
Since MOVE SDK v2.16
{% endhint %}

```typescript
MoveSdk.getMoveConfig(): Promise<MoveSdkConfig>;
```

| **Return**                                         |                                                                                                        |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| [MoveConfig](/move-platform/sdk/models/moveconfig) | Move Configuration passed in setup/update or configuration from backend if *useBackendConfig* is set.. |

### **Step Counter**

{% hint style="info" %}
Since MOVE SDK v2.14
{% endhint %}

See section [Permission Handling](/move-platform/sdk/appendix/react-native/permission-handling) in Appendix.

For Android please see the section [**Step Counter (via Google Health Connect)**](/move-platform/sdk/api-interface/android/services#step-counter-via-google-health-connect)


# Flutter

API interface


# Initialization

API Interface / Flutter

The MOVE SDK must be initialized natively. For the first init, the SDK expects to be setup after user onboarding using Flutter. In this case, Flutter passes the required auth code or [MoveAuth](/move-platform/sdk/models/moveauth), and [MoveConfig](/move-platform/sdk/models/moveconfig) objects.

In all future inits, the SDK expects to be initialized natively at app start points (MainApplication for Android). This is to guarantee that the MOVE SDK is set up and active before the limited time provided by the OS in background wakeups is consumed.&#x20;

The native init will re-use the last authentication and configs objects passed to the SDK from the Flutter initialization.

```dart
import 'package:movesdk/movesdk.dart';
```

## LifeCycle

## **Android**

To initialize the SDK natively, in your MainApplication:

```kotlin
import io.dolphin.move.MoveSdk
import io.dolphin.move.MoveInitOptions // optional
...
class MainApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        val sdk = MoveSdk.init(this)
        // or optionally:
        val queueOptions = MoveInitOptions(maxQueueSizeMB = ...)
        val sdk = MoveSdk.init(this, initOptions = queueOptions)
        ...
        // you can use the native class furhter on
        // eg. sdk.allowMockLocations(true)
    }
}
```

### **Notification**

To use the MoveSdk in the background, it is required to configure the trip or als recognition notification, like shown in the following:

```kotlin
sdk.recognitionNotification(
    NotificationCompat.Builder(this, recognitionChannel)
        .setContentTitle("MOVE SDK")
        .setContentText("Trip detection")
        .setChannelId(recognitionChannel)
)
```

Make sure that you are also creating a notification channel. More information about notifications can be found at [Notification Management](/move-platform/sdk/appendix/android/notification-management).

## iOS

{% hint style="info" %}
For iOS the SDK is automatically initialized in the `FlutterPlugin` lifecycle during `didFinishLaunchingWithOptions.`
{% endhint %}

Additional options can be configured via the App's `Info.plist` .

<table><thead><tr><th width="214.66666666666669">Key</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>MoveSdkMaxQueueSizeMB</code></td><td>Number</td><td>Queue size limit of SDK to keep storage bellow. See <a href="/move-platform/sdk/models/moveinitoptions">MoveInitOptions</a>.</td></tr></tbody></table>

## Setup MOVE SDK

### With MoveAuth

To setup the MOVE SDK with a registered user you have to provide [**MoveAuth**](/move-platform/sdk/models/moveauth#flutter), [**MoveConfig**](/move-platform/sdk/models/moveconfig#flutter):

```dart
Future<void> setup(
        MoveAuth auth,
        MoveConfig moveConfig,
        {MoveOptions? options}
)
```

<table data-header-hidden><thead><tr><th width="196.66666666666669"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td></td></tr><tr><td><code>auth</code></td><td><a href="/move-platform/sdk/models/moveauth#flutter">MoveAuth</a> object to authenticate the user. See <a href="/move-platform/backend/example-requests#create-a-new-user">Move Backend</a> section for acquiring credentials.</td></tr><tr><td><code>moveConfig</code></td><td><a href="/move-platform/sdk/models/moveconfig#flutter">MoveConfig</a> object to setup <a href="/move-platform/sdk/api-interface/flutter/services#detection-services">services</a>.</td></tr><tr><td><code>options</code></td><td>Optional <a href="/move-platform/sdk/models/moveoptions#flutter">MoveOptions</a> object</td></tr></tbody></table>

{% hint style="warning" %}
Will be removed in future versions, use `setupWithCode(...)` instead.
{% endhint %}

### **With authCode**

Alternative to the approach with the MoveAuth you can setup the MOVE SDK with an authentication string. This **authCode** must be fetched from the backend using the userId (see [MOVE Backend - Example request](/move-platform/backend/example-requests#create-a-new-user-authcode)).

```dart
Future<MoveAuthResult> setupWithCode(
        String authCode,
        MoveConfig moveConfig,
        {MoveOptions? options}
)
```

<table data-header-hidden><thead><tr><th width="214.66666666666669"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td></td></tr><tr><td><code>authCode</code></td><td>authCode string to authenticate the user. See <a href="/move-platform/backend/example-requests#create-a-new-user-authcode">Move Backend</a> section for acquiring credentials.</td></tr><tr><td><code>moveConfig</code></td><td><a href="/move-platform/sdk/models/moveconfig#flutter">MoveConfig</a> object to setup <a href="/move-platform/sdk/api-interface/flutter/services#detection-services">services</a>.</td></tr><tr><td><code>options</code></td><td>Optional <a href="/move-platform/sdk/models/moveoptions#flutter">MoveOptions</a> object</td></tr><tr><td><strong>Returns</strong></td><td></td></tr><tr><td><a href="/move-platform/sdk/models/moveauthresult#flutter">MoveAuthResult</a></td><td></td></tr></tbody></table>

## **Shutdown SDK**

Shutdown SDK shared instance.

Stops SDK services, send the queued user data and de-initializes the SDK. After that is executed,  the [MoveSDKState](/move-platform/sdk/models/movesdkstate) will transit to `.unknown`.

{% hint style="warning" %}
**Precondition:** SDK must be initialized.
{% endhint %}

```dart
Future<MoveShutdownResult> shutdown({bool force = true, int? timeoutSeconds})
```

<table data-header-hidden><thead><tr><th width="217.66666666666669"></th><th width="158"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td><strong>Default</strong></td><td></td></tr><tr><td><code>force</code></td><td><code>true</code></td><td>If true, <code>shutdown</code> executes immediately. Pending Data may be lost.</td></tr><tr><td><code>timeoutSeconds</code></td><td></td><td>Ignored if <code>force == true</code>.<br>If <code>timeout > 0</code> unsuccessful shutdown will continue trying to send data until timeout expires, the app is terminated, or a call to <code>setup(authCode: ...)</code> are made.</td></tr><tr><td><strong>Returns</strong></td><td></td><td></td></tr><tr><td><a href="/move-platform/sdk/models/moveshutdownresult#flutter">MoveShutdownResult</a></td><td></td><td></td></tr></tbody></table>

## Configuration services

### Update authentication

Updates SDK [MoveAuth](/move-platform/sdk/models/moveauth). The host app was expected to fetch a new [MoveAuth](/move-platform/sdk/models/moveauth) using its project API key and pass it to the MoveSDK using the following API:

```dart
@Deprecated('obsolete')
Future<MoveAuthError?> updateAuth(MoveAuth auth)
```

{% hint style="danger" %}
**Deprecated:** Token expiry is no longer a valid auth state forwarded to the app and does not need to be handled.
{% endhint %}

### Update configuration

Updates SDK MoveConfig.

```dart
Future<void> updateConfig(MoveConfig config, {MoveOptions? options})
```

<table><thead><tr><th width="186.4285714285714">Parameters</th><th width="150"> </th></tr></thead><tbody><tr><td><code>config</code></td><td>The new MoveConfig to use.</td></tr><tr><td><code>options</code></td><td><strong>Optional:</strong> The updated MoveOptions to use</td></tr><tr><td><strong>Throws</strong></td><td></td></tr><tr><td><em>uninitialized</em></td><td>The SDK is in <code>unknown</code> state.</td></tr></tbody></table>


# Services

API Interface / Flutter

```dart
import 'package:movesdk/movesdk.dart';
```

## **Detection Services**

### **Start Automatic Detection**

Starts the required detection services stated in the [MoveConfig](/move-platform/sdk/models/moveconfig) passed on initialization. Starting the service will set the [MoveSDKState](/move-platform/sdk/models/movesdkstate) to `.running`.

Returns false if the SDK is not in `.ready` state.

```dart
Future<bool> MoveSdk.startAutomaticDetection()
```

### **Stop Automatic Detection**

Stops the automatic detection service, including all SDK services like driving detection, points of interest, walking and places. Stopping the service will set the [MoveSDKState](/move-platform/sdk/models/movesdkstate) back to `.ready`.&#x20;

Returns false if the SDK is not in `.ready` state.

```dart
Future<bool> MoveSdk.stopAutomaticDetection()
```

### **Force Trip Recognition**

Temporarily calibrates the SDK to the highest detection mode.

In order to optimize battery consumption, the SDK goes through different detection modes with different battery consumption levels, depending on the user's current behavior and activity. In general, the SDK is responsible for alternating between those different detection modes.&#x20;

The SDK also provides hosting apps this API to call if they have their own reasons (like buttons, sensors or beacons) to believe that the user is starting a trip. This will make sure the SDK is on the highest detection state to detect the trip faster.

```dart
Future<void> MoveSdk.forceTripRecognition()
```

### **Manual Start Trip**

Manually force the start of a trip, bypassing trip validation checks. This non-standard SDK usage may be feasible only in situations where active user input can be expected. Using the metadata parameter, self-defined information can be added to each trip which can be fetched from the [timeline](/move-platform/backend/move-backend/move-timeline-api#trip-metadata).

```dart
Future<bool> startTrip(Map<String, String>? metadata)
```

Returns false if the SDK is not in `.ready` state.

{% hint style="warning" %}
**Precondition**: MOVE SDK must be in`READY`[MoveSdkState](/move-platform/sdk/models/movesdkstate#flutter).

Manually starting a trip bypasses additional trip detection checks. Manually started trips must be ended with [`finishCurrentTrip()`](#finish-current-trip)`.`

It is recommended not to use [MoveOptions](/move-platform/sdk/models/moveoptions#flutter) `motionPermissionMandatory` or `backgroundLocationPermissionMandatory`with this API, as they will be ignored.
{% endhint %}

### **Finish Current Trip**

Ends the current ongoing trip.

This API will end the ongoing trip and set [MoveTripState](/move-platform/sdk/models/movetripstate) back to `.idle`. The SDK is responsible for detecting the trip start and end points. The SDK also provides hosting apps this API to call if they have their own reasons (like sensors or beacons) to believe that the user's trip has ended.

{% hint style="warning" %}
**Precondition**:[ MoveTripState](/move-platform/sdk/models/movetripstate) should be in an active trip.
{% endhint %}

```dart
Future<void> MoveSdk.finishCurrentTrip()
```

{% hint style="info" %}
If this API is called while the user is active on a driving trip, a new trip will start again right away. If the intention is to un-track the ongoing trip, call `ignoreCurrentTrip`API.

More information about trip states can be found in [MoveTripState](/move-platform/sdk/models/movetripstate).
{% endhint %}

### **Ignore Current Trip**

Ignores the current ongoing trip.&#x20;

This API will set the ongoing [MoveTripState](/move-platform/sdk/models/movetripstate) to `.ignored`. Data of ignored trips is purged and not sent to the server.

{% hint style="warning" %}
**Precondition**: [MoveTripState](/move-platform/sdk/models/movetripstate) should be in an active trip.
{% endhint %}

```dart
Future<void> MoveSdk.ignoreCurrentTrip()
```

## Processing Services

### **Keep in foreground (Android only)**

When an Android application is in the background it may receive limited data (location, sensors, etc.). To improve this behavior, it is possible to put the application always in the foreground with a visible notification that cannot be discarded. Just because it's visible it doesn't mean that it is performing any data collection at all. So this should not have any significant battery impact at all.

{% hint style="info" %}
Disabled by default. Since it may be annoying to the user, it should only be enabled in case of problems.
{% endhint %}

```dart
Future<void> MoveSdk.keepInForeground(bool enabled)
```

### **Keep active (Android only)**

To save battery consumption, the SDK is using several triggers to start its data listeners. In case of trouble, these triggers can be circumvented by allowing the MoveSdk to stay active all the time. In that case the SDK is always monitoring required data and is therefore consuming more battery. Depending on the configuration, it may happen that the notification (see[ notification handling](/move-platform/sdk/appendix/android/notification-management)) is always visible to the user.

{% hint style="info" %}
Disabled by default. Since this is consuming more battery, it should only be enabled in case of problems.
{% endhint %}

```dart
Future<void> MoveSdk.keepActive(bool enabled)
```

### **Get SDK State**

Gets the current[ MoveSDKState](/move-platform/sdk/models/movesdkstate);

```dart
Future<MoveState> getState() async
```

### Get Trip State

Get the current [MoveTripState](/move-platform/sdk/models/movetripstate).

```dart
Future<MoveTripState> getTripState() async
```

### Get Auth State

Get the current [MoveAuthState](/move-platform/sdk/models/moveauthstate).

```dart
Future<MoveAuthState> getAuthState() async
```

### **Set SDK State Listener**

Provide a block to be invoked every time [MoveSDKState](/move-platform/sdk/models/movesdkstate) changes.

{% hint style="info" %}
Set the [MoveSDKState](/move-platform/sdk/models/movesdkstate) listener before initializing the SDK to anticipate the SDK [State](/move-platform/sdk/models/movesdkstate) changes triggered by the initialization API. \
Here the host app can start the SDK services when [MoveSDKState](/move-platform/sdk/models/movesdkstate) is`.ready`or handle errors if occurred.
{% endhint %}

```dart
Stream<MoveState> setSdkStateListener() async*
```

### **Set SDK Auth State Listener**

Provide a block to be invoked every time [MoveAuthState](/move-platform/sdk/models/moveauthstate) changes.

```dart
Stream<MoveAuthState> setAuthStateListener() async*
```

{% hint style="warning" %}

### Authentication Expiry

The host app is expected to monitor [MoveAuthState](/move-platform/sdk/models/moveauthstate) updates via `setAuthStateListener`() API and handle those changes accordingly.

Check [Authentication updates and expiry](/move-platform/sdk/models/moveauthstate#authentication-updates-and-expiry) for more details about authentication expiry and renewal.
{% endhint %}

### **Set Trip State Listener**

Provide a block to be invoked every time [MoveTripState](/move-platform/sdk/models/movetripstate) changes.

```dart
Stream<MoveTripState> setTripStateListener() async*
```

### Set Errors Listener

Provide a block to be invoked every time [MoveServiceFailure](/move-platform/sdk/models/moveservicefailure) changes.

```dart
Stream<List<MoveServiceError>> setServiceErrorListener() async*
```

### Set Warnings Listener

Provide a block to be invoked every time [MoveServiceWarning](/move-platform/sdk/models/moveservicewarning) changes.

```dart
Stream<List<MoveServiceWarning>> setServiceWarningListener() async*
```

### Resolve Error

Forces a permission recheck, useful for example after the motion permission request was given in iOS.

```dart
Future<void> resolveError()
```

### **Delete Local Data**

```dart
Future<void> deleteLocalData()
```

Deletes all runtime properties and databases from all registered modules. Data that has not yet been synced to the backend will be lost.

### **Synchronize User Data**

Used to force synchronizing user data with the SDK server. Limited to once per 2 minutes.

```dart
Future<bool> synchronizeUserData()
```

Returns whether data upload is still in progress.

## Other Services

### Live Location TAG

{% hint style="info" %}
New feature since MOVE SDK 2.8.0
{% endhint %}

{% hint style="warning" %}
Deprecated since MOVE SDK 2.17.0
{% endhint %}

Adds a Tag (=string value) to trip events. This tag information is added to the timeline data.

To clear the Tag pass `null` as parameter.

After a [`shutdown(...)`](/move-platform/sdk/api-interface/flutter/initialization#shutdown-sdk) the tag is also cleared.

```dart
Future<bool> setLiveLocationTag(String? tag)
```

<table data-header-hidden><thead><tr><th width="158"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td></td></tr><tr><td>tag</td><td>String <code>[a-z] [0-9]</code> and <code>null</code> to clear the Tag.</td></tr></tbody></table>

<table data-header-hidden><thead><tr><th width="160"></th><th></th></tr></thead><tbody><tr><td><strong>Return values</strong></td><td></td></tr><tr><td>true</td><td>Live Location Tag is applied.</td></tr><tr><td>true</td><td>Live Location Tag is cleared. (parameter <code>null</code>)</td></tr><tr><td>false</td><td>Live Location Tag exceeds the limit of 200 characters.</td></tr><tr><td>false</td><td>Live Location Tag is blank or empty.</td></tr><tr><td>false</td><td>If the passed chars are not one of these [a-z] [0-9].</td></tr></tbody></table>

### Initiate Assistance Call

*New feature in MOVE SDK 2.x; configuration in MOVE dashboard pending - please* [*get in touch*](mailto:info@dolph.in?subject=MOVE%20SDK)*.*

Initiate an assistance call to emergency services.

```dart
Future<MoveAssistanceCallStatus> initiateAssistanceCall()
```

Returns a promise with a [MoveAssistanceCallStatus](/move-platform/sdk/models/moveassistancecallstatus#android).

{% hint style="warning" %}
**Precondition:** The assistance call service needs to be configured in the MOVE dashboard. The SDK needs to be in *ready* or *running* state.
{% endhint %}

### Set Assistance MetaData

```dart
Future<void> setAssistanceMetaData(String? assistanceMetadataValue)
```

<table><thead><tr><th width="281.3333333333333"></th><th width="176"></th><th></th></tr></thead><tbody><tr><td><strong>Parameters</strong></td><td></td><td></td></tr><tr><td><code>data</code></td><td><code>String</code></td><td>A string to be sent with each assistance call or impact</td></tr></tbody></table>

The metadata string is set once, and then sent to the server with each and every manual assistance call and with AID report. The contents of the string can be anything, e.g. JSON data. The assistance data is persisted once set.

### Geocode

Geo-code address lookup.

Geocode will use the system's native Geocode API or fallback to contacting the MOVE backend to attempt a geo-lookup.

```dart
Future<MoveGeocodeResult> geocode(double latitude, double longitude) async
```

| **Parameters** |          |                         |
| -------------- | -------- | ----------------------- |
| `latitude`     | `double` | GPS location latitude.  |
| `longitude`    | `double` | GPS location longitude. |

Returns an object of type MoveGeocodeResult with either the Address as a result string, or a [MoveGeocodeError](/move-platform/sdk/models/movegeocodeerror).

```dart
class MoveGeocodeResult {
  String? result;
  MoveGeocodeError? error;
}
```

{% hint style="warning" %}
**Throttle:** *Geocode* is limited to a maximum of 100 lookups per hour.

The native API may have its own throttling and maybe used up for the app calling this function.
{% endhint %}

### **Set Remote Config Change Listener**&#x20;

{% hint style="info" %}
Since MOVE SDK v2.5
{% endhint %}

Provide a block to be invoked every time [MoveConfig](/move-platform/sdk/models/moveconfig#flutter) was successfully fetched from the server.

```dart
Stream<MoveConfig> setRemoteConfigChangeListener() async*
```

| **Parameters** |                                                                                                                           |
| -------------- | ------------------------------------------------------------------------------------------------------------------------- |
| listener       | A callback returning a [MoveConfig](/move-platform/sdk/models/moveconfig#flutter) object after a successful server fetch. |

## Log Listener

```dart
Stream<String> setLogListener()
```

Returns a stream of log messages from the MOVE SDK. Use this for debugging purposes. Disable in production builds.

## Trip Start Listener

```dart
Stream<DateTime> setTripStartListener()
```

Returns a stream that emits a `DateTime` whenever a new trip is started. Can be used to trigger app-specific actions at trip start (e.g. show a local notification).

## Device Discovery

{% hint style="danger" %}
Due to limitations in Android’s Classic Bluetooth APIs, reliable connection status tracking may not always be possible. For more details and available workarounds, see [Forcing the Signal - Classic Bluetooth](/move-platform/sdk/appendix/android/forcing-the-signal-classic-bluetooth).
{% endhint %}

### Scanning Devices

Start scanning for devices which can be registered on the SDK for trip device discovery. A block will get invoked each time new devices are found.

```dart
Stream<List<MoveDevice>> startScanningDevices(
      {List<MoveDeviceFilter> filter = const [MoveDeviceFilter.paired],
      String? uuid,
      int? manufacturerId}) async*
```

<table><thead><tr><th width="208">Parameters</th><th width="194.33333333333334"></th><th></th></tr></thead><tbody><tr><td>filter</td><td>MoveDeviceFilter</td><td>Filter devices by type. See bellow.</td></tr><tr><td>uuid</td><td>string</td><td>UUID String required to scan beacons.</td></tr><tr><td>manufacturerId</td><td>int</td><td>Manufacturer ID needed to scan beacons.</td></tr></tbody></table>

Opens a stream which will receive a list of new unique devices scanned. Device scanning will be stopped when the stream is closed.

A list of filters can be specified to filter which devices to scan for:

<table><thead><tr><th width="193">MoveDeviceFilter</th><th></th></tr></thead><tbody><tr><td>paired</td><td>Scan for paired devices. <strong>Default</strong></td></tr><tr><td>connected</td><td>Show the connected devices.</td></tr><tr><td>beacon</td><td>Scan for beacon devices. <code>uuid</code> and <code>manufacturerId</code> required.</td></tr></tbody></table>

### Set MoveDevice Connection State Listener

{% hint style="info" %}
Since MOVE SDK v2.10.0
{% endhint %}

Set a [MoveDevice](/move-platform/sdk/models/movedevice#flutter) connection state listener to be fired when the Bluetooth connection state of a previously registered [MoveDevice](/move-platform/sdk/models/movedevice#flutter) has changed.

```dart
Stream<List<MoveDevice>> setDeviceStateListener() async*
```

| **Parameters**                                                                                 |                                                                                                                         |
| ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| listener -> [MoveDeviceStateListener](/move-platform/sdk/models/listeners-callbacks#flutter-8) | A callback returning the [MoveDevice](/move-platform/sdk/models/movedevice#flutter) which connection state was changed. |

### Get Registered Devices

Get a list of devices ([MoveDevice](/move-platform/sdk/models/movedevice#flutter)) registered to be discovered during trips.

```dart
Future<List<MoveDevice>> getRegisteredDevices() async
```

### Register Devices

Register devices ([MoveDevice](/move-platform/sdk/models/movedevice#flutter)) to be discovered during trips.

```dart
Future<void> registerDevices(List<MoveDevice> devices) async
```

### Register Beacon Service

Register a beacon service identifier ([MoveDevice](/move-platform/sdk/models/movedevice#flutter)) to be discovered during trips.

```dart
Future<void> registerService(String uuid) async
```

### Unregister Devices

Unregister devices ([MoveDevice](/move-platform/sdk/models/movedevice#flutter)) to be discovered during trips.

```dart
Future<void> unregisterDevices(List<MoveDevice> devices) async
```

{% hint style="info" %}
Since MOVE SDK v2.13: Devices are persisted after [shutdown](/move-platform/sdk/api-interface/flutter/initialization#shutdown-sdk).
{% endhint %}

### Discover Devices

```dart
Stream<List<MoveScanResult>> setDeviceDiscoveryListener() async*
```

Opens a stream to receive updates when devices are scanned for during trips. See [MoveScanResult](/move-platform/sdk/models/movescanresult#flutter).

### Health Listener

Opens a stream to receive updates when values of MoveHealthItems changed. See MoveHealtItem (iOS) / MoveHealthScore (Android).

```dart
Stream<List<MoveHealthItem>> setHealthListener() async*
```

### **Get Configuration**

Gets the current used Move configuration set in setup/update or configuration. If options flag `useBackendConfig` is set returns configuration set in dashboard.&#x20;

{% hint style="info" %}
Since MOVE SDK v2.16
{% endhint %}

```dart
Future<MoveConfig> getMoveConfig() async
```

| **Return**                                         |                                                                                                        |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| [MoveConfig](/move-platform/sdk/models/moveconfig) | Move Configuration passed in setup/update or configuration from backend if *useBackendConfig* is set.. |

### **Step Counter**

{% hint style="info" %}
Since MOVE SDK v2.14
{% endhint %}

Should you require the Steps permission for the Health service there is a convenience function to request it:

```dart
Future<bool> requestHealthPermissions() async
```

{% hint style="warning" %}
Since MOVE SDK v2.16 HealthKit integration for is available on demand only. Contact us for support.
{% endhint %}


# Models


# Listeners/Callbacks

MOVE Models

{% tabs %}
{% tab title="Android" %}
**Threading:** Callbacks may be delivered on any thread. Always use `runOnUiThread {}` or `lifecycleScope.launch(Dispatchers.Main)` before updating UI from within any callback.
{% endtab %}

{% tab title="Flutter" %}
**Threading:** Callbacks are delivered as Streams. Use `StreamBuilder` or `listen()` to consume them. No manual thread switching required.
{% endtab %}
{% endtabs %}

## SDK State Listener

Triggers whenever the [MoveSDKState](/move-platform/sdk/models/movesdkstate) changes.

{% hint style="info" %}
Set an MOVE SDK State listener using`sdkStateListener`([Android](https://docs.movesdk.com/move-platform/sdk/models/pages/-MZIfp4AHvpUSOaycA60#DolphinSdk.Builderv1.1-sdkstatelistenerSdkstatelistener)/[iOS](/move-platform/sdk/api-interface/ios/services#set-sdk-state-listener)) API to anticipate handling the MOVE SDK State changes, start detection services when [MoveSDKState](/move-platform/sdk/models/movesdkstate) is `.ready` or handle`.error` if occurred.
{% endhint %}

{% hint style="warning" %}
**React Native only**: For android platform it is necessary to start listen explicitly by calling:

```typescript
if (Platform.OS === 'android') {
    MoveSdk.startNativeSdkStateListener();
}
```

{% endhint %}

{% tabs %}
{% tab title="Android" %}

```kotlin
interface StateListener {
    fun onStateChanged(sdk: MoveSdk, state: MoveSdkState)
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
typealias MoveSDKStateCallback = (_ state: MoveSDKState) -> Void

typealias AsyncMoveSDKStateCallback = (_ state: MoveSDKState) async -> Void
```

{% endtab %}

{% tab title="React Native" %}

```typescript
static addSdkStateListener(sdkStateChanged: (state: SdkState) => void): ListenerSubscription;
```

{% endtab %}

{% tab title="Flutter" %}

```dart
Stream<MoveState> setSdkStateListener()
```

{% endtab %}
{% endtabs %}

| **Parameter**                                          |                                                                |
| ------------------------------------------------------ | -------------------------------------------------------------- |
| [MoveSDKState](/move-platform/sdk/models/movesdkstate) | Latest [MoveSDKState](/move-platform/sdk/models/movesdkstate). |

## Auth State Update Listener

Triggers whenever the [MoveAuthState](/move-platform/sdk/models/moveauth) changes.

{% hint style="warning" %}

### Authentication Expiry

The host app is expected to monitor [MoveAuthState](/move-platform/sdk/models/moveauthstate) updates via `authStateUpdateListener` API and handle those changes accordingly.

Check [Authentication updates and expiry](/move-platform/sdk/models/moveauthstate#authentication-updates-and-expiry) for more details about authentication expiry and renewal.
{% endhint %}

{% tabs %}
{% tab title="Android" %}

```kotlin
interface AuthStateUpdateListener {
    fun onAuthStateUpdate(state: MoveAuthState)
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
typealias MoveAuthStateCallback = (_ state: MoveAuthState) -> Void

typealias AsyncMoveAuthStateCallback = (_ state: MoveAuthState) async -> Void
```

{% endtab %}

{% tab title="React Native" %}

```typescript
static addAuthStateListener(authStateChanged: (event: AuthStateEvent) => void): ListenerSubscription;
```

{% endtab %}

{% tab title="Flutter" %}

```dart
Stream<MoveAuthState> setAuthStateListener()
```

{% endtab %}
{% endtabs %}

| **Parameter**                                            |                                                                  |
| -------------------------------------------------------- | ---------------------------------------------------------------- |
| [MoveAuthState](/move-platform/sdk/models/moveauthstate) | Latest [MoveAuthState](/move-platform/sdk/models/moveauthstate). |

## Trip State Listener

Triggers whenever the [MoveTripState](/move-platform/sdk/models/movetripstate) changes.

{% tabs %}
{% tab title="Android" %}

```kotlin
interface TripStateListener {
    fun onTripStateChanged(sdk: MoveSdk, tripState: MoveTripState)
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
typealias MoveTripStateCallback = (_ tripState: MoveTripState) -> Void

typealias AsyncMoveTripStateCallback = (_ tripState: DolphinMoveSDK.MoveTripState) async -> Void
```

{% endtab %}

{% tab title="React Native" %}

```typescript
static addTripStateListener(tripStateChanged: (state: TripState) => void): ListenerSubscription;
```

{% endtab %}

{% tab title="Flutter" %}

```dart
Stream<MoveTripState> setTripStateListener()
```

{% endtab %}
{% endtabs %}

| **Parameter**                                            |                                                                  |
| -------------------------------------------------------- | ---------------------------------------------------------------- |
| [MoveTripState](/move-platform/sdk/models/movetripstate) | Latest [MoveTripState](/move-platform/sdk/models/movetripstate). |

## Trip Start Listener

Triggers whenever a trip actually starts.

{% tabs %}
{% tab title="Android" %}

```kotlin
interface TripStartListener {
    fun onTripStarted(startDate: Date)
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
typealias MoveTripStartCallback = (_ startDate: Date) -> Void

typealias AsyncMoveTripStartCallback = (_ startDate: Date) async -> Void
```

{% endtab %}

{% tab title="React Native" %}

```typescript
MoveSdk.addTripStartListener(tripStartTriggered: (start: Date) => void): ListenerSubscription;
```

{% endtab %}

{% tab title="Flutter" %}

```dart
Stream<DateTime> setTripStartListener()
```

{% endtab %}
{% endtabs %}

| **Parameter**   |                                    |
| --------------- | ---------------------------------- |
| Date / DateTime | The actual start time of the trip. |

## Trip Metadata Provider

This triggers whenever a trip is ending, allowing the host app to append metadata along with that trip if needed.

{% hint style="info" %}
Trip Metadata is only available for car, cycling, train, tram, metro, and bus items. Metadata is also unavailable if public transport data is sourced from POIs.
{% endhint %}

{% tabs %}
{% tab title="Android" %}

```kotlin
interface TripMetadataProvider {
    fun provideMetadata(start: Long, end: Long): Map<String, String>
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
typealias MoveMetaDataCallback = (_ tripStart: Date, _ tripEnd: Date) -> [String: String]
```

{% endtab %}
{% endtabs %}

| **Parameter**     | **Type**    |                              |
| ----------------- | ----------- | ---------------------------- |
| start / tripStart | Long / Date | Trip start timestamp / date. |
| end / tripEnd     | Long / Date | Trip end timestamp / date.   |

| **Return**                                  |
| ------------------------------------------- |
| A String dictionary of the trip's metadata. |

## Service Failure Callback

Triggers whenever [MoveServiceFailures](/move-platform/sdk/models/moveservicefailure) change.

{% tabs %}
{% tab title="Android" %}

```kotlin
interface MoveErrorListener {
    fun onMoveError(serviceFailures: List<MoveServiceFailure>)
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
typealias MoveServiceFailureCallback = (_ permissions: [MoveServiceFailure]) -> Void

typealias AsyncMoveServiceFailureCallback = (_ permissions: [MoveServiceFailure]) async -> Void
```

{% endtab %}

{% tab title="React Native" %}

```typescript
static addErrorsListener(errorsReceived: (errors: ErrorListType) => void): ListenerSubscription;
```

{% endtab %}

{% tab title="Flutter" %}

```dart
Stream<List<MoveServiceError>> setServiceErrorListener()
```

{% endtab %}
{% endtabs %}

| **Parameter**                                                                                                     |                                                                              |
| ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| <p><a href="/move-platform/sdk/models/moveservicefailure">MoveServiceFailure</a><br>Flutter: MoveServiceError</p> | List of [MoveServiceFailures](/move-platform/sdk/models/moveservicefailure). |

## Service Warning Callback

Triggers whenever [MoveServiceWarnings](/move-platform/sdk/models/moveservicewarning) change.

{% tabs %}
{% tab title="Android" %}

```kotlin
interface MoveWarningListener {
    fun onMoveWarning(serviceWarnings: List<MoveServiceWarning>)
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
typealias MoveServiceWarningCallback = (_ permissions: [MoveServiceWarning]) -> Void

typealias AsyncMoveServiceWarningCallback = (_ permissions: [MoveServiceWarning]) async -> Void
```

{% endtab %}

{% tab title="React Native" %}

```typescript
static addWarningsListener(warningsReceived: (warnings: ErrorListType) => void): ListenerSubscription;
```

{% endtab %}

{% tab title="Flutter" %}

```dart
Stream<List<MoveServiceWarning>> setServiceWarningListener()
```

{% endtab %}
{% endtabs %}

| **Parameter**                                                      |                                                                              |
| ------------------------------------------------------------------ | ---------------------------------------------------------------------------- |
| [MoveServiceWarning](/move-platform/sdk/models/moveservicewarning) | List of [MoveServiceWarnings](/move-platform/sdk/models/moveservicewarning). |
|                                                                    |                                                                              |

## Initialization Listener

Represents the potential errors occurring when updating the [MoveAuth](/move-platform/sdk/models/moveauth).

{% tabs %}
{% tab title="Android" %}

```kotlin
interface InitializeListener {
    fun onError(error: MoveConfigurationError)
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
typealias MoveInitializationCallback = (_ error: MoveConfigurationError) -> Void
```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="130">Parameter</th><th width="216"></th><th></th></tr></thead><tbody><tr><td><strong>Parameter</strong></td><td><strong>Type</strong></td><td></td></tr><tr><td>error</td><td><a href="/move-platform/sdk/models/moveconfigurationerror">MoveConfigurationError</a></td><td><p>An error to notify when the configuration could </p><p>not be loaded from the server.</p></td></tr></tbody></table>

## Log Callback

Triggers whenever a new log event occurs.

{% tabs %}
{% tab title="Android" %}

```kotlin
interface MoveLogCallback {
    fun onLogReceived(eventName: String, value: String?)
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
typealias MoveLogCallback = (_ log: String, _ value: String) -> Void

typealias AsyncMoveLogCallback = (_ event: String, _ value: String?) async -> Void
```

{% endtab %}

{% tab title="React Native" %}

```typescript
static addLogListener(logReceived: (event: MoveSdkLog) => void): ListenerSubscription;

export type MoveSdkLog = {
  message: string;
  value?: string;
};
```

{% endtab %}

{% tab title="Flutter" %}
Stream setLogListener()
{% endtab %}
{% endtabs %}

| **Parameter** | **Type** |                     |
| ------------- | -------- | ------------------- |
| log           | String   | New log event.      |
| value         | String   | Log value. Optional |

The SDK will trigger log messages to improve debugging.

## Remote Config Change Listener

{% hint style="info" %}
Since MOVE SDK v2.5
{% endhint %}

Will be triggered when the [MoveConfig](/move-platform/sdk/models/moveconfig) was successfully fetched from the server via [updateConfig](/move-platform/sdk/api-interface/android/services#update-config) (Android) / [update](/move-platform/sdk/api-interface/ios/setup#update-config) (iOS).

If the MoveConfig object couldn't be fetched from the server then a [MoveConfigurationError](/move-platform/sdk/models/moveconfigurationerror) ServiceUnreachable will be triggered.

{% tabs %}
{% tab title="Android" %}

```kotlin
interface RemoteConfigChangeListener {
    fun onConfigChanged(config: MoveConfig)
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
typealias MoveRemoteConfigChangeCallback = (_ config: MoveConfig) -> Voidstatic addConfigChange(warningsReceived: (warnings: ErrorListType) => void): ListenerSubscription

typealias AsyncMoveRemoteConfigChangeCallback = (_ config: DolphinMoveSDK.MoveConfig) async -> Void
```

{% endtab %}

{% tab title="React Native" %}

```typescript
static addRemoteConfigChangeListener(configChangeReceived: (config: Array<IssueListService>) => void): ListenerSubscription
```

{% endtab %}

{% tab title="Flutter" %}

```dart
Stream<MoveConfig> setRemoteConfigChangeListener()
```

{% endtab %}
{% endtabs %}

## Setup Authorization Callback

{% hint style="info" %}
Since MOVE SDK v2.9
{% endhint %}

Will return the success or failure of the internal MOVE SDK authentication process during [setup](/move-platform/sdk/api-interface/android/initialization#setup). (also see [MoveAuthResult](/move-platform/sdk/models/moveauthresult))

{% tabs %}
{% tab title="Android" %}

```kotlin
interface MoveAuthCallback {
    fun onResult(result: MoveAuthResult)
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
typealias MoveAuthCallback = (_ result: MoveAuthResult) -> Void

typealias AsyncMoveAuthCallback = (_ result: DolphinMoveSDK.MoveAuthResult) async -> Void
```

{% endtab %}

{% tab title="React Native" %}

{% endtab %}

{% tab title="Flutter" %}

```dart
Future<MoveAuthResult> setupWithCode(
    String authCode,
    MoveConfig moveConfig,
    MoveOptions? options,
  )
```

{% endtab %}
{% endtabs %}

## Device Discovery Listener

{% hint style="info" %}
Since MOVE SDK v2.4
{% endhint %}

Will be triggered during a [BDD - Device Discovery](/move-platform/move-services#bdd-device-discovery) scan.&#x20;

{% tabs %}
{% tab title="Android" %}

```kotlin
interface DeviceDiscoveryListener {
    fun onScanResult(results: List<MoveScanResult)
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
typealias MoveDeviceDiscoveryCallback = (_ results: [MoveScanResult]) -> Void

typealias AsyncMoveDeviceDiscoveryCallback = (_ results: [DolphinMoveSDK.MoveScanResult]) async -> Void
```

{% endtab %}

{% tab title="React Native" %}

```typescript
static addDeviceDiscoveryListener(onScanResult: (state: Array<MoveScanResult>) => void): ListenerSubscription
```

{% endtab %}

{% tab title="Flutter" %}

```dart
Stream<List<MoveScanResult>> setDeviceDiscoveryListener()
```

{% endtab %}
{% endtabs %}

| **Parameter** |                                                                      |
| ------------- | -------------------------------------------------------------------- |
| results       | List of [MoveScanResult](/move-platform/sdk/models/movescanresult)'s |

## MoveDevice State Listener / Callback

{% hint style="info" %}
Since MOVE SDK v2.10.0
{% endhint %}

Will be triggered when the status of a registered [MoveDevice](/move-platform/sdk/models/movedevice) changes. This [MoveDevice](/move-platform/sdk/models/movedevice) must be previously registered. See chapters "Register Device" ([Android](/move-platform/sdk/api-interface/android/services#register-device), [iOS](/move-platform/sdk/api-interface/ios/services#register-device))

{% tabs %}
{% tab title="Android" %}

```kotlin
interface MoveDeviceStateListener {
    fun onStateChanged(device: MoveDevice)
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
public typealias MoveDeviceStateCallback = (_ results: [MoveDevice]) -> Void

typealias AsyncMoveDeviceStateCallback = (_ results: [DolphinMoveSDK.MoveDevice]) async -> Void
```

{% endtab %}

{% tab title="React Native" %}

```typescript
static addDeviceStateListener(onScanResult: (results: Array<MoveSdkDevice>) => void): ListenerSubscription
```

{% endtab %}

{% tab title="Flutter" %}

```dart
Stream<List<MoveDevice>> setDeviceStateListener()
```

{% endtab %}
{% endtabs %}

## SDK Health Listener / Callback

{% hint style="info" %}
Since MOVE SDK v2.11.0
{% endhint %}

Will be triggered when the health score of the MOVE SDK changes. A [MoveHealthItem](/move-platform/sdk/models/movehealthitem) (iOS, React Native) / [MoveHealthScore](/move-platform/sdk/models/movehealthscore) (Android) with the current data is provided.

{% tabs %}
{% tab title="Android" %}

```kotlin
interface MoveHealthScoreListener {
    fun onMoveHealthScoreChanged(score: MoveHealthScore)
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
typealias MoveHealthScoreCallback = (_ result: [MoveHealthItem]) -> Void

typealias AsyncMoveHealthScoreCallback = (_ result: [DolphinMoveSDK.MoveHealthItem]) async -> Void
```

{% endtab %}

{% tab title="React Native" %}

```typescript
static addHealthListener(scoreReceived: (health: MoveHealthScore) => void): ListenerSubscription
```

{% endtab %}

{% tab title="Flutter" %}

```dart
Stream<List<MoveHealthItem>> setHealthListener()
```

{% endtab %}
{% endtabs %}


# MoveAssistanceCallStatus

A callback status for an initiated Assistance Call.

{% tabs %}
{% tab title="Android" %}

```kotlin
enum class MoveAssistanceCallStatus {
    SUCCESS,
    INITIALIZATION_ERROR,
    LOCATION_ERROR, // Deprecated with v2.3+
    NETWORK_ERROR
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
enum MoveAssistanceCallStatus {
    case success
    case initializationError
    case locationError // Deprecated with v2.4.0+
    case networkError
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:movesdk/io/dolphin/move/move_assistance_call_status.dart';// Some code
```

```dart
enum MoveAssistanceCallStatus {
    success,
    initializationError,
    networkError,
}
```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="270"></th><th></th></tr></thead><tbody><tr><td><strong>MoveAssistanceCallStatus</strong></td><td></td></tr><tr><td>success</td><td>The call was successfully sent</td></tr><tr><td>initializationError</td><td>The call could not be sent because MoveDetectionService.AssistanceCall is unauthorised. (see <a href="/move-platform/sdk/models/moveconfig">MoveConfig</a>)</td></tr><tr><td><del>locationError</del></td><td>The call could not be sent due to missing location. <em><strong>Deprecated with v2.3+</strong></em></td></tr><tr><td>networkError</td><td>The call could not be sent due to network issues.</td></tr></tbody></table>


# MoveAuth

MOVE Models

The [MoveAuth ](/move-platform/sdk/models/moveauth)object is used to validate the usage of the MOVE SDK and configure its services according to project specifications.

{% tabs %}
{% tab title="Android" %}

```kotlin
data class MoveAuth(
    var projectId: Long,
    var userId: String,
    var accessToken: String,
    var refreshToken: String
)
```

{% endtab %}

{% tab title="iOS" %}

```swift
struct MoveAuth {
    var userToken: String
    var refreshToken: String
    var userID: String
    var projectID: Int
}
```

{% endtab %}

{% tab title="React Native" %}

```javascript
export type MoveSdkAuth = {
  userId: string;
  accessToken: string;
  refreshToken: string;
  projectId: number;
};
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:movesdk/io/dolphin/move/move_auth.dart';
```

```dart
class MoveAuth {
  String projectId;
  String userId;
  String accessToken;
  String refreshToken;
}
```

{% endtab %}
{% endtabs %}

| **MoveAuth** | **Type**               |                                                                                                                                      |
| ------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| accessToken  | String                 | User's session-based access token.                                                                                                   |
| refreshToken | String                 | User's session-based refresh token.                                                                                                  |
| userID       | String                 | Unique identifier of the user.                                                                                                       |
| projectID    | String / Android: Long | Unique identifier of the MOVE project. Can be obtained from the [MOVE Dashboard](/move-platform/sdk/getting-started/move-dashboard). |

{% hint style="warning" %}

### Authentication Expiry

Since MOVE SDK v2.6.7, token refresh is handled automatically and internally by the SDK.
{% endhint %}

| **MoveAuth related**        |                                                                                                           |
| --------------------------- | --------------------------------------------------------------------------------------------------------- |
| `authStateUpdateListener()` | Block to be invoked every time MOVE SDK [MoveAuthState](/move-platform/sdk/models/moveauthstate) changes. |
| `getAuthState()`            | Gets the current [MoveAuthState](/move-platform/sdk/models/moveauthstate).                                |


# MoveAuthError

MOVE Models

{% hint style="danger" %}
**Deprecated:** update(auth:) was deprecated.
{% endhint %}

Represents the potential errors occurring when updating the [MoveAuth](/move-platform/sdk/models/moveauth).

{% tabs %}
{% tab title="Android" %}

```kotlin
sealed class MoveAuthError {
    object AuthInvalid : MoveAuthError()
    object Throttle : MoveAuthError()
    object ServiceUnreachable : MoveAuthError()
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
@available(*, deprecated, message: "update(auth:) was deprecated.")
enum MoveAuthError {  
    case authInvalid 
    case throttle
    case serviceUnreachable
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:movesdk/io/dolphin/move/move_auth_error.dart';
```

```dart
@Deprecated('obsolete')
enum MoveAuthError {
    authInvalid,
    throttle,
    serviceUnreachable,
}
```

{% endtab %}
{% endtabs %}

| **MoveAuthError**  |                                                               |
| ------------------ | ------------------------------------------------------------- |
| authInvalid        | Indicates that the passed auth is not the same used in setup. |
| throttle           | Update called too often. Limit: 5 times per minute.           |
| serviceUnreachable | Bad connection or service failure                             |

| **MoveAuthError related** |                                                                                  |
| ------------------------- | -------------------------------------------------------------------------------- |
| Update Auth               | For more info about updating the [MoveAuth](/move-platform/sdk/models/moveauth). |


# MoveAuthResult

MOVE Models

{% tabs %}
{% tab title="Android" %}

```kotlin
data class MoveAuthResult(
    val status: AuthSetupStatus,
    val description: String,
)

enum class AuthSetupStatus {
    SUCCESS,
    INVALID_CODE,
    NETWORK_ERROR;
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
enum MoveAuthResult {
    case success
    case networkError(String)
    case invalidCode(String)
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
enum AuthSetupStatus {
  success,
  networkError,
  invalidCode,
}

class MoveAuthResult {
  AuthSetupStatus status;
  String description;
}
```

{% endtab %}
{% endtabs %}

| MoveAuthResult |                                                                 |
| -------------- | --------------------------------------------------------------- |
| status         | see MoveAuthStatus                                              |
| description    | A slightly more descriptive description of the success / error. |

| MoveAuthStatus |                                                                                            |
| -------------- | ------------------------------------------------------------------------------------------ |
| success        | Code was accepted by the backend. Authentication is valid.                                 |
| invalid\_code  | <p>Authentication is invalid.</p><p>e.g. Code is empty, invalid or expired</p>             |
| network\_error | <p>A network error was triggered.<br>e.g. Client error, Server exception, timeout, ...</p> |


# MoveAuthState

MOVE Models

{% hint style="info" %}
**Note:** When `INVALID` is received, the SDK remains in its current MoveSdkState (`RUNNING` or `READY`). However, all backend requests will be rejected until the issue is resolved. The host app should call `shutdown(force:true)` and re-register the user.
{% endhint %}

Returns the current MOVE SDK Authentication State.

{% tabs %}
{% tab title="Android" %}

```kotlin
enum class MoveAuthState {
    UNKNOWN,
    VALID,
    INVALID,
    @Deprecated("Do not use this state in your code")
    EXPIRED(MoveAuth)
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
enum MoveAuthState {
    case unknown
    
    @available(*, deprecated, message: "Token expiry was removed.")
    case expired
    
    case valid
    
    case invalid
}
```

{% endtab %}

{% tab title="React Native" %}

```javascript
export type AuthState = 'UNKNOWN' | 'VALID' | 'INVALID' | 'EXPIRED';
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:movesdk/io/dolphin/move/move_auth_state.dart';
```

```dart
enum MoveAuthState {
  unknown,
  
  @Deprecated('obsolete')
  expired,
  
  invalid,
  
  valid,
}
```

{% endtab %}
{% endtabs %}

| MoveAuthState                                           |                                                                                                                                |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| expired([MoveAuth](/move-platform/sdk/models/moveauth)) | Latest [MoveAuth](/move-platform/sdk/models/moveauth) expired and the MOVE SDK can't refresh it. **Deprecated in SDK v2.6.7**. |
| valid                                                   | Authentication is valid.                                                                                                       |
| invalid                                                 | Authentication is invalid. e.g. User has logged in on multiple devices. **New since SDK v2.4**                                 |
| unknown                                                 | MOVE SDK auth state is pending, and will be updated when the server is contacted. The app should ignore this state.            |

{% hint style="warning" %}
**If the MoveAuthState is invalid the MOVE backend no longer accepts MOVE SDK requests from this host app.**
{% endhint %}

### Authentication updates and invalidation

[MoveAuth](/move-platform/sdk/models/moveauth) is session-based, hence it expires and requires to be renewed. For simplicity, the MOVE SDK handles refreshing the token for the host app whenever it expires.

In case the MOVE SDK fails to refresh authentication, because of a conflicting login on another device, or because the user was blocked on the backend, it will trigger `MoveAuthState.invalid`. The host app is expected to logout the user and call`shutdown(force: true)`([Android](/move-platform/sdk/api-interface/android/services#shutdown-sdk) / [iOS](/move-platform/sdk/api-interface/ios/setup#shutdown)).

{% hint style="warning" %}

#### Authentication Updates

The host app is responsible for monitoring `MoveAuthState` updates and handling its state updates by:

* `.invalid`: The MOVE SDK has invalidated its internal user token at once. e.g. User has logged in on multiple devices. If necessary the host app has to register the user again (see [register - MOVE Admin API](/move-platform/backend/move-backend/move-admin-api#gettingstartedwiththedolphinmovetimelineservice-authentication-1)).
  {% endhint %}

| MoveAuthState related APIs                                                                                                                                                                                                                                                                                                                                                                                                           |                                                                                                  |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ |
| `authStateUpdateListener` ([Android](https://docs.movesdk.com/move-platform/sdk/models/pages/-MZIfp4AHvpUSOaycA60#dolphinsdk.builderv1.1-initializationinitializationlistener-1) / [iOS](/move-platform/sdk/api-interface/ios/setup#set-sdk-auth-state-listener) / [React](/move-platform/sdk/api-interface/react-native/services#set-sdk-auth-state-listener) / [Flutter](/move-platform/sdk/models/listeners-callbacks#flutter-1)) | Block to be invoked every time [MoveAuthState](/move-platform/sdk/models/moveauthstate) changes. |


# MoveConfig

MOVE Models

The MOVE SDK offers to detect different modes of transport and driving services. The host app can configure which driving services to activate and modes of transport to detect by setting the [MoveConfig](/move-platform/sdk/models/moveconfig) object when initializing the MOVE SDK.

{% hint style="warning" %}
**The host app can only configure its MOVE SDK services to the set or subset of services subscribed** by the MOVE project ID in the [MOVE dashboard](/move-platform/sdk/getting-started/move-dashboard). You will get a failure list with [MoveError.Unauthorized](/move-platform/sdk/models/moveservicefailure) error if services are not configured.
{% endhint %}

{% tabs %}
{% tab title="Android" %}

```kotlin
data class MoveConfig(
    var moveDetectionServices: List<MoveDetectionService> = emptyList(),
)

...

sealed class MoveDetectionService {
    class Driving(val drivingServices: List<DrivingService>? = null) : MoveDetectionService()
    object Cycling : MoveDetectionService()
    class Walking(val walkingServices: List<WalkingService>? = null) : MoveDetectionService()
    object Places : MoveDetectionService()
    object PublicTransport : MoveDetectionService()
    object PointsOfInterest : MoveDetectionService()
    object AutomaticImpactDetection : MoveDetectionService()
    object AssistanceCall : MoveDetectionService()
    object Health : MoveDetectionService()
}
    
```

{% endtab %}

{% tab title="iOS" %}

```swift
struct MoveConfig {
    enum DetectionService {
        case driving([DrivingService])
        case cycling
        case walking([WalkingService])
        case places
        case publicTransport
        case pointsOfInterest
        case automaticImpactDetection
        case assistanceCall
        case health
    }

    enum DrivingService {
        case drivingBehavior
        case distractionFreeDriving
        case deviceDiscovery
    }
    
    enum WalkingService {
        case location
    }
 
    var detectionServices: [TimelineDetectionService]
}
```

{% endtab %}

{% tab title="React Native" %}

```javascript
export type MoveSdkConfig = {
  timelineDetectionServices: TimelineDetectionService[];
  drivingServices: DrivingService[];
  walkingServices: WalkingService[];
};
export type DrivingService = 'DISTRACTION_FREE_DRIVING' | 'DRIVING_BEHAVIOUR' | 'DEVICE_DISCOVERY';
export type WalkingService = 'LOCATION';
export type TimelineDetectionService =
  | 'DRIVING'
  | 'CYCLING'
  | 'WALKING'
  | 'PUBLIC_TRANSPORT'
  | 'AUTOMATIC_IMPACT_DETECTION'
  | 'ASSISTANCE_CALL'
  | 'POINTS_OF_INTEREST'
  | 'HEALTH';
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:movesdk/io/dolphin/move/move_detection_service.dart';
```

```dart
enum MoveDetectionService {
  assistanceCall,
  automaticImpactDetection,
  cycling,
  driving,
  distractionFreeDriving,
  drivingBehaviour,
  deviceDiscovery,
  health,
  places,
  pointsOfInterest,
  publicTransport,
  walking,
}

final moveConfig = MoveConfig([
  MoveDetectionService.driving,
  MoveDetectionService.drivingBehaviour,
  MoveDetectionService.distractionFreeDriving,
  MoveDetectionService.cycling,
  MoveDetectionService.walking,
  MoveDetectionService.automaticImpactDetection,
  MoveDetectionService.assistanceCall,
  // ...
]);
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Please check also the platform specific configuration pages ([Android](/move-platform/sdk/api-interface/android/initialization) / [iOS](/move-platform/sdk/api-interface/ios/intialization)).
{% endhint %}

<table data-header-hidden><thead><tr><th width="209.33333333333331">MoveConfig</th><th width="246"></th><th></th></tr></thead><tbody><tr><td><strong>MoveConfig</strong></td><td></td><td></td></tr><tr><td><strong>DetectionServices</strong></td><td></td><td>List of required modes of transportation to be detected.</td></tr><tr><td></td><td>driving</td><td>Detect the driving activity.</td></tr><tr><td></td><td>cycling</td><td>Detect the cycling activity.</td></tr><tr><td></td><td>walking</td><td>Detect the walking activity.</td></tr><tr><td></td><td>places</td><td>Detect places where user spent time.<br><strong>Note:</strong> This feature is not publicly available.</td></tr><tr><td></td><td>publicTransport</td><td>Detect public transport trips</td></tr><tr><td></td><td>pointsOfInterest</td><td>Monitor and track points of interest </td></tr><tr><td></td><td>automaticImpactDetection</td><td>Detect impacts while driving or as stand alone service.</td></tr><tr><td></td><td>assistanceCall</td><td>Enable assistance call.</td></tr><tr><td><strong>DrivingServices</strong></td><td></td><td>List of required driving services to be detected.</td></tr><tr><td></td><td>distractionFreeDriving</td><td>Detect the user's distraction-free driving duration during a trip.</td></tr><tr><td></td><td>drivingBehavior</td><td>Detect the user's driving behavior during a trip.</td></tr><tr><td></td><td>deviceDiscovery</td><td>Scanning for registered devices during a trip. (since MOVE SDK v2.4)</td></tr><tr><td><strong>WalkingServices</strong></td><td>location</td><td><strong>Note:</strong> This feature is not publicly available.</td></tr></tbody></table>

{% hint style="info" %}
Each [MoveConfig](/move-platform/sdk/models/moveconfig) requires one or more permissions (see for [Android](/move-platform/sdk/appendix/android/permission-handling) and [iOS](/move-platform/sdk/appendix/ios/permission-handling)). **Individual MOVE SDK services will not function without the required permissions.** Check [MoveSDKState](/move-platform/sdk/models/movesdkstate) for more details.
{% endhint %}


# MoveConfigurationError

MOVE Models

{% tabs %}
{% tab title="Android" %}

```kotlin
sealed class MoveConfigurationError {
    object ServiceUnreachable : MoveConfigurationError()
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
enum MoveConfigurationError {   
    case serviceUnreachable
}
```

{% endtab %}
{% endtabs %}

| **Move Configuration Error** |                                   |
| ---------------------------- | --------------------------------- |
| ServiceUnreachable           | Bad connection or service failure |


# MoveDevice

MOVE Models

{% hint style="info" %}
Since MOVE SDK v2.4
{% endhint %}

MoveDevice is used to register / unregister relevant car audio devices and beacons if the optional [BDD - Device Discovery](/move-platform/move-services#bdd-device-discovery) feature is configured with setup(...). It is also used when the relevant scan results are delivered to the host app.

{% hint style="warning" %}
Till MOVE SDK v2.12.0: After a .shutdown() the previous registered devices will be unregistered.
{% endhint %}

{% hint style="warning" %}
Since MOVE SDK v2.13.0: The registered Bluetooth devices will be stored in the SDK Backend. After a re-registration / login with the same userId the registered Bluetooth devices are available again.
{% endhint %}

{% tabs %}
{% tab title="Android" %}

```kotlin
class MoveDevice internal constructor(
    val id: String,
    val name: String,
    val manufacturerId: Int? = null,
    val isConnected: Boolean = false,
    val uuid: String? = null,
    val major: Int? = null,
    val minor: Int? = null,
    val state: MoveDeviceState = MoveDeviceState.NOT_SYNCHRONIZED,
    val displayName: String = "",
)
```

{% endtab %}

{% tab title="iOS" %}

```swift
public class MoveDevice {
    public var id: String
    public var name: String
    public var displayName: String
    public var isConnected: Bool
    public var state: MoveDeviceState

    public init(name: String, id: String)
    public init(name: String, proximityUUID: UUID, major: UInt16, minor: UInt16)
    public init(proximityUUID: UUID)
}
```

{% endtab %}

{% tab title="React Native" %}

```typescript
export type MoveSdkDevice = {
    name: string;
    displayName: string;
    data: string;
    id: string;
    isConnected?: boolean;
    state?: MoveSdkDeviceState;
};
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:movesdk/io/dolphin/move/move_device.dart';
```

```dart
class MoveDevice {
  String name;
  String data;
  bool isConnected;
  String displayName;
  MoveDeviceState state;
}
```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="270.55859375">MoveDevice</th><th width="162.10546875"></th><th></th></tr></thead><tbody><tr><td><strong>MoveDevice</strong></td><td><strong>Type</strong></td><td></td></tr><tr><td>id</td><td>String</td><td>A device identifier to uniquely identify the device i.e: MAC address. This is used for equality checks. This id is sent to the server during trip device discovery.<br><strong>Note:</strong> For Classic Bluetooth devices, the Bluetooth device must be paired with the phone before registration. BLE Beacons do not require pairing.</td></tr><tr><td>name</td><td>String</td><td>The name of the device.</td></tr><tr><td>displayName</td><td>String</td><td><p><em>Since MOVE SDK 2.17.0</em></p><p>An editable custom name for the device. defaults to name.</p></td></tr><tr><td>manufacturerId <strong>(Android only)</strong></td><td>Integer</td><td>A company identification of the beacon. You can find a list of companies at <a href="https://www.bluetooth.com/specifications/assigned-numbers/">www.bluetooth.com</a>.</td></tr><tr><td>data <strong>(Flutter/React only)</strong></td><td>String</td><td>Opaque data field to convert to native object.</td></tr><tr><td>isConnected</td><td>Boolean</td><td><p><em>Since MOVE SDK v2.9.1</em></p><p>The connection state of the registered MoveDevice. Will be updated via the <a href="/move-platform/sdk/models/listeners-callbacks#movedevice-state-listener-callback">deviceStateListener</a>.</p></td></tr><tr><td>uuid</td><td>String</td><td><p><em>Since MOVE SDK v2.13.0</em></p><p>Universally Unique Identifier of a group of beacons.</p></td></tr><tr><td>major</td><td>Int</td><td><p><em>Since MOVE SDK v2.13.0</em></p><p>The subgroup within a UUID.</p></td></tr><tr><td>minor</td><td>Int</td><td><p>S<em>ince MOVE SDK v2.13.0</em></p><p>Used to identify an individual beacon.</p></td></tr><tr><td>state</td><td><a href="/move-platform/sdk/models/movedevice/movedevicestate">MoveDeviceState</a></td><td><em>Since MOVE SDK 2.17.0</em><br>A state indicating errors during synchronization of the device with the backend.</td></tr></tbody></table>

| **MoveDevice related**                                                                                      |                       |
| ----------------------------------------------------------------------------------------------------------- | --------------------- |
| [Device Discovery Listener](/move-platform/sdk/models/listeners-callbacks#device-discovery-listener)        | Listeners / Callbacks |
| [MoveDevice State Listener](/move-platform/sdk/models/listeners-callbacks#movedevice-state-change-listener) | Listeners / Callbacks |

#### Registering all beacons for a Service UUID

To register all beacons for a specific proximity UUID, register a beacon device with empty *major*, *minor*.

For Android you can use code like:

{% hint style="info" %}
**Note:** `MoveDevice` cannot be instantiated directly. Use the provided factory methods: `createClassicDevice()`, `createBeacon()`, or `createBeacons()`.
{% endhint %}

```kotlin
fun createBeacons(uuid: String): MoveDevice {
    return MoveDevice(
        id = uuid,
        name = "Beacons $uuid",
        manufacturerId = null,
        isConnected = false,
        uuid = uuid,
        major = null,
        minor = null,
        ...
    )
    
...

MoveSdk.get()?.registerDevices(
    listOf(
        MoveDevice.createBeacons("B325A5E9-F12E-4E60-869A-36FEC22A225A")
    )
)
```

For react native there is a helper function:

```typescript
MoveSDK.beaconDevices(serviceUUID)
```

For Flutter:

```dart
// Create a BLE Beacon device
final device = MoveDevice(
  "My Beacon",                                    // name
  '{"uuid":"YOUR-BEACON-UUID","major":1,"minor":1}', // data (JSON)
  false,                                          // isConnected
  "My Beacon Display Name",                       // displayName
  MoveDeviceState.notSynchronized,                // initial state
);

// Register the device
await moveSdk.registerDevices([device]);

// MoveDevice objects are obtained via startScanningDevices().
// For direct registration with a known UUID, use startScanningDevices() 
// with the uuid filter parameter to find the device first.
moveSdk.startScanningDevices(
  filter: [MoveDeviceFilter.beacon],
  uuid: "YOUR-BEACON-UUID",
).listen((items) {
  // Register scanned devices directly
  moveSdk.registerDevices(items);
});

```

{% hint style="info" %}
**Note:** The `data` field must contain a JSON string with the device identifiers. For BLE beacons include `uuid`, `major`, and `minor`. For Classic Bluetooth devices include the MAC address as `id`.
{% endhint %}


# MoveDeviceState

When a device is registered, it is synchronized with the backend so that it will persist across installations. If the device has a malformed identifier it may be rejected by the backend. The device property *state* will reflect this status and the app will be notified via the [deviceStateListener](/move-platform/sdk/models/listeners-callbacks#movedevice-state-listener-callback).

{% tabs %}
{% tab title="Android" %}

```kotlin
enum class MoveDeviceState {
    OK,
    NOT_SYNCHRONIZED,
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
public enum MoveDeviceState {
	case ok
	case notSynchronized
}
```

{% endtab %}

{% tab title="React Native" %}

```typescript
export type MoveSdkDeviceState = 'OK' | 'NOT_SYNCHRONIZED';
```

{% endtab %}

{% tab title="Flutter" %}

```kotlin
enum MoveDeviceState {
  ok,
  notSynchronized,
}
```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="270.55859375">MoveDevice</th><th></th></tr></thead><tbody><tr><td><strong>MoveDevice</strong></td><td></td></tr><tr><td>ok</td><td>No error.</td></tr><tr><td>notSynchronized</td><td>There was an error and the device was not accepted by the backend, possibly due to malformed id.</td></tr></tbody></table>


# MoveDeviceStatus

MOVE Models

{% hint style="info" %}
Android: Deprecated since v2.17.2

iOS: Deprecated since v2.17
{% endhint %}

[MoveDeviceStatus](/move-platform/sdk/models/movedevicestatus) represents the current device's system permissions (for [Android](/move-platform/sdk/appendix/android/permission-handling) / [iOS](/move-platform/sdk/appendix/ios/permission-handling)) and services status.

{% tabs %}
{% tab title="Android" %}

```kotlin
MoveDeviceStatus {  
    isLocationGranted: Boolean
    isBackgroundPermissionGranted: Boolean
    isPreciseLocationGranted: Boolean
    isMotionGranted: Boolean
    isOverlayGranted: Boolean
    isPhoneGranted: Boolean
    isGyroPresent: Boolean
    isAccelerometerPresent: Boolean
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
struct MoveDeviceStatus {   
    var isLocationGranted: Bool
    var isPreciseLocationGranted: Bool
    var isMotionGranted: Bool
    var isGyroPresent: Bool
    var isAccelerometerPresent: Bool
    var isBackgroundPermissionGranted: Bool
    var isDistractionDetectionPossible: Bool
    var isDrivingBehaviourPossible: Bool
}
```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="295">MoveDeviceStatus</th><th width="84"></th><th width="95"></th><th></th></tr></thead><tbody><tr><td><strong>MoveDeviceStatus</strong></td><td><strong>OS</strong></td><td><strong>Type</strong></td><td></td></tr><tr><td>isLocationGranted</td><td>A/iOS</td><td>Boolean</td><td>Indicates if system's location permission is granted.</td></tr><tr><td>isPreciseLocationGranted</td><td>A/iOS</td><td>Boolean</td><td>Indicates if location precision permission is granted (iOS 14), resp. If the location accuracy is high (Android / Google Play Services).</td></tr><tr><td>isMotionGranted</td><td>A/iOS</td><td>Boolean</td><td>Indicates if system's motion(iOS)/activity recognition (Android) permission is granted.</td></tr><tr><td>isGyroPresent</td><td>A/iOS</td><td>Boolean</td><td>Indicates if the device's gyroscope sensor is available. </td></tr><tr><td>isAccelerometerPresent</td><td>A/iOS</td><td>Boolean</td><td>Indicates if the device's accelerometer sensor is available. </td></tr><tr><td>isBackgroundPermissionGranted</td><td>A/iOS</td><td>Boolean</td><td>Indicates if system's background location permission is granted.</td></tr><tr><td>isOverlayGranted</td><td>A</td><td>Boolean</td><td>Indicates if system's overlay permission is granted.</td></tr><tr><td>isDistractionDetectionPossible</td><td>iOS</td><td>Boolean</td><td>Indicates if all the permissions required for the Distraction detection service are granted. Check <a href="/move-platform/sdk/models/moveconfig">Config</a> for more info.</td></tr><tr><td>isDrivingBehaviourPossible</td><td>iOS</td><td>Boolean</td><td>Indicates if all the permissions required for the Driving behaviour service are granted. Check <a href="/move-platform/sdk/models/moveconfig">Config</a> for more info.</td></tr></tbody></table>

| **MoveDeviceStatus related**                                                                                                                                          |                                                                                                |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| getDeviceStatus() (in [Android](/move-platform/sdk/api-interface/android/services#get-device-status) / [iOS](/move-platform/sdk/api-interface/ios#get-device-status)) | Gets the current [MoveDeviceStatus](/move-platform/sdk/models/movedevicestatus)*.*             |
| MoveDeviceStatusCallback (iOS only)                                                                                                                                   | [Device Status Callback](/move-platform/sdk/models/listeners-callbacks#device-status-callback) |


# MoveGeocodeError

Status returned by a geo-lookup.

{% tabs %}
{% tab title="Android" %}

```kotlin
enum class MoveGeocodeError {
    RESOLVE_FAILED,
    SERVICE_UNREACHABLE,
    THRESHOLD_REACHED,
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
enum MoveGeocodeError: Error {
    case resolveFailed
    case thresholdReached
    case serviceUnreachable
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:movesdk/io/dolphin/move/move_geocode_result.dart';// Some code
```

```dart
enum MoveGeocodeError {
    resolveFailed,
    thresholdReached,
    serviceUnreachable,
}
```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="211.5"></th><th></th></tr></thead><tbody><tr><td><strong>MoveGeocodeError</strong></td><td></td></tr><tr><td>resolveFailed</td><td>Error indicating that the passed coordinates can't be resolved.</td></tr><tr><td>thresholdReached</td><td>Maximum defined threshold reached. This threshold is not changeable.</td></tr><tr><td>serviceUnreachable</td><td>Error indicating that MOVE SDK server is unreachable.</td></tr></tbody></table>


# MoveHealthItem

{% hint style="info" %}
**Note:** `MoveHealthScore` is for diagnostic purposes only. It helps identify potential integration issues.
{% endhint %}

{% hint style="info" %}
**Note:** Health monitoring uses platform-specific models. iOS and React Native use `MoveHealthItem`. Android uses `MoveHealthScore`. Flutter uses `MoveHealthItem` with a simplified structure (reason + description only).
{% endhint %}

{% tabs %}
{% tab title="iOS" %}

```swift
struct MoveHealthItem {
    enum Reason: String {
        case batteryLevel
        case cpuUsage
        case diskUsage
        case internetUsage
        case memoryUsage
        case newVersion
        case unimplementedListeners
    }

    let reason: Reason
    let description: String
}

```

{% endtab %}

{% tab title="React Native" %}

```typescript
export type HealthReasons =
  | 'BATTERY_LEVEL'
  | 'CPU_USAGE'
  | 'DISK_USAGE'
  | 'INTERNET_USAGE'
  | 'MEMORY_USAGE'
  | 'NEW_VERSION'
  | 'UNIMPLEMENTED_LISTENERS';
```

```typescript
export type HealthListItem = {
  reason: HealthReasons;
  description: string;
};
```

{% endtab %}

{% tab title="Flutter" %}

```dart
class MoveHealthItem {
  final MoveHealthReason reason;  // Health event reason
  final String description;       // Human-readable description
}

enum MoveHealthReason {
  batteryLevel,
  cpuUsage,
  diskUsage,
  internetUsage,
  memoryUsage,
  newVersion,
  unimplementedListeners,
}
```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="237.5"></th><th></th><th></th></tr></thead><tbody><tr><td><strong>MoveHealthItem</strong></td><td></td><td></td></tr><tr><td>reason</td><td><strong>MoveHealthItem.Reason</strong></td><td>Reason for the health report issue.</td></tr><tr><td>description</td><td>String</td><td>Description of the issue.</td></tr><tr><td></td><td></td><td></td></tr><tr><td><strong>Reason</strong></td><td>String</td><td></td></tr><tr><td>memoryUsage</td><td></td><td>High memory usage.</td></tr><tr><td>cpuUsage</td><td></td><td>High CPU usage.</td></tr><tr><td>diskUsage</td><td></td><td>Not reported on iOS.</td></tr><tr><td>batteryLevel</td><td></td><td>Low battery.</td></tr><tr><td>internetUsage</td><td></td><td>No internet.</td></tr><tr><td>newVersion</td><td></td><td>New version available.</td></tr><tr><td>unimplementedListeners</td><td></td><td>Any of the required listeners was unimplemented. See: <a href="/move-platform/sdk/api-interface/ios/setup">Setup</a>.</td></tr></tbody></table>


# MoveHealthScore

{% hint style="info" %}
**Note:** `MoveHealthScore` is for diagnostic purposes only. It helps identify potential integration issues.
{% endhint %}

{% hint style="info" %}
**Note:** Health monitoring uses platform-specific models. iOS and React Native use `MoveHealthItem`. Android uses `MoveHealthScore`. Flutter uses `MoveHealthItem` with a simplified structure (reason + description only).
{% endhint %}

{% tabs %}
{% tab title="Android" %}

```kotlin
data class MoveHealthScore(
    val reason: List<HealthReason>,
    val configuration: String,
    val battery: Int,
    val mobileConnection: String,
    val listeners: MoveHealthListeners,
    val resources: MoveHealthResources,
    val versions: List<MoveHealthVersion>?,
)

enum class HealthReason {
    CPU_USAGE,
    DISK_USAGE,
    BATTERY_LEVEL,
    INTERNET_USAGE,
    MEMORY_USAGE,
    NEW_VERSION,
    UNIMPLEMENTED_LISTENERS;
}

data class MoveHealthListeners(
    val auth: Boolean,
    val state: Boolean,
    val trip: Boolean,
    val failure: Boolean,
    val warning: Boolean,
)

data class MoveHealthResources(
    val cpu: Int,
    val memory: MoveHealthResourcesMemory,
    val disk: MoveHealthResourcesDisk,
)

data class MoveHealthResourcesMemory(
    val totalBytes: Long,
    val freeBytes: Long,
    val usedBytes: Long,
)

data class MoveHealthResourcesDisk(
    val totalBytes: Long,
    val freeBytes: Long,
    val usedBytes: Long,
)

data class MoveHealthVersion(
    val version: String?,
    val warning: String?,
    val message: String?,
)

```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="217.5"></th><th width="223"></th><th></th></tr></thead><tbody><tr><td><strong>MoveHealthScore</strong></td><td></td><td></td></tr><tr><td>reason</td><td>List&#x3C;HealthReason></td><td>A list of areas that could cause problems.</td></tr><tr><td>configuration</td><td>String</td><td>The current configuration as a readable text.</td></tr><tr><td>battery</td><td>Int</td><td>The charge value of the battery.</td></tr><tr><td>mobileConnection</td><td>String</td><td>The type of connection.</td></tr><tr><td>listeners</td><td>MoveHealthListeners</td><td>An overview of implemented listeners.</td></tr><tr><td>resources</td><td>MoveHealthResources</td><td>An overview about available / used memory / disk and cpu.</td></tr><tr><td>versions</td><td>List&#x3C;MoveHealthVersion></td><td>An overview / reminder of (new) MOVE SDK versions with important changes.</td></tr></tbody></table>


# MoveNotification

{% tabs %}
{% tab title="Android" %}

```kotlin
data class MoveNotification(
    val recognitionTitle: String,
    val recognitionText: String,
    val drivingTitle: String,
    val drivingText: String,
)
```

{% endtab %}
{% endtabs %}

Used with `setNotificationText()` to customize notification texts.

| recognitionTitle | Title for the recognition notification. |
| ---------------- | --------------------------------------- |
| recognitionText  | Text for the recognition notification.  |
| drivingTitle     | Title for the trip notification.        |
| drivingText      | Text for the trip notification.         |


# MoveOptions

MOVE Models

{% hint style="info" %}
MoveOptions class since MOVE SDK v2.3
{% endhint %}

{% tabs %}
{% tab title="Android" %}

```kotlin
data class MoveOptions(
    val motionPermissionRequired: Boolean = false,
    val backgroundLocationPermissionMandatory: Boolean = false,
    val overlayPermissionMandatory: Boolean = true,
    val useBackendConfig: Boolean = false,
    val deviceDiscovery: DeviceDiscovery? = null,
)
```

{% endtab %}

{% tab title="iOS" %}

```swift
public class MoveOptions: Codable {
    var motionPermissionMandatory: Bool
    var backgroundLocationPermissionMandatory: Bool
    var useBackendConfig: Bool
    var deviceDiscovery: DeviceDiscovery
}
```

{% endtab %}

{% tab title="React Native" %}

```typescript
export declare type MoveSdkOptions = {
    motionPermissionMandatory?: boolean;
    backgroundLocationPermissionMandatory?: boolean;
    overlayPermissionMandatory?: boolean;
    useBackendConfig?: boolean;
    deviceDiscovery?: MoveSdkDeviceDiscovery;
};
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:movesdk/io/dolphin/move/move_options.dart';
```

```dart
class MoveOptions {
    bool? motionPermissionMandatory;
    bool? backgroundLocationPermissionMandatory;
    bool? useBackendConfig;
    DeviceDiscoveryOptions? deviceDiscovery;
}
```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="265.3333333333333">MoveOptions</th><th width="164"></th><th width="95"></th><th></th></tr></thead><tbody><tr><td><strong>MoveOptions</strong></td><td><strong>Type</strong></td><td><strong>Default</strong></td><td></td></tr><tr><td>motionPermissionRequired (Android) / motionPermissionMandatory (iOS)</td><td>Boolean</td><td>false</td><td>Pass <strong>true</strong> if you want the motion permission (activity recognition) to be mandatory for driving service.</td></tr><tr><td>backgroundLocationPermissionMandatory (<strong>Since MOVE SDK v2.6)</strong></td><td>Boolean</td><td>false</td><td>Pass <strong>true</strong> if you want the background location permission to be mandatory for driving service.</td></tr><tr><td><p><strong>ANDROID ONLY:</strong></p><p>overlayPermissionMandatory (<strong>Since MOVE SDK v2.6.9</strong>)<br><br><strong>Flutter:</strong> <code>overlayPermissionMandatory</code> is not configurable via Flutter MoveOptions. The default is <code>true</code>.</p></td><td>Boolean</td><td>true</td><td>Pass <strong>false</strong> if you don't want the overlay permission mandatory for driving service. <strong>Attention: in this case the device must be equipped with a gyroscope!</strong></td></tr><tr><td>useBackendConfig<br>(<strong>Since MOVE SDK v2.5)</strong></td><td>Boolean</td><td>false</td><td>Pass <strong>true</strong> to use the MOVE Dashboard configuration instead of the local <code>MoveConfig</code>. When enabled, the local <code>MoveConfig</code> passed in <code>setup()</code> is ignored and the backend configuration takes precedence.</td></tr><tr><td>deviceDiscovery</td><td><a href="/move-platform/sdk/models/moveoptions/devicediscovery">DeviceDiscovery</a></td><td>null</td><td>Create / pass a DeviceDiscovery object if you want to have more control over the <a href="/move-platform/move-services#bdd-device-discovery">BDD - Device Discovery</a> feature.</td></tr></tbody></table>

<table data-header-hidden><thead><tr><th width="359.5">MoveOptions related</th><th></th></tr></thead><tbody><tr><td><strong>MoveOptions related</strong></td><td></td></tr><tr><td><a href="/move-platform/sdk/models/moveoptions/devicediscovery">DeviceDiscovery</a></td><td></td></tr><tr><td><a href="/move-platform/sdk/api-interface/android/services#update-config">updateConfig</a>(...) (Android) / <br><a href="/move-platform/sdk/api-interface/ios/setup#update-config">update</a>(...) (iOS)</td><td></td></tr><tr><td><a href="/move-platform/sdk/models/listeners-callbacks#remote-config-change-listener">RemoteConfigChangeListener</a></td><td></td></tr></tbody></table>


# DeviceDiscovery

MOVE Models

{% hint style="info" %}
Since MOVE SDK v2.4
{% endhint %}

{% hint style="warning" %}
Please note that MoveDevices can only be registered if the SDK has been configured with .setup()
{% endhint %}

{% tabs %}
{% tab title="Android" %}

```kotlin
data class DeviceDiscovery(
    val startDelay: Long?,
    val duration: Long?,
    val interval: Long?,
    val stopScanOnFirstDiscovered: Boolean = false,
    val ensureSynced: Boolean = false,
)
```

{% endtab %}

{% tab title="iOS" %}

```swift
public struct DeviceDiscovery {
    public var startDelay: TimeInterval = 120
    public var interval: TimeInterval = 300
    public var duration: TimeInterval = 10
    public var stopScanOnFirstDiscovered: Bool = false
    public var ensureSynced: Bool = false
}
```

{% endtab %}

{% tab title="React Native" %}

```tsx
export type MoveSdkDeviceDiscovery = {
  startDelay?: number;
  duration?: number;
  interval?: number;
  stopScanOnFirstDiscovered?: boolean;
  ensureSynced?: boolean;
};
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:movesdk/io/dolphin/move/device_discovery_options.dart';
```

```dart
class DeviceDiscoveryOptions {
  int? startDelay;
  int? duration;
  int? interval;
  bool? stopScanOnFirstDiscovered;
  bool? ensureSynced;
}

final options = MoveOptions(
  deviceDiscovery: DeviceDiscoveryOptions(
    startDelay: 120,
    duration: 10,
    interval: 300,
    stopScanOnFirstDiscovered: false,
    ensureSynced: false,
  ),
);
```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="265.3333333333333"></th><th width="108"></th><th width="90"></th><th></th></tr></thead><tbody><tr><td><strong>DeviceDiscovery</strong></td><td><strong>Type</strong></td><td><strong>Default</strong></td><td></td></tr><tr><td>startDelay</td><td>Number</td><td>120</td><td>Device discovery delay from start of the trip in seconds. If <code>null</code>, the default value is used.</td></tr><tr><td>duration</td><td>Number</td><td>10</td><td>Device discovery scan duration in seconds. If <code>null</code>, the default value is used.</td></tr><tr><td>interval</td><td>Number</td><td>300</td><td>Device discovery repeat interval in seconds. If <code>null</code>, the default value is used.</td></tr><tr><td>stopScanOnFirstDiscovered</td><td>Boolean</td><td>false</td><td>Stop detection on first device discovered.</td></tr><tr><td>ensureSynced</td><td>Boolean</td><td>false</td><td><p><em><strong>since MOVE SDK 2.17.0</strong></em></p><p>If set to true devices which fail synchronisation with the backend will automatically be unregistered. See <em>state</em> in <a href="/move-platform/sdk/models/movedevice/movedevicestate">MoveDeviceState</a>.</p></td></tr></tbody></table>

| **DeviceDiscovery related**                                                                                                                                                                                 |                                                                                                          |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `.setup(..., options:...)`                                                                                                                                                                                  | During setup it is possible to add DeviceDiscovery options to the MOVE SDK.                              |
| Device Discovery Listener ([Android](/move-platform/sdk/api-interface/android/services#set-device-discovery-listener) / [iOS](/move-platform/sdk/api-interface/ios/services#set-device-discovery-listener)) | Fired when previous registered [MoveDevice](/move-platform/sdk/models/movedevice#android)'s are scanned. |
| [MoveOptions](/move-platform/sdk/models/moveoptions)                                                                                                                                                        |                                                                                                          |


# MoveInitOptions

MOVE Models

{% hint style="info" %}
MoveInitOptions class since MOVE SDK v2.19.0
{% endhint %}

{% tabs %}
{% tab title="Android" %}

```kotlin
data class MoveInitOptions(
    val maxQueueSizeMB: Long = 0,
)
```

{% endtab %}

{% tab title="iOS" %}

```swift
public struct MoveInitOptions {
    	public var maxQueueSizeMB: Int
}
```

{% endtab %}

{% tab title="React Native" %}
Set via Info.plist and onCreate, or Expo plugin. See [Initialization](/move-platform/sdk/api-interface/react-native/initialization).
{% endtab %}

{% tab title="Flutter" %}
Set via Info.plist and onCreate. See [Initialization](/move-platform/sdk/api-interface/flutter/initialization).
{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="265.3333333333333">MoveInitOptions</th><th width="90.7421875"></th><th width="95"></th><th></th></tr></thead><tbody><tr><td><strong>MoveInitOptions</strong></td><td><strong>Type</strong></td><td><strong>Default</strong></td><td></td></tr><tr><td>maxQueueSizeMB</td><td>Long</td><td>0</td><td>Cap, in megabytes, on the combined on-disk size of the temporary local databases.<br>A value below 20 is silently raised to 20MB. When exceeded, the SDK evicts the oldest, lowest-priority data. A value of 0 means unlimited.</td></tr></tbody></table>

<table data-header-hidden><thead><tr><th width="359.5">MoveOptions related</th><th></th></tr></thead><tbody><tr><td><strong>MoveInitOptions related</strong></td><td></td></tr><tr><td><a href="/move-platform/sdk/api-interface/android/initialization#init">init()</a></td><td></td></tr></tbody></table>


# MoveSdkState

MOVE Models

Represent the different SDK States.

{% tabs %}
{% tab title="Android" %}

```kotlin
sealed class MoveSdkState {
    Uninitialised()
    Ready()
    Running()
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
enum MoveSDKState {
    case unintialized
    case ready
    case running
}
```

{% endtab %}

{% tab title="React Native" %}

```javascript
export type SdkState = 'UNINITIALIZED' | 'READY' | 'RUNNING';
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:movesdk/io/dolphin/move/move_state.dart';
```

```dart
enum MoveState {
  ready,
  running,
  unknown,
}
```

{% endtab %}
{% endtabs %}

| **MoveState**                       |                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| uninitialized (Flutter see unknown) | The MOVE SDK is not initialized.                                                                                                                                                                                                                                                                                                                                                                                                                             |
| ready                               | The MOVE SDK is initialized and ready to start services. Transitions to this state after successful initialization or after calling `stopAutomaticDetection()`.                                                                                                                                                                                                                                                                                              |
| running                             | The MOVE SDK is running its services. Transited to this state after calling startAutomaticDetection() ([Android](/move-platform/sdk/api-interface/android/services#start-automatic-detection) / [iOS](/move-platform/sdk/api-interface/ios#start-automatic-detection) / [React](/move-platform/sdk/api-interface/react-native/services#start-automatic-detection) / [Flutter](/move-platform/sdk/api-interface/flutter/services#start-automatic-detection)). |
| Flutter: unknown                    | Initial state before `MoveSdk.init()` has been called, or after `shutdown()` has completed. The SDK is not initialized and no data collection is active.                                                                                                                                                                                                                                                                                                     |

For further information please see [Android](/move-platform/sdk/getting-started/android/quick-start) / [iOS](/move-platform/sdk/getting-started/ios/quick-start) / [React](/move-platform/sdk/getting-started/react-native) / [Flutter](/move-platform/sdk/getting-started/flutter).


# MoveSdkAndroidConfig

MOVE Models(React Native)

When running an Android application in background, several limits apply, which also have impact on retrieving locations. To circumvent this, an application needs to show a foreground service with a notification visible to the user. \
\
Therefore, it is necessary to pass an additional notification configuration object for Android. For more information on that please check[ notification management](/move-platform/sdk/appendix/android/notification-management).

Here is how *moveSdkAndroidConfig* could look like:

```javascript
import { NotificationConfig, MoveSdkAndroidConfig } from 'react-native-move-sdk';

const tripChannel = {
	id: 'CT',
	name: 'Trips',
	description: 'Trips Description',
};

const recognitionNotification: NotificationConfig = {
	title: 'MOVE SDK Trip Recognition',
	text: 'SDK trip recognition is running',
	channel: tripChannel,
};

const tripNotification: NotificationConfig = {
	title: 'MOVE SDK Trip Running',
	text: 'SDK is recording your trip',
	channel: tripChannel,
};

const moveSdkAndroidConfig: MoveSdkAndroidConfig = {
	notifications: {
		recognitionNotification,
		tripNotification,
	},
};
```

[**recognitionNotification**](https://docs.movesdk.com/move-platform/sdk/api-interface/android-1/builder#dolphinsdk.builderv1.1-recognitionnotificationrecognitionnotifications) config object - whenever the MOVE SDK tries to detect for example activities, trips or even more.

[**tripNotification**](https://docs.movesdk.com/move-platform/sdk/api-interface/android-1/builder#trip-notifications) config object - when there is an active trip ([MoveTripState ](/move-platform/sdk/models/movetripstate)`.Running`).

{% hint style="info" %}
Don't forget to create a notification [channel](https://developer.android.com/training/notify-user/channels)
{% endhint %}


# MoveTripState

MOVE Models

Returns the current user's driving state.

{% tabs %}
{% tab title="Android" %}

```kotlin
enum class MoveTripState {
    UNKNOWN,
    IDLE,
    DRIVING,
    HALT,
    IGNORED
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
enum MoveTripState {
    case unknown
    case driving
    case halt
    case idle
    case ignored
}
```

{% endtab %}

{% tab title="React Native" %}

```javascript
export type TripState = 'UNKNOWN' | 'DRIVING' | 'HALT' | 'IDLE' | 'IGNORED';
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:movesdk/io/dolphin/move/move_trip_state.dart';
```

```dart
enum MoveTripState {
  unknown,
  idle,
  driving,
  halt,
  ignored,
}
```

{% endtab %}
{% endtabs %}

| **MoveTripState** |                                                                                                        |
| ----------------- | ------------------------------------------------------------------------------------------------------ |
| unknown           | Initial state before the MOVE SDK detection service has started.                                       |
| idle              | Device is in state idle.                                                                               |
| driving           | Device is actively driving in a trip.                                                                  |
| halt              | Device is holding position in a trip (e.g. car is not moving, car is standing at a red traffic light). |
| ignored           | Device is in a trip that is flagged as ignored by the host app.                                        |

Trip goes through different states during the MOVE SDK's life cycle. Initially the `MoveTripState` is `.unknown`, until the service is started.&#x20;

When service successfully starts, the `MoveTripState` will transit to `.idle` state.

When the user starts driving a car or riding a bicycle (if [configured](/move-platform/sdk/models/moveconfig)), a trip will start and the `MoveTripState` will transit to `.driving`. During the trip, the user could sometimes choose to go to *temporarily* idle (like in traffic jams, traffic stops, etc.), this is expressed through the `.halt` `MoveTripState`. Halt state means that the user is in an active trip, but is currently stationary. As soon as the MOVE SDK detects that the user's trip has ended, `MoveTripState` will transit back again to `.idle`.

While being on a trip, the host app can choose to ignore the ongoing trip using the `ignoreCurrentTrip` API ([Android](/move-platform/sdk/api-interface/android/services#ignore-current-trip) / [iOS](/move-platform/sdk/api-interface/ios/services#ignore-current-trip) / [React](/move-platform/sdk/api-interface/react-native/services#ignore-current-trip) / [Flutter](/move-platform/sdk/api-interface/flutter/services#ignore-current-trip)). This will transit the `MoveTripState` to `.ignored` `MoveTripState`. Ignored trips are purged and not forwarded to the server or further processed.

<table data-header-hidden><thead><tr><th width="399">MoveTripState related</th><th></th></tr></thead><tbody><tr><td><strong>MoveTripState related</strong></td><td></td></tr><tr><td><code>getTripState</code> (<a href="/move-platform/sdk/api-interface/android/services#get-trip-state">Android</a> / <a href="/move-platform/sdk/api-interface/ios/services#get-trip-state">iOS</a> / <a href="/move-platform/sdk/api-interface/react-native/services#get-trip-state">React</a> / <a href="/move-platform/sdk/api-interface/flutter/services#get-trip-state">Flutter</a>)</td><td>Gets the current <code>MoveTripState</code> .</td></tr><tr><td><code>tripStateListener</code>(<a href="/move-platform/sdk/api-interface/android/initialization#trip-state-listener">Android</a> / <a href="/move-platform/sdk/api-interface/ios/services#set-trip-state-listener">iOS</a> / <a href="/move-platform/sdk/api-interface/react-native/services#set-trip-state-listener">React</a> / <a href="/move-platform/sdk/api-interface/flutter/services#set-trip-state-listener">Flutter</a>)</td><td>Provide a block to be invoked every time <code>MoveTripState</code> changes.</td></tr><tr><td><code>finishCurrentTrip</code> (<a href="/move-platform/sdk/api-interface/android/services#finish-current-trip">Android</a> / <a href="/move-platform/sdk/api-interface/ios/services#finish-current-trip">iOS</a> / <a href="/move-platform/sdk/api-interface/react-native/services#finish-current-trip">React</a>  <a href="/move-platform/sdk/api-interface/flutter/services#finish-current-trip">Flutter</a>)</td><td>Ends the current ongoing trip.</td></tr><tr><td><code>ignoreCurrentTrip</code> (<a href="/move-platform/sdk/api-interface/android/services#ignore-current-trip">Android</a> / <a href="/move-platform/sdk/api-interface/ios/services#ignore-current-trip">iOS</a> / <a href="/move-platform/sdk/api-interface/react-native/services#ignore-current-trip">React</a> / <a href="/move-platform/sdk/api-interface/flutter/services#ignore-current-trip">Flutter</a>)</td><td>Ignores the current ongoing trip.</td></tr></tbody></table>


# MoveScanResult

MOVE Models

{% hint style="info" %}
Since MOVE SDK v2.4
{% endhint %}

{% tabs %}
{% tab title="Android" %}

```kotlin
data class MoveScanResult(
    val device: MoveDevice,
    val isDiscovered: Boolean,
)
```

{% endtab %}

{% tab title="iOS" %}

```swift
public struct MoveScanResult {
    let device: MoveDevice
    let isDiscovered: Bool
}
```

{% endtab %}

{% tab title="React Native" %}

```tsx
export type MoveScanResult = {
    isDiscovered: boolean;
    device: MoveSdkDevice;
    name: string;
};
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:movesdk/io/dolphin/move/move_device.dart';
```

```dart
class MoveScanResult {
  bool isDiscovered;
  MoveDevice device;
}
```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="265.3333333333333"></th><th width="138"></th><th></th></tr></thead><tbody><tr><td><strong>MoveScanResult</strong></td><td><strong>Type</strong></td><td></td></tr><tr><td>device</td><td><a href="/move-platform/sdk/models/movedevice">MoveDevice</a></td><td></td></tr><tr><td>isDiscovered</td><td>Boolean</td><td>This MoveDevice was found / not found during the last <a href="/move-platform/move-services#bdd-device-discovery">BDD - DeviceDiscovery</a> scan.</td></tr></tbody></table>

| **MoveScanResult related**                                                                                                |   |
| ------------------------------------------------------------------------------------------------------------------------- | - |
| [MoveDevice](/move-platform/sdk/models/movedevice)                                                                        |   |
| deviceDiscoveryListener ([Android](/move-platform/sdk/api-interface/android/services#set-service-warning-listener) / iOS) |   |


# MoveServiceFailure

MOVE Models

{% tabs %}
{% tab title="Android" %}

```kotlin
data class MoveServiceFailure( 
    val service: MoveDetectionService, 
    val reasons: List<MoveError>
)

sealed class MoveError {

    object Unauthorized : MoveError()
    object LocationPermissionMissing : MoveError()
    object PhonePermissionMissing : MoveError()
    object OverlayPermissionMissing : MoveError()
    object MotionPermissionMissing : MoveError()
    object BackgroundLocationPermissionMissing : MoveError()
    object BatteryPermissionMissing : MoveError()
    object AccelerometerMissing : MoveError()
    object GooglePlayLocationAccuracyMissing : MoveError()
    object GyroscopeMissing : MoveError()
    object HealthConnectClientMissing : MoveError()
    object HealthConnectRequiresUpdate : MoveError()
    object HealthConnectReadStepsPermissionMissing : MoveError()
    object HealthConnectBackgroundReadStepsPermissionMissing : MoveError()
    
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
struct MoveServiceFailure {
    enum Reason {
        case unauthorized
        case missingPermission([MovePermission])
    }

    var service: MoveConfig.DetectionService
    var reason: Reason
}

enum MovePermission: Int {
    case location
    case backgroundLocation
    case preciseLocation
    case motionActivity
    case gyroscope
    case accelerometer
    case steps
}
```

{% endtab %}

{% tab title="React Native" %}

```typescript
export type ErrorReasons =
  | 'BACKGROUND_LOCATION_PERMISSION_MISSING'
  | 'LOCATION_PERMISSION_MISSING'
  | 'MOTION_PERMISSION_MISSING'
  | 'ACTIVITY_PERMISSION_MISSING'
  | 'BATTERY_PERMISSION_MISSING'
  | 'UNAUTHORIZED'
  | 'INTERNET_PERMISSION_MISSING'
  | 'PHONE_PERMISSION_MISSING'
  | 'OVERLAY_PERMISSION_MISSING'
  | 'ACCELEROMETER_MISSING'
  | 'GOOGLE_PLAY_LOCATION_ACCURACY_MISSING'
  | 'PRECISE_LOCATION_PERMISSION_MISSING' 
  | 'HEALTH_CONNECT_CLIENT_MISSING' 
  | 'HEALTH_CONNECT_REQUIRES_UPDATE' 
  | 'HEALTH_CONNECT_READ_STEPS_PERMISSION_MISSING' 
  | 'HEALTH_CONNECT_BACKGROUND_READ_STEPS_PERMISSION_MISSING';

export type IssueListService =
  | TimelineDetectionService
  | DrivingService
  | WalkingService;

export type IssueListItem<ReasonsType> = {
  reasons: Array<ReasonsType>;
  service?: IssueListService;
};

export type ErrorListType = Array<IssueListItem<ErrorReasons>>;
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:movesdk/io/dolphin/move/move_service_warning.dart';
```

```dart
class MoveServiceError {
  final MoveDetectionService service;
  final List<MoveError> reasons;
}
```

```dart
enum MoveError {
  accelerometerMissing,
  activityPermissionMissing,
  backgroundLocationPermissionMissing,
  batteryPermissionMissing,
  bluetoothScanPermissionMissing,
  googlePlayLocationAccuracyMissing,
  gyroscopeMissing,
  healthConnectReadStepsPermissionMissing,
  healthConnectBackgroundReadStepsPermissionMissing,
  internetPermissionMissing,
  locationPermissionMissing,
  motionPermissionMissing,
  phonePermissionMissing,
  preciseLocationPermissionMissing,
  overlayPermissionMissing,
  unauthorized,
}
```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th>Parameter</th><th></th><th data-hidden></th></tr></thead><tbody><tr><td><strong>Field</strong></td><td></td><td></td></tr><tr><td>service</td><td>see <code>MoveDetectionService</code> in <a href="/move-platform/sdk/models/moveconfig">MoveConfig</a></td><td></td></tr><tr><td>reasons</td><td>List of required Permissions (<a href="/move-platform/sdk/appendix/android/permission-handling">Android</a> / <a href="/move-platform/sdk/appendix/ios/permission-handling">iOS</a>) / Features or unauthorized if not in server config.</td><td></td></tr><tr><td>Unauthorized</td><td>The configured service is not included in your project subscription. Contact the MOVE SDK team to enable it.</td><td></td></tr></tbody></table>


# MoveServiceWarning

MOVE Models

{% tabs %}
{% tab title="Android" %}

```kotlin
data class MoveServiceWarning(
    val service: MoveDetectionService,
    val warnings: List<MoveWarning>
)
    
sealed class MoveWarning {

    object ActivityPermissionMissing : MoveWarning()
    object BackgroundLocationPermissionMissing : MoveWarning()
    object BluetoothPermissionMissing : MoveWarning()
    object EnergySaver : MoveWarning()
    object LocationMode : MoveWarning()
    object MockProvider : MoveWarning()
    object MockProviderLocation : MoveWarning()
    object BatteryOptimization : MoveWarning()
    object GpsOff : MoveWarning()
    object Offline : MoveWarning()
    object NoSim : MoveWarning()
    object Rooted : MoveWarning()
    object GoEdition : MoveWarning()
    object PlayServicesMissing : MoveWarning()
    object BackgroundRestricted : MoveWarning()
    object GooglePlayLocationAccuracyMissing : MoveWarning()
    object NotificationPermissionMissing : MoveWarning()
    class LocationPowerMode(val mode: Int) : MoveWarning()
    object BluetoothTurnedOff : MoveWarning()
    object BluetoothScanPermissionMissing : MoveWarning()
    object BluetoothConnectPermissionMissing : MoveWarning()
    object FineLocationPermissionMissing : MoveWarning()
    object NotificationMissing : MoveWarning()
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
struct MoveServiceWarning {
    enum Reason {
        case missingPermission([MovePermission])
    }

    var service: MoveConfig.DetectionService
    var reason: Reason
}

enum MovePermission: Int {
    case location
    case backgroundLocation
    case preciseLocation
    case motionActivity
    case gyroscope
    case accelerometer
    case bluetooth
    case bluetoothScan
}
```

{% endtab %}

{% tab title="React Native" %}

```typescript
export type WarningReasons =
  | 'BACKGROUND_LOCATION_PERMISSION_MISSING'
  | 'MOTION_PERMISSION_MISSING'
  | 'ACTIVITY_PERMISSION_MISSING'
  | 'BATTERY_OPTIMIZATION'
  | 'BLUETOOTH_TURNED_OFF'
  | 'BLUETOOTH_SCAN_PERMISSION_MISSING'
  | 'BLUETOOTH_CONNECT_PERMISSION_MISSING'
  | 'GOOGLE_PLAY_LOCATION_ACCURACY_MISSING'
  | 'NOTIFICATION_PERMISSION_MISSING'
  | 'FINE_LOCATION_PERMISSION_MISSING'
  | 'BLUETOOTH_PERMISSION_MISSING' 
  | 'NOTIFICATION_MISSING'
  | 'GO_EDITION'
  | 'ROOTED'
  | 'NO_SIM'
  | 'BACKGROUND_RESTRICTED'
  | 'MOCK_PROVIDER_LOCATION'
  | 'MOCK_PROVIDER'
  | 'LOCATION_MODE'
  | 'PLAY_SERVICES_MISSING'
  | 'LOCATION_POWER_MODE(0)'
  | 'LOCATION_POWER_MODE(1)'
  | 'LOCATION_POWER_MODE(2)'
  | 'LOCATION_POWER_MODE(3)'
  | 'LOCATION_POWER_MODE(4)'
  | 'ENERGY_SAVER';

export type IssueListService =
  | TimelineDetectionService
  | DrivingService
  | WalkingService;

export type IssueListItem<ReasonsType> = {
  reasons: Array<ReasonsType>;
  service?: IssueListService;
};

export type WarningListType = Array<IssueListItem<WarningReasons>>;
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:movesdk/io/dolphin/move/move_service_warning.dart';
```

```dart
class MoveServiceWarning {
  final MoveDetectionService? service;
  final List<MoveWarning> reasons;
}
```

```dart
enum MoveWarning {
  activityPermissionMissing,
  backgroundLocationPermissionMissing,
  backgroundRestricted,
  batteryOptimization,
  bluetoothConnectPermissionMissing,
  bluetoothPermissionMissing,
  bluetoothScanPermissionMissing,
  bluetoothTurnedOff,
  energySaver,
  fineLocationPermissionMissing,
  goEdition,
  googlePlayLocationAccuracyMissing,
  gpsOff,
  locationMode,
  locationPowerMode,
  mockProvider,
  mockProviderLocation,
  noSim,
  notificationPermissionMissing,
  offline,
  playServicesMissing,
  rooted,
  notificationMissing,
}
```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="206" align="center"></th><th></th></tr></thead><tbody><tr><td align="center"><strong>Field</strong></td><td></td></tr><tr><td align="center">service</td><td>see <code>MoveDetectionService</code> in <a href="/move-platform/sdk/models/moveconfig">MoveConfig</a></td></tr><tr><td align="center">reason</td><td>List of optional <code>MoveServiceWarning</code></td></tr></tbody></table>

<table data-header-hidden><thead><tr><th width="206" align="center"></th><th></th></tr></thead><tbody><tr><td align="center"><strong>LocationPowerMode</strong></td><td></td></tr><tr><td align="center">0</td><td>Either the location providers shouldn't be affected by battery saver or battery saver is off.</td></tr><tr><td align="center">1</td><td>In this mode, the GPS based location provider should be disabled when battery saver is on and the device is non-interactive.</td></tr><tr><td align="center">2</td><td>All location providers should be disabled when battery saver is on and the device is non-interactive.</td></tr><tr><td align="center">3</td><td>In this mode, all the location providers will be kept available, but location fixes should only be provided to foreground apps.</td></tr><tr><td align="center">4</td><td>In this mode, location will not be turned off, but LocationManager will throttle all requests to providers when the device is non-interactive.</td></tr></tbody></table>


# MoveShutdownResult

A result for the shutdown function with force: false.

{% tabs %}
{% tab title="Android" %}

```kotlin
enum class MoveShutdownResult {
    SUCCESS,
    NETWORK_ERROR,
    UNINITIALIZED;
}
```

{% endtab %}

{% tab title="iOS" %}

```swift
public enum MoveShutdownResult {
    case success
    case networkError
    case uninitialized
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:movesdk/io/dolphin/move/move_shutdown_result.dart';// Some code
```

```dart
enum MoveShutdownResult {
    success,
    networkError,
    uninitialized,
}
```

{% endtab %}

{% tab title="React" %}

```typescript
export declare type ShutdownReturnType = 'NETWORK_ERROR' | 'SUCCESS' | 'UNINITIALIZED';
```

{% hint style="warning" %}
Error results will be returned with a rejected promise.
{% endhint %}
{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="229"></th><th></th></tr></thead><tbody><tr><td><strong>MoveShutdownResult</strong></td><td></td></tr><tr><td>success</td><td>The shutdown completed.</td></tr><tr><td>networkError</td><td><p>Pending data in the queue could not be sent to the backend.</p><ul><li><code>shutdown(force: false)</code>: SDK remains active and does not shut down. Retry later.</li><li><code>shutdown(force: true)</code>: SDK shuts down regardless. Pending data is lost.</li></ul></td></tr><tr><td>uninitialized</td><td>The SDK was not setup. No user active.</td></tr></tbody></table>


# Troubleshooting


# iOS

## Cocoapods

When setting up a new project with XCode 15.0 or above you need to make sure **User Script Sandboxing** is turned off.&#x20;

Error:&#x20;

```
Command PhaseScriptExecution failed with a nonzero exit  code
```

Build log:

```
Run custom shell script '[CP] Embed Pods Frameworks'
```

Solution:

Set **User Script Sandboxing** to **No** in the project or target **Build Settings**.

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2F2snOld4BdHQW7HTJq8oJ%2FScreenshot%202024-01-16%20at%2016.11.00.png?alt=media&amp;token=608c1a04-0945-4440-a978-7feb7f9f8b9d" alt=""><figcaption><p>Target <strong>Build Settings</strong>.</p></figcaption></figure>

## Swift Package Manager

Package resolution fails with:

```
failed with: invalid archive returned from 'https://storage.googleapis.com/cdn.dolph.in/sdk/.../DolphinMoveSDK.xcframework.zip'
```

Solution:

```
# this is required
rm -rf ~/Library/Caches/org.swift.swiftpm

# this may be required
rm -rf ~/Library/org.swift.swiftpm
```

"File > Packages > Reset Package Caches" is not sufficient.

Neither is  `swift package purge-cache`.

## Derived Data

Sometimes build issues can arise when updating to a new version, such as from 2.14 -> 2.15, and it is necessary to clear the build data. By default this is located at "*\~/Library/Developer/Derived Data*".

This may also be a necessary step in a build system, i.e:

#### Fastlane

This is often a common step. See: <https://docs.fastlane.tools/actions/clear_derived_data/>

```ruby
clean_build_artifacts
clear_derived_data
```


# Appendix


# Token refresh

Since MOVE SDK v2.6.7, token refresh is handled **automatically and internally** by the SDK. Host applications using `setup(...)` do not need to implement any token refresh logic.

The SDK uses the `refreshToken` internally to obtain a new `accessToken` whenever needed, without any action required from the host app.

**Authentication State Monitoring**

The host app should monitor MoveAuthState via the `AuthStateUpdateListener`. The only actionable state is `INVALID`. When this occurs, the user should be logged out and `shutdown(force: true)` should be called.


# Android

References


# Permission Handling

Description of required permissions, how to request and manage them.

* [Permission Overview](/move-platform/sdk/appendix/android/permission-handling/permission-overview)
* [Runtime Permissions](/move-platform/sdk/appendix/android/permission-handling/runtime-permissions)


# Permission Overview

The library requires at least the following permissions to access MOVE SDK services.

```xml
<!-- ====================================================== -->
<!-- MOVE SDK - AndroidManifest.xml Permission Reference    -->
<!-- Comment out permissions for services you don't use.    -->
<!-- ====================================================== -->

<!-- Required for reliable background operation - strongly recommended for all configurations -->
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

<!-- Required for all services -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />

<!-- Required for: Driving, Cycling, Walking, DFD, DBE, POI, Public Transport, AID, Assistance Call -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- Driving, Cycling, Walking -->
<!-- Since SDK 2.6: optional if backgroundLocationPermissionMandatory = false in MoveOptions -->
<!-- Since SDK 2.19.0: strongly recommended for AID if used without Driving / Cycling -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

<!-- Required for: Cycling, Walking. Strongly recommended for: Driving -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

<!-- Required for Android 13+ (API 33+) -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<!-- Required for: Distraction-Free Driving (DFD) -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

<!-- Required for: Distraction-Free Driving (DFD) -->
<!-- Since SDK 2.6.9: optional if overlayPermissionMandatory = false in MoveOptions -->
<!-- Attention: if optional, device must have a gyroscope -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

<!-- Required for: Assistance Call (Android 11 and lower) -->
<uses-permission android:name="android.permission.BLUETOOTH" />

<!-- Required for: Driving (Device Discovery), Assistance Call (Android 12+) -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

<!-- Required for: BLE scanning (Android 12+) -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />

<!-- Required for: Bluetooth scanning (Android 11 and lower) -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

<!-- Required for: Assistance Call (background internet check) -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />

<!-- Required for: Health Connect (Step Counter) -->
<uses-permission android:name="android.permission.health.READ_STEPS" />
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND" />
```

Depending on the used services, different permissions are required. The following table gives an overview what's required:

<table data-header-hidden><thead><tr><th width="138.6377598211822"></th><th width="138.109375"></th><th width="233.61772853185596">Permissions</th><th></th></tr></thead><tbody><tr><td><strong>Battery Optimization</strong></td><td><strong>Strongly recommended</strong></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#REQUEST_IGNORE_BATTERY_OPTIMIZATIONS">REQUEST_IGNORE_BATTERY_OPTIMIZATIONS</a></td><td>Permission an application must hold in order to use <a href="https://developer.android.com/reference/android/provider/Settings#ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"><code>Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS</code></a>.</td></tr><tr><td><strong>Mode of Transport</strong></td><td>Driving</td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION">ACCESS_FINE_LOCATION</a></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACTIVITY_RECOGNITION">ACTIVITY_RECOGNITION</a> [2]</td></tr><tr><td></td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_BACKGROUND_LOCATION">ACCESS_BACKGROUND_LOCATION</a> [5]</td><td><a href="https://developer.android.com/reference/android/Manifest.permission#POST_NOTIFICATIONS">POST_NOTIFICATIONS</a> [4]</td></tr><tr><td></td><td></td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#BLUETOOTH_CONNECT">BLUETOOTH_CONNECT</a></td></tr><tr><td></td><td></td><td></td><td>GooglePlayLocationAccuracy [1]</td></tr><tr><td></td><td>Cycling</td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION">ACCESS_FINE_LOCATION</a></td><td>GooglePlayLocationAccuracy [1]</td></tr><tr><td></td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_BACKGROUND_LOCATION">ACCESS_BACKGROUND_LOCATION</a> [5]</td><td></td></tr><tr><td></td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACTIVITY_RECOGNITION">ACTIVITY_RECOGNITION</a></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#POST_NOTIFICATIONS">POST_NOTIFICATIONS</a> [4]</td></tr><tr><td></td><td>Walking</td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACTIVITY_RECOGNITION">ACTIVITY_RECOGNITION</a></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#POST_NOTIFICATIONS">POST_NOTIFICATIONS</a> [4]</td></tr><tr><td></td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_BACKGROUND_LOCATION">ACCESS_BACKGROUND_LOCATION</a> [5]</td><td></td></tr><tr><td><strong>Driving Services</strong></td><td>Distraction-Free-Driving (DFD)</td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION">ACCESS_FINE_LOCATION</a></td><td></td></tr><tr><td></td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#READ_PHONE_STATE">READ_PHONE_STATE</a></td><td></td></tr><tr><td></td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#SYSTEM_ALERT_WINDOW">SYSTEM_ALERT_WINDOW</a> [6]</td><td></td></tr><tr><td></td><td>Driving behaviour events (DBE)</td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION">ACCESS_FINE_LOCATION</a></td><td></td></tr><tr><td><strong>Other services</strong></td><td>Points of Interest</td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION">ACCESS_FINE_LOCATION</a></td><td></td></tr><tr><td></td><td></td><td>GooglePlayLocationAccuracy [1]</td><td></td></tr><tr><td></td><td>Public Transport</td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION">ACCESS_FINE_LOCATION</a></td><td></td></tr><tr><td></td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACTIVITY_RECOGNITION">ACTIVITY_RECOGNITION</a></td><td></td></tr><tr><td></td><td></td><td>GooglePlayLocationAccuracy [1]</td><td></td></tr><tr><td></td><td>Automatic Impact Detection</td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION">ACCESS_FINE_LOCATION</a></td><td>GooglePlayLocationAccuracy [1]</td></tr><tr><td></td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_BACKGROUND_LOCATION">ACCESS_BACKGROUND_LOCATION</a> [7]</td><td></td></tr><tr><td></td><td>Assistance Call</td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION">ACCESS_FINE_LOCATION</a> [3]</td></tr><tr><td></td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#FOREGROUND_SERVICE_LOCATION">FOREGROUND_SERVICE_LOCATION</a></td><td>Allows a regular application to use <a href="https://developer.android.com/reference/android/app/Service#startForeground(int,%20android.app.Notification)"><code>Service.startForeground</code></a> with the type "location".</td></tr><tr><td></td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#BLUETOOTH">BLUETOOTH</a></td><td>Phone call/speaker switch recognition.</td></tr><tr><td></td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#BLUETOOTH_CONNECT">BLUETOOTH_CONNECT</a></td><td>Needed only for communicates with already-paired Bluetooth devices. Android 12</td></tr><tr><td></td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#BLUETOOTH_SCAN">BLUETOOTH_SCAN</a></td><td>Needed to scan devices such as BLE.</td></tr><tr><td></td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#BLUETOOTH_ADMIN">BLUETOOTH_ADMIN</a></td><td>Needed to scan devices on Android 11 and lower.</td></tr><tr><td></td><td></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#CHANGE_NETWORK_STATE">CHANGE_NETWORK_STATE</a></td><td>To check internet connection in background.</td></tr><tr><td></td><td>Health</td><td><a href="https://developer.android.com/reference/android/health/connect/HealthPermissions#READ_STEPS">READ_STEPS</a></td><td>Health Connect</td></tr><tr><td></td><td></td><td><a href="https://developer.android.com/reference/android/health/connect/HealthPermissions#READ_HEALTH_DATA_IN_BACKGROUND">READ_HEALTH_DATA_IN_BACKGROUND</a></td><td>Health Connect</td></tr></tbody></table>

{% hint style="info" %}
**Note:** `SYSTEM_ALERT_WINDOW` (Overlay) and `REQUEST_IGNORE_BATTERY_OPTIMIZATIONS` require special handling. They cannot be requested via `requestPermissions()`.
{% endhint %}

{% hint style="info" %}
\[1] GooglePlayLocationAccuracy = isNetworkLocationPresent + isNetworkLocationUsable

\[2] improves trip recognition and classification considerably

\[3] required permission deprecated with v2.4.0+

\[4] see [POST\_NOTIFICATION](/move-platform/sdk/appendix/android/permission-handling/runtime-permissions) Runtime Permission

\[5] Since SDK 2.6: if *backgroundLocationPermissionMandatory* in [MoveOptions](/move-platform/sdk/models/moveoptions) is **true** the permission [ACCESS\_BACKGROUND\_LOCATION](https://developer.android.com/reference/android/Manifest.permission#ACCESS_BACKGROUND_LOCATION) is mandatory else this permission is optional.

\[6] Since SDK 2.6.9: if *overlayPermissionMandatory* in [MoveOptions](/move-platform/sdk/models/moveoptions) is **false** the permission [SYSTEM\_ALERT\_WINDOW](https://developer.android.com/reference/android/Manifest.permission#SYSTEM_ALERT_WINDOW) is **NOT** mandatory anymore. **Attention: in this case the device must be equipped with a gyroscope!**

\[7] Since SDK 2.19.0: strongly recommended if Automatic Impact Detection is used without Driving / Cycling. If the permission is missing, the [MoveServiceWarning](/move-platform/sdk/models/moveservicewarning) `BackgroundLocationPermissionMissing` is reported.
{% endhint %}

{% hint style="warning" %}
Grant the [Background Location](/move-platform/sdk/appendix/android/permission-handling/runtime-permissions#background-location) permission is strongly recommended. Similarly for the optional Activity Recognition permission (Driving) - make sure to request this from the user, otherwise it will degrade the quality of the service.
{% endhint %}

More Information regarding the Android system permissions can be found here: <https://developer.android.com/reference/android/Manifest.permission>

The required permissions must be granted before the MOVE SDK service can be used. In case of missing permissions this will be presented by [MoveServiceFailure](/move-platform/sdk/models/moveservicefailure) and/or by [MoveServiceWarning](/move-platform/sdk/models/moveservicewarning).

For more information about "dangerous permissions" visit the [official developer page](https://developer.android.com/guide/topics/permissions/overview).

In fact the MOVE SDK is not aware of permission changes, the developer can tell the MOVE SDK that the error is resolved.

```kotlin
val moveSdk = MoveSdk.get()
if (moveSdk != null) {
    val errors = moveSdk.getServiceErrors()
    if (errors.isNotEmpty()) {
        moveSdk.resolveError()
    }
}
```


# Runtime Permissions

In Android there are some [permissions](https://developer.android.com/guide/topics/permissions/overview#dangerous_permissions) which require a request during runtime. Keep in mind that those need to be defined in the manifest as well. Before init of the MOVE SDK the proper permissions should have been already requested.&#x20;

### Display over other apps

The overlay permission ([SYSTEM\_ALERT\_WINDOW](https://developer.android.com/reference/android/Manifest.permission#SYSTEM_ALERT_WINDOW)) ,which is required for distraction free driving, needs to be requested in a specific way. The user is lead to the app settings where the permission needs to be enabled.

Starting with Android 11, the user will only be taken to the settings overview screen, and the user needs to select the specific app itself.

```kotlin
val intent = Intent(
    Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
    Uri.parse("package:$packageName"))
startActivityForResult(intent, OVERLAY_REQUEST_CODE)
```

###

![Android App Info - Display over other apps](https://394612935-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXD5xlIFUYU8eK_kkLo%2F-McxM5LgwW5HR7ulVbpe%2F-McxoadttLu3hzrDV5Yf%2Fdevice-2021-06-24-133941.png?alt=media\&token=01f4e6c2-3ccc-41da-9fac-4e333f341429)

### Background location

Since Android 10 there is an additional background location which should be also requested when asking for location permission. In Android 11 the user must go to the location settings of the app to grant the "**Allow all the time**" permission.

![](https://394612935-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXD5xlIFUYU8eK_kkLo%2F-Ma7-Qp0tvRtlszHh2aC%2F-MaKm8RJuFvnXlq_gHv6%2Fimage.png?alt=media\&token=c1bfea51-62c5-4134-82dc-c1c639fff4af)

![](https://394612935-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXD5xlIFUYU8eK_kkLo%2F-McxM5LgwW5HR7ulVbpe%2F-McxncGAwHg9FJ2NF_ct%2Fdevice-2021-06-24-133608.png?alt=media\&token=8bd2043f-a537-412c-a1ae-7421d8ac2a9e)

### Notification permission

From the [Google developer documentation](https://developer.android.com/develop/ui/views/notifications/notification-permission):&#x20;

"*Android 13 (API level 33) and higher supports a* [*runtime permission*](https://developer.android.com/guide/topics/permissions/overview#runtime) *for sending* [*non-exempt*](https://developer.android.com/develop/ui/views/notifications/notification-permission#exemptions) *(including Foreground Services (FGS)) notifications from an app:* [*`POST_NOTIFICATIONS`*](https://developer.android.com/reference/android/Manifest.permission#POST_NOTIFICATIONS)*. This change helps users focus on the notifications that are most important to them.*"

```xml
<manifest ...>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <application ...>
        ...
    </application>
</manifest>
```


# Battery optimization

### Request battery optimization whitelist

Android has various power-saving modes across all manufacturers. One common feature is the [doze mode](https://developer.android.com/training/monitoring-device-state/doze-standby). This mode prevents the application from wakeup and has a negative impact on detection of the MOVE SDK. To circumvent this, the application can request to be whitelisted for such optimizations.&#x20;

```kotlin
fun isIgnoringBatteryOptimizations(context: Context): Boolean {
    val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager
    return pm.isIgnoringBatteryOptimizations(context.packageName)
}

@SuppressLint("BatteryLife")
fun requestIgnoreBatteryOptimization(activity: Activity) {
    if (!isIgnoringBatteryOptimizations(activity)) {
        val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply {
            data = Uri.parse("package:${activity.packageName}")
        }
        try {
            activity.startActivityForResult(intent, BATTERY_REQUEST_CODE)
        } catch (t: Throwable) {
            // handle exception
        }
    }
}
```

![Ignore battery optimizations](https://394612935-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXD5xlIFUYU8eK_kkLo%2F-McxM5LgwW5HR7ulVbpe%2F-Mcxo-EBAfcTCX0pott3%2F2021-06-24%2013_36_30-Window.png?alt=media\&token=67fdf9bf-9965-4724-8630-0d3a49d1d351)

{% hint style="warning" %}
Requesting battery optimizations is not mandatory, but strongly recommended.
{% endhint %}

{% hint style="danger" %}
Google Play allows this request only if the core functionality is impacted. Depending on your usecase of the app it may get suspended / rejected from the Play Store. Please check the[ offical docs](https://developer.android.com/training/monitoring-device-state/doze-standby#exemption-cases) for additional information.&#x20;
{% endhint %}

## Third party battery saving

Some manufacturers have their own implementations of battery saving features. Since we cannot cover all manufacturers here, a nice source for tips of keeping the app alive can be found at [dontkillmyapp](https://dontkillmyapp.com/).


# Notification Management

{% hint style="info" %}
For a complete implementation example including `NotificationChannel` setup, see the [Quick Start](/move-platform/sdk/getting-started/android/quick-start).
{% endhint %}

{% hint style="warning" %}
Since Android 13 there is a new [Notification Runtime Permission](/move-platform/sdk/appendix/android/permission-handling/runtime-permissions#notification-permission) introduced.
{% endhint %}

{% hint style="danger" %}
When running an Android application in background, several [limits ](https://developer.android.com/about/versions/oreo/background)apply, which also have [impact](https://developer.android.com/about/versions/oreo/background-location-limits) on retrieving locations. To circumvent this, an application needs to show a [foreground service ](https://developer.android.com/guide/components/foreground-services)with a notification visible to the user.
{% endhint %}

The notification is visible to the user and should therefore be maintained by the host app. For this reason the initialization provides three methods to pass a [notification](https://developer.android.com/training/notify-user/build-notification):

* [Recognition ](https://docs.movesdk.com/move-platform/sdk/appendix/android/pages/-MZIfp4AHvpUSOaycA60#dolphinsdk.builderv1.1-recognitionnotificationrecognitionnotifications)- Whenever the MOVE SDK tries to detect for example activities, trips or even more
* [Trip ](/move-platform/sdk/api-interface/android/initialization#trip-notifications)- When there is an active trip ([MoveTripState ](/move-platform/sdk/models/movetripstate)`.Running`).

By providing a [Notification.Builder ](https://developer.android.com/reference/android/app/Notification.Builder)you can freely customize the visible notification. With the *notificationId* you can even update the notification whenever you need to.&#x20;

{% hint style="info" %}
Don't forget to create a notification [channel](https://developer.android.com/training/notify-user/channels)
{% endhint %}

![Example notification ](https://394612935-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXD5xlIFUYU8eK_kkLo%2F-McxsOq3vXEBdq9LLpa3%2F-Mcxwlf8B-xYSh-yhQ9W%2F2021-06-24%2014_15_49-Window.png?alt=media\&token=ca1bb967-6daa-45bb-977c-d8da0720dc22)


# Forcing the Signal - Classic Bluetooth

### Background

Bluetooth connections are now very reliable, but problems can still occur. Especially with classic Bluetooth connections and also problems with missing [permissions](/move-platform/sdk/appendix/android/permission-handling). Some Bluetooth problems could also occur if the necessary permissions are granted during ongoing operations.

{% hint style="danger" %}
Please ensure that all necessary permissions are obtained before any app specific Bluetooth operations.
{% endhint %}

Unlike Bluetooth Low Energy (BLE), where connection status and changes can be reliably tracked, detecting the current connection status of Classic Bluetooth devices on Android comes with certain limitations. The Android system provides **only limited information** about existing connections to Bluetooth devices—especially when those connections were not initiated directly by the app itself.&#x20;

### Challenge

Android does not offer a reliable API to determine whether a Classic Bluetooth device is currently connected, **unless the connection was explicitly established by the app**. While system broadcasts like `BluetoothDevice.ACTION_ACL_CONNECTED` and `BluetoothDevice.ACTION_ACL_DISCONNECTED` do exist, they come with significant limitations:

* **Not guaranteed**: These broadcasts may be suppressed by power-saving mechanisms or system restrictions (e.g., Doze mode, background limitations).
* **Ephemeral**: They are only emitted when the connection state changes and are not retained—an app that starts later cannot reliably reconstruct the current connection state.

### Impact on the MOVE SDK

If a Bluetooth connection is established outside of the MOVE SDK (e.g., by another app or directly by the system), our Android module **cannot reliably detect** the actual connection status. This limitation applies only to Classic Bluetooth devices and **not** to BLE devices.

### Use-case example

Imagine the device of a user is already connected via classic Bluetooth with the car. Now the user installs your app with the MOVE SDK included or the necessary Bluetooth permissions were not granted yet.

The app has never received a `BluetoothDevice.ACTION_ACL_CONNECTED`  or `BluetoothDevice.ACTION_ACL_DISCONNECTED` . Now we are in the situation that the app does not know if the (already connected) car is connected or disconnected.

### Hint: Forcing ACL Broadcasts

It is possible to **force the system to emit** `BluetoothDevice.ACTION_ACL_CONNECTED` or `ACTION_ACL_DISCONNECTED` broadcasts by toggling the Bluetooth state on the device.

For example you can add the following message to the device registration screen in your app:

> **Please turn Bluetooth off and on again on your smartphone.**

This action resets the internal Bluetooth stack and trigger connection status updates, which in turn picked up by your SDK's`BroadcastReceiver`.


# iOS

References


# Permissions Handling

Description of required permissions, how to request and manage them.

## Required Permissions

{% hint style="danger" %}
Due to Apple's static code analysis, additional strings must be configured in the *Info.plist* to pass validation when uploading to the *AppStore* and *Testflight* even for features that are not used.

Required Strings:

* NSBluetoothAlwaysUsageDescription
* NSHealthShareUsageDescription
* NSHealthUpdateUsageDescription
* NSLocationAlwaysAndWhenInUseUsageDescription
* NSLocationAlwaysUsageDescription
* NSLocationWhenInUseUsageDescription
* NSMotionUsageDescription
  {% endhint %}

On SDK initialization, the host app passes a [MoveConfig](/move-platform/sdk/models/moveconfig) object to configure which of the SDK services should be activated. Some of those services require system permissions to be granted, or other features to be available.&#x20;

{% hint style="info" %}
&#x20;From a usability perspective, Apple provides some guidelines about [Requesting Permissions](https://developer.apple.com/design/human-interface-guidelines/ios/app-architecture/requesting-permission/) as part of their Human Interface Guidelines.
{% endhint %}

\
The table below shows each of the [MoveConfig](/move-platform/sdk/models/moveconfig) options and the corresponding required and optional permissions or sensors.

| **Service**        |                          | **Required permissions**                                                                                                 | **Optional permissions\[\*]**                                 |
| ------------------ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------- |
| Driving            | Driving                  | Location Permission Precise Location                                                                                     | Motion Permission Background Location Permission              |
|                    | Distraction-Free-Driving | Gyroscope and Accelerometer availability                                                                                 |                                                               |
|                    | Driving Behavior events  | Gyroscope and Accelerometer availability                                                                                 |                                                               |
|                    | Device Detection         |                                                                                                                          | Bluetooth Permission                                          |
| Cycling            | Bicycle                  | <p>Location Permission</p><p>Motion Permission Precise Location</p>                                                      | Background Location Permission                                |
| Walking            | Walking                  | Motion Permission                                                                                                        | Background Location Permission                                |
|                    | Location                 | LocationPermission Precise Location                                                                                      | Background Location Permission                                |
| Places             | Places                   | LocationPermission Precise Location                                                                                      |                                                               |
| Points of Interest | Points of Interest       | Location Permission Precise Location                                                                                     | Background Location Permission                                |
| Public Transport   | Public Transport stops   | Location Permission Precise Location                                                                                     | Background Location Permission                                |
| Impact Detection   | Impact Detection         | <p>Location Permission Precise Location</p><p>Gyroscope and Accelerometer availability</p>                               | <p>Motion Permission</p><p>Background Location Permission</p> |
| Assistance Call    | Assistance Call          | <p><del>Location Permission Precise Location</del><br><strong>(required permission deprecated with v2.4.0+)</strong></p> | <p>Location Permission Precise Location<br></p>               |
| Health             | Health Steps             | HealthKit, steps read Permission                                                                                         |                                                               |

{% hint style="info" %}
\[\*] Optional permissions can be set to required on `setup` by passing a [MoveOptions](/move-platform/sdk/models/moveoptions#ios) object with the flags `motionPermissionMandatory` and `backgroundLocationPermissionMandatory` to `true.`
{% endhint %}

## **Location Permission**

### **Authorization**

{% hint style="info" %}
This section considers the iOS 13 system location permissions changes.&#x20;
{% endhint %}

Starting iOS 13, system location is split into 2 layers: [`CLAuthorizationStatus`](https://developer.apple.com/documentation/corelocation/clauthorizationstatus) and [`CLAccuracyAuthorization`](https://developer.apple.com/documentation/corelocation/claccuracyauthorization)

#### [`CLAuthorizationStatus`](https://developer.apple.com/documentation/corelocation/clauthorizationstatus):

can be granted with one of the multiple access levels. Focusing only on the MOVE SDK relevant ones:

* [`CLAuthorizationStatus.authorizedAlways`](https://developer.apple.com/documentation/corelocation/clauthorizationstatus/authorizedalways): The user authorized the app to start and access location services at any time. Can be requested by calling [requestWhenInUseAuthorization()](https://developer.apple.com/documentation/corelocation/cllocationmanager/1620562-requestwheninuseauthorization).
* [`CLAuthorizationStatus.authorizedWhenInUse`](https://developer.apple.com/documentation/corelocation/clauthorizationstatus/authorizedwheninuse): The user authorized the app to start location services only while the app is in use. Can be requested by calling [requestAlwaysAuthorization()](https://developer.apple.com/documentation/corelocation/cllocationmanager/1620551-requestalwaysauthorization).

Starting with iOS 13, when an app requests[`.authorizedAlways`](https://developer.apple.com/documentation/corelocation/clauthorizationstatus/authorizedalways)the system prevents apps from directly receiving the[`.authorizedAlways`](https://developer.apple.com/documentation/corelocation/clauthorizationstatus/authorizedalways)access level. Instead, the operating system breaks the access into 2 steps.

* First, the operating system shows the user the permission prompt for [`.authorizedWhenInUse`](https://developer.apple.com/documentation/corelocation/clauthorizationstatus/authorizedwheninuse)
* Later on, the operating system shows the [`.authorizedAlways`](https://developer.apple.com/documentation/corelocation/clauthorizationstatus/authorizedalways) permission prompt when the app (in our case the MOVE SDK embedded in your app) fetches the location in the background for the first time.

Check this WWDC19 [session](https://developer.apple.com/videos/play/wwdc2019/705/) and [apple documentation](https://developer.apple.com/documentation/corelocation/cllocationmanager/1620551-requestalwaysauthorization) for further information about the iOS 13 authorization status changes.

{% hint style="danger" %}

#### Automatic Detection

The MOVE SDK can automatically wake up the app and activate its services (like trip detection, etc..) fully in the background and without any user interaction. Even if the app was killed by the user.

None of the SDK automatic detection services will work except if background location permission[`authorizationAlways`](https://developer.apple.com/documentation/corelocation/clauthorizationstatus/authorizedalways)is granted. Otherwise, the services will only work when the host app is in the foreground.
{% endhint %}

#### [`CLAccuracyAuthorization`](https://developer.apple.com/documentation/corelocation/claccuracyauthorization):

Starting iOS 13, Apple introduced 2 levels of accuracy access:

* [`.fullAccuracy`](https://developer.apple.com/documentation/corelocation/claccuracyauthorization/fullaccuracy): The user authorized the app to access location data with full accuracy.
* [`.reducedAccuracy`](https://developer.apple.com/documentation/corelocation/claccuracyauthorization/reducedaccuracy): The user authorized the app to access location data with reduced accuracy.

{% hint style="warning" %}
The MOVE SDK **requires** full accuracy access to precisely detect trips and deliver high-quality service.
{% endhint %}

### **Plist**

Apple requires apps requesting any system permission to provide reasoning for granting the permission. This reasoning is known as "purpose string" and is defined in the app's  `Info.plist` file. Those purpose strings are displayed as an explanation of why the app needs those access types, in the alert shown by the system to ask the user for permission.

In the case of location permission, each access level requires including one or more corresponding keys with purpose strings.

| **Key**                                                                                                                                                                            | Required if                                                                  |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| [`NSLocationWhenInUseUsageDescription`](https://developer.apple.com/documentation/bundleresources/information_property_list/nslocationwheninuseusagedescription)                   | Your app requests "*When In Use*" authorization or "*Always*" authorization. |
| [`NSLocationAlwaysAndWhenInUseUsageDescription`](https://developer.apple.com/documentation/bundleresources/information_property_list/nslocationalwaysandwheninuseusagedescription) | Your app requests "*Always"* authorization.                                  |
| [`NSLocationAlwaysUsageDescription`](https://developer.apple.com/documentation/bundleresources/information_property_list/nslocationalwaysusagedescription)                         | Your app supports iOS 10 and earlier and requests "*Always"* authorization.  |

### **Background Mode**

Moreover, for background location access, Location update Background Modes must be enabled:

1. Go to the **Capabilities** tab of your target settings
2. Turn on **Background Modes** and enable **Location updates**

![Location updates background mode capability](https://394612935-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXD5xlIFUYU8eK_kkLo%2F-Ma7-Qp0tvRtlszHh2aC%2F-MaWrFoEnyiReo8XoJL3%2Fimage.png?alt=media\&token=171c219f-f0e1-4d9a-9fe8-a0ccb47078a6)

{% hint style="info" %}
For more details about how to request location permissions, check out this Apple [document](https://developer.apple.com/documentation/corelocation/requesting_authorization_for_location_services).
{% endhint %}

### Sample Code

Requesting[`.authorizedAlways`](https://developer.apple.com/documentation/corelocation/clauthorizationstatus/authorizedalways)location authorization looks something like this:

```swift
import CoreLocation
 
class Permission: NSObject {
    let locationManager = CLLocationManager()
 
    func requestLocationPermission() {
        locationManager.delegate = self
        locationManager.requestAlwaysAuthorization()
    }  
}
 
extension Permission: CLLocationManagerDelegate {
    public func locationManager(_: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        // status
    }
}
```

## **Motion Permission**

### **.plist**

Same as with Location permission, Motion permission requires including the [NSMotionUsageDescription](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW21) with its corresponding purpose string in the app's `Info.plist` file.

```
// Example .plist for permissions.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>NSBluetoothPeripheralUsageDescription</key>
	<string></string>
	<key>NSBluetoothAlwaysUsageDescription</key>
	<string></string>
	<key>CMMotionActivity</key>
	<string>We need your motion..</string>
	<key>CLAccuracyAuthorization</key>
	<string>We need your location...</string>
	<key>NSMotionUsageDescription</key>
	<string>We need your motion...</string>
	<key>NSLocationAlwaysUsageDescription</key>
	<string>We need your location..</string>
	<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
	<string>We need your location..</string>
	<key>NSLocationWhenInUseUsageDescription</key>
	<string>We need your location..</string>
	
...
```

### **Permission**

There is no direct way to request Motion Activities access permission like with Locations. Instead, the permission prompts the first time the Motions API is called.

Requesting the motion permission will look something like this:

```swift
import CoreMotion
 
func requestCoreMotionPermission() {
    let manager = CMMotionActivityManager()
    let now = Date()
    
    switch CMMotionActivityManager.authorizationStatus() {
    case .restricted, .denied:
	// "NotAuthorized
    case .authorized:
	// "Authorized"
    case .notDetermined:
        manager.queryActivityStarting(from: now, to: now, to: .main) { activities, error in
        if let error = error as? NSError, error.code == Int(CMErrorMotionActivityNotAuthorized.rawValue) {
	    // "NotAuthorized"
	    } else {
	    // "Authorized"
	    }
        }
    }   
}
```

## Bluetooth Permission

When using the *Device Detection* feature it's possible to get warnings for the Bluetooth permission and power status from the SDK.

These checks will only be performed when the App itself has requested Bluetooth permission from the user, specifically if[`CBCentralManager.authorization`](https://developer.apple.com/documentation/corebluetooth/cbmanager/3377595-authorization) is anything other than `.notDetermined`.

Requesting the Bluetooth permission is done by creating an instance of the *CBCentralManager* type. This is entirely optional, and it's still possible to use the *Device Detection* service without this.

### **Plist**

<table data-header-hidden><thead><tr><th width="384">Key</th><th>Required if</th></tr></thead><tbody><tr><td><strong>Key</strong></td><td>Required if</td></tr><tr><td><a href="https://developer.apple.com/documentation/bundleresources/information_property_list/nsbluetoothalwaysusagedescription"><code>NSBluetoothAlwaysUsageDescription</code></a></td><td>Submitting an App to Testflight or AppStore.</td></tr><tr><td><a href="https://developer.apple.com/documentation/bundleresources/information_property_list/nsbluetoothperipheralusagedescription">NSBluetoothPeripheralUsageDescription</a> </td><td>Required only your application is built for iOS 13.0 or below.</td></tr></tbody></table>

## Health Permissions

{% hint style="warning" %}
MoveSDK 2.15: Health permissions are only required when [Health](/move-platform/move-services#health) services are needed, and the additional MoveSDKHealth framework is used. See [Installation](/move-platform/sdk/getting-started/ios/installation).
{% endhint %}

The *Health* service requires additional permission strings and entitlements.

The [NSHealthShareUsageDescription](https://developer.apple.com/documentation/BundleResources/Information-Property-List/NSHealthShareUsageDescription) permission string in the Info.plist is required when submitting to the AppStore regardless of whether the Health service is in use, similar to bluetooth permission strings.

<table><thead><tr><th width="279.765625">Key</th><th>Required if</th><th>Comment</th></tr></thead><tbody><tr><td><a href="https://developer.apple.com/documentation/BundleResources/Information-Property-List/NSHealthShareUsageDescription">NSHealthShareUsageDescription</a></td><td>Submitting an App to Testflight or AppStore.</td><td>This text must be at least 12 characters long.</td></tr><tr><td><a href="https://developer.apple.com/documentation/BundleResources/Information-Property-List/NSHealthUpdateUsageDescription">NSHealthUpdateUsageDescription</a></td><td>Submitting an App to Testflight or AppStore.</td><td>This text must be at least 12 characters long.</td></tr></tbody></table>

### Entitlements

Additional entitlements are required to guarantee health data synchronization:

<table><thead><tr><th width="279.765625">Entitlement</th><th>Comment</th></tr></thead><tbody><tr><td>com.apple.developer.healthkit</td><td>Required for Health service.</td></tr><tr><td>com.apple.developer.healthkit.background-delivery</td><td>Health data remains encrypted while the device is locked and cannot be accessed. This entitlement is necessary to wake up the app when health data is available.  It is not guaranteed when the App wakes up for health reasons. </td></tr></tbody></table>

### Provisioning

When the above entitlements are enabled HealthKit must be added to the App Identifier under the corresponding section in **Certificates, Identifiers & Profiles** in the [Apple Developer Portal](https://developer.apple.com/account/resources/identifiers/list).


# App Store

## App Submission

According to Apple [review guidelines](https://developer.apple.com/app-store/review/guidelines/) (last 17. April 2023 - section 2.5.4 "*Multitasking apps may only use background services for their intended purposes: VoIP, audio playback, location, task completion, local notifications, etc."*), when releasing an app that uses location background mode, it is required to inform its users that the use of background locations can have an impact on the device's battery life.

Hence, When submitting an app that includes MOVE SDK for approval on the App Store, you must include the following message in the app description:

> Continued use of GPS running in the background can dramatically decrease battery life.

## Privacy Section

In late 2020, Apple started requiring any new or updated app to include details about the data they capture and what they do with it, in the new app's privacy section.&#x20;

This is a list of what the MOVE SDK collects and the impact of the SDK on the new privacy section:

{% tabs %}
{% tab title="Motion" %}
Motion

* Used for App Functionality
* Linked to the user's identity
  {% endtab %}

{% tab title="Location" %}
**Precise Location**

* Used for App Functionality
* Linked to the user's identity
  {% endtab %}

{% tab title="Identifiers" %}
**User ID**

* Used for App Functionality
* Linked to the user's identity

**Device ID**

* Used for App Functionality
* Linked to the user's identity
  {% endtab %}
  {% endtabs %}

{% hint style="danger" %}
Due to Apple's static code analysis additional strings must be configured in the *Info.plist* to pass validation when uploading to the *AppStore*`and`*Testflight* even when this feature is not used. See section [iOS Permission Handling](/move-platform/sdk/appendix/ios/permission-handling#bluetooth-permission) for details.
{% endhint %}


# React Native

It is recommended to build with the new turbo module architecture.

{% hint style="danger" %}
There is a bug in Move SDK version 2.14.0 when building with the old architecture.

Please use version 2.14.1 instead.
{% endhint %}

### Expo

See [permission handling](/move-platform/sdk/appendix/react-native/permission-handling#expo) for proper configuration.

{% hint style="warning" %}
Since Move SDK version 2.14.0, when building with Expo,

a minimum of Expo version 52.x is required.
{% endhint %}


# Permission Handling

## Required Permissions

The required permissions for the individual services vary according to the platform type. See the sections *Permissions Handling* for [iOS](/move-platform/sdk/appendix/ios/permission-handling) and [Android](/move-platform/sdk/appendix/android/permission-handling) respectively.

Missing required and optional permissions will be reported by the SDK through the MoveServiceFailure and MoveServiceWarning listeners and listed individually so there is no need for the application to do it's own permission checks except during the onboarding process where user permission must be queried.

In best practice, this onboarding step is performed before any setup of the SDK happens, but permission changes at any later point in time is possible.

If permission checks happen at a later point make sure to call the `MoveSdk.resolveError()` function to ensure a timely activation of the affected services.

{% hint style="warning" %}
Due to Apple's static code analysis additional strings must be configured in the *Info.plist* to pass validation when uploading to the *AppStore*`and`*Testflight* even when this feature is not used. See section [iOS Permission Handling](/move-platform/sdk/appendix/ios/permission-handling#bluetooth-permission) for details.

*Move SDK 2.15*: Health permissions/entitlements are only required if MoveSDKHealth extension framework is used.
{% endhint %}

## Special Permissions

Due to the fact that some permission requests are not available directly from react native, the SDK offers an api that can be used to request the necessary permissions and check the status of those permissions:

### Shared

Asks for the Steps permission for Health service:

```typescript
MoveSdk.requestHealthPermissions(): Promise<boolean>
```

{% hint style="info" %}
Before using requestHealthPermissions() in Android make sure you registered permission handler in your activity and added corresponding intents to AndroidManifest!
{% endhint %}

In your MainActivity class:

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    // ...
    NativeMoveSdkWrapper.getInstance(this.applicationContext).registerRequestPermissionLauncher(this)
    // ...
    super.onCreate(null)
}
```

In AndroidManifest:

```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <!--Other permissions-->
  <!-- ... -->
  <uses-permission android:name="android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND"/>
  <uses-permission android:name="android.permission.health.READ_STEPS"/>
  <application android:name=".MainApplication">
    <activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
      <!--Other intents-->
      <!-- ... -->
      <!--Intent filters for Health Connect-->
      <intent-filter>
        <action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE"/>
        <category android:name="android.intent.category.HEALTH_PERMISSIONS"/>
      </intent-filter>
      <intent-filter>
        <action android:name="android.intent.action.VIEW_PERMISSION_USAGE"/>
        <category android:name="android.intent.category.HEALTH_PERMISSIONS"/>
      </intent-filter>
      <!--Intent filters for Health Connect-->
    </activity>
  </application>
</manifest>
```

### Android

#### Draw Overlays

Ask for draw over other apps permission:

```typescript
MoveSdk.requestDrawOverlaysPermission(): void
```

Check if draw over other apps permission is granted:

```typescript
MoveSdk.canDrawOverlays(): Promise<boolean>
```

#### Ignoring Battery Optimisation

Ask for ignoring battery optimisation for this app:

```typescript
MoveSdk.requestAppIgnoringBatteryOptimization(): void
```

Check if battery optimisation is ignored for this app:

```typescript
MoveSdk.isAppIgnoringBatteryOptimization(): Promise<boolean>
```

### iOS

#### Motion Permission

*ios.permission.MOTION* is available directly from react native, but requesting this permission via react native on simulators could be problematic. This method helps to request motion permission on simulators:

```typescript
MoveSdk.requestMotionPermission(): void
```

### Expo

If you are generating your project files with expo make sure to add the necessary capabilities to your expo config. See <https://docs.expo.dev/build-reference/ios-capabilities/>

Example:

```javascript
expo: {
	...
	ios: {
		...
		infoPlist: {
			NSLocationAlwaysAndWhenInUseUsageDescription: '...',
			NSLocationAlwaysUsageDescription: '...',
			NSLocationWhenInUseUsageDescription: '...',
			NSMotionUsageDescription: '...',
			NSLocationTemporaryUsageDescriptionDictionary: {
				'LOCATION-ACCURACY': '...',
			},
			UIBackgroundModes: ['location', 'remote-notification'],
			NSBluetoothAlwaysUsageDescription: '...',
			NSHealthShareUsageDescription: '...',
			NSHealthUpdateUsageDescription: '...',
		},
		entitlements: {
			'com.apple.developer.healthkit': true,
			'com.apple.developer.healthkit.background-delivery': true,
		},
		...
	...
},
```


# MOVE Backend

MOVE Backend APIs

The most current version of the MOVE backend APIs can be found in [**the Swagger documentation**](https://cdn.dolph.in/docs/swagger-ui/index.html?url=https://cdn.dolph.in/docs/openapi/sdk-v2_0-oas.yaml#/). The base URL of the MOVE SDK is:\
<https://sdk.dolph.in/>

#### Applying the Swagger Specification

You can use the Swagger Swagger Specification   as our most up-to-date **documentation** of the backend APIs. If you want to "Try it out" as offered in the Swagger Specification, please note that you need to "Authorize" your access to your MOVE project beforehand. There is a respective button on the top right of the Swagger:

* Press "Authorize" in the Swagger
* Use **`basicAuth`**
* Username: corresponds to the project ID of your MOVE project, which you can find in "[Configuration section](https://dashboard.movesdk.com/admin/sdkConfig)" of the MOVE dashboard.
* Password: corresponds to your API key from the respective section in the [MOVE Dashboard](https://dashboard.movesdk.com/admin/sdkConfig/keys). (Please note that any of your keys will work, but make sure it is "write only" = false).

In addition to using the Swagger Specification for human documentation you can use it to **automatically generate your client**. Use the Swagger generator of your programming language and your choice.

#### Authentication <a href="#gettingstartedwiththedolphinmovetimelineservice-authentication" id="gettingstartedwiththedolphinmovetimelineservice-authentication"></a>

The MOVE SDK uses Basic Authentication. The project id is your username, and the API Key is the password.

Example:

`Authorization: Basic cHJvamVjdElkOmFwaUtleQ==`

*cHJvamVjdElkOmFwaUtleQ==* is the string *projectId:apiKey* Base64 encoded.

API Keys can be found in the[ ](/move-platform/sdk/getting-started/move-dashboard)[MOVE Dashboard](https://dashboard.movesdk.com/admin/sdkConfig/keys), it is also possible to create new ones there.


# MOVE Admin API

MOVE Backend APIs

## Authentication <a href="#gettingstartedwiththedolphinmovetimelineservice-authentication" id="gettingstartedwiththedolphinmovetimelineservice-authentication"></a>

### Fetch or create <a href="#gettingstartedwiththedolphinmovetimelineservice-authentication" id="gettingstartedwiththedolphinmovetimelineservice-authentication"></a>

Registration or login of a user is equivalent to obtaining the security tokens and initialising the frontend MOVE SDK with those tokens. In other words: use the registration request to obtain the user tokens, and then forward the user tokens to your app for initializing the MOVE SDK (using a [MoveAuth](/move-platform/sdk/models/moveauth) object).

{% hint style="info" %}
Api Key: [MOVE Backend](/move-platform/backend/move-backend)
{% endhint %}

## Create or fetch user

<mark style="color:green;">`POST`</mark> `https://sdk.dolph.in/v20/user`

This request enables users to either fetch an existing user or create a new one. The response object includes an access token, which can be used to initialize the MOVE SDK on your mobile device. This access token is valid for 5 days. The registration process supports both new and existing user IDs.

#### Headers

| Name                                            | Type   | Description                       |
| ----------------------------------------------- | ------ | --------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | string | **Basic \<ProjectId>:\<API-Key>** |

#### Request Body

| Name                                     | Type   | Description                                                                                                                                                                                                                                                                                                                                            |
| ---------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| userId<mark style="color:red;">\*</mark> | string | An ID for the given user should be unique                                                                                                                                                                                                                                                                                                              |
| qualifier                                | string | An unique device identifier (see Get Device Qualifier [Android](/move-platform/sdk/api-interface/android/services#get-device-qualifier) / [iOS](/move-platform/sdk/api-interface/ios/services#get-device-qualifier) / [React](/move-platform/sdk/api-interface/react-native/services) / [Flutter](/move-platform/sdk/api-interface/flutter/services)). |

{% tabs %}
{% tab title="200 " %}

```
{
  "accessToken": "string",
  "refreshToken": "string",
  "userId": "string",
  "audience": "string",
  "installationId": "string",
  "projectId": 0
}
```

{% endtab %}

{% tab title="403: Forbidden Invalid authorization" %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Fetch auth code

<mark style="color:green;">`GET`</mark> `https://sdk.dolph.in/v20/user/authcode`

The Auth Code is a unique identifier (UUID) used to initialize the SDK on the front end. This code is fetched from the backend and is valid for 10 minutes. By using the Auth Code, you simplify the process of integrating the SDK into your front-end application.

#### Headers

<table><thead><tr><th>Name</th><th width="234">Type</th><th>Description</th></tr></thead><tbody><tr><td>Authorization<mark style="color:red;">*</mark></td><td>string</td><td><strong>Basic &#x3C;ProjectId>:&#x3C;API-Key></strong></td></tr></tbody></table>

#### Query Parameters

<table><thead><tr><th>Name</th><th width="234">Type</th><th>Description</th></tr></thead><tbody><tr><td>userId<mark style="color:red;">*</mark></td><td>string</td><td>The unique identifier for the user for whom the Auth Code is being requested.</td></tr></tbody></table>

#### Response Body

<table><thead><tr><th>Name</th><th width="227">Type</th><th>Description</th></tr></thead><tbody><tr><td>authCode<mark style="color:red;">*</mark></td><td>string</td><td>UUID to initalize SDK valid for 10 minutes</td></tr></tbody></table>

{% tabs %}
{% tab title="200 " %}

```
{
  "authCode": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```

{% endtab %}

{% tab title="403 Forbidden" %}

```
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Delete User <a href="#gettingstartedwiththedolphinmovetimelineservice-gettingnotifiedaboutnewtimelineitems" id="gettingstartedwiththedolphinmovetimelineservice-gettingnotifiedaboutnewtimelineitems"></a>

This request permanently deletes all user data associated with a specific user ID. Please note that the data is irreversibly lost.

<mark style="color:red;">`DELETE`</mark> `https://sdk.dolph.in/v20/user`

Deletes all user data permanently and all of its data

#### Headers

| Name                                            | Type   | Description                       |
| ----------------------------------------------- | ------ | --------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | String | **Basic \<ProjectId>:\<API-Key>** |
|                                                 |        |                                   |

#### Request Body

| Name                                        | Type   | Description            |
| ------------------------------------------- | ------ | ---------------------- |
| userId<mark style="color:red;">\*</mark>    | String | Id of Move SDK user    |
| projectId<mark style="color:red;">\*</mark> | String | Id of MOVE SDK project |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## User Config

API for retrieving or modifying user configuration settings.

### Fetch user config

<mark style="color:blue;">`GET`</mark> `https://sdk.dolph.in/v20/user/config`

fetch the current config for the given user

#### Query Parameters

| Name                                        | Type   | Description            |
| ------------------------------------------- | ------ | ---------------------- |
| projectId<mark style="color:red;">\*</mark> | String | Id of MOVE SDK project |
| userId                                      | String | Id of Move SDK user    |

#### Headers

| Name          | Type   | Description                       |
| ------------- | ------ | --------------------------------- |
| Authorization | String | **Basic \<ProjectId>:\<API-Key>** |

{% tabs %}
{% tab title="200: OK " %}

```
{
  "eco": {
    "co2EmissionBase": 160,
    "co2EngineType": "INTERNAL_COMBUSTION"
  }
}
```

{% endtab %}
{% endtabs %}

### Get user config history

<mark style="color:blue;">`GET`</mark> `https://sdk.dolph.in/v20/user/config/history`

Retrieves the change history of a user's configuration settings within a custom time range.&#x20;

#### Headers

| Name          | Type   | Required | Description                                      |
| ------------- | ------ | -------- | ------------------------------------------------ |
| Authorization | string | Yes      | Bearer token or Basic authentication credentials |

#### Query Parameters

| Name      | Type    | Required | Description                                                                                            |
| --------- | ------- | -------- | ------------------------------------------------------------------------------------------------------ |
| projectId | integer | Yes      | ID of the MOVE project                                                                                 |
| userId    | string  | Yes      | Unique ID of the user                                                                                  |
| from      | integer | No       | Unix timestamp start value                                                                             |
| to        | integer | No       | Unix timestamp end value                                                                               |
| limit     | integer | No       | Maximum number of history entries                                                                      |
| setting   | string  | No       | If provided, only returns history entries for this specific setting, for example `eco.co2EmissionBase` |

#### Request Body

No request body required.

#### Response

{% tabs %}
{% tab title="200: OK " %}

```json
{
  "history": [
    {
      "timestamp": 1716470400,
      "setting": "eco.co2EmissionBase",
      "value": 170
    }
  ]
}
```

{% endtab %}
{% endtabs %}

### Get user device history

<mark style="color:blue;">`GET`</mark> `https://sdk.dolph.in/v20/user/device/history`

Retrieves the Bluetooth / Beacon device registration history for a user within a custom time range.

Each returned entry represents one device lifecycle event, either `REGISTER` or `DEREGISTER`. Results are ordered by the event timestamp in descending order, meaning the newest event is returned first.

#### Headers

| Name          | Type   | Required | Description                                      |
| ------------- | ------ | -------- | ------------------------------------------------ |
| Authorization | string | Yes      | Bearer token or Basic authentication credentials |

#### Query Parameters

| Name      | Type    | Required | Description                       |
| --------- | ------- | -------- | --------------------------------- |
| projectId | integer | Yes      | ID of the MOVE project            |
| userId    | string  | Yes      | Unique ID of the user             |
| from      | integer | No       | Unix timestamp start value        |
| to        | integer | No       | Unix timestamp end value          |
| limit     | integer | No       | Maximum number of history entries |

#### Notes

* Bluetooth devices are identified by `deviceId`.
* Beacon devices are identified by the combination of `uuid`, `major`, and `minor`.
* If no matching events are found for the specified time range, the endpoint returns an empty array.

#### Request Body

No request body required.

#### Response

{% tabs %}
{% tab title="200: OK " %}

```json
{
   "history":[
      {
         "deviceType":"BLUETOOTH",
         "deviceId":"AA:BB:CC:DD:EE:FF",
         "eventType":"REGISTER",
         "timestamp":"2026-07-08T11:12:00.837Z"
      },
      {
         "deviceType":"BEACON",
         "uuid":"fda50693-a4e2-4fb1-afcf-c6eb07647825",
         "major":100,
         "minor":1,
         "eventType":"REGISTER",
         "timestamp":"2026-07-08T10:45:13.221Z"
      }
   ]
}
```

{% endtab %}
{% endtabs %}

| Name                                           | Type    | Description                                                                 |
| ---------------------------------------------- | ------- | --------------------------------------------------------------------------- |
| history.kind<mark style="color:red;">\*</mark> | string  | Type of registered device (`BLUETOOTH` or `BEACON`).                        |
| history.type                                   | string  | Bluetooth device identifier. Present only when `deviceType` is `BLUETOOTH`. |
| history.eventTimestamp                         | string  | Time the event occurred, in ISO 8601 UTC format.                            |
| history.name                                   | string  | Name of device                                                              |
| history.deviceId                               | string  | Bluetooth device identifier. Present only when `deviceType` is `BLUETOOTH`. |
| history.uuid                                   | string  | Beacon UUID. Present only when `deviceType` is `BEACON`.                    |
| history.major                                  | integer | Beacon major value. Present only when `deviceType` is `BEACON`.             |
| history.minor                                  | integer | Beacon minor value. Present only when `deviceType` is `BEACON`.             |

## Patch user config

<mark style="color:purple;">`PATCH`</mark> `https://sdk.dolph.in/v20/user/config`

update the current config for the given user

#### Query Parameters

| Name                                        | Type   | Description            |
| ------------------------------------------- | ------ | ---------------------- |
| userId<mark style="color:red;">\*</mark>    | String | Id of Move SDK user    |
| projectId<mark style="color:red;">\*</mark> | String | Id of MOVE SDK project |
|                                             |        |                        |

#### Headers

| Name                                            | Type   | Description                       |
| ----------------------------------------------- | ------ | --------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | String | **Basic \<ProjectId>:\<API-Key>** |

### User scores

This API enables you to retrieve scores for a specific user, with a focus on Exposure to Risk (ETR) and Move scores. Detailed parameters and responses are provided below

#### Exposure to risk

Why It's Important: The more time you spend driving, the greater your exposure to the risk of accidents. This risk is influenced not just by the distance traveled but also by the duration and timing of each trip. For instance, many accidents occur within the first few minutes of a drive, and the risk increases during extended journeys. Avoiding very short trips and taking breaks on longer ones can help mitigate this risk.&#x20;

How It Works: The ETR Score is calculated based on the number and duration of your trips. Additionally, the type of roads you travel on is factored into the score, with highways being the safest and rural roads posing higher risks. This score helps you understand and manage your exposure to risk, guiding you towards safer driving habits.MOVE Score

#### MOVE Score

Why It's Important: The MOVE Score is your total risk score, offering a clear and comprehensive understanding of your driving safety. It reflects your overall driving habits, combining key factors that influence driving risks.&#x20;

How It Works: This score merges your MOVE IQ, which evaluates your driving style, with your ETR, which considers how often and how long you drive. By bringing together these aspects, the MOVE Score provides a complete overview of your driving safety, taking into account both the quality of your driving and your time on the road.

## User scores

<mark style="color:blue;">`GET`</mark> `https://sdk.dolph.in/v20/scores/user`

Fetch scores of user, at the moment only ETR and Move score is supported.

#### Query Parameters

| Name                                        | Type    | Description                                                                                             |
| ------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------- |
| userId<mark style="color:red;">\*</mark>    | String  | Id of Move SDK user                                                                                     |
| projectId<mark style="color:red;">\*</mark> | String  | Id of MOVE SDK project                                                                                  |
| startTs<mark style="color:red;">\*</mark>   | Integer | Start timestamp for the score retrieval.                                                                |
| endTs<mark style="color:red;">\*</mark>     | Integer | End timestamp for the score retrieval.                                                                  |
| timeframe                                   | String  | Timeframe for the score calculation. Available values include DAILY, WEEKLY, MONTHLY, YEARLY, and NONE. |

#### Headers

| Name                                            | Type   | Description                       |
| ----------------------------------------------- | ------ | --------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | String | **Basic \<ProjectId>:\<API-Key>** |

{% tabs %}
{% tab title="200: OK " %}
This example response includes Exposure to Risk and Move scores along with historical data for various timeframes (daily, weekly, monthly, yearly).

```json
{
  "etr": 0,
  "moveScore": 0,
  "moveIq": 0,
  "dates": "string",
  "history": {
    "daily": [
      {
        "year": 2023,
        "month": 11,
        "day": 9,
        "weekOfYear": 45,
        "date": "09.11.2023",
        "score": 94,
        "moveScore": 94,
        "moveIq": 94,
        "calculated": "2023-11-09T15:04:13.941729Z"
      }
    ],
    "weekly": [
      {
        "year": 2023,
        "month": 11,
        "day": 9,
        "weekOfYear": 45,
        "date": "09.11.2023",
        "score": 94,
        "moveScore": 94,
        "moveIq": 94,
        "calculated": "2023-11-09T15:04:13.941729Z"
      }
    ],
    "monthly": [
      {
        "year": 2023,
        "month": 11,
        "day": 9,
        "weekOfYear": 45,
        "date": "09.11.2023",
        "score": 94,
        "moveScore": 94,
        "moveIq": 94,
        "calculated": "2023-11-09T15:04:13.941729Z"
      }
    ],
    "yearly": [
      {
        "year": 2023,
        "month": 11,
        "day": 9,
        "weekOfYear": 45,
        "date": "09.11.2023",
        "score": 94,
        "moveScore": 94,
        "moveIq": 94,
        "calculated": "2023-11-09T15:04:13.941729Z"
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

## Access Management&#x20;

### Block / Unblock User

Use this API endpoint to block or unblock a MOVE SDK User. When a user is blocked, the MOVE SDK Backend will return an HTTP Error 403 for all subsequent requests made by the blocked user.

## Block or unblock Move SDK user

<mark style="color:green;">`POST`</mark> `https://sdk.dolph.in/v20/access/block`

#### Request Body

| Name                                        | Type    | Description |
| ------------------------------------------- | ------- | ----------- |
| projectId<mark style="color:red;">\*</mark> | Int     |             |
| userId<mark style="color:red;">\*</mark>    | String  |             |
| block<mark style="color:red;">\*</mark>     | Boolean |             |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}


# MOVE TIMELINE API

MOVE Backend APIs

## Retrieving Timeline Items <a href="#gettingstartedwiththedolphinmovetimelineservice-retrievingtimelineitems" id="gettingstartedwiththedolphinmovetimelineservice-retrievingtimelineitems"></a>

For all Timeline API calls, the projectId needs to be specified as a query parameter.

#### What is a Timeline Item? <a href="#gettingstartedwiththedolphinmovetimelineservice-whatisatimelineitem" id="gettingstartedwiththedolphinmovetimelineservice-whatisatimelineitem"></a>

A timeline item represents an activity of a given user, it consists of a projectId, a userId, a start timestamp, an end timestamp, a type and a set of features. Which are described in the following sections.

Each timeline item is uniquely identified by the combination of projectId, userId and start time.

**Example Timeline Item**

```json
{
    "projectId": 1000, // an integer
    "userId": "123456789", // a string
    "startTs": "2020-10-16T10:13:00Z", // time formatted according to RFC 3339, e.g. "2020-07-10T06:59:44.377Z"
    "endTs": "2020-10-16T10:20:00Z", // time formatted according to RFC 3339, e.g. "2020-07-10T06:59:44.377Z"
    "type": "CAR", // a string, valid types are UNKNOWN, DRIVING, TRAIN, TRAM, CAR, METRO, FAKETRIP, WALKING, IDLE, CYCLING 
    "features": {
        ... // an object of features
    }
}
```

New feature types may be added in the future, a client should be able to deal with additional/unknown types of features.

**Start Location**

The GPS coordinates where the item started. Included with **DRIVING** and **CYCLING** trips.

* `lat` – Latitude in decimal degrees.
* `lon` – Longitude in decimal degrees.
* `timeZone` – IANA time zone identifier for the start location.
* `country` – Country information for the start location:
  * `alpha3` – ISO 3166-1 alpha-3 country code.
  * `alpha2` – ISO 3166-1 alpha-2 country code.
  * `name` – Full country name.

```json
"startLocation": {
  "lat": 51.878093,
  "lon": -0.396672,
  "timeZone": "Europe/London",
  "country": {
    "alpha3": "GBR",
    "alpha2": "GB",
    "name": "United Kingdom"
  }
```

**End Location**

The GPS coordinates where the item ended. Included with **DRIVING** and **CYCLING** trips.

* `lat` – Latitude in decimal degrees.
* `lon` – Longitude in decimal degrees.
* `timeZone` – IANA time zone identifier for the end location.
* `country` – Country information for the end location:
  * `alpha3` – ISO 3166-1 alpha-3 country code.
  * `alpha2` – ISO 3166-1 alpha-2 country code.
  * `name` – Full country name.

```json
"endLocation": {
    "lat": 51.419797,
    "lon": -0.223466,
    "timeZone": "Europe/London",
    "country": {
      "alpha3": "GBR",
      "alpha2": "GB",
      "name": "United Kingdom"
    }
  }
```

**Transport**

The type of transport that was used for the given trip. The Mode of Transport recognition is multi-stage and is mostly based on GPS coordinates and data about the position taken from OpenStreetMap data (e.g. speed, proximity to streets and public transport stations). In general, the algorithms are tuned towards distinguishing trips in car-like vehicles (including buses and taxi cabs) from non-car vehicles (e.g. bicycles, trains, metro). \
Note: Quality metrics reported in the following have a maximum variability of +- 3%-points.

* FAKETRIP - GPS sensors in mobile phones are not always accurate. Jumps of GPS data around the actual "real-world" position of the device may occur at all times; particularly in dense cities with bad visibility of the GPS satellites, when the phone is stacked e.g. beneath a laptop computer in the backpack, or even sometimes when weather conditions are bad. In rare situations, such GPS jumps may follow a pattern that makes our first stage SDK modules in the SDK frontends believe that the device is in an actual trip. Later stages in the SDK backend will label these trips as FAKETRIP.
* CAR - users of our apps usually have a preference for using cars in their day-to-day activities. In this (slightly biased) population, the detection of car trips (including car-like vehicles such as taxi cabs and buses) has a true positive rate of about 98% and a false positive rate of less than 5%.
* PUBLIC\_TRANSPORT - The recognition of public transport has multiple vectors: e.g. we may detect a tram trip through GPS like a CAR trip, or we may see a person moving from subway station to subway station and infer (since there are no GPS signals underground) that the person must have taken the subway. Since this contains an element of inference and heuristics, the detection/classification of public transport cannot be 100% perfect. Our tests show a true positive rate for railroad-based vehicles of more than 90%. However, bad GPS may further reduce the overall detection of public transport trips.\
  Note that currently we are unable to include buses or taxi into this category; although we can achieve this through hardware (e.g. cheap Bluetooth beacons) in the user's private car. Please get in touch for a more detailed discussion.
* BICYCLE - Cycling detection is based not only on GPS data but relies heavily on the activities recognized by the OS of the mobile device. Its quality may vary depending on the hardware of the mobile device, as well as the OS version used (e.g. Google Pixel and Huawei Android phones differ quite substantially in their sensitivity and update frequency of activity recognition).
* UNKNOWN - Whenever the user moves in ways that we cannot categorize, this will be UNKNOWN. For example, users on a boat trip on the sea, which is too far from the road network; or skiing in the mountains - these activities are fast and stable enough to be recorded as a trip, but cannot be verified/classified as a trip.

We are constantly working on improving these algorithms. Therefore, please be advised to use the "probabilities" merely as a rough indicator, but never base any filtering mechanisms on these data, as our machine learning algorithms may improve/change these numbers at any time.

```json
"transport": {
    "type": "TRAIN",  // possible types are CAR, METRO, TRAIN, TRAM, BICYCLE, FAKETRIP
    "probabilities": { // how probable each transport type is
      "TRAIN": 0,
      "TRAM": 0.064,
      "CAR": 0.832,
      "METRO": 0.002,
      "FAKETRIP": 0.08
    }
},
```

**Phone Distractions**

Times where the user used their phone. Included with DRIVING and CYCLING trips.

```json
"phoneDistractions": {
  "distractions": [
    {
      "type": "PHONE_CALL_HANDS_FREE", // the type of distractions, possible distractions are SWIPE_AND_TYPE (the user touched their phone), PHONE_CALL (the user made a phone call without any hands free equipment), PHONE_CALL_HANDS_FREE (the user made a phone call with hands free equipment)
      "start": "2021-05-27T12:57:10.234Z",  // time formatted according to RFC 3339, e.g. "2020-07-10T06:59:44.377Z"
      "end": "2021-05-27T12:57:10.234Z"  // time formatted according to RFC 3339, e.g. "2020-07-10T06:59:44.377Z"
    }
  ],
  "secondsPerType": {
    "PHONE_CALL": 0,
    "PHONE_CALL_HANDS_FREE": 0,
    "SWIPE_AND_TYPE": 0
  }
},
```

#### Driving Behavior Events

Returns a list of driving behavior events. Valid types of events are: CORNERING, ACCELERATION, BRAKING

```json
"drivingBehaviorEvents": {
  "events": [
    {
      "time": 0, // UNIX timestamp of event
      "type": "CORNERING", 
      "strength": 0, value between 1 (soft) to 3 (hard)
      "lat": 0, latitude of event
      "lon": 0, long event of vent
      "rawAccel": 0 // raw acceleration of event
    }
  ],
  "validTime": 0 // how many seconds of the trip could be analyse
}
```

#### **GPS Stats**

Provides basic information about the gps points for this timeline item.

`distance` contains the distance traveled in meters, `maxSpeed` the maximum speed in kph, `averageSpeed` contains the average speed in kph.

`distancePerWayTypeMeters` contains the distance that was traveled for each way type. A way type classifies the road that a trip point lies on into one of 3 categories: motorway, city or other. When the way type for a point is `motorway` it is on a major highway such as a Freeway or the Autobahn. When it is classified as `city` it lies on a residential road with a speed limit of less than 50 kph. All other roads are classified as `other`.

```json
 "gpsStats": {
    "distance": 0,
    "maxSpeed": 0,
    "averageSpeed": 0,
    "distancePerWayTypeMeters": {
       "motorway": 1540,
       "city": 507,
       "other": 11513
    }
}
```

#### Trip Metadata

It is possible to add custom metadata to every trip. Keys may be at most 255 characters long, values may be at most 1000 characters long.

```json
"metas": {
  "metaItem1": "example",
  "metaItem2": "123",
  "metaItem3": "example 2"
}
```

#### Dangerous Areas

The dangerous areas the user passed through in this timeline item. Inside a dangerous area speeding is punished more severely. Every project defines its own dangerous areas in the Move Dashboard.

The Dangerous Area Id is also found in the [points ](#v20-timeline-startts-points)request.

```json
"dangerous_areas": {
  "areas": [
    {
      "id": "d0bd9509-20b1-43d8-8b19-1c56b2db1fdb"
      "name": "name"
      "lat": 48.1770551 // longitude of the dangerous area position
      "lon": 16.3752482 // latitude of the dangerous area position
      "radius": 200 // radius of the danngerous area
    }
  ]
}
```

#### Bluetooth Information (btInfo)

This feature checks whether the smartphone is connected to a car's Bluetooth system or a beacon. The collected data provides insights into Bluetooth usage and connectivity during the trip.

**Bluetooth Registered Devices (registeredDevices)**

This section lists all detected Bluetooth devices, including:

* **deviceId**: The MAC address of the Bluetooth device.
* **name**: The device name, e.g., "My Skoda".
* **type**: Indicates if it is a Bluetooth device (BT) or a beacon.
* **activeTime**: The duration (in seconds) the device was connected (only for BT devices).
* **percentage**: The percentage of time the device remained connected (only for BT devices).
* **found**: Indicates if the device was detected at least once.
* **scans**: The number of times the system searched for beacons (only for beacons).
* **discoveries**: The number of times a beacon was found (only for beacons).

**Bluetooth Events (btEvents)**

This section tracks Bluetooth connection events during the trip:

* **deviceId**: The MAC address of the Bluetooth device.
* **name**: The name of the device.
* **time**: The timestamp of the event.
* **type**: The event type:
  * **c** = BT state of the device changed to connected (BT only)
  * **d** = BT state of the device changed to disconnected (BT only)
  * **ac** = device already connected (BT only)
  * **s** = discovered during a search (beacons only)
  * **n** = not found during a search (beacons only)

```json
"btInfo": {
  "registeredDevices": [
    {
      "deviceId": "string",
      "name": "string",
      "type": "string",
      "activeTime": 0,
      "percentage": 0,
      "found": true,
      "scans": 0,
      "discoveries": 0
    }
  ],
  "btEvents": [
    {
      "deviceId": "string",
      "name": "string",
      "time": "2025-02-11T09:31:26.038Z",
      "type": "string"
    }
  ]
}
```

**Scores**

The individual features above give you the raw data for characterizing and scoring your trip. For example. Based on this, you can calculate scores for your users.

* distraction-free driving (DFD): score is reduced for usage of phone or swipe-and-type during trip as specified in the feature phone\_distractions (in minutes)
* speed: the score is diminished when driving faster than the the speed limit, based on the speed and the maximum allowed speed in the separate API for GPS points
* driving behavior events (DBE): sensors will identify events where driving was not smooth for Acceleration, Braking or Cornering (in 3 levels of severity)
* eco-sensors: awards a better score for an eco-friendly driving-style, and assumes that a driver who constantly brakes and accelerates uses more fuel than a driver who manages to drive very smoothly; similar to an aggregation of DBE, but more sensitive.\
  Note, that this insufficient to define a comprehensive Eco-score, which also addresses type of car/fuel, overall transport mix, distance/minutes driven on a daily basis, or other factors you may want to include&#x20;
* you can come up with your own scoring mechanisms, such as:
  * Trip duration (short): users should ideally only take the car for trips longer than x minutes, since short trips are very prone to accidents
  * Trip duration (long): drivers will get tired on long-trips, so take a rest of at least e.g. 10 minutes or more after every 2 hours of driving
  * Eco-score: calculate your own eco-score, based on Eco-sensors (see above, the mix of transport-types and/or based on the type of car/fuel the user defined in your app

We also make **score suggestions** for scores 0-100, that are based on data analyses of our current user base. We geared the scores to see a Gaussian distribution of aggregated scores (total score per user) with a mean somewhere around 80 or 90. After all, we want to positively encourage people to improve their driving style (which is hard if we gave them bad scores for decent driving style). Please note that this is a global generic scoring distribution. However, age, culture and other factors may influence the driving style. So you may want to adjust your scoring mechanism to suit your user base.

Note that scores may not be there in case they cannot be calculated; e.g. DFD scores are not calculated in case Android phones do not grant the PHONE permission; DBE scores are not calculated in case the phone is used or is located at an unstable place in the car.

```json
"scores": {
    "DFD":100,
    "SPEED":63,
    "ACCELERATION":85,
    "BRAKING":73,
    "CORNERING":95,
    "ECO_SENSOR": 67
}
```

## /v20/timeline/{startTs}

<mark style="color:blue;">`GET`</mark> `https://sdk.dolph.in/v20/timeline/{startTs}`

Fetch a single timeline item

#### Path Parameters

| Name                                      | Type   | Description                                  |
| ----------------------------------------- | ------ | -------------------------------------------- |
| startTs<mark style="color:red;">\*</mark> | Number | start timestamp of the request timeline item |

#### Query Parameters

| Name                                        | Type    | Description |
| ------------------------------------------- | ------- | ----------- |
| projectId<mark style="color:red;">\*</mark> | integer |             |
| userId<mark style="color:red;">\*</mark>    | string  |             |

#### Headers

| Name                                            | Type   | Description                       |
| ----------------------------------------------- | ------ | --------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | string | **Basic \<ProjectId>:\<API-Key>** |

{% tabs %}
{% tab title="200 " %}

```json
{
  "productId": 0,
  "contractId": "string",
  "startTs": "2021-06-24T07:40:25.455Z",
  "endTs": "2021-06-24T07:40:25.455Z",
  "type": "UNKNOWN",
  "features": {
    "startLocation": {
      "lat": 0,
      "lon": 0
    },
    "endLocation": {
      "lat": 0,
      "lon": 0
    },
    "source": {
      "id": "string",
      "name": "string"
    },
    "scores": {
      "additionalProp1": 0,
      "additionalProp2": 0,
      "additionalProp3": 0
    },
    "drivingBehaviorEvents": {
      "events": [
        {
          "time": 0,
          "type": "CORNERING",
          "strength": 0,
          "lat": 0,
          "lon": 0,
          "rawAccel": 0
        }
      ],
      "validTime": 0
    },
    "phoneDistractions": {
      "distractions": [
        {
          "type": "PHONE_CALL_HANDS_FREE",
          "start": "2021-06-24T07:40:25.456Z",
          "end": "2021-06-24T07:40:25.456Z"
        }
      ],
      "secondsPerType": {
        "PHONE_CALL": 0,
        "PHONE_CALL_HANDS_FREE": 0,
        "SWIPE_AND_TYPE": 0
      }
    },
    "gpsStats": {
      "distance": 0,
      "maxSpeed": 0,
      "averageSpeed": 0
    },
    "transport": {
      "type": "TRAIN",
      "probabilities": {
        "TRAIN": 0,
        "TRAM": 0,
        "BUS": 0,
        "CAR": 0,
        "METRO": 0,
        "FAKETRIP": 0
      }
    },
    "metas": {
      "additionalProp1": "string",
      "additionalProp2": "string",
      "additionalProp3": "string"
    }
  }
}
```

{% endtab %}

{% tab title="404 No single item was found for this timestamp" %}

```
```

{% endtab %}
{% endtabs %}

## Delete timeline Item

<mark style="color:red;">`DELETE`</mark> `https://sdk.dolph.in/v20/timeline/{startTs}`

Delete a single timeline item. startTs is an unix timestamp.

#### Path Parameters

| Name                                       | Type    | Description                 |
| ------------------------------------------ | ------- | --------------------------- |
| startTs <mark style="color:red;">\*</mark> | integer | Start time of timeline item |

#### Query Parameters

| Name                                         | Type    | Description |
| -------------------------------------------- | ------- | ----------- |
| projectId <mark style="color:red;">\*</mark> | integer |             |
| userId <mark style="color:red;">\*</mark>    | string  |             |

{% tabs %}
{% tab title="200: OK Deletion successful" %}

```javascript
{
    // Response
}
```

{% endtab %}

{% tab title="404: Not Found Item not found" %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## /v20/timeline

<mark style="color:blue;">`GET`</mark> `https://sdk.dolph.in/v20/timeline`

Fetch the latest timeline items in a given time range for a user

#### Query Parameters

| Name                                                      | Type    | Description                                                                                                        |
| --------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------ |
| limit                                                     | integer | The maximum number of items to return. Default: 10, The maximum accepted value is 10 000.                          |
| to                                                        | integer | UNIX timestamp. NO items with a startTS later than this will be returned                                           |
| from                                                      | integer | UNIX timestamp. NO items with an endTS earlier than this will be returned                                          |
| projectId<mark style="color:red;">\*</mark>               | string  |                                                                                                                    |
| userId<mark style="color:red;">\*</mark>                  | string  |                                                                                                                    |
| allowedItems                                              | String  | list of allowed types. If empty all types are allowed.                                                             |
| ~~tag~~  <mark style="color:$danger;">(deprecated)</mark> | String  | List of tags to filter the results, search in metas field of timeline item. Checks key and value of the meta data. |

#### Headers

| Name                               | Type   | Description                       |
| ---------------------------------- | ------ | --------------------------------- |
| <mark style="color:red;">\*</mark> | string | **Basic \<ProjectId>:\<API-Key>** |

{% tabs %}
{% tab title="200 " %}

```json
[
  {
    "productId": 0,
    "contractId": "string",
    "startTs": "2021-06-24T07:40:44.941Z",
    "endTs": "2021-06-24T07:40:44.941Z",
    "type": "UNKNOWN",
    "features": {
      "startLocation": {
        "lat": 0,
        "lon": 0
      },
      "endLocation": {
        "lat": 0,
        "lon": 0
      },
      "source": {
        "id": "string",
        "name": "string"
      },
      "scores": {
        "additionalProp1": 0,
        "additionalProp2": 0,
        "additionalProp3": 0
      },
      "drivingBehaviorEvents": {
        "events": [
          {
            "time": 0,
            "type": "CORNERING",
            "strength": 0,
            "lat": 0,
            "lon": 0,
            "rawAccel": 0
          }
        ],
        "validTime": 0
      },
      "phoneDistractions": {
        "distractions": [
          {
            "type": "PHONE_CALL_HANDS_FREE",
            "start": "2021-06-24T07:40:44.941Z",
            "end": "2021-06-24T07:40:44.941Z"
          }
        ],
        "secondsPerType": {
          "PHONE_CALL": 0,
          "PHONE_CALL_HANDS_FREE": 0,
          "SWIPE_AND_TYPE": 0
        }
      },
      "gpsStats": {
        "distance": 0,
        "maxSpeed": 0,
        "averageSpeed": 0
      },
      "transport": {
        "type": "TRAIN",
        "probabilities": {
          "TRAIN": 0,
          "TRAM": 0,
          "BUS": 0,
          "CAR": 0,
          "METRO": 0,
          "FAKETRIP": 0
        }
      },
      "metas": {
        "additionalProp1": "string",
        "additionalProp2": "string",
        "additionalProp3": "string"
      },
      "dangerous_areas": {
        "areas": [
          {
            "id": "d0bd9509-20b1-43d8-8b19-1c56b2db1fdb"
            "name": "name"
            "lat": 48.1770551
            "lon": 16.3752482
            "radius": 200
          }
        ]
      }
    }
  }
]
```

{% endtab %}
{% endtabs %}

## &#x20;​/v20​/timeline​/batch

<mark style="color:green;">`POST`</mark> `https://sdk.dolph.in ​/v20​/timeline​/batch`

Fetch a batch of timeline items

#### Request Body

| Name                                        | Type   | Description                            |
| ------------------------------------------- | ------ | -------------------------------------- |
| startTs<mark style="color:red;">\*</mark>   | string | Start time of requested timeline items |
| projectId<mark style="color:red;">\*</mark> | string |                                        |
| userId<mark style="color:red;">\*</mark>    | string |                                        |

{% tabs %}
{% tab title="200 " %}

```json
[
  {
    "productId": 0,
    "contractId": "string",
    "startTs": "2021-06-24T07:40:44.941Z",
    "endTs": "2021-06-24T07:40:44.941Z",
    "type": "UNKNOWN",
    "features": {
      "startLocation": {
        "lat": 0,
        "lon": 0
      },
      "endLocation": {
        "lat": 0,
        "lon": 0
      },
      "source": {
        "id": "string",
        "name": "string"
      },
      "scores": {
        "additionalProp1": 0,
        "additionalProp2": 0,
        "additionalProp3": 0
      },
      "drivingBehaviorEvents": {
        "events": [
          {
            "time": 0,
            "type": "CORNERING",
            "strength": 0,
            "lat": 0,
            "lon": 0,
            "rawAccel": 0
          }
        ],
        "validTime": 0
      },
      "phoneDistractions": {
        "distractions": [
          {
            "type": "PHONE_CALL_HANDS_FREE",
            "start": "2021-06-24T07:40:44.941Z",
            "end": "2021-06-24T07:40:44.941Z"
          }
        ],
        "secondsPerType": {
          "PHONE_CALL": 0,
          "PHONE_CALL_HANDS_FREE": 0,
          "SWIPE_AND_TYPE": 0
        }
      },
      "gpsStats": {
        "distance": 0,
        "maxSpeed": 0,
        "averageSpeed": 0
      },
      "transport": {
        "type": "TRAIN",
        "probabilities": {
          "TRAIN": 0,
          "TRAM": 0,
          "BUS": 0,
          "CAR": 0,
          "METRO": 0,
          "FAKETRIP": 0
        }
      },
      "metas": {
        "additionalProp1": "string",
        "additionalProp2": "string",
        "additionalProp3": "string"
      }
    }
  }
]
```

{% endtab %}
{% endtabs %}

## ​/v20​/timeline​/{startTs}​/points

<mark style="color:blue;">`GET`</mark> `https://sdk.dolph.in ​/v20​/timeline​/{startTs}​/points`

Fetch the GPS Coordinates for the given timeline item. Not all timeline items have GPS points, for example IDLE items have no points.

#### Path Parameters

| Name                                        | Type   | Description                           |
| ------------------------------------------- | ------ | ------------------------------------- |
| start\_ts<mark style="color:red;">\*</mark> | string | start time of requested timeline item |

#### Query Parameters

| Name                                        | Type   | Description                                  |
| ------------------------------------------- | ------ | -------------------------------------------- |
| withWayPointInfo                            | string | Whether to fetch detailed info for waypoints |
| userId<mark style="color:red;">\*</mark>    | string |                                              |
| projectId<mark style="color:red;">\*</mark> | string |                                              |

{% tabs %}
{% tab title="200 " %}

```json
[
    {
        "timestamp": "2020-10-16T13:17:34.691Z",
        "lat": 48.12356,
        "lon": 16.122556,
        "wayPointInfo": { // will not be given if withWayPointInfo is false
            "speed": 45 // the speed of the user at the given coordinate
            "speedLimit": 50, // the speed limit at the given way point
            "wayType": "city", // on what kind of road the gps point lies valid values are "city", "tunnel", "motorway" and "other"
            "roadLat": 48.124599, // latitude on the matched road point
            "roadLon": 16.125567 // longitude on the matched road point
            "dangerousAreaId": "01bd3c3a-930c-4449-a035-827d091d72ed" //UUID of Dangerous Area
        }
    },
    ...
]
```

{% endtab %}
{% endtabs %}

## Label trip

<mark style="color:purple;">`PATCH`</mark> `https://sdk.dolph.in/v20/timeline/admin/label/{ts}/{label}`

Change type of a trip

#### Query Parameters

| Name                                        | Type   | Description                      |
| ------------------------------------------- | ------ | -------------------------------- |
| ts<mark style="color:red;">\*</mark>        | string | start timestamp of timeline item |
| label<mark style="color:red;">\*</mark>     | String | Label of timeline item           |
| projectId<mark style="color:red;">\*</mark> | String |                                  |
| userId<mark style="color:red;">\*</mark>    | String |                                  |

#### Headers

| Name                                            | Type   | Description                      |
| ----------------------------------------------- | ------ | -------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | String | BASIC \<PRODUCT*ID>:\<API\_KEY>* |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "productId": 0,
  "contractId": "string",
  "startTs": "2022-04-11T07:46:17.168Z",
  "endTs": "2022-04-11T07:46:17.168Z",
  "type": "UNKNOWN",
  "features": {
    "startLocation": {
      "lat": 0,
      "lon": 0,
      "name": null
    },
    "endLocation": {
      "lat": 0,
      "lon": 0,
      "name": null
    },
    "source": {
      "id": "string",
      "name": "string"
    },
    "scores": {
      "additionalProp1": 0,
      "additionalProp2": 0,
      "additionalProp3": 0
    },
    "drivingBehaviorEvents": {
      "events": [
        {
          "time": 0,
          "type": "CORNERING",
          "strength": 0,
          "lat": 0,
          "lon": 0,
          "rawAccel": 0
        }
      ],
      "validTime": 0
    },
    "phoneDistractions": {
      "distractions": [
        {
          "type": "PHONE_CALL_HANDS_FREE",
          "start": "2022-04-11T07:46:17.169Z",
          "end": "2022-04-11T07:46:17.169Z"
        }
      ],
      "secondsPerType": {
        "PHONE_CALL": 0,
        "PHONE_CALL_HANDS_FREE": 0,
        "SWIPE_AND_TYPE": 0
      }
    },
    "gpsStats": {
      "distance": 0,
      "maxSpeed": 0,
      "averageSpeed": 0
    },
    "transport": {
      "type": "TRAIN",
      "probabilities": {
        "TRAIN": 0,
        "TRAM": 0,
        "BUS": 0,
        "CAR": 0,
        "METRO": 0,
        "FAKETRIP": 0
      }
    },
    "metas": {
      "additionalProp1": "string",
      "additionalProp2": "string",
      "additionalProp3": "string"
    },
    "dangerousAreas": {
      "areas": [
        {
          "id": "string",
          "name": "string",
          "lat": 0,
          "lon": 0,
          "radius": 0
        }
      ]
    }
  }
}
```

{% endtab %}
{% endtabs %}

### Vehicle Timeline

#### Endpoint

```http
GET /v20/timeline/vehicle
```

#### Description

Retrieves a list of timeline events for a specific **vehicle** within a defined time range. This API is useful for inspecting activity (e.g., trips, idling, or movement) tied to a **vehicle UUID**, independent of any specific user.

You can filter by a time window using Unix timestamps in **seconds**, and optionally limit the number of results.

***

#### Query Parameters

| Name        | Type                   | Required | Description                                             |
| ----------- | ---------------------- | -------- | ------------------------------------------------------- |
| `vehicleId` | string                 | ✅        | UUID of the vehicle                                     |
| `projectId` | integer                | ✅        | ID of the project the vehicle belongs to                |
| `from`      | integer (Unix seconds) | ❌        | Start of the time range (Unix timestamp in **seconds**) |
| `to`        | integer (Unix seconds) | ❌        | End of the time range (Unix timestamp in **seconds**)   |
| `limit`     | integer                | ❌        | Maximum number of items to return                       |

***

#### Response

A list of timeline entries containing details about each trip or event:

```json
[
  {
    "projectId": 42,
    "userId": "user-123",
    "startTs": "2025-06-10T08:00:00Z",
    "endTs": "2025-06-10T08:45:00Z",
    "type": "DRIVING",
    "features": {
      "gpsStats": {
        "distance": 15000,
        "averageSpeed": 52,
        "maxSpeed": 92
      },
      "eco": {
        "co2EmittedGrams": 120.0,
        "co2EngineType": "INTERNAL_COMBUSTION"
      },
      "startLocation": {
        "lat": 48.2082,
        "lon": 16.3738,
        "name": "Vienna City Center"
      },
      "endLocation": {
        "lat": 48.2100,
        "lon": 16.4000,
        "name": "Vienna East"
      }
    }
  }
]
```

***

####

The Open API Specification for the MOVE SDK API is available [here](https://cdn.dolph.in/docs/swagger-ui/index.html?url=https://cdn.dolph.in/docs/openapi/sdk-v2_0-oas.yaml#/).

## Getting notified about new timeline items <a href="#gettingstartedwiththedolphinmovetimelineservice-gettingnotifiedaboutnewtimelineitems" id="gettingstartedwiththedolphinmovetimelineservice-gettingnotifiedaboutnewtimelineitems"></a>

Notification about new timeline items happens via webhooks that can be defined in the MOVE Dashboard > Configuration > Timeline Notifier.

The webhook will be called with a POST request that contains a JSON body with a list of new timeline items. Updates are sent every 1000 items or every 5 seconds (whatever comes first). The information transmitted to the webhook is limited, you may request additional information via timeline API, preferably batched.

#### Schema <a href="#gettingstartedwiththedolphinmovetimelineservice-schema" id="gettingstartedwiththedolphinmovetimelineservice-schema"></a>

```json
{
    "items": [
        {
            "projectId": <yourProjectId>, // integer
            "userId": <userId>, // string
            "startTime": <startTime>, // time formatted according to RFC 3339, e.g. "2020-07-10T06:59:44.377Z"
            "endTime": <endTime>, // time formatted according to RFC 3339, e.g. "2020-07-10T06:59:44.377Z"
            "type": <type> // string, one of IDLE, CYCLING, WALKING, DRIVING
        }, ...
    ]
}
```

If the webhook receiver is not available or does not respond with an HTTP 200 Status the request will be retried, until an HTTP 200 Status is received.

#### Security <a href="#gettingstartedwiththedolphinmovetimelineservice-security" id="gettingstartedwiththedolphinmovetimelineservice-security"></a>

With every request, a signature is being sent in the "X-Dolphin-Signature" Header that may be used to verify that the request has acutally been made by the Move SDK. The signature is calculated as an HMAC with SHA-256 of the request body, with the secret (token) you gave us during the receiver setup. The format of the header is "sha256=\<base64-encoded-hash>".


# MOVE State API

MOVE Backend APIs

Returns a list of state changes over the given time range.

For the `STATUS` property the possible values are:

* `UNINITIALISED` - initial state
* `READY` -  after initialisation / setup or after stopAutomaticDetection ([Android](/move-platform/sdk/api-interface/android/services#stop-automatic-detection) / [iOS](/move-platform/sdk/api-interface/ios/services#stop-automatic-detection) / [React](/move-platform/sdk/api-interface/react-native/services#stop-automatic-detection) / [Flutter](/move-platform/sdk/api-interface/flutter/services#stop-automatic-detection))
* `RUNNING` -  after calling startAutomaticDetection ([Android](/move-platform/sdk/api-interface/android/services#start-automatic-detection) / [iOS](/move-platform/sdk/api-interface/ios/services#start-automatic-detection) / [React](/move-platform/sdk/api-interface/react-native/services#start-automatic-detection) / [Flutter](/move-platform/sdk/api-interface/flutter/services#start-automatic-detection))

## history

<mark style="color:blue;">`GET`</mark> `https://sdk.dolph.in/v20/state/history`

Returns a list of state changes over the given time range.

For the `STATUS` property the possible values are:

#### Path Parameters

| Name | Type   | Description |
| ---- | ------ | ----------- |
|      | String |             |

#### Query Parameters

| Name                                        | Type    | Description                                                                                                          |
| ------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------- |
| projectId<mark style="color:red;">\*</mark> | Integer |                                                                                                                      |
| userId<mark style="color:red;">\*</mark>    | String  |                                                                                                                      |
| properties                                  | String  | A comma separated list of state properties that shall be returned. At the moment the only possible value is 'STATUS' |
| from                                        | integer | A unix timestamp, start of query range.                                                                              |
| to                                          | integer | A unix timestamp, end of query range.                                                                                |
| limit                                       | integer | Maximum number of items to return, must be greater than or equal to zero.                                            |

#### Headers

| Name                                            | Type   | Description                       |
| ----------------------------------------------- | ------ | --------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | String | **Basic \<ProjectId>:\<API-Key>** |

{% tabs %}
{% tab title="200: OK " %}

```json
{
  "history": [
    {
      "data": {
        "STATUS": "RUNNING"
      },
      "timestamp": "2022-07-20T05:38:10.586Z"
    },
    {
      "data": {
        "STATUS": "READY"
      },
      "timestamp": "2022-07-20T04:38:10.586Z"
    },
    {
      "data": {
        "STATUS": "UNINITIALISED"
      },
      "timestamp": "2022-07-20T03:38:10.586Z"
    }
  ]
}
```

{% endtab %}
{% endtabs %}


# MOVE Last Location API

MOVE Backend APIs

Returns the last known location of an SDK user.  The `context` describes the location source. At the moment the following contexts exist:

* TIMELINE-END: last timeline location
* CAR-END: last car trip location
* TRIP-POSITION: live updates during a trip
* USERPOS: user position - reported about once per day (if OS wakes up app at all), independent of user timeline; NOTE may be older than e.g. *timeline-end*, so please check timestamp
* TAG: Trip position can be tagged the context name is&#x20;

  ```
  TAG:TAG_NAME
  ```

## Last location&#x20;

<mark style="color:blue;">`GET`</mark> `https://sdk.dolph.in/v20/location`

Returns last position of each context

#### Query Parameters

| Name                                         | Type    | Description |
| -------------------------------------------- | ------- | ----------- |
| projectId <mark style="color:red;">\*</mark> | integer |             |
| userId<mark style="color:red;">\*</mark>     | String  |             |

#### Headers

| Name                                            | Type   | Description                       |
| ----------------------------------------------- | ------ | --------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | String | **Basic \<ProjectId>:\<API-Key>** |

{% tabs %}
{% tab title="200: OK " %}

```json
[
  {
    "context": "string",
    "lat": 0,
    "lon": 0,
    "accuracy": 0,
    "timestamp": "2022-08-08T09:51:44.109Z"
  }
]
```

{% endtab %}
{% endtabs %}

## Last context location

<mark style="color:blue;">`GET`</mark> `https://sdk.dolph.in/v20/location/{context}`

Returns last location of specific context

#### Path Parameters

| Name                                      | Type   | Description                                   |
| ----------------------------------------- | ------ | --------------------------------------------- |
| context<mark style="color:red;">\*</mark> | String | timeline-end, car-end, userpos, trip-position |

#### Query Parameters

| Name                                        | Type   | Description |
| ------------------------------------------- | ------ | ----------- |
| userId<mark style="color:red;">\*</mark>    | String |             |
| projectId<mark style="color:red;">\*</mark> | String |             |

#### Headers

| Name          | Type   | Description                       |
| ------------- | ------ | --------------------------------- |
| Authorization | String | **Basic \<ProjectId>:\<API-Key>** |

{% tabs %}
{% tab title="200: OK " %}

```json
{
  "context": "string",
  "lat": 0,
  "lon": 0,
  "accuracy": 0,
  "timestamp": "2022-08-08T09:37:46.648Z"
}
```

{% endtab %}
{% endtabs %}


# Move Health API

## Fetch steps

<mark style="color:green;">`GET`</mark> `https://sdk.dolph.in/v20/health/steps`

Retrieves a user's step count within a specified time range, including the total number of steps as well as a breakdown per device.

#### Headers

<table><thead><tr><th>Name</th><th width="234">Type</th><th>Description</th></tr></thead><tbody><tr><td>Authorization<mark style="color:red;">*</mark></td><td>string</td><td><strong>Basic &#x3C;ProjectId>:&#x3C;API-Key></strong></td></tr></tbody></table>

#### Query Parameters

<table><thead><tr><th>Name</th><th width="234">Type</th><th>Description</th></tr></thead><tbody><tr><td>userId<mark style="color:red;">*</mark></td><td>string</td><td>The user id</td></tr><tr><td>projectId<mark style="color:red;">*</mark></td><td>integer</td><td>Id of MOVE SDK project</td></tr><tr><td>from<mark style="color:red;">*</mark></td><td>integer</td><td>Start of the time range (Unix epoch timestamp in seconds)</td></tr><tr><td>to<mark style="color:red;">*</mark></td><td>integer</td><td>End of the time range (Unix epoch timestamp in seconds)</td></tr></tbody></table>

#### Response Body

<table><thead><tr><th>Name</th><th width="227">Type</th><th>Description</th></tr></thead><tbody><tr><td>total</td><td>integer</td><td>Aggregated step count from all devices.</td></tr><tr><td>devices</td><td>array</td><td>List of individual device contributions, each with:</td></tr><tr><td>from</td><td>integer</td><td>Start of the time range (Unix epoch timestamp in seconds)</td></tr><tr><td>to</td><td>integer</td><td>End of the time range (Unix epoch timestamp in seconds)</td></tr><tr><td>devices.name</td><td>string</td><td>Name of device </td></tr><tr><td>devices.total</td><td>integer</td><td>Step count reported by the device</td></tr></tbody></table>

{% tabs %}
{% tab title="200 " %}

```
{
  "total": 12312,
  "devices": [
    {
      "name": "Apple Watch",
      "total": 10112
    },
    {
      "name": "Apple iPhone",
      "total": 5400
    }
  ]
}
```

{% endtab %}
{% endtabs %}

### Fetch steps (batch)

**POST** `/v20/health/steps/query`

Returns a list of step-count results for one or more users within a specified time range. Each result includes the total number of steps and a per-device breakdown.

#### Headers

<table><thead><tr><th>Name</th><th width="234">Type</th><th>Description</th></tr></thead><tbody><tr><td>Authorization<mark style="color:red;">*</mark></td><td>string</td><td><strong>Basic &#x3C;ProjectId>:&#x3C;API-Key></strong></td></tr></tbody></table>

#### Request Body

<table><thead><tr><th>Name</th><th width="227">Type</th><th>Description</th></tr></thead><tbody><tr><td>projectId</td><td>integer</td><td>Your project identifier</td></tr><tr><td>queries.userId</td><td>string</td><td>The user identifier.</td></tr><tr><td>queries.from</td><td>integer</td><td>Start of the time range (Unix timestamp)</td></tr><tr><td>queries.from</td><td>integer</td><td>End of the time range (Unix timestamp)</td></tr></tbody></table>

```json
{
  "projectId": 12345,
  "queries": [
    {
      "userId": "user_001",
      "from": 1711929600,
      "to": 1712016000
    },
    {
      "userId": "user_002",
      "from": 1711929600,
      "to": 1712016000
    }
  ]
}
```

#### Response Body

<table><thead><tr><th>Name</th><th width="227">Type</th><th>Description</th></tr></thead><tbody><tr><td>results.projectId</td><td>integer</td><td>Echoed project ID</td></tr><tr><td>results.userId</td><td>string</td><td>Echoed user ID</td></tr><tr><td>results.total</td><td>integer</td><td>Total steps in the time range.</td></tr><tr><td>results.devices.name</td><td>string</td><td>Device name (e.g., “Apple Watch”).</td></tr><tr><td>results.devices.name</td><td>integer</td><td>Steps attributed to that device.</td></tr><tr><td>results.from</td><td>integer</td><td>Start of the time range (Unix timestamp)</td></tr><tr><td>results.to</td><td>integer</td><td>End of t he time range(Unix timestamp)</td></tr></tbody></table>

{% tabs %}
{% tab title="200 " %}

```json
{
  "results": [
    {
      "projectId": 12345,
      "userId": "user_001",
      "total": 12312,
      "from": 1711929600
      "to": 1712016000
      "devices": [
        { "name": "Apple Watch", "total": 10112 },
        { "name": "Apple iPhone", "total": 5400 }
      ]
    },
    {
      "projectId": 12345,
      "userId": "user_002",
      "total": 8421,
      "from": 1711929600
      "to": 1712016000
      "devices": [
        { "name": "Apple Watch", "total": 6200 },
        { "name": "Apple iPhone", "total": 3221 }
      ]
    }
  ]
}
```

{% endtab %}
{% endtabs %}


# Move Vehicle API

Manage vehicles and their associated hardware devices in the MOVE SDK. This includes creating, editing, deleting vehicles and managing device assignments like Bluetooth or Beacon hardware.

***

### Create Vehicle

**Endpoint**

```http
POST /v20/vehicle
```

**Description**\
Create a new vehicle in the specified project.

#### Query Parameters

* `projectId` (string, required): Project to which the vehicle is assigned

#### Headers

* `Authorization` (string, required): Bearer JWT

#### Request Body

```json
{
  "name": "Fleet Car A",
  "props": {
    "color": "white",
    "plate": "ABC-1234"
  }
}
```

#### Response

```json
{
  "id": "a4e9bc28-1234-4b79-b60f-d8db49fc63b9",
  "name": "Fleet Car A",
  "props": {
    "color": "white",
    "plate": "ABC-1234"
  },
  "devices": []
}
```

***

### Get Vehicle

**Endpoint**

```http
GET /v20/vehicle/{vehicleId}
```

**Description**\
Retrieve details for a vehicle by its UUID.

#### Path Parameters

* `vehicleId` (string, required): UUID of the vehicle

#### Query Parameters

* `projectId` (string, required)

#### Headers

* `Authorization` (string, required)

#### Response

```json
{
  "id": "a4e9bc28-1234-4b79-b60f-d8db49fc63b9",
  "name": "Fleet Car A",
  "props": {
    "color": "white"
  },
  "devices": [
    {
      "deviceId": "bt-001",
      "type": "BT"
    }
  ]
}
```

***

### Edit Vehicle

**Endpoint**

```http
POST /v20/vehicle/{vehicleId}
```

**Description**\
Update the metadata of a vehicle (not its devices).

#### Path Parameters

* `vehicleId` (string, required): UUID

#### Query Parameters

* `projectId` (string, required)

#### Request Body

```json
{
  "name": "Fleet Car B",
  "props": {
    "color": "black"
  }
}
```

#### Response

```json
{
  "id": "a4e9bc28-1234-4b79-b60f-d8db49fc63b9",
  "name": "Fleet Car B",
  "props": {
    "color": "black"
  }
}
```

***

### Delete Vehicle

**Endpoint**

```http
DELETE /v20/vehicle/{vehicleId}
```

**Description**\
Deletes a vehicle and all related data. **This action is irreversible.**

#### Path Parameters

* `vehicleId` (string, required): UUID

#### Query Parameters

* `projectId` (string, required)

#### Headers

* `Authorization` (string, required)

**Response**

Http Response Code: 201

***

### Add / Update Vehicle Devices

**Endpoint**

```http
POST /v20/vehicle/{vehicleId}/device
```

**Description**\
Assign or update hardware devices for the vehicle. This can be either Bluetooth (BT) or Beacon (BEACON) devices.

#### Allowed `type` values:

* `BT`
* `BEACON`

#### Path Parameters

* `vehicleId` (string, required): UUID

#### Query Parameters

* `projectId` (string, required)

#### Headers

* `Authorization` (string, required)

#### Request Body

BEACON: uuid, major and minor&#x20;

BT: only Device Id

```json
{
  "name": "Beacon Front Seat",
  "type": "BEACON",
  "uuid": "c1f85fd9-f1f2-43a1-9094-feb872d2cb13",
  "major": 123,
  "minor": 456
}
```

#### Response

```json
{
  "id": "a4e9bc28-1234-4b79-b60f-d8db49fc63b9",
  "devices": [
    {
      "deviceId": "beacon-42",
      "type": "BEACON"
    }
  ]
}
```

***

### Remove Device

**Endpoint**

```http
DELETE /v20/vehicle/{vehicleId}/device
```

**Description**\
Unassigns a specific device from the vehicle.

#### Query Parameters

* `projectId` (string, required)
* `device` (string, required): ID of the device to remove

#### Path Parameters

* `vehicleId` (string, required): UUID

#### Headers

* `Authorization` (string, required)

#### Response

Returns vehicle without deleted device

```json
{
  "id": "a4e9bc28-1234-4b79-b60f-d8db49fc63b9",
  "name": "Fleet Car B",
  "props": {
    "color": "black"
  },
  "devices": [
     {
      "type": "BT",
      "deviceId": "2B:BB:3D:BA:42:92-tsco",
      "qualifier": "1000:mmue1:BT:2B:BB:3D:BA:42:92-tsco", // used internally 
      "userId": "mmue1"
    }
  ]
}
```


# MOVE Generic Notifier

MOVE Generic Notifier

The generic notifier transmits all information that does not fit into the Timeline API. The SDK Backend sends a batch of notifications to a defined URL, which can be defined in the [MOVE Dashboard > Configuration > Notifier](https://dashboard.movesdk.com/admin/sdkConfig/receiver?selected=2). The request body is a list of notification items.

The definition of a notification item is:

| **Name**  | **Type**             | **Example**                            |
| --------- | -------------------- | -------------------------------------- |
| id        | String UUID          | "cdfac1e3-39dd-4312-aa2b-9e4b6b5f1b49" |
| projectId | Number               | 1000                                   |
| userId    | String               | "C2021030510"                          |
| time      | String (Instant)     | "2021-04-16T09:33:41.409927Z"          |
| type      | String               | "CustomeType"                          |
| data      | Map (String, String) | "data": { "test" : "t123"}             |

### POI event notifications

Each MOVE project can define its ["Points of Interest" in the MOVE Dashboard](https://dashboard.movesdk.com/admin/poi). Whenever a user device sends a Point of Interest (POI), this event will be sent through the Generic Notifier. The data is defined as such:

* **distance** - distance of the user device to the POI, when the POI triggered
* **inTrip** - whether or not the device was in a trip, when the POI triggered
* **name** - the POI name you defined in the MOVE Dashboard
* **lat/lon** - the position of the user
* **tags** - any tags you may have entered in the MOVE Dashboard

Example JSON:

```typescript
    "id": "cdfac1e3-39dd-4312-aa2b-9e4b6b5f1b49",
    "projectId": 1000,
    "userId": "2021030510",
    "time": "2021-04-16T09:33:41.409927Z",
    "type": "POI",
    "data": {
      "distance" : "15",
      "inTrip" : "false", 
      "name" : "Office", 
      "lon" : "15.167910010896458", 
      "lat" : "48.16988434573538"   
    }
```

### Weather Event

This notification warns users of extreme weather events that could affect their parked cars.

Example JSON:

```json
{
   "id": "cdfac1e3-39dd-4312-aa2b-9e4b6b5f1b49",
    "projectId": 1000,
    "userId": "2021030510",
    "time": "2021-04-16T09:33:41.409927Z",
    "type": "WEATHER_EVENT",
    "data": {
      "movementtype": "parked/LIO",
      "origin": "airflow-weather",
      "predictedtime": "1678078800",
      "weather": "Cold under 3 (1) between 06:00 and 09:00",
      "location": "3423 Sankt Andrä-Wördern (Tullner Straße 22)- Niederösterreich/Österreich" 
    }
}
```

This is a JSON object that contains data related to a weather event. The object has several key-value pairs that provide information about the event.

#### Key-Value Pairs

* **id**: A unique identifier for the event. It is a string value in the format of UUID.
* **projectId**: The project identifier associated with the event. It is an integer value.
* **userId**: The user identifier associated with the event. It is a string value.
* **time**: The time when the event occurred. It is a string value in the format of ISO 8601 with timezone.
* **type**: The type of the event. In this case, it is a weather event and the value is "WEATHER\_EVENT".
* **data**: A JSON object that contains additional data related to the event.
  * **movementtype**: The type of movement associated with the event. It is a string value.
  * **origin**: The source of the weather data. It is a string value.
  * **predictedtime**: The predicted time for the weather event. It is a string value in UNIX timestamp format.
  * **weather**: A description of the weather event. It is a string value.
  * **location**: The location where the weather event occurred. It is a string value that contains the address information in a specific format.

### Score Event

Whenever a user's score is calculated, a notification is sent to inform them of the newly calculated score.

There are two score types:

Exposure to Risk (ETR)\
Move Score (MOVE)

Fields

* score: Current score value, ranging from 0 to 1000.
* days: Number of days included in the calculation period (maximum: 365).
* type: Score type (ETR or MOVE).
* numberOfTrips: Number of trips included in the score calculation period.
* totalDistance: Total distance driven during the score calculation period, in meters.

Example JSON:

```json
{
    "id": "cdfac1e3-39dd-4312-aa2b-9e4b6b5f1b49",
    "projectId": 1000,
    "userId": "2021030510",
    "time": "2021-04-16T09:33:41.409927Z",
    "type": "SCORE",
    "data": {
        "score": 897,
        "days": 289,
        "totalDistance": 931211,
        "type": "ETR",
        "numberOfTrips": 41
    }
}
```

### State

Sent when a user's device or permission state changes. The notification is debounced: if multiple state changes occur within a short window, only one notification is sent with the final state.

State notifications enable you to communicate with users when critical permissions are missing — for example, prompting them to grant "Location Access: Always" so that background trip detection works reliably.

The `type` for State notifications is `STATE_PERMISSON` .

The `data` map contains JSON-serialized objects under these keys:

| Key                              | Description                                          |
| -------------------------------- | ---------------------------------------------------- |
| `STATE_NOTIFIER`                 | Simplified permission summary (most common fields)   |
| `STATE_PERMISSION_DEVICE_STATUS` | Full device permission state                         |
| `STATE_PERMISSION_DYNAMIC`       | Dynamic device state (connectivity, GPS, power mode) |

**`STATE_NOTIFIER`**

A simplified view of the most important permissions. Parse the value as a JSON object:

```json
{
  "location": true,
  "bgDetection": false,
  "motion": true,
  "phone": null,
  "overlay": null,
  "health": null,
  "improvedLocationAccuracy": true,
  "ignoreBatteryOptimization": true,
  "keepUnusedAppPermission": true,
  "keepUnusedAppStorage": true
}
```

| Field                       | Type     | Description                                                                                                                                                   |
| --------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `location`                  | Boolean? | Location permission granted. Android: `ACCESS_FINE_LOCATION` or `ACCESS_COARSE_LOCATION`. iOS: `CLLocationManager` authorization.                             |
| `bgDetection`               | Boolean? | Background location access. Android: `ACCESS_BACKGROUND_LOCATION` (Android 10+). iOS: background location authorization. Required for passive trip detection. |
| `motion`                    | Boolean? | Motion/activity recognition permission. Android: `ACTIVITY_RECOGNITION` (Android 10+). iOS: `CMMotionActivityManager` authorization.                          |
| `phone`                     | Boolean? | Phone state permission (`READ_PHONE_STATE`). Android only; always null on iOS.                                                                                |
| `overlay`                   | Boolean? | Draw-over-other-apps permission. Android only; always null on iOS.                                                                                            |
| `health`                    | String?  | Health data permissions. Android: HealthConnect permission names (e.g. `"readSteps"`). iOS: HealthKit permission identifiers.                                 |
| `improvedLocationAccuracy`  | Boolean? | Enhanced location using WiFi/cell/Bluetooth. Android only; always null on iOS.                                                                                |
| `ignoreBatteryOptimization` | Boolean? | App exempt from battery optimization. Android only; always null on iOS. When false, background detection may be unreliable.                                   |
| `keepUnusedAppPermission`   | Boolean? | System will not auto-revoke permissions for unused apps (Android 11+). Android only.                                                                          |
| `keepUnusedAppStorage`      | Boolean? | System will not restrict storage for unused apps (Android 12+). Android only.                                                                                 |

**`STATE_PERMISSION_DEVICE_STATUS`**

The full device permission state. Parse as a JSON object.

| Field                        | Type     | Platform | Description                                                   |
| ---------------------------- | -------- | -------- | ------------------------------------------------------------- |
| `gyro`                       | Boolean? | Both     | Device has a functional gyroscope.                            |
| `accelerometer`              | Boolean? | Both     | Device has a functional accelerometer.                        |
| `magnetometer`               | Boolean? | Both     | Device has a functional magnetometer (compass).               |
| `bgDetection`                | Boolean? | Both     | Background location access granted.                           |
| `location`                   | Boolean? | Both     | Location permission granted.                                  |
| `motion`                     | Boolean? | Both     | Motion/activity recognition permission granted.               |
| `phone`                      | Boolean? | Android  | Phone state permission granted.                               |
| `overlay`                    | Boolean? | Android  | System overlay permission granted.                            |
| `improvedLocationAccuracy`   | Boolean? | Android  | Device using multiple location sources for enhanced accuracy. |
| `preciseLocationPermission`  | Boolean? | Both     | Fine/precise location access (vs. approximate only).          |
| `googlePlayLocationAccuracy` | Boolean? | Android  | Google Play Services providing high-accuracy location.        |
| `ignoreBatteryOptimization`  | Boolean? | Android  | App exempt from battery optimization restrictions.            |
| `keepUnusedAppPermission`    | Boolean? | Android  | Permissions not auto-revoked for unused apps (Android 11+).   |
| `keepUnusedAppStorage`       | Boolean? | Android  | Storage not restricted for unused apps (Android 12+).         |
| `postNotification`           | Boolean? | Both     | Notification posting permission (Android 13+, iOS always).    |
| `bluetoothConnect`           | Boolean? | Both     | Bluetooth device connection permission (Android 12+).         |
| `bluetoothScan`              | Boolean? | Both     | Bluetooth scanning permission (Android 12+).                  |
| `health`                     | String?  | Both     | Health data permission identifiers.                           |

**`STATE_PERMISSION_DYNAMIC`**

Dynamic device state reflecting current system settings and hardware status. Parse as a JSON object.

| Field                  | Type     | Platform | Description                                                              |
| ---------------------- | -------- | -------- | ------------------------------------------------------------------------ |
| `gps`                  | Boolean? | Both     | GPS/location services enabled on the device.                             |
| `mockProvider`         | Boolean? | Android  | An app with mock location capability is installed.                       |
| `mockProviderLocation` | Boolean? | Android  | Current location is from a mock provider (active spoofing).              |
| `wifi`                 | Boolean? | Both     | WiFi enabled.                                                            |
| `sim`                  | Boolean? | Android  | SIM card present.                                                        |
| `powerSaveMode`        | Boolean? | Both     | Device in low-power / battery-saver mode. May reduce sensor frequency.   |
| `playServicesVersion`  | String?  | Android  | Google Play Services version installed.                                  |
| `geofence`             | Boolean? | Both     | Geofencing operational (no initialization errors).                       |
| `locationPowerMode`    | Int?     | Android  | System location power save mode (Android 9+).                            |
| `standbyBucket`        | Int?     | Android  | App standby bucket; lower = less restricted (Android 9+).                |
| `bluetooth`            | Boolean? | Both     | Bluetooth hardware enabled.                                              |
| `online`               | Boolean? | Both     | Device has an active internet connection.                                |
| `mobileData`           | Boolean? | Both     | Cellular data available.                                                 |
| `healthConnectState`   | String?  | Android  | HealthConnect framework status: available, requires update, unavailable. |
| `healthApps`           | String?  | Android  | Installed health/fitness apps (comma-separated package names).           |
| `timeZone`             | String?  | Both     | Device timezone identifier (e.g. `"Europe/Berlin"`).                     |


# MOVE Assistance Notifier

Sends user alarms in emergencies.

* manual (BCALL) - triggered in the mobile app whenever e.g. a user pushes an ALARM-button which calls the “initiate assistance call” service in the MOVE SDK
* automatic (AID) - an Automatic Impact Detection can be configured as part of the MOVE features. Whenever a serious impact is detected during a car trip, the MOVE SDK sends an automatic alarm with some additional data to contextualize the impact. The threshold helps to filter false positives. &#x20;

#### AID

Automatic Impact Detection fields:

* asi: This field assesses the potential risk to occupants during full-scale crash tests involving roadside safety hardware.
* lon: Specifies the impact's longitudal position.
* lat: Specifies the impact's latitudinal position.
* axis: Describes whether the impact was frontal or longitudinal.
* speed: Represents the current speed at the time of impact.
* type: AID or BCALL

Example JSON:

```json

"id": "cdfac1e3-39dd-4312-aa2b-9e4b6b5f1b49",
"projectId": 1000,
"userId": "2021030510",
"time": "2021-04-16T09:33:41.409927Z",
"type": "ASSISTANCE",
"data": {
  "asi": "1.2132596667716633",
  "lon": "16.407404",
  "axis": "LONGITUDINAL",
  "type": "AID",
  "lat": "48.179639",
  "speed": "0"
}
```

#### BCALL

Manual call for assistance&#x20;

* type: BCALL or AID
* lon: Specifies the impact's longitudal position.
* lat: Specifies the impact's latitudinal position.
* speed: current speed

Example JSON:

```json

"id": "cdfac1e3-39dd-4312-aa2b-9e4b6b5f1b49",
"projectId": 1000,
"userId": "2021030510",
"time": "2021-04-16T09:33:41.409927Z",
"type": "ASSISTANCE",
"data": {
  "lon": "20.943821",
  "type": "BCALL",
  "lat": "52.208246",
  "speed": "null"
}
```

&#x20;


# Example requests

MOVE Backend APIs

This site shows example request between your project backend and Move SDK API.

### Create a new user

Use your Move SDK Project Id and your API Key as Basic Auth to register a new User. The `userId` may be any arbitrary string, only **:** is forbidden. The maximum length of `userId` is 100 characters.

Request:

```http
POST https://sdk.dolph.in/v20/user
content-type: application/json
Authorization: Basic {PROJECT_ID}:{API_KEY}

{
  "userId": "string"
}
```

Response:

```json
{
  "accessToken": "{ACCESS_TOKEN}", // allows communication with MOVE SDK back-end
  "refreshToken": "{REFRESH_TOKEN}", // allows Move App to renew access token
  "userId": "{USER_ID}", 
  "audience": "{NAME_OF_API_KEY}", 
  "projectId": {PROJECT_ID}
}
```

Initialize your Move SDK App with these tokens.

### Create a new user (authCode)

Use your Move SDK Project Id and your API Key as Basic Auth to register a new User. The `userId` may be any arbitrary string, only **:** is forbidden. The maximum length of `userId` is 100 characters.

Request:

```http
GET https://sdk.dolph.in/v20/user/authcode
content-type: application/json
Authorization: Basic {PROJECT_ID}:{API_KEY}

{
  "userId": "string"
}
```

Response:

```json
{
  "authCode": "{AUTHENTICATION_CODE}"
}
```

### **Fetch user timeline**

Fetch user timeline easily with:

Request:

```http
GET https://sdk.dolph.in/v20/timeline?userId={USER_ID}&projectId={PROJECT_ID}
content-type: application/json
Authorization: Basic {PROJECT_ID}:{API_KEY}
```

Response:

```json
[
  {
    "projectId": {PROJECT_ID},
    "userId": "{USER_ID}",
    "startTs": "2022-10-16T08:06:00Z",
    "endTs": "2022-10-16T09:41:00Z",
    "type": "IDLE",
    "features": {
      "source": {
        "id": "",
        "name": "timeline"
      }
    }
  },
  {
    "projectId": {PROJECT_ID},
    "userId": "{USER_ID}",
    "startTs": "2022-10-17T05:58:00Z",
    "endTs": "2022-10-17T06:03:00Z",
    "type": "CYCLING",
    "features": {
      "startLocation": {
        "lat": 48.328016,
        "lon": 16.204514,
        "timeZone": "Europe/Vienna"
      },
      "endLocation": {
        "lat": 48.3338,
        "lon": 16.20949,
        "timeZone": "Europe/Vienna"
      },
      "source": {
        "id": "585497",
        "name": "trip"
      },
      "gpsStats": {
        "distance": 947,
        "maxSpeed": 23,
        "averageSpeed": 13
      },
      "metas": {},
      "dangerousAreas": {
        "areas": []
      }
    }
  }
]
```

Every timeline item has the following properties:

* projectId: Move SDK Project ID
* userId: Id of specific User
* startTs: start timestamp as an ISO 8601 date time
* endTs: end timestamp as an ISO 8601 date time
* type: Mode of transport

### Fetch specific timeline items

Convert the `startTs`  of a given timeline item to a UNIX timestamp to fetch a specific timeline item. For example,&#x20;

* in the user timeline you find a timeline item with `startTs` in UTC time

  ```
  "startTs":"2022-04-12T16:25:00Z"
  ```
* Conversion into unix timestamp (UTC) is "1649780700" - this is your START\_TS for fetching the specific timeline item.
* Please note, if you want to display the trip in human readable form, you may want to translate the startTs to the local timezone (which you can find in "startLocation / timeZone"; e.g. "Europe/Vienna").

Request:

```http
GET https://sdk.dolph.in/v20/timeline/{START_TS}?userId={USER_ID}&projectId={PROJECT_ID}
content-type: application/json
Authorization: Basic {PROJECT_ID}:{API_KEY}
```

Response:

```json
{
  "projectId": {PROJECT_ID},
  "userId": "{USER_ID}",
  "startTs": "2022-10-17T05:58:00Z",
  "endTs": "2022-10-17T06:03:00Z",
  "type": "CYCLING",
  "features": {
    "startLocation": {
      "lat": 48.328016,
      "lon": 16.204514,
      "timeZone": "Europe/Vienna"
    },
    "endLocation": {
      "lat": 48.3338,
      "lon": 16.20949,
      "timeZone": "Europe/Vienna"
    },
    "source": {
      "id": "585497",
      "name": "trip"
    },
    "gpsStats": {
      "distance": 947,
      "maxSpeed": 23,
      "averageSpeed": 13
    },
    "metas": {},
    "dangerousAreas": {
      "areas": []
    }
  }
}
```

### Fetch way points

Some timeline item types like CAR and CYCLING return way points.

Request:

```http
GET https://sdk.dolph.in/v20/timeline/{START_TS}/points?userId={USER_ID}&projectId={PROJECT_ID}&withWayPointInfo=true
content-type: application/json
Authorization: Basic {PROJECT_ID}:{API_KEY}
```

Response:

```json
[
  {
    "lat": 48.31712,
    "lon": 16.2256,
    "timestamp": "2022-09-01T14:50:08Z",
    "wayPointInfo": {
      "speed": 66,
      "speedLimit": 100,
      "wayType": "other",
      "origLat": 48.317138,
      "origLon": 16.225608
    }
  },
  {
    "lat": 48.31711,
    "lon": 16.22608,
    "timestamp": "2022-09-01T14:50:10Z",
    "wayPointInfo": {
      "speed": 67,
      "speedLimit": 100,
      "wayType": "other",
      "origLat": 48.317118,
      "origLon": 16.226084
    }
  }
]
```

Important: The Move SDK always tries to match GPS points to an existing road. For the original way points withWayPointInfo is required.

### Label item

Relabel existing timeline items with a PATCH request:

```http
PATCH https://sdk.dolph.in/timeline/label/{START_TS}/{NEW_MODE_OF_TRANSPORT}?userId={USER_ID}&projectId={PROJECT_ID}
Content-Type: application/json; charset=UTF-8
Authorization: Basic {PROJECT_ID}:{API_KEY}
```

Possible mode of transports:

* UNKNOWN&#x20;
* DRIVING&#x20;
* TRAIN&#x20;
* TRAM
* CAR
* METRO
* FAKETRIP
* WALKING&#x20;
* IDLE&#x20;
* CYCLING

The response to this request is the existing timeline item with the new type.

### Delete item

Delete a single timeline item.

```http
DELETE https://sdk.dolph.in/v20/timeline/{START_TS}?userId={USER_ID}&projectId={PROJECT_ID}
Content-Type: application/json; charset=UTF-8
Authorization: Basic {PROJECT_ID}:{API_KEY}
```

### Fetch last user location

Every user has 4 last locations, in different contexts:

* car-end: last position of his car&#x20;
* timeline-end: end location of last timeline item
* trip-position: updates live during a trip
* user-pos: updates user walking position

```http
GET https://sdk.dolph.in/v20/location?projectId={PROJECT_ID}&userId={USER_ID}
Content-Type: application/json; charset=UTF-8
Authorization: Basic {PROJECT_ID}:{API_KEY}
```

Response:

```json
[
  {
    "context": "car-end",
    "lat": 48.322418,
    "lon": 16.203955,
    "timestamp": "2022-10-15T16:29:00Z"
  },
  {
    "context": "timeline-end",
    "lat": 48.3338,
    "lon": 16.20949,
    "timestamp": "2022-10-17T06:03:00Z"
  },
  {
    "context": "trip-position",
    "lat": 48.214684,
    "lon": 16.413719,
    "timestamp": "2022-10-17T07:04:41Z"
  },
  {
    "context": "userpos",
    "lat": 48.214723,
    "lon": 16.413646,
    "timestamp": "2022-10-17T07:03:10Z"
  }
]

```


# FAQ

<details>

<summary><strong>All permissions granted but I don’t have trips, what is wrong?</strong></summary>

The issue might be caused by third-party battery saver apps. For instance, Honor and Huawei devices have built-in launch settings (found in Battery usage details) that manage apps automatically by default. This setting can cause GPS and network restrictions for the Move SDK when it runs in the background. We recommend disabling this feature to ensure proper functionality.

</details>

<details>

<summary><strong>Can I use Move SDK on several devices with the same user?</strong></summary>

You can only use one device at a time. When you log in on a new device, the token for the Move SDK on the previous device becomes invalid.

</details>

<details>

<summary><strong>How can I enhance trip detection percentage on the Android?</strong></summary>

Resolve all errors and warnings reported by Move SDK. To see errors you can use the [Get Service Failures](https://docs.movesdk.com/move-platform/sdk/api-interface/android/services#get-service-failures) function or set up [Service Error Listener](https://docs.movesdk.com/move-platform/sdk/api-interface/android/services#set-service-error-listener). To see warnings you can use [Get Service Warnings](https://docs.movesdk.com/move-platform/sdk/api-interface/android/services#get-service-warnings) or set up [Service Warning Listener](https://docs.movesdk.com/move-platform/sdk/api-interface/android/services#set-service-warning-listener).

1. Use the [Force Trip Recognition](https://docs.movesdk.com/move-platform/sdk/api-interface/android/services#force-trip-recognition) feature in cases where you know the trip is ongoing.
2. Use the [Keep in foreground](https://docs.movesdk.com/move-platform/sdk/api-interface/android/services#keep-in-foreground) feature.
3. Use the [Keep active](https://docs.movesdk.com/move-platform/sdk/api-interface/android/services#keep-active) feature.

</details>

<details>

<summary><strong>What is authentication state invalid?</strong></summary>

[MoveAuth](https://docs.movesdk.com/move-platform/sdk/models/moveauth) is session-based, hence it expires and requires to be renewed. For simplicity, the MOVE SDK handles refreshing the token for the host app whenever it expires.

In case the MOVE SDK fails to refresh authentication, because of a conflicting login on another device, or because the user was blocked on the backend, it will trigger `MoveAuthState.invalid`. The host app is expected to logout the user and call`shutdown(force: true)`([Android](https://docs.movesdk.com/move-platform/sdk/api-interface/android/services#shutdown-sdk) / [iOS](https://docs.movesdk.com/move-platform/sdk/api-interface/ios/setup#shutdown)).

</details>

<details>

<summary><strong>Do you use swagger files? Where can I find these swagger files?</strong></summary>

Yes.

<https://cdn.dolph.in/docs/swagger-ui/index.html?url=https://cdn.dolph.in/docs/openapi/sdk-v2_0-oas.yaml#/>

</details>

<details>

<summary><strong>When should you use a WRITE ONLY API Key?</strong></summary>

An API Key should never be stored on a frontend device. However, for testing purposes, you can create a WRITE ONLY Key. This key allows you to register a User directly from your end device without involving a backend. It's important to note that this key cannot fetch user data.

</details>

<details>

<summary><strong>How can I retrieve SDK User data via API?</strong></summary>

In the Move Dashboard, you can access the CAR icon which provides helpful links for retrieving SDK User Data via HTTP requests. For authentication, use your SDK Project ID as the username and your API Key as the password.

<img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2F0riIBdXw2yasX90tz2LP%2F48cdd429-d7fe-46dd-b6d5-a5a35a1cfd06.png?alt=media&amp;token=4957bd05-6d52-4710-81fc-d712a1aae40a" alt="" data-size="original">

</details>

<details>

<summary><strong>Where do I get technical support?</strong></summary>

<https://dolphin-technologies.atlassian.net/servicedesk/customer/portal/4/create/25>

</details>


# MOVE Pilot: Give Health Connect Permissions (Android 13 and below)

For the MOVE Pilot App to collect information about walked steps two things need to be done

* Health Connect needs to be installed, and MOVE Pilot needs access to it.
* There must be a fitness app that reports data into Health Connect installed on your device, such as Samsung Health or Google Fit. If you have a smartwatch or a fitness tracker, you have likely installed such an app already.

This guide covers both of those steps.

### Installing Health Connect & Granting Permissions

To allow MOVE Pilot access to Health , you need the "Health Connect" app and must grant permissions.

Follow these steps:

{% columns fullWidth="false" %}
{% column %}

### 1. Download Health Connect

Get the "Health Connect" app from the [Google Play Store](https://play.google.com/store/apps/details?id=com.google.android.apps.healthdata)
{% endcolumn %}

{% column %}

<div data-full-width="false"><figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FjHbHk69uy54u6nA6humK%2FHealth-1.png?alt=media&amp;token=01b7a291-cd0f-4d13-b655-96bd4e506039" alt=""><figcaption></figcaption></figure></div>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 2. Open Health Connect

Launch the app and tap "Get Started"
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2F8HWOxyCrTkTbxHuWOY5e%2FHealth-2.png?alt=media&amp;token=807a9074-24f3-4888-a329-b1b0a76131c5" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 3. Allow MOVE Pilot to access your steps

* Tap “Allow all” to enable data sharing.
* Once the “Allow” button becomes active, tap “Allow” to confirm your choice.
  {% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FHMXLtXwr6S1ADIPP0oBn%2FHealth-3%201.png?alt=media&amp;token=b50265b8-6a24-477f-9f6e-d4aeb4c069ff" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 4. Allow Usage Access

When prompted, tap “Allow”.
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FSadXcB0mTN1cRRthrMcq%2FHealth-4.png?alt=media&amp;token=3d1bfcf5-3ab1-4794-9667-6fe7db893373" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 5. Open Usage Access Settings

A pop-up titled “Turn on usage access?” will appear — tap “Open settings”.
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FgjL10c20oNOac2zdMnr4%2FHealth-5.png?alt=media&amp;token=25f52acc-9128-4e60-b86c-dd7186d74a9f" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 6. Select Health Connect

In the Usage access settings, tap “Health Connect”.
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FULSeenwFlkLCYaBwOscs%2FHealth-7-1.png?alt=media&amp;token=15974dbe-79d0-4b48-b75c-743a3c1d246e" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 7. Enable Usage Access

Toggle “Permit usage access” ON and then tap the back arrow to return to the Usage access overview.
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FGsDv5NhWPbXkVVsEZMnR%2FHealth-6.png?alt=media&amp;token=1c4a79cb-9ced-434b-a369-fe9047c085c1" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 8. Return to Health Connect

Tap the back arrow again to return to the Health Connect permissions screen.
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FB018dKwR8wXfztnllQxD%2FHealth-7.png?alt=media&amp;token=e2b90125-6cc0-4a03-8f1e-144ac5600ef7" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 9. Allow MOVE Pilot Background Access

Tap “Allow” so that MOVE Pilot can access your step data in the background.
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2F5QXBD1b0INJX19e0gdAa%2FHealth-4-1.png?alt=media&amp;token=bcaec01c-2a72-4c66-a73e-02d3827304b3" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

### Installing an App that reports data into Health Connect

#### Samsung Health

* Install Samsung Health
* Complete on-boarding in the App
* Go to "My Page" > "⋮" > "Settings" > "Connected apps and services" > "Health Connect" > Grant All

#### Google Fit

* Install Google Fit
* Complete on-boarding in the App
* Go to "Profile" (bottom right) > "Settings" > Enable "Sync Fit with Health Connect"


# MOVE Pilot: Setting up Google Fit / Samsung Health

For the MOVE Pilot App to collect information about walked steps there must be a fitness app that reports data into Health Connect installed on your device, such as Samsung Health or Google Fit.&#x20;

If you have a wearable that tracks steps, you have likely installed such an app already, in that case you need to make sure that it reports data into Health Connect.

This guide covers the set-up for both Samsung Health and Google Fit.

## Samsung Health

* Install Samsung Health
* Complete on-boarding in the App
* Go to "My Page" > "⋮" > "Settings" > "Connected apps and services" > "Health Connect" > Grant All

## Google Fit

{% columns %}
{% column %}

### 1. Download the Google Fit app

Get the "Google Fit" app from the [Google Play Store](https://play.google.com/store/apps/details?id=com.google.android.apps.fitness\&hl=en)
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FNhfUls1rhAQl8cXqXWVB%2FScreenshot_20250929_133545_Google%20Play%20Store.jpg?alt=media&amp;token=cdf9f038-4fca-4aeb-bc64-41b3fe7193f1" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 2. Open Google Fit

Launch the App and complete the onboarding
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2Fnap6SaPtOu0FsZv9HMk1%2FScreenshot_20250929_134033_Fit.jpg?alt=media&amp;token=5bc932f7-e783-47e2-9e0a-d8d5c9e164a6" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 3. Go to the Profile Page

Open the profile page using the button on the bottom right
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2F2mAwAnzJBRk986NSmekg%2FScreenshot_20250929_134107_Fit.jpg?alt=media&amp;token=e245d5d5-a872-47d0-a9e0-396840a7a4a8" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 4. Open Settings

Open the Settings using the gearbox icon
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FEtrtA2UyXwJezKmy9JsN%2FScreenshot_20250929_134113_Fit.jpg?alt=media&amp;token=76c189bb-4b4e-4236-8729-fdc18a074751" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 5. Enable Sync with Health Connect

Toggle the "Sync with Health Connect" toggle on
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FAvGJS3AXbDcF3BOMdnBd%2FScreenshot_20250929_134411_Fit.jpg?alt=media&amp;token=c67334c3-412d-47b6-810d-77e2beb67361" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 6. Start Health Connect onboarding

Tap "Set up" to start the Google Fit onboarding for Health Connect
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FknkxhhXcgLS46rP9S53k%2FScreenshot_20250929_134416_Fit.jpg?alt=media&amp;token=3072fed5-08da-4e67-abd0-9f245efed335" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 7. Allow Google Fit access to Health Connect

Tap "Allow all", and then "Allow" to grant Google Fit access to Health Connect

{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FyMmL2G1Me0cG8d8s89TZ%2FScreenshot_20250929_134432_HealthConnect.jpg?alt=media&amp;token=96314559-79ec-40aa-80c2-dd6a3192fd76" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}


# MOVE Pilot: Give HealthKit Permissions (iOS)

To show your steps in MOVE Pilot, you need the "Health Connect" app and must grant permissions.

Follow these steps:

{% columns fullWidth="false" %}
{% column %}

### 1. Open HealthKit Settings via the MOVE Pilot Permissions Screen

* Go to the "Permissions" page in the MOVE Pilot App
* Click on the "Health app" button
  {% endcolumn %}

{% column %}

<div data-full-width="false"><figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FOspCMTeHXZ2UqNKPIjGn%2FIMG_2893.PNG?alt=media&amp;token=41c673c7-2d10-4ced-8a3b-e7ec74a11844" alt=""><figcaption></figcaption></figure></div>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 2. Go to "Apps"

On the "Sharing" page, tap "Apps"
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2F1wTYDR4oMRIE8PtGjSnI%2FIMG_2894.PNG?alt=media&amp;token=31d2353a-27bd-4fc6-a78b-d95b7b8d4f8a" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 3. Select "MOVE Pilot"

Tap "MOVE Pilot"
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2Fk2fnUmSqPh6Xtne5CtuX%2FIMG_2895%20(1).PNG?alt=media&amp;token=5470a605-7928-4cf0-a4c7-5206339466ce" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}

### 4. Grant Access to MOVE Pilot

Press "Turn On All" to allow MOVE Pilot access to your steps
{% endcolumn %}

{% column %}

<figure><img src="https://394612935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fmwu27YShuN4k8SNwEG4H%2Fuploads%2FV9yabKZSbUFDzmIJmDvq%2FSharing.jpeg?alt=media&amp;token=d9ce0315-d9fc-446a-a884-9995b02ce638" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}


# Changelog

Here, you'll find a detailed list of updates, enhancements, and bug fixes for each version by platform.  Stay tuned for more updates as we continue to improve and expand our features!

## Frontends

{% content-ref url="/pages/-MZJSfPRqawKT\_SVEa1w" %}
[Android](/move-platform/changelog/android)
{% endcontent-ref %}

{% content-ref url="/pages/-MZJShd4Sv7DW\_71hk0n" %}
[iOS](/move-platform/changelog/ios)
{% endcontent-ref %}

{% content-ref url="/pages/UPWTzoAWQYbJzoI2fbR3" %}
[React](/move-platform/changelog/react)
{% endcontent-ref %}

{% content-ref url="/pages/cgqPoy6LiwvTOlCVEyxK" %}
[Flutter](/move-platform/changelog/flutter)
{% endcontent-ref %}

## Backend

{% content-ref url="/pages/PFyy1VssqJ8DYVd5aOqU" %}
[Backend](/move-platform/changelog/backend)
{% endcontent-ref %}


# Android

Changelog

## 2.19.0.107 - 2026-10-08

* Added [MoveInitOptions](/move-platform/sdk/models/moveinitoptions) with `maxQueueSizeMB` (optional parameter of [MoveSdk.init()](/move-platform/sdk/api-interface/android/initialization#init))
* Automatic Impact Detection can be used without Driving / Cycling (background location permission recommended)
* Health Connect: improved step synchronization on Android 14+
* Bugfixes & Improvements

## 2.18.2.106 - 2026-10-02

* Bugfixes & Improvements

## 2.18.1.105 - 2026-09-08

* Bugfixes & Improvements

## 2.18.0.104 - 2026-07-21

* compileSdk / targetSdk 36
* Gradle 9.1, AGP 9.0.1, Kotlin toolchain 2.3.21 (2.1-compatible metadata), Room 2.8.4
* Added soft shutdown with timeout.
* Health Connect: added diagnostic check when Health Connect is not available (Android 14 and below)
* Device discovery: fixed duplicate beacon reporting for UUID-only registrations
* Fixed re-registration of Bluetooth devices after shutdown
* Bugfixes & Improvements

## 2.17.2.101 - 2026-06-10

* Hotfix reregister BT Devices after shutdown
* [MoveDeviceStatus](/move-platform/sdk/models/movedevicestatus#android) deprecated

## 2.17.0.100 - 2026-04-26

* Added [MoveDevice](/move-platform/sdk/models/movedevice) display name
* Added [MoveDeviceState](/move-platform/sdk/models/movedevice/movedevicestate)
* Live Location TAG feature [setLiveLocationTag(...)](/move-platform/sdk/api-interface/android/services#live-location-tag) deprecated

## 2.16.0.99 - 2026-02-04

* Added [getMoveConfig](/move-platform/sdk/api-interface/android/services#get-move-sdk-config)
* Bugfixes & Improvements
* Gradle upgrade to 8.10.1
* kotlin 1.9.25 to 2.0.21

## 2.15.0.98 - 2025-11-25

* device discovery: [find beacons with only UUID registration](/move-platform/sdk/models/movedevice)
* Bugfixes & Improvements
  * AID
  * Step Counter

## 2.14.2.97 - 2025-09-24

* Enable step count synchronization.
* Expand initial step count data to a day.

## 2.14.1.96 - 2025-09-05

* SDK updated for 16 KB page size compliance
* bugfix for missing metadata submission during manual started trips

## 2.14.0.95 - 2025-08-07

* Added step counter from [Health Connect](https://developer.android.com/health-and-fitness/guides/health-connect/develop/get-started) - [service](/move-platform/sdk/api-interface/android/services#step-counter-health-connect), [permissions](/move-platform/sdk/appendix/android/permission-handling/permission-overview)
* Bugfixes & Improvements

## 2.13.0.94 - 2025-05-22

* Added uuid, major, minor to MoveDevice
* Registered Bluetooth devices stored in the backend. Persistence after shutdown / re-registration / login.

## 2.12.0.92 - 2025-04-03

* Changed the way data is transmitted to our systems, which reduces memory consumption in some situations
* Bugfixes & Improvements

## 2.11.2.93 - 2025-02-25

* Bugfixes & Improvements (Android 14)

## 2.11.1.91 - 2025-02-25

* Bugfixes & Improvements (Android 14)

## 2.11.0.90 - 2025-02-04

* Health Listener added
* [updateConfig](/move-platform/sdk/api-interface/android/services#update-config) changed - new optional parameter [MoveOptions](/move-platform/sdk/models/moveoptions#android) added
* Bugfixes & Improvements

## 2.10.1.88 - 2024-10-15

* Bugfixes & Improvements

## 2.10.0.87 - 2024-08-16

* [MoveHealthScoreListener](/move-platform/sdk/api-interface/android/services#set-health-score-listener), [MoveHealthScore](/move-platform/sdk/models/movehealthscore) added
* [Bluetooth connection callback / listener](/move-platform/sdk/models/listeners-callbacks#movedevice-state-listener-callback) added ([setDeviceStateListener](/move-platform/sdk/api-interface/android/services#set-movedevice-connection-state-listener))
* Bugfixes & Improvements

## 2.9.0.86 - 2024-07-29

* [Auth Module](/move-platform/sdk/api-interface/android/initialization#with-authcode) reworked
* Preparation for SDK Health feature
* Bugfixes & Improvements

## 2.8.0.85 - 2024-05-14

* Manual start trip feature [`startTrip(...)`](/move-platform/sdk/api-interface/android/services#manual-start-trip) added
* Live Location TAG feature [setLiveLocationTag(...)](/move-platform/sdk/api-interface/android/services#live-location-tag) added
* Bugfixes & Improvements

## 2.7.0.84 - 2024-04-05

* Bugfixes & Improvements

## 2.6.9.83 - 2024-03-05

* Bugfixes & Improvements

## 2.6.9.82 - 2024-02-28

* **MoveError** `NotificationMissing` moved to **MoveWarning** `NotificationMissing`
* Bugfixes & Improvements

## 2.6.9.81 - 2024-02-09

* Bugfixes & Improvements

## 2.6.9.80 - 2024-02-09

* Bugfixes & Improvements
* New [MoveOptions](/move-platform/sdk/models/moveoptions#android) `overlayPermissionMandatory`
* New MoveError `GyroscopeMissing`

## 2.6.8 - 2024-01-24

* Bugfixes & Improvements

## 2.6.7 - 2024-01-19

* Deprecated authentication state `expired`
* Other minor bugfixes & Improvements

## 2.6.4 - 2023-12-01

* Bugfixes & Improvements

## 2.6.2 - 2023-11-10

* Bugfixes & Improvements

## 2.6.1 - 2023-10-13

* Bugfixes & Improvements

## 2.6.0 - 2023-09-13

#### Api changes

* Added TripStartListener
* Added backgroundLocationPermissionRequired to [MoveOptions](/move-platform/sdk/models/moveoptions)

#### Additional

* Changed compileSdkVersion and targetSdkVersion to 34
* Updated Android libraries

#### Fixed

* Minor bugfixes

## 2.5.3 - 2023-08-29

#### Api changes

* Added optional `useBackendConfig` to MoveConfig

#### Fixed

* Fix warning message during 0 registered devices
* Other minor bugfixes

## 2.4.1 - 2023-07-31

#### Api changes

#### Fixed

* Fix for java.lang.NoSuchMethodError
* No BDD scanning if there are no registered devices
* Other minor bugfixes

## 2.4.0 - 2023-07-26

#### Api changes

{% hint style="warning" %}
Added new request body part **`qualifier`** to the [register user](/move-platform/backend/move-backend/move-admin-api#register-user) request!

For backwards compatibilities please consider sending this parameter always in the future.
{% endhint %}

* new Bluetooth Device Discovery Feature implemented
  * Added [**DeviceDiscovery**](/move-platform/sdk/models/moveoptions/devicediscovery) options to (optional) [**MoveOptions**](/move-platform/sdk/models/moveoptions)
  * Added [**MoveDevice**](/move-platform/sdk/models/movedevice)
  * Added [**MoveScanResult**](/move-platform/sdk/models/movescanresult)
  * Added **DeviceDiscoveryListener** / Callback
* Added [MoveAuthState](/move-platform/sdk/models/moveauthstate).INVALID

### Fixed

* Minor bugfixes

## 2.3.0 - 2023-05-22

#### Api changes

* Added [MoveOptions](/move-platform/sdk/models/moveoptions) (motionPermissionRequired)
* Added "Google Play Location Accuracy" mandatory for POI and PUBLIC\_TRANSPORT
* AssistanceCall feature doesn't require permissions anymore

#### Bugfixes

* Trips not recorded after app installation and user registration
* Minor bugfixes

## 2.2.1 - 2023-04-20

#### Api changes

* Improved POI sending
* Added "Google Play Location Accuracy" mandatory for POI and PUBLIC\_TRANSPORT
* Added motion-permission-mandatory as an option.

#### Bugfixes

* Default notification problems
* PT-POIs are not sent
* Huge gap in trip detection
* Minor bugfixes

## 2.2.0 - 2023-03-24

#### Api changes

* Added new method [*getDeviceQualifier*](/move-platform/sdk/api-interface/android/services#get-device-qualifier)
* Added callback with shutdown [MoveShutdownResult](/move-platform/sdk/models/moveshutdownresult#android)
* Changed [shutdown](/move-platform/sdk/api-interface/android/services#shutdown-sdk).
* Added `MoveAuthError` for auth-related errors returned by `updateAuth()`. `MoveConfigurationError` remains unchanged and is used for SDK setup errors returned by `initializationListener`.
* Changed MoveInitialisationListener to [InitializationListener](/move-platform/sdk/api-interface/ios/setup#set-sdk-initialization-listener)

#### **Bugfixes**

* Fixed state sending

## 2.1.1 - 2023-02-17

#### Improvements

* Changed location precision in trip events

#### API Changes

* AssistanceCallState changed to [MoveAssistanceCallStatus](/move-platform/sdk/models/moveassistancecallstatus)

#### **Bugfixes**

* Improved state sending
* Fixed crash in driving module
* Removed extra POI events

## 2.1.0 - 2023-02-03

#### Api changes

* Added new method [*setAssistanceMetaData*](/move-platform/sdk/api-interface/react-native/services#set-assistance-metadata)

#### **Bugfixes**

* Improved state sending

## 2.0.0 - 2022-11-10

* Splitted init(...) into [MoveSDK.init()](/move-platform/sdk/api-interface/android/initialization#init) & persisted [MoveSDK.setup(...)](/move-platform/sdk/api-interface/ios/setup)
* Removed MoveAuth from AuthState.Valid
* Removed MoveSDK.Builder
* Introduced MoveDetectionServices
* Added [MoveErrors ](/move-platform/sdk/models/moveservicefailure#android)+ [Listeners](/move-platform/sdk/models/listeners-callbacks#android-4)
* Added [MoveWarnings ](/move-platform/sdk/models/moveservicewarning#android)+ [Listeners](/move-platform/sdk/models/listeners-callbacks#android-5)
* Added [Geocoding ](/move-platform/sdk/api-interface/android/services#geocoding)Service
* Added [AID ](/move-platform/sdk/models/moveconfig#android)(Automatic Impact Detection) Service
* Added [AssistanceCall ](/move-platform/sdk/api-interface/ios/services#initiate-assistance-call)Service
* Added LogListener

## 1.5.2.30 - 2022-02-15

### Fixed

* Solved issue in [MoveAuthState](/move-platform/sdk/models/moveauthstate) notification
* Reduced data consumption with Points of Interest

## 1.5.1.29 - 2022-02-2

### Fixed

* Minor bugfixes

## 1.5.0.26 - 2022-01-31

### Added

* Timeline detection services PLACES & PUBLIC TRANSPORT
* setConsoleLogging state API

## 1.3.2.25 - 2021-09-30

### Added

* Improvement of DBE sensors
* Logcat message reduction

## 1.3.0 - 2021-05-31

### Added

* Support of [Points of Interest](/move-platform/move-services#points-of-interest) by using *OtherServices*

### Fixed

* Minor bugfixes

###


# iOS

Changelog

## 2.19.0 - 2026-10-08

* Added maxQueueSize via [MoveInitOptions](/move-platform/sdk/models/moveinitoptions#ios).
* Stability improvements.

## 2.18.0 - 2026-07-20

* Stability improvements.
* Added soft [shutdown](/move-platform/sdk/api-interface/ios/setup#shutdown) with timeout.

## 2.17.0 - 2026-04-23

* Added [MoveDevice](/move-platform/sdk/models/movedevice) display name.
* Added [MoveDeviceState](/move-platform/sdk/models/movedevice/movedevicestate).
* Deprecated live trip tag.

## 2.16.0 - 2025-02-04

* Added [GetMoveConfig](/move-platform/sdk/api-interface/ios/services#get-configuration) function.

## 2.15.0 - 2025-12-04

* Split iOS HealthKit functionality into [seperate framework](/move-platform/sdk/getting-started/ios/installation#health-kit-extension).
* Added [beacon uuid registration](/move-platform/sdk/models/movedevice).
* Impact handling improvements.

## 2.14.3 - 2025-09-24

* Enable step count synchronization.
* Expand initial step count data to a day.&#x20;

## 2.14.2 - 2025-09-18

* Fixed a bug with step count record deletion upload.

## 2.14.1 - 2025-08-22

* Fixed a bug for the step counting service.

## 2.14.0 - 2025-08-07

* Added Health Step-Counting service. (See important changes in [Permission Handling](/move-platform/sdk/appendix/ios/permission-handling#health-permissions)).
* Small bug fixes & Stability improvements.

## 2.13.0 - 2025-05-22

* Registered Bluetooth devices stored in the backend. Persistence after shutdown / re-registration / login.

## 2.12.0 - 2025-04-03

* Changed the way data is transmitted to our systems, which reduces memory consumption in some situations
* Bugfixes & Improvements

## 2.11.0 - 2025-02-04

* Fixed bugs affecting app lifecycle.
* Fixed a bug resending daily location data when timeline activity service is off.
* Added [`setHealthListener(...)`](/move-platform/sdk/api-interface/ios/services#set-health-listener).

## 2.10.1 - 2024-11-06

* Fixed a bug which prompted the motion permission dialog from the SDK.

## 2.10.0 - 2024-08-21

* Added [`setDeviceStateListener(...)`](/move-platform/sdk/api-interface/ios/services#set-movedevice-connection-state-listener).

## 2.9.0 - 2024-07-29

* Added [`setup(authCode: ...)`](/move-platform/sdk/api-interface/ios/setup#setup-auth-config).

## 2.8.0 - 2024-05-14

* Added manual [`startTrip(...)`](/move-platform/sdk/api-interface/ios/services#manual-start-trip) functionality.
* Stability improvements.
* Added [`setLiveLocationTag(...)`](/move-platform/sdk/api-interface/ios/services#live-location-tag).
* Added [PrivacyAPI Manifest](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files) file.

## 2.7.0 - 2024-04-03

* Fixed battery consumption.
* Stability improvements.

## 2.6.9 <mark style="color:red;">(High Battery Consumption Warning)</mark> - 2024-02-09

* Stability fixes concerning region monitoring.

## 2.6.9 <mark style="color:red;">(High Battery Consumption Warning)</mark> - 2024-02-09

* Stability and threading improvements.

{% hint style="warning" %}
This version may lead to excessive battery consumption on your devices. We advise against its use to avoid draining batteries quickly.
{% endhint %}

## 2.6.7 - 2024-23-01

* Deprecated authentication state `expired`.
* Stability fixes.
* Fixes in permission handling.

## 2.6.4 - 2023-11-28

* Fix an issue with CarPlay device detection.

## 2.6.3 - 2023-11-5

* Split Bluetooth permission check into Bluetooth permission/status.

## 2.6.2 - 2023-10-24

* Added some internal fixes.

## 2.6.1 - 2023-10-11

* Added bluetooth permission check

## 2.6.0 - 2023-09-13

#### Api changes

* Added TripStartListener
* Added backgroundLocationPermissionRequired to [MoveOptions](/move-platform/sdk/models/moveoptions#ios)

## 2.5.3 - 2023-08-25

#### Api changes

* Added optional `useBackendConfig` to MoveConfig

## 2.4.2 - 2023-08-21

* Split MoveDevice displayName from identifier.

## 2.4.1 - 2023-06-31

* Fix device discovery listener

## 2.4.0 - 2023-06-20

#### Api changes

* new Bluetooth Device Discovery Feature implemented
  * Added **DeviceDiscovery** options to (optional) **MoveOptions**
  * Added **MoveDevice**
  * Added **MoveScanResult**
  * Added **DeviceDiscoveryListener** / Callback

## 2.3.3 - 2023-05-19

• Added a fix for assistance call in case of no GPS.

• Improvements to in-trip activities.

## 2.3.2 - 2023-04-27

• Trip detection stability fixes

## 2.3.1 - 2023-04-26

• Trip detection stability fixes

## 2.3.0 - 2023-04-25

• Added *motion-permission-mandatory* option.

## 2.2.1 - 2023-04-03

• Added fix for background location in iOS 16.4

## 2.2.0 - 2023-03-17

* Added [InitializationListener](/move-platform/sdk/api-interface/ios/setup#set-sdk-initialization-listener).
* Added force option to [shutdown(...)](/move-platform/sdk/api-interface/ios/setup#shutdown), and [callback](/move-platform/sdk/models/moveshutdownresult).
* Added [getDeviceQualifier()](/move-platform/sdk/api-interface/ios/services#get-device-qualifier).

## 2.1.0 - 2023-01-25

* Added [setAssistanceMetadata(...)](/move-platform/sdk/api-interface/ios/services#set-assistance-metadata).
* Added [MoveAssistanceCallStatus](/move-platform/sdk/models/moveassistancecallstatus)

## 2.0.0  - 2022-11-10

* Splitted init(...) into [MoveSDK.init()](/move-platform/sdk/api-interface/react-native/initialization#ios) & persisted [MoveSDK.setup(...)](/move-platform/sdk/api-interface/ios/setup#setup-auth-config)
* Removed MoveAuth from AuthState.Valid
* Removed MoveSDK.Builder
* Introduced MoveDetectionServices
* Added [MoveErrors ](/move-platform/sdk/models/moveservicefailure#ios)+ [Listeners](/move-platform/sdk/models/listeners-callbacks#service-failure-callback)
* Added [MoveWarnings ](/move-platform/sdk/models/moveservicewarning#ios)+ [Listeners](/move-platform/sdk/models/listeners-callbacks#service-warning-callback)
* Added [Geocoding ](/move-platform/sdk/api-interface/ios/services#geocoding)Service
* Added [AID ](/move-platform/sdk/models/moveconfigurationerror#ios)(Automatic Impact Detection) Service
* Added [AssistanceCall ](/move-platform/sdk/api-interface/ios/services#initiate-assistance-call)Service
* Added LogListener

## 1.5.0 - 2022-01-31

### Added

* Timeline detection services PLACES & PUBLIC TRANSPORT
* setConsoleLogging state API

### Improved

* Loads on main thread and overall SDK performance

## 1.3.4 - 2021-11-30

### Added

* Trip detection improvements
* POI detection improvements

### Fixed

* Minor bugfixes

## 1.3.0 - 2021-05-31

### Added

* Support of [Points of Interest](/move-platform/move-services#points-of-interest) by using *OtherServices*

### Fixed

* Minor bugfixes


# React

Changelog

## 2.19.0 - 2026-10-08

* Added maxQueueSize via [MoveInitOptions](/move-platform/sdk/models/moveinitoptions#ios).
* Stability improvements.
* Sunset DolphinMoveSDK Cocoapods framework.

## 2.18.0 - 2026-08-19

* Stability improvements.
* Added soft [shutdown](/move-platform/sdk/api-interface/flutter/initialization#shutdown-sdk) with timeout.

## 2.17.1 - 2026-05-27

* Fixed a bug that made it impossible to register Bluetooth devices on Android

## 2.17.0 - 2026-04-29

* Added [MoveDevice](/move-platform/sdk/models/movedevice) display name.
* Added [MoveDeviceState](/move-platform/sdk/models/movedevice/movedevicestate).
* Deprecated live trip tag.

## 2.16.0 - 2025-02-04

* Added [GetMoveConfig](/move-platform/sdk/api-interface/ios/services#get-configuration) function.
* Added move expo plugin.&#x20;

## 2.15.0 - 2025-12-04

* Split iOS [HealthKit functionality.](/move-platform/sdk/getting-started/react-native)
* Added [beacon uuid registration](/move-platform/sdk/models/movedevice).
* Impact handling improvements.

## 2.14.5 - 2025-09-24

* Enable step count synchronization.
* Expand initial step count data to a day.&#x20;
* SDK updated for 16 KB page size compliance. (Android)
* bugfix for missing metadata submission during manual started trips.

## 2.14.4 - 2025-09-18

* Fixed a bug with step count record deletion upload.

## 2.14.3 - 2025-09-08

* Fixed [startScanningDevices](/move-platform/sdk/api-interface/react-native/services#start-scanning-devices) in old architecture (iOS).

## 2.14.2 - 2025-08-22

* Fixed an iOS bug in the trip counting service.

## 2.14.1 - 2025-08-16

* Fixes for using old architecture. (if: `newArchEnabled: false`). See [Appendix](/move-platform/sdk/appendix/react-native).

## 2.14.0 - 2025-08-07

* Added Health Step-Counting service. (See important changes in [Permission Handling](/move-platform/sdk/appendix/react-native/permission-handling)).
* Small bug fixes & Stability improvements.

## 2.13.0 - 2025-05-27

* Registered Bluetooth devices stored in the backend. Persistence after shutdown / re-registration / login.

## 2.12.0 - 2025-04-03

* Changed the way data is transmitted to our systems, which reduces memory consumption in some situations.
* Bugfixes & Improvements.
  * Fix in lazy loading SDK.

## 2.11.0 - 2025-02-25

* Added [`setHealthListener(...)`](/move-platform/sdk/api-interface/react-native/services#set-health-score-listener).
* Added [MoveOptions](/move-platform/sdk/models/moveoptions#react-native) to [`updateConfig(...)`](/move-platform/sdk/api-interface/react-native/services#update-config).
* Platform specific stability fixes, see: [iOS](https://docs.movesdk.com/move-platform/changelog/pages/-MZJShd4Sv7DW_71hk0n#id-2.11.0-2025-02-04) / [Android](https://docs.movesdk.com/move-platform/changelog/pages/-MZJSfPRqawKT_SVEa1w#id-2.11.0.90-2025-02-04) SDK 2.11.

## 2.10.4 - 2025-02-14

* iOS: Fixed device registration scanner "[connected](/move-platform/sdk/api-interface/react-native/services#start-scanning-devices)" filter.
* Move SDK State Listener [changes for android platform](/move-platform/sdk/models/listeners-callbacks#react-native).

## 2.10.3 - 2024-11-06

* iOS: Fixed a bug which prompted the motion permission dialog from the SDK.

## 2.10.2 - 2024-10-28

* Added *ENERGY\_SAVER* to [warning reasons](/move-platform/sdk/models/moveservicewarning#react-native).
* Added "[connected](/move-platform/sdk/api-interface/react-native/services#start-scanning-devices)" filter for scanning.

## 2.10.1 - 2024-09-23

* Added [`setLogListener(...)`](/move-platform/sdk/api-interface/react-native/services#set-log-listener).

## 2.10.0 - 2024-09-02

* Added [`setDeviceStateListener(...)`](/move-platform/sdk/api-interface/react-native/services#set-movedevice-connection-state-listener).

## 2.9.0 - 2024 -08-19

* Added [`setup(authCode: ...)`](/move-platform/sdk/api-interface/react-native/initialization#javascript).

## 2.8.1 - 2024-08-01

* Bugfixes

## 2.8.0 - 2024-05-22

* Manual start trip feature [`startTrip(...)`](/move-platform/sdk/api-interface/react-native/services#manual-start-trip) added.
* Live Location TAG feature [`setLiveLocationTag(...)`](/move-platform/sdk/api-interface/react-native/services#live-location-tag) added.
* Bugfixes & Improvements

## 2.6.4 - 2023-11-15

* Add call monitor sub types

## 2.6.0 - 2023-09-19

* Added [`TripStartListener`](/move-platform/sdk/models/listeners-callbacks#react-native-3)
* Added `backgroundLocationPermissionRequired` to [`MoveOptions`](/move-platform/sdk/models/moveoptions#react-native)
* Add Bluetooth Info (Permission, Active/Inact) to state API (2.6.1)

## 2.5.0 - 2023-09-19

* Added optional `useBackendConfig` to [`MoveConfig`](/move-platform/sdk/models/moveconfig#react-native)

## 2.4.9 - 2023-09-08

* Bugfixes & stability.

## 2.4.0 - 2023-07-26

* Added device discovery.
* Add auth invalid state.

## 2.3.9 - 2023-07-20

* Bugfixes & stability.

## 2.3.0 - 2023-05-23

* Added [`motion-permission-mandatory`](/move-platform/sdk/models/moveoptions#react-native) option.


# Flutter

Changelog

## 2.19.0 - 2026-10-19

* Added optional `maxQueueSizeMB` init parameter. Limits the local offline queue size in MB; the native SDK enforces its own minimum. 0/unset = unlimited (default).

## 2.18.0 - 2026-07-30

* Stability improvements.
* Added soft [shutdown](/move-platform/sdk/api-interface/flutter/initialization#shutdown-sdk) with timeout.

## 2.17.0 - 2026-05-05

* Added [MoveDevice](/move-platform/sdk/models/movedevice#flutter) display name.
* Added [MoveDeviceState](/move-platform/sdk/models/movedevice/movedevicestate). Ensure synchronized option.
* Live Location TAG feature [setLiveLocationTag(...) ](/move-platform/sdk/api-interface/flutter/services#live-location-tag)deprecated

## 2.16.0 - 2026-02-13

* Added GetMoveConfig method.
* Added [beacon uuid registration](/move-platform/sdk/models/movedevice).

## 2.14.1 - 2025-11-06

* Enable step count synchronization.
* Expand initial step count data to a day.&#x20;
* Android: SDK updated for 16 KB page size compliance
* Android: bugfix for missing metadata submission during manual started trips

## 2.14.0 - 2025-08-19

* Added [Health Step-Counting](/move-platform/sdk/api-interface/flutter/services#step-counter) service. (See important changes in Permission Handling for [iOS](/move-platform/sdk/appendix/ios/permission-handling#health-permissions)/[Android](/move-platform/sdk/appendix/android/permission-handling/permission-overview)).
* Small bug fixes & Stability improvements.

## 2.13.0 - 2025-06-11

* Registered Bluetooth devices stored in the backend. Persistence after shutdown / re-registration / login.
* Android: Update to 'com.android.tools:desugar\_jdk\_libs:2.1.4'

## 2.12.0 - 2025-04-15

* Changed the way data is transmitted to our systems, which reduces memory consumption in some situations
* Bugfixes & Improvements
* Added Swift package manager support.

## 2.11.0 - 2025-03-04

* Added updateConfig with options
* Added health listener

## 2.10.1 - 2025-01-07

* iOS: Fixed a bug which prompted the motion permission dialog from the SDK.
* Android: Bugfixes & Improvements

## 2.10.0 - 2024-09-02

* Added `setDeviceStateListener(...)`.

## 2.9.0 - 2024-08-19

* Added `setupWithCode(...)`.

## 2.8.0 - 2024-05-24

* Added [set live location tag](/move-platform/sdk/api-interface/flutter/services#live-location-tag).
* Bugfixes & Improvements

## 2.7.0 - 2024-05-24

* Added manual [startTrip](/move-platform/sdk/api-interface/flutter/services#manual-start-trip) API.
* Bugfixes & Improvements

## 2.6.7 - 2024-02-01

* Bugfixes & Improvements
* Code documentation.
* Deprecated auth state expired and [updateAuth](/move-platform/sdk/api-interface/flutter/services#set-sdk-auth-state-listener) API.

## 2.6.4 - 2024-02-01

* Fix a bug with iOS device detection / CarPlay.
* Fix a bug with Android [shutdown force: false](/move-platform/sdk/api-interface/flutter/initialization#shutdown-sdk).
* Internal API changes.

## 2.6.2 - 2023-12-12

* Bugfixes & Improvements
* Added iOS Bluetooth permission check.
* Fix Android permission warnings.

## 2.6.0 - 2023-11-14

* Added TripStartListener.
* Added backgroundLocationPermissionRequired to [MoveOptions](/move-platform/sdk/models/moveoptions#flutter).

## 2.5.0 - 2023-10-17

* Added optional useBackendConfig to [MoveConfig](/move-platform/sdk/models/moveconfig#flutter).

## 2.4.0 - 2023-08-04

* Add [device discovery](/move-platform/sdk/api-interface/flutter/services#device-discovery) functionality.
* Add [auth invalid](/move-platform/sdk/models/moveauth#flutter) state.
* Change [options](/move-platform/sdk/models/moveoptions#flutter) format.

## 2.3.1+3 - 2023-07-05

* minor CI changes

## 2.3.1+2 - 2023-07-05

* Fixed [MOVE config](/move-platform/sdk/models/moveconfig#flutter)

## 2.3.1+1 - 2023-06-27 <a href="#id-2311" id="id-2311"></a>

* Fixed deprecated code
* Update README

Update README

## 2.3.1 - 2023-06-23

* initial release


# Backend

Changelog

## 2025-07-07

* Query Steps

## 2025-07-07

* Vehicle API
* Health Steps API

## 2025-02-11

* Add Bt Info to timeline API

## 2024-08-26

* Added user auth code&#x20;

## 2024-01-08

* Added user endpoint /v20/user&#x20;
* Old endpoint /v20/auth is deprecated


# Data privacy (GDPR)

This website uses cookies from Google to deliver and enhance its services' quality and analyze traffic.  Learn More:  https\://policies.google.com/technologies/cookies

## Data collection for Move SDK

The following describes which kind of user data is transmitted to the MOVE Plattform.&#x20;

{% hint style="warning" %}
The application is responsible for complying with the[ Google Play Policy](https://play.google.com/about/developer-content-policy/) or Apple Policy.
{% endhint %}

| Configuration                                                                     | Transmitted                                                                   |
| --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| [Driving](/move-platform/move-services#trip-detection)                            | Locations & Activities (walking, running , cycling, vehicle) during trip      |
| [Bicycle](/move-platform/move-services#modes-of-transport)                        | Locations & Activities (walking, running, cycling, vehicle)  during trip      |
| [Walking](/move-platform/move-services#modes-of-transport)                        | Activities 24/7                                                               |
| [Distraction free driving](/move-platform/move-services#distraction-free-driving) | <p>Phone call events during trip, <br>Touchscreen interaction during trip</p> |
| [Driving behaviour events](/move-platform/move-services#driving-behaviour-events) | Sensor data during trip                                                       |
| [Points of interests](/move-platform/move-services#points-of-interest)            | Location on target point                                                      |

{% hint style="info" %}
**Note:**

* All collected data by the MOVE SDK is transmitted to the Dolphin Technologies backend for processing.
* Host app developers are responsible for declaring all data collection and sharing in the Google Play Data Safety section and Apple Privacy Nutrition Label.
* To delete locally stored SDK data, call `deleteLocalData()`.
* User data on the Dolphin Technologies backend can be managed via the [MOVE Dashboard](https://dashboard.movesdk.com/), including data deletion and feature configuration.
  {% endhint %}


# Introduction

The MOVE SDK enables you to collect **location data**, **motion information** and **other sensor data** from your users’ smartphones. This data is then transmitted to our backend, where it is evaluated, enriched with industry leading machine learning algorithms and applied to a comprehensive **24/7 timeline**.&#x20;

This timeline gives you insights on where your users move and how they get there, be it in the past, the present or even the future (via our prediction algorithms).&#x20;

With our MOVE SDK, you will gain a deep understanding of your users’ personas and service them in a whole new way, completely transforming the way you interact with them.

![](https://1197996007-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXD5xlIFUYU8eK_kkLo%2Fuploads%2FgbtGiqeakzBPaD2kZiBF%2Fmove-diagram-docs.png?alt=media\&token=45700846-624b-449a-86b7-c6ad55e23865)

## Why MOVE SDK?

### Available for iOS and Android

Available for iOS and Android, the MOVE SDK is always up-to-date, using the latest technologies and adapting ahead to new OS features and updates.&#x20;

### Easy integration

Simple SDK setup, clear documentation, sample apps and development support will guarantee a fast and smooth integration of the SDK in any iOS or Android app.

### Fully autonomous and self launched

After the SDK is set up and its services are launched, it will handle automatically waking up in the background and collecting the required data in a fully autonomous way, without any user interactions, even if the app is closed.

### Battery efficient&#x20;

Each SDK instance running on a user’s phone learns about its user’s activity, which is then used to personalize its life cycle in the background. This optimizes the SDK for each user based on his/her daily routines and accurately collects data in a battery-efficient manner.

### Accurate analysis

The SDK collects GPS and IMU data in high frequencies to accurately analyze the user’s mode of transportation and driving behavior, based on different driving events like phone usage while driving, speeding, acceleration, cornering, and braking.&#x20;

### Optimized bandwidth usage

The SDK uses lightweight intelligent algorithms to process the data on the device before sending it to the server to optimize the bandwidth usage.

### Cost-sensitive

You can tune the SDK to your requirements and will only be charged for the services required by your app.


# MOVE Services

The following services are provided out of the box by MOVE.

### Trip Detection

The MOVE SDK uses specialized trip detection algorithms to autonomously recognize trips fully in the background, collect relevant data in high frequencies, process the data, then send it to the MOVE platform for further processing.

### Mode Of Transport

MOVE will detect different modes of transport, using AI and machine learning algorithms to classify which mode of transportation was used in the trip. The host app can also choose which mode(s) (walking, cycling, driving, public transport) it is interested in detecting.

### Driving Behaviour Events

The MOVE platform uses sophisticated machine learning algorithms to accurately profile user’s driving behavior by computing scores for driving events like speeding, acceleration, cornering, and braking from the data collected and processed by the MOVE SDK.

### Distraction Free Driving

The MOVE platform feeds its machine learning-based DFD analyzer (Distraction-Free Driving) with Accelerometer and Gyroscope sensor data that is collected and processed by the MOVE SDK to compute the driver’s DFD score.

### User Timeline

The MOVE platform processes all different collected inputs, from computed activities to different sensor data, to generate a singular merged user timeline representing all the user’s activities throughout a day.

### Points of Interest

POI is a great feature provided by the OS that can monitor places of interest of a user, like airports, shops, school zones, etc...The iOS and Android platforms have different/severe limitations on the number of POIs that can be monitored. The MOVE SDK and platform together provide a dynamic layer over the OS where host apps can monitor an unlimited number of POIs for the user.


# Getting Started

Your shortcut through the MOVE platform into a runnable app is:

1. register and create a project in the [MOVE Dashboard](https://dashboard.movesdk.com/)
2. obtain the productId and API key from the [configuration page](#configuration-add-move-features) of your new MOVE project
3. clone the code sample app ([Android](/move-platform/move-sdk-1.x/sdk/getting-started/android) and [iOS](/move-platform/move-sdk-1.x/sdk/getting-started/ios-1)), adapt the productId and API key to your project
4. install the app on your mobile phone, take the phone everywhere you go for a couple of days
5. check the results in the [MOVE timeline](#timeline-explore-user-contracts)

{% hint style="info" %}
You can check out our sample app on [Bitbucket](https://bitbucket.org/dolphin-technologies/workspace/projects/MS)!&#x20;

With your product id and API key you can get this up and running in merely a few minutes.
{% endhint %}

{% hint style="warning" %}
After installing and running MOVE on your mobile phone, make sure that the OS allows MOVE to operate:

* all [permissions](/move-platform/move-sdk-1.x/sdk/models/movestate) are given
* for Android: all battery settings are set to allow MOVE to work in the background
* check in the [timeline of the MOVE Dashboard,](#timeline-explore-user-contracts) whether there is a basic connection, by searching for your contract ID (defined in the registration after installing on the phone)
* take the phone everywhere you go for a couple of days\
  (MOVE needs some minimum activity outdoors before it starts recording, so you have to actually walk, make a car trip, take the subway, or do whatever MOVE feature you are interested in for 5 minutes or longer)
  {% endhint %}


# MOVE Dashboard

Getting Started

The MOVE Dashboard at [https://dashboard.movesdk.com](https://dashboard.move.dolph.in/) is (a) the console where you can set up and configure your MOVE projects, and (b) the initial place for inspecting and troubleshooting your MOVE apps.&#x20;

If you already created your project in the MOVE Dashboard, and obtained a product ID and API key, you can skip this chapter and explore first steps for [Android](/move-platform/move-sdk-1.x/sdk/getting-started/android) and [iOS](/move-platform/move-sdk-1.x/sdk/getting-started/ios-1).

## Registration and first project

On first opening the page, please register and enter your details. Note that your first couple of users are free, so you can experiment with the MOVE SDK.

After your first login, you will see a pretty empty space. You can create your first MOVE project, using the <img src="https://1197996007-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXD5xlIFUYU8eK_kkLo%2Fuploads%2FH67RKsxLeCxPjfqKHegf%2Fimage.png?alt=media&amp;token=3d89eb23-a7c4-4a9a-9cc2-71a5f3dc46f5" alt="" data-size="line"> in the bottom of the navigation bar. If you created multiple projects, you can select your project in the drop-down list in the top of the navigation bar.

## Access Control - manage developer rights

This page allows you to add developer colleagues to this project in the MOVE Dashboard. Make sure that your colleague has registered with the MOVE Dashboard previously; then enter her/his email address and role in order to add her/him to the project. Next time your colleague loads the MOVE Dashboard, s/he will be able to select the project in the drop-down list located on top of the navigation bar.

You can choose between an "admin" and a "reader" role. An admin has rights to change the configuration of the project, which has direct implications on monthly cost. A reader is mainly able to view user contracts in the "Timeline" section. We recommend you use the "reader" role for e.g. frontend developers or testers.

## Configuration - add MOVE features

The configuration of your MOVE project is split into 4 parts. Please make sure to select the right project in the drop-down menu of the navigation bar before you proceed. Also, please note that configuration changes may have an impact on your cost.

### Configuration

With these settings you can activate or deactivate MOVE features like Walking, Driving, or Public Transport. You will find a short syllabus of each feature in the MOVE Dashboard, and more detailed technical specifications in the chapter [API Interface](/move-platform/move-sdk-1.x/sdk/api-interface) in these docs.

### Manage API keys

Create an API key that allows secure access to the MOVE APIs. Some of the use cases include

1. use the API key in your backend in order to fetch data from the Timeline API or the Notifier API (see [Timeline/authentication](/move-platform/move-sdk-1.x/backend/getting-started-with-the-dolphin-move-timeline-service#gettingstartedwiththedolphinmovetimelineservice-authentication))
2. use the API key in your frontend to authenticate your mobile MOVE SDK (see our code sample on [Bitbucket](https://bitbucket.org/dolphin-technologies/workspace/projects/MS)). For security reasons, we recommend to use write-only keys for this scenario, or preferably the next option:
3. use the API key in your backend in order to create tokens that are user-specific, andforward these tokens e.g. to your users' smartphones (see [Android](/move-platform/move-sdk-1.x/sdk/api-interface/ios/intialization), [iOS](/move-platform/move-sdk-1.x/sdk/models/moveauthstate))

You can create, expire and delete as many API keys as you want on this page. The following parameters pertain to each API key:

* **key** - copy the key from here
* **audience** - you can set this to whatever roles or rights segmentation you like to use in your systems; not relevant for MOVE
* **duration** - validity time (in hours) of the access token (only relevant to you in special scenarios)
* **write-only** - two different key types are available: write only (write-only=true; for all SDK functions that send and process data), and read-write (write-only=false; for all SDK functions / APIs you may use for reading data)

### Notifier

The [MOVE Generic Notifier](/move-platform/move-sdk-1.x/backend/generic-notifier) pushes important events to your backend. This contains real-time events like POIs (Points of Interest), as well as more administrative data about user devices, that you may want to use to allow more targeted communication with your users.&#x20;

Notifier events are pushed to your backend via a web hook: Set up a service, that is capable of receiving [notifier events](/move-platform/move-sdk-1.x/backend/generic-notifier). Enter the URL of your service into this configuration page, as well as a token to be used for signing the event.

### Timeline Receiver

The [MOVE Timeline](/move-platform/move-sdk-1.x/backend/getting-started-with-the-dolphin-move-timeline-service) contains all the key results of MOVE compiled into a chronological timeline. Whenever a new timeline item is created for a user, MOVE pushes update notifications to your backend. Timeline items are not created in real-time; MOVE tries to clean up the timeline as much as possible from the raw data we receive from the devices, and is also enhancing the basic data with additional added value data - this may take some time. Note that we strictly avoid to change the timeline retrospectively, to simplify processing for your backend.

Timeline events are pushed to your backend via a web hook: Set up a service, that is capable of receiving [timeline events](/move-platform/move-sdk-1.x/backend/getting-started-with-the-dolphin-move-timeline-service). Enter the URL of your service into this configuration page, as well as a token to be used for signing the event.

## Timeline - explore user contracts

The timeline offers you details about individual users - in terms of (a) their timeline on a day-per-day basis, (b) their device, and (c) some more detailed logs for debugging (in cooperation with the MOVE community).

You can filter individual users by filtering their contract ID. In the timeline, you can select a specific day and inspect each individual timeline item on that day. On the top right of the map you can filter for specific transport types, and also (in case of CAR transport types) display event types like Speed or DBE (including Acceleration, Braking and Cornering).

On top of the timeline page, there are some details of the user device: manufacturer/device name, OS version, MOVE SDK version.

Back on the start page with the filter for specific users, you can alternatively also look into the Logs. Please note that we currently do not offer a manual of how to interpret the logs. In case you have problems e.g. initializing your MOVE SDK or receiving all transport types, please get in touch and we will analyse the logs together.

## Points of Interest - get notified when user is close by

In addition to detecting user movements as timeline items, the MOVE SDK also offers to detect real-time whenever a user is close to a specific location. You can define such a location as a "Point of Interest", by either right-clicking on the map, using the "add Point of Interest"-button beneath the map, or by importing a CSV-list.

A Point of Interest is defined by the following characteristics (mandatory):

* Name - any string you choose for your PoI
* Latitude/Longitude - GPS location on the map

Trigger properties (optional):

* In Trip - trigger a POI notification even if a user is in a trip (e.g. CAR, CYCLING, PUBLIC TRANSPORT). Please note that the frontend (iOS, Android) may flip back and forth between trip detection, whenever the user is moving outside with some speed, or due to GPS jumps. Those will be filtered
* On Enter - a POI event is triggered when entering the POI
* On Exit - a POI event is triggered when leaving the POI
* Active - the POI is active (or not)
* Tags - tags you may want to add to the POI for your convenience. These tags will be forwarded to you in the [POI event](/move-platform/move-sdk-1.x/backend/generic-notifier#poi-event-notifications) that is sent through the [Generic Notifier](/move-platform/move-sdk-1.x/backend/generic-notifier).


# Android

Getting Started

{% hint style="warning" %}

## Prerequisites&#x20;

* Android 7.0+,
* Android Studio > 2020.3.1

Apps hosting MOVE SDK should always be built using the latest released Android and Android Studio versions.
{% endhint %}

For a quick start, you can download and build our public [sample application](https://bitbucket.org/dolphin-technologies/move-android-sample/).&#x20;




---

[Next Page](https://docs.movesdk.com/move-platform/llms-full.txt/1)

