<p align="center">
  <a href="https://fingerprint.com">
    <picture>
     <source media="(prefers-color-scheme: dark)" srcset="https://fingerprintjs.github.io/home/resources/logo_light.svg" />
     <source media="(prefers-color-scheme: light)" srcset="https://fingerprintjs.github.io/home/resources/logo_dark.svg" />
     <img src="https://fingerprintjs.github.io/home/resources/logo_dark.svg" alt="Fingerprint logo" width="312px" />
   </picture>
  </a>
</p>
<p align="center">
  <a href="https://pypi.org/project/fingerprint-pro-server-api-sdk/"><img alt="PyPI" src="https://img.shields.io/pypi/v/fingerprint-pro-server-api-sdk"></a>
  <a href="https://fingerprintjs.github.io/fingerprint-pro-server-api-python-sdk/"><img src="https://fingerprintjs.github.io/fingerprint-pro-server-api-python-sdk/badges.svg" alt="coverage"></a>
  <a href="https://github.com/fingerprintjs/fingerprint-pro-server-api-python-sdk/actions/workflows/release.yml"><img src="https://github.com/fingerprintjs/fingerprint-pro-server-api-python-sdk/actions/workflows/release.yml/badge.svg" alt="CI badge" /></a>
  <a href="https://github.com/fingerprintjs/fingerprint-pro-server-api-python-sdk/actions/workflows/test.yml"><img src="https://github.com/fingerprintjs/fingerprint-pro-server-api-python-sdk/actions/workflows/test.yml/badge.svg" alt="CI badge" /></a>
  <a href="https://github.com/fingerprintjs/fingerprint-pro-server-api-python-sdk/actions/workflows/functional_tests.yml"><img src="https://github.com/fingerprintjs/fingerprint-pro-server-api-python-sdk/actions/workflows/functional_tests.yml/badge.svg" alt="CI badge" /></a>
  <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/:license-mit-blue.svg?style=flat"/></a>
  <a href="https://discord.gg/39EpE2neBg"><img src="https://img.shields.io/discord/852099967190433792?style=logo&label=Discord&logo=Discord&logoColor=white" alt="Discord server"></a>
</p>

# Fingerprint Server Python SDK

[Fingerprint](https://fingerprint.com) is a device intelligence platform offering industry-leading accuracy.
The Fingerprint Server Python SDK is an easy way to interact with the Fingerprint [Server API](https://dev.fingerprint.com/reference/pro-server-api) from your Python application. You can retrieve visitor history or individual identification events.


This Python package is automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) project:

- API version: 3
- Package version: 8.11.0
- Build package: io.swagger.codegen.v3.generators.python.PythonClientCodegen

## Requirements

The following Python versions are supported:

- Python >= 3.9

## Installation & Usage
### pip install

You can install the package directly from the Github

```sh
pip install git+https://github.com/fingerprintjs/fingerprint-pro-server-api-python-sdk.git
```

Or from the PyPI

```sh
pip install fingerprint_pro_server_api_sdk
```

Then import the package:
```python
import fingerprint_pro_server_api_sdk
```

### Setuptools

Install via [Setuptools](http://pypi.python.org/pypi/setuptools).

```sh
python setup.py install --user
```
(or `sudo python setup.py install` to install the package for all users)

Then import the package:
```python
import fingerprint_pro_server_api_sdk
```

## Getting Started

Please follow the [installation procedure](#installation--usage) and then run the following:

```python
import fingerprint_pro_server_api_sdk

# Configure API key authorization and region
configuration = fingerprint_pro_server_api_sdk.Configuration(api_key="SECRET_API_KEY")
# configuration = fingerprint_pro_server_api_sdk.Configuration(api_key="SECRET_API_KEY", region="eu")

# create an instance of the API class
api_instance = fingerprint_pro_server_api_sdk.FingerprintApi(configuration)
```

## Examples

Fetching visits using visitorId:
```python
import fingerprint_pro_server_api_sdk
from fingerprint_pro_server_api_sdk.rest import ApiException, KnownApiException

configuration = fingerprint_pro_server_api_sdk.Configuration(api_key="SECRET_API_KEY")
api_instance = fingerprint_pro_server_api_sdk.FingerprintApi(configuration)

visitor_id = 'visitor_id_example'  # str | Unique [visitor identifier](https://dev.fingerprint.com/docs/js-agent#visitorid) issued by Fingerprint Pro.
#request_id = 'request_id_example'  # str | The unique event [identifier](https://dev.fingerprint.com/docs/js-agent#requestid).
#linked_id = 'linked_id_example'  # str | Filter visits by your custom identifier.   You can use [`linkedId`](https://dev.fingerprint.com/docs/js-agent#linkedid) to associate identification requests with your own identifier, for example: session ID, purchase ID, or transaction ID. You can then use this `linked_id` parameter to retrieve all events associated with your custom identifier.  (optional)
limit = 10  # int | Limit scanned results.   For performance reasons, the API first scans some number of events before filtering them. Use `limit` to specify how many events are scanned before they are filtered by `requestId` or `linkedId`. Results are always returned sorted by the timestamp (most recent first). By default, the most recent 100 visits are scanned, the maximum is 500.  (optional)
#pagination_key = 'pagination_key_example' # str | Use `paginationKey` to get the next page of results.   When more results are available (e.g., you requested 200 results using `limit` parameter, but a total of 600 results are available), the `paginationKey` top-level attribute is added to the response. The key corresponds to the `requestId` of the last returned event. In the following request, use that value in the `paginationKey` parameter to get the next page of results:  1. First request, returning most recent 200 events: `GET api-base-url/visitors/:visitorId?limit=200` 2. Use `response.paginationKey` to get the next page of results: `GET api-base-url/visitors/:visitorId?limit=200&paginationKey=1683900801733.Ogvu1j`  Pagination happens during scanning and before filtering, so you can get less visits than the `limit` you specified with more available on the next page. When there are no more results available for scanning, the `paginationKey` attribute is not returned.  (optional)

try:
    api_response = api_instance.get_visits(visitor_id, limit=2)
    print(api_response)
except KnownApiException as e:
    structured_error = e.structured_error
    print("Error: %s\n" % structured_error.error)
except ApiException as e:
    print("Exception when calling FingerprintApi->visitors_visitor_id_get: %s\n" % e)
```

Delete visits using visitorId:
```python
import fingerprint_pro_server_api_sdk
from fingerprint_pro_server_api_sdk.rest import ApiException, KnownApiException

configuration = fingerprint_pro_server_api_sdk.Configuration(api_key="SECRET_API_KEY")
api_instance = fingerprint_pro_server_api_sdk.FingerprintApi(configuration)

visitor_id = 'visitor_id_example'  # str | Unique [visitor identifier](https://dev.fingerprint.com/docs/js-agent#visitorid) issued by Fingerprint Pro.

try:
    api_instance.delete_visitor_data(visitor_id)
except KnownApiException as e:
    structured_error = e.structured_error
    print("Error: %s\n" % structured_error.error)
except ApiException as e:
    print("Exception when calling FingerprintApi->delete_visitor_data: %s\n" % e)
```

Fetching events for requestId:
```python
import fingerprint_pro_server_api_sdk
from fingerprint_pro_server_api_sdk.rest import ApiException, KnownApiException

configuration = fingerprint_pro_server_api_sdk.Configuration(api_key="SECRET_API_KEY")
api_instance = fingerprint_pro_server_api_sdk.FingerprintApi(configuration)

request_id = 'request_id_example'  # str | The unique event [identifier](https://dev.fingerprint.com/docs/js-agent#requestid).

try:
    events_response = api_instance.get_event(request_id)

except KnownApiException as e:
    structured_error = e.structured_error
    print("Error code: %s. Error message: %s\n" % (structured_error.error.code, structured_error.error.message))
except ApiException as e:
    print("Exception when calling FingerprintApi->get_event: %s\n" % e)
```

Search events with custom filters:
```python
import fingerprint_pro_server_api_sdk
from fingerprint_pro_server_api_sdk.rest import ApiException, KnownApiException

configuration = fingerprint_pro_server_api_sdk.Configuration(api_key="SECRET_API_KEY")
api_instance = fingerprint_pro_server_api_sdk.FingerprintApi(configuration)

limit = 20                      # int | Limit the number of events returned.
pagination_key = 'key_example'  # str | Use `pagination_key` to get the next page of results.   When more results are available (e.g., you requested up to 200 results for your search using `limit`, but there are more than 200 events total matching your request), the `paginationKey` top-level attribute is added to the response. The key corresponds to the `timestamp` of the last returned event. In the following request, use that value in the `pagination_key` parameter to get the next page of results:  1. First request, returning most recent 200 events: `GET api-base-url/events/search?limit=200` 2. Use `response.paginationKey` to get the next page of results: `GET api-base-url/events/search?limit=200&pagination_key=1740815825085`  (optional)
visitor_id = 'VISITOR_ID'       # str | Unique [visitor identifier](https://dev.fingerprint.com/reference/get-function#visitorid) issued by Fingerprint Pro. Filter for events matching this `visitor_id`.  (optional)
bot = 'good'                    # str | Filter events by the bot detection result, specifically: events where <'any'|'good'|'bad'|'none'> kind of bot was detected.  (optional)
ip_address = '192.168.0.1/32'   # str | Filter events by IP address range. The range can be as specific as a single IP (/32 for IPv4 or /128 for IPv6)  All ip_address filters must use CIDR notation, for example, 10.0.0.0/24, 192.168.0.1/32  (optional)
linked_id = 'linked_id_example' # str | Filter events by your custom identifier.   You can use [linked IDs](https://dev.fingerprint.com/reference/get-function#linkedid) to associate identification requests with your own identifier, for example, session ID, purchase ID, or transaction ID. You can then use this `linked_id` parameter to retrieve all events associated with your custom identifier.  (optional)
start = 1738687200000           # int | Filter events with a timestamp greater than the start time, in Unix time (milliseconds).  (optional)
end = 1738773600000             # int | Filter events with a timestamp smaller than the end time, in Unix time (milliseconds).  (optional)
reverse = True                 # bool | Sort events in reverse timestamp order.  (optional)
suspect = False                # bool | Filter events previously tagged as suspicious via the [Update API](https://dev.fingerprint.com/reference/updateevent).  (optional)

try:
    # Get events via search
    api_response = api_instance.search_events(limit, pagination_key=pagination_key, visitor_id=visitor_id, bot=bot, ip_address=ip_address, linked_id=linked_id, start=start, end=end, reverse=reverse, suspect=suspect)
    print(api_response)

except KnownApiException as e:
    structured_error = e.structured_error
    print("Error code: %s. Error message: %s\n" % (structured_error.error.code, structured_error.error.message))
except ApiException as e:
    print("Exception when calling FingerprintApi->get_event: %s\n" % e)
```

Update event for requestId:
```python
import fingerprint_pro_server_api_sdk
from fingerprint_pro_server_api_sdk import EventsUpdateRequest
from fingerprint_pro_server_api_sdk.rest import ApiException, KnownApiException

configuration = fingerprint_pro_server_api_sdk.Configuration(api_key="SECRET_API_KEY")
api_instance = fingerprint_pro_server_api_sdk.FingerprintApi(configuration)

request_id = 'request_id_example'  # str | The unique event [identifier](https://dev.fingerprint.com/docs/js-agent#requestid).
body = EventsUpdateRequest(linked_id='foo')  # EventsUpdateRequest |
# body = EventsUpdateRequest(tag={'bar': 123})
# body = EventsUpdateRequest(suspect=True)
# body = EventsUpdateRequest(linked_id='foo', tag={'bar': 123}, suspect=False)

try:
    api_instance.update_event(body, request_id)
except KnownApiException as e:
    structured_error = e.structured_error
    print("Error code: %s. Error message: %s\n" % (structured_error.error.code, structured_error.error.message))
except ApiException as e:
    print("Exception when calling FingerprintApi->update_event: %s\n" % e)
```

## Sealed results

This SDK provides utility methods for decoding [sealed results](https://dev.fingerprint.com/docs/sealed-client-results).
```python
import base64
import os

from dotenv import load_dotenv

from fingerprint_pro_server_api_sdk import unseal_event_response, DecryptionKey, DecryptionAlgorithm

load_dotenv()

sealed_result = base64.b64decode(os.environ["BASE64_SEALED_RESULT"])
key = base64.b64decode(os.environ["BASE64_KEY"])

try:
    event_response = unseal_event_response(sealed_result, [DecryptionKey(key, DecryptionAlgorithm['Aes256Gcm'])])
    print("\n\n\nEvent response: \n", event_response.products)
except Exception as e:
    print("Exception when calling unsealing events response: %s\n" % e)
    exit(1)

print("Unseal successful!")

exit(0)
```
To learn more, refer to example located in [sealed_results_example.py](sealed_results_example.py).

## Webhook signature validation

This SDK provides utility method for verifying the HMAC signature of the incoming webhook request.
```python
import os
from flask import Flask, request, jsonify
from fingerprint_pro_server_api_sdk import WebhookValidation

app = Flask(__name__)

@app.route('/api/webhook', methods=['POST'])
def webhook_handler():
    try:
        # Retrieve the secret key from environment variables
        secret = os.getenv("WEBHOOK_SIGNATURE_SECRET")
        if not secret:
            return jsonify({"message": "Secret key is not configured."}), 400

        # Get the "fpjs-event-signature" header from the incoming request
        header = request.headers.get('fpjs-event-signature')
        if not header:
            return jsonify({"message": "Missing fpjs-event-signature header."}), 400

        # Read the raw body of the incoming request
        data = request.get_data()

        # Validate the webhook signature
        is_valid = WebhookValidation.is_valid_webhook_signature(header, data, secret)
        if not is_valid:
            return jsonify({"message": "Webhook signature is invalid."}), 403

        # Process the webhook data here
        return jsonify({"message": "Webhook received."}), 200

    except Exception as e:
        # Handle any unexpected errors
        return jsonify({"error": str(e)}), 500

if __name__ == '__main__':
    # Start the Flask application on the specified host and port
    app.run(host='0.0.0.0', port=5000)
```
To learn more, refer to example located in [webhook_signature_example.py](webhook_signature_example.py).

## Documentation for API Endpoints

All URIs are relative to *https://api.fpjs.io*

Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
*FingerprintApi* | [**delete_visitor_data**](docs/FingerprintApi.md#delete_visitor_data) | **DELETE** /visitors/{visitor_id} | Delete data by visitor ID
*FingerprintApi* | [**get_event**](docs/FingerprintApi.md#get_event) | **GET** /events/{request_id} | Get event by request ID
*FingerprintApi* | [**get_related_visitors**](docs/FingerprintApi.md#get_related_visitors) | **GET** /related-visitors | Get Related Visitors
*FingerprintApi* | [**get_visits**](docs/FingerprintApi.md#get_visits) | **GET** /visitors/{visitor_id} | Get visits by visitor ID
*FingerprintApi* | [**search_events**](docs/FingerprintApi.md#search_events) | **GET** /events/search | Get events via search
*FingerprintApi* | [**update_event**](docs/FingerprintApi.md#update_event) | **PUT** /events/{request_id} | Update an event with a given request ID

## Documentation For Models

 - [Botd](docs/Botd.md)
 - [BotdBot](docs/BotdBot.md)
 - [BotdBotResult](docs/BotdBotResult.md)
 - [BrowserDetails](docs/BrowserDetails.md)
 - [ClonedApp](docs/ClonedApp.md)
 - [DeprecatedGeolocation](docs/DeprecatedGeolocation.md)
 - [DeveloperTools](docs/DeveloperTools.md)
 - [Emulator](docs/Emulator.md)
 - [Error](docs/Error.md)
 - [ErrorCode](docs/ErrorCode.md)
 - [ErrorPlainResponse](docs/ErrorPlainResponse.md)
 - [ErrorResponse](docs/ErrorResponse.md)
 - [EventsGetResponse](docs/EventsGetResponse.md)
 - [EventsUpdateRequest](docs/EventsUpdateRequest.md)
 - [FactoryReset](docs/FactoryReset.md)
 - [Frida](docs/Frida.md)
 - [Geolocation](docs/Geolocation.md)
 - [GeolocationCity](docs/GeolocationCity.md)
 - [GeolocationContinent](docs/GeolocationContinent.md)
 - [GeolocationCountry](docs/GeolocationCountry.md)
 - [GeolocationSubdivision](docs/GeolocationSubdivision.md)
 - [GeolocationSubdivisions](docs/GeolocationSubdivisions.md)
 - [HighActivity](docs/HighActivity.md)
 - [IPBlocklist](docs/IPBlocklist.md)
 - [IPBlocklistDetails](docs/IPBlocklistDetails.md)
 - [IPInfo](docs/IPInfo.md)
 - [IPInfoASN](docs/IPInfoASN.md)
 - [IPInfoDataCenter](docs/IPInfoDataCenter.md)
 - [IPInfoV4](docs/IPInfoV4.md)
 - [IPInfoV6](docs/IPInfoV6.md)
 - [Identification](docs/Identification.md)
 - [IdentificationConfidence](docs/IdentificationConfidence.md)
 - [IdentificationSeenAt](docs/IdentificationSeenAt.md)
 - [Incognito](docs/Incognito.md)
 - [Jailbroken](docs/Jailbroken.md)
 - [LocationSpoofing](docs/LocationSpoofing.md)
 - [MitMAttack](docs/MitMAttack.md)
 - [PrivacySettings](docs/PrivacySettings.md)
 - [ProductBotd](docs/ProductBotd.md)
 - [ProductClonedApp](docs/ProductClonedApp.md)
 - [ProductDeveloperTools](docs/ProductDeveloperTools.md)
 - [ProductEmulator](docs/ProductEmulator.md)
 - [ProductFactoryReset](docs/ProductFactoryReset.md)
 - [ProductFrida](docs/ProductFrida.md)
 - [ProductHighActivity](docs/ProductHighActivity.md)
 - [ProductIPBlocklist](docs/ProductIPBlocklist.md)
 - [ProductIPInfo](docs/ProductIPInfo.md)
 - [ProductIdentification](docs/ProductIdentification.md)
 - [ProductIncognito](docs/ProductIncognito.md)
 - [ProductJailbroken](docs/ProductJailbroken.md)
 - [ProductLocationSpoofing](docs/ProductLocationSpoofing.md)
 - [ProductMitMAttack](docs/ProductMitMAttack.md)
 - [ProductPrivacySettings](docs/ProductPrivacySettings.md)
 - [ProductProximity](docs/ProductProximity.md)
 - [ProductProxy](docs/ProductProxy.md)
 - [ProductRawDeviceAttributes](docs/ProductRawDeviceAttributes.md)
 - [ProductRemoteControl](docs/ProductRemoteControl.md)
 - [ProductRootApps](docs/ProductRootApps.md)
 - [ProductSuspectScore](docs/ProductSuspectScore.md)
 - [ProductTampering](docs/ProductTampering.md)
 - [ProductTor](docs/ProductTor.md)
 - [ProductVPN](docs/ProductVPN.md)
 - [ProductVelocity](docs/ProductVelocity.md)
 - [ProductVirtualMachine](docs/ProductVirtualMachine.md)
 - [Products](docs/Products.md)
 - [Proximity](docs/Proximity.md)
 - [Proxy](docs/Proxy.md)
 - [ProxyConfidence](docs/ProxyConfidence.md)
 - [ProxyDetails](docs/ProxyDetails.md)
 - [RawDeviceAttribute](docs/RawDeviceAttribute.md)
 - [RawDeviceAttributeError](docs/RawDeviceAttributeError.md)
 - [RawDeviceAttributes](docs/RawDeviceAttributes.md)
 - [RelatedVisitor](docs/RelatedVisitor.md)
 - [RelatedVisitorsResponse](docs/RelatedVisitorsResponse.md)
 - [RemoteControl](docs/RemoteControl.md)
 - [RootApps](docs/RootApps.md)
 - [SDK](docs/SDK.md)
 - [SearchEventsResponse](docs/SearchEventsResponse.md)
 - [SearchEventsResponseEvents](docs/SearchEventsResponseEvents.md)
 - [SupplementaryID](docs/SupplementaryID.md)
 - [SuspectScore](docs/SuspectScore.md)
 - [Tag](docs/Tag.md)
 - [Tampering](docs/Tampering.md)
 - [Tor](docs/Tor.md)
 - [VPN](docs/VPN.md)
 - [VPNConfidence](docs/VPNConfidence.md)
 - [VPNMethods](docs/VPNMethods.md)
 - [Velocity](docs/Velocity.md)
 - [VelocityData](docs/VelocityData.md)
 - [VelocityIntervals](docs/VelocityIntervals.md)
 - [VirtualMachine](docs/VirtualMachine.md)
 - [Visit](docs/Visit.md)
 - [VisitorsGetResponse](docs/VisitorsGetResponse.md)
 - [Webhook](docs/Webhook.md)
 - [WebhookClonedApp](docs/WebhookClonedApp.md)
 - [WebhookDeveloperTools](docs/WebhookDeveloperTools.md)
 - [WebhookEmulator](docs/WebhookEmulator.md)
 - [WebhookFactoryReset](docs/WebhookFactoryReset.md)
 - [WebhookFrida](docs/WebhookFrida.md)
 - [WebhookHighActivity](docs/WebhookHighActivity.md)
 - [WebhookIPBlocklist](docs/WebhookIPBlocklist.md)
 - [WebhookIPInfo](docs/WebhookIPInfo.md)
 - [WebhookJailbroken](docs/WebhookJailbroken.md)
 - [WebhookLocationSpoofing](docs/WebhookLocationSpoofing.md)
 - [WebhookMitMAttack](docs/WebhookMitMAttack.md)
 - [WebhookPrivacySettings](docs/WebhookPrivacySettings.md)
 - [WebhookProximity](docs/WebhookProximity.md)
 - [WebhookProxy](docs/WebhookProxy.md)
 - [WebhookRawDeviceAttributes](docs/WebhookRawDeviceAttributes.md)
 - [WebhookRemoteControl](docs/WebhookRemoteControl.md)
 - [WebhookRootApps](docs/WebhookRootApps.md)
 - [WebhookSupplementaryIDs](docs/WebhookSupplementaryIDs.md)
 - [WebhookSuspectScore](docs/WebhookSuspectScore.md)
 - [WebhookTampering](docs/WebhookTampering.md)
 - [WebhookTor](docs/WebhookTor.md)
 - [WebhookVPN](docs/WebhookVPN.md)
 - [WebhookVelocity](docs/WebhookVelocity.md)
 - [WebhookVirtualMachine](docs/WebhookVirtualMachine.md)

## Documentation For Authorization


## ApiKeyHeader

- **Type**: API key
- **API key parameter name**: Auth-API-Key
- **Location**: HTTP header

## ApiKeyQuery

- **Type**: API key
- **API key parameter name**: api_key
- **Location**: URL query string


## Documentation for sealed results

- [SealedResults](docs/SealedResults.md)
- [DecryptionKey](docs/DecryptionKey.md)

## Support

To report problems, ask questions or provide feedback, please use [Issues](https://github.com/fingerprintjs/fingerprint-pro-server-api-python-sdk/issues).
If you need private support, you can email us at [oss-support@fingerprint.com](mailto:oss-support@fingerprint.com).

## License

This project is licensed under the [MIT License](https://github.com/fingerprintjs/fingerprint-pro-server-api-python-sdk/blob/main/LICENSE).
