From f543622d4d34e64d9c50338ee4ef44d166d39803 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
extends
return new RequestError('Unknown error', undefined, response.status, response.statusText, response)
}
- static fromPlainError(body: ErrorPlainResponse, response: Response) {
- return new RequestError(body.error, body, response.status, response.statusText, response)
- }
-
static fromErrorResponse(body: ErrorResponse, response: Response) {
return new RequestError(body.error.message, body, response.status, body.error.code, response)
}
@@ -61,16 +57,4 @@ export class TooManyRequestsError extends RequestError<429, ErrorResponse> {
super(body.error.message, body, 429, body.error.code, response)
this.retryAfter = getRetryAfter(response)
}
-
- static fromPlain(error: ErrorPlainResponse, response: Response) {
- return new TooManyRequestsError(
- {
- error: {
- message: error.error,
- code: 'TooManyRequests',
- },
- },
- response
- )
- }
}
diff --git a/src/errors/handleErrorResponse.ts b/src/errors/handleErrorResponse.ts
index 486bd60a..853b713a 100644
--- a/src/errors/handleErrorResponse.ts
+++ b/src/errors/handleErrorResponse.ts
@@ -1,4 +1,4 @@
-import { ErrorPlainResponse, ErrorResponse } from '../types'
+import { ErrorResponse } from '../types'
import { RequestError, TooManyRequestsError } from './apiErrors'
function isErrorResponse(value: unknown): value is ErrorResponse {
@@ -13,10 +13,6 @@ function isErrorResponse(value: unknown): value is ErrorResponse {
)
}
-function isPlainErrorResponse(value: unknown): value is ErrorPlainResponse {
- return Boolean(value && typeof value === 'object' && 'error' in value && typeof value.error === 'string')
-}
-
export function handleErrorResponse(json: any, response: Response): never {
if (isErrorResponse(json)) {
if (response.status === 429) {
@@ -26,13 +22,5 @@ export function handleErrorResponse(json: any, response: Response): never {
throw RequestError.fromErrorResponse(json, response)
}
- if (isPlainErrorResponse(json)) {
- if (response.status === 429) {
- throw TooManyRequestsError.fromPlain(json, response)
- }
-
- throw RequestError.fromPlainError(json, response)
- }
-
throw RequestError.unknown(response)
}
diff --git a/src/generatedApiTypes.ts b/src/generatedApiTypes.ts
index 2f0dc0c3..f84f9ac3 100644
--- a/src/generatedApiTypes.ts
+++ b/src/generatedApiTypes.ts
@@ -1,5 +1,5 @@
export interface paths {
- '/events/{request_id}': {
+ '/events/{event_id}': {
parameters: {
query?: never
header?: never
@@ -7,33 +7,35 @@ export interface paths {
cookie?: never
}
/**
- * Get event by request ID
+ * Get an event by event ID
* @description Get a detailed analysis of an individual identification event, including Smart Signals.
- * Please note that the response includes mobile signals (e.g. `rootApps`) even if the request originated from a non-mobile platform.
- * It is highly recommended that you **ignore** the mobile signals for such requests.
*
- * Use `requestId` as the URL path parameter. This API method is scoped to a request, i.e. all returned information is by `requestId`.
+ * Use `event_id` as the URL path parameter. This API method is scoped to a request, i.e. all returned information is by `event_id`.
*
*/
get: operations['getEvent']
+ put?: never
+ post?: never
+ delete?: never
+ options?: never
+ head?: never
/**
- * Update an event with a given request ID
- * @description Change information in existing events specified by `requestId` or *flag suspicious events*.
+ * Update an event
+ * @description Change information in existing events specified by `event_id` or *flag suspicious events*.
+ *
+ * When an event is created, it can be assigned `linked_id` and `tags` submitted through the JS agent parameters.
+ * This information might not have been available on the client initially, so the Server API permits updating these attributes after the fact.
*
- * When an event is created, it is assigned `linkedId` and `tag` submitted through the JS agent parameters. This information might not be available on the client so the Server API allows for updating the attributes after the fact.
+ * **Warning** It's not possible to update events older than one month.
*
- * **Warning** It's not possible to update events older than 10 days.
+ * **Warning** Trying to update an event immediately after creation may temporarily result in an
+ * error (HTTP 409 Conflict. The event is not mutable yet.) as the event is fully propagated across our systems. In such a case, simply retry the request.
*
*/
- put: operations['updateEvent']
- post?: never
- delete?: never
- options?: never
- head?: never
- patch?: never
+ patch: operations['updateEvent']
trace?: never
}
- '/events/search': {
+ '/events': {
parameters: {
query?: never
header?: never
@@ -41,10 +43,24 @@ export interface paths {
cookie?: never
}
/**
- * Get events via search
- * @description Search for identification events, including Smart Signals, using multiple filtering criteria. If you don't provide `start` or `end` parameters, the default search range is the last 7 days.
+ * Search events
+ * @description ## Search
+ *
+ * The `/v4/events` endpoint provides a convenient way to search for past events based on specific parameters. Typical use cases and queries include:
+ *
+ * - Searching for events associated with a single `visitor_id` within a time range to get historical behavior of a visitor.
+ * - Searching for events associated with a single `linked_id` within a time range to get all events associated with your internal account identifier.
+ * - Excluding all bot traffic from the query (`good` and `bad` bots)
*
- * Please note that events include mobile signals (e.g. `rootApps`) even if the request originated from a non-mobile platform. We recommend you **ignore** mobile signals for such requests.
+ * If you don't provide `start` or `end` parameters, the default search range is the **last 7 days**.
+ *
+ * ### Filtering events with the`suspect` flag
+ *
+ * The `/v4/events` endpoint unlocks a powerful method for fraud protection analytics. The `suspect` flag is exposed in all events where it was previously set by the update API.
+ *
+ * You can also apply the `suspect` query parameter as a filter to find all potentially fraudulent activity that you previously marked as `suspect`. This helps identify patterns of fraudulent behavior.
+ *
+ * Smart Signals not activated for your workspace or are not included in the response.
*
*/
get: operations['searchEvents']
@@ -63,22 +79,13 @@ export interface paths {
path?: never
cookie?: never
}
- /**
- * Get visits by visitor ID
- * @description Get a history of visits (identification events) for a specific `visitorId`. Use the `visitorId` as a URL path parameter.
- * Only information from the _Identification_ product is returned.
- *
- * #### Headers
- *
- * * `Retry-After` — Present in case of `429 Too many requests`. Indicates how long you should wait before making a follow-up request. The value is non-negative decimal integer indicating the seconds to delay after the response is received.
- *
- */
- get: operations['getVisits']
+ get?: never
put?: never
post?: never
/**
* Delete data by visitor ID
* @description Request deleting all data associated with the specified visitor ID. This API is useful for compliance with privacy regulations.
+ *
* ### Which data is deleted?
* - Browser (or device) properties
* - Identification requests made from this browser (or device)
@@ -96,8 +103,7 @@ export interface paths {
* ### Corollary
* After requesting to delete a visitor ID,
* - If the same browser (or device) requests to identify, it will receive a different visitor ID.
- * - If you request [`/events` API](https://dev.fingerprint.com/reference/getevent) with a `request_id` that was made outside of the 10 days, you will still receive a valid response.
- * - If you request [`/visitors` API](https://dev.fingerprint.com/reference/getvisits) for the deleted visitor ID, the response will include identification requests that were made outside of those 10 days.
+ * - If you request [`/v4/events` API](https://dev.fingerprint.com/reference/getevent) with an `event_id` that was made outside of the 10 days, you will still receive a valid response.
*
* ### Interested?
* Please [contact our support team](https://fingerprint.com/support/) to enable it for you. Otherwise, you will receive a 403.
@@ -109,34 +115,9 @@ export interface paths {
patch?: never
trace?: never
}
- '/related-visitors': {
- parameters: {
- query?: never
- header?: never
- path?: never
- cookie?: never
- }
- /**
- * Get Related Visitors
- * @description Related visitors API lets you link web visits and in-app browser visits that originated from the same mobile device.
- * It searches the past 6 months of identification events to find the visitor IDs that belong to the same mobile device as the given visitor ID.
- *
- * ⚠️ Please note that this API is not enabled by default and is billable separately. ⚠️
- *
- * If you would like to use Related visitors API, please contact our [support team](https://fingerprint.com/support).
- * To learn more, see [Related visitors API reference](https://dev.fingerprint.com/reference/related-visitors-api).
- *
- */
- get: operations['getRelatedVisitors']
- put?: never
- post?: never
- delete?: never
- options?: never
- head?: never
- patch?: never
- trace?: never
- }
- '/webhook': {
+}
+export interface webhooks {
+ event: {
parameters: {
query?: never
header?: never
@@ -145,424 +126,259 @@ export interface paths {
}
get?: never
put?: never
- post?: never
+ /** Webhook */
+ post: operations['postEventWebhook']
delete?: never
options?: never
head?: never
patch?: never
- /**
- * Dummy path to describe webhook format.
- * @description Fake path to describe webhook format. More information about webhooks can be found in the [documentation](https://dev.fingerprint.com/docs/webhooks)
- */
- trace: {
- parameters: {
- query?: never
- header?: never
- path?: never
- cookie?: never
- }
- requestBody?: {
- content: {
- 'application/json': components['schemas']['Webhook']
- }
- }
- responses: {
- /** @description Dummy for the schema */
- default: {
- headers: {
- [name: string]: unknown
- }
- content?: never
- }
- }
- }
+ trace?: never
}
}
-export type webhooks = Record
export interface components {
schemas: {
- BrowserDetails: {
- browserName: string
- browserMajorVersion: string
- browserFullVersion: string
- os: string
- osVersion: string
- device: string
- userAgent: string
- }
- GeolocationCity: {
- name: string
- }
- GeolocationCountry: {
- code: string
- name: string
- }
- GeolocationContinent: {
- code: string
- name: string
- }
- GeolocationSubdivision: {
- isoCode: string
- name: string
- }
- GeolocationSubdivisions: components['schemas']['GeolocationSubdivision'][]
+ /** @description Unique identifier of the user's request. The first portion of the event_id is a unix epoch milliseconds timestamp For example: `1758130560902.8tRtrH`
+ * */
+ EventId: string
/**
- * @deprecated
- * @description This field is **deprecated** and will not return a result for **applications created after January 23rd, 2024**. Please use the [IP Geolocation Smart signal](https://dev.fingerprint.com/docs/smart-signals-overview#ip-geolocation) for geolocation information.
+ * Format: int64
+ * @description Timestamp of the event with millisecond precision in Unix time.
*/
- DeprecatedGeolocation: {
- /** @description The IP address is likely to be within this radius (in km) of the specified location. */
- accuracyRadius?: number
- /** Format: double */
- latitude?: number
- /** Format: double */
- longitude?: number
- postalCode?: string
- /** Format: timezone */
- timezone?: string
- city?: components['schemas']['GeolocationCity']
- country?: components['schemas']['GeolocationCountry']
- continent?: components['schemas']['GeolocationContinent']
- subdivisions?: components['schemas']['GeolocationSubdivisions']
+ Timestamp: number
+ /** @description A customer-provided id that was sent with the request. */
+ LinkedId: string
+ /** @description Environment Id of the event. For example: `ae_47abaca3db2c7c43`
+ * */
+ EnvironmentId: string
+ /** @description Field is `true` if you have previously set the `suspect` flag for this event using the [Server API Update event endpoint](https://dev.fingerprint.com/reference/updateevent). */
+ Suspect: boolean
+ Integration: {
+ /** @description The name of the specific integration, e.g. "fingerprint-pro-react". */
+ name?: string
+ /** @description The version of the specific integration, e.g. "3.11.10". */
+ version?: string
+ subintegration?: {
+ /** @description The name of the specific subintegration, e.g. "preact". */
+ name?: string
+ /** @description The version of the specific subintegration, e.g. "10.21.0". */
+ version?: string
+ }
}
- /** @description A customer-provided value or an object that was sent with identification request. */
- Tag: {
- [key: string]: unknown
+ /** @description Contains information about the SDK used to perform the request. */
+ SDK: {
+ /**
+ * @description Platform of the SDK used for the identification request.
+ * @enum {string}
+ */
+ platform: 'js' | 'android' | 'ios' | 'unknown'
+ /** @description Version string of the SDK used for the identification request. For example: `"3.12.1"`
+ * */
+ version: string
+ integrations?: components['schemas']['Integration'][]
}
+ /** @description `true` if we determined that this payload was replayed, `false` otherwise.
+ * */
+ Replayed: boolean
+ /** @description The rule(s) associated with triggering the webhook via rule engine. */
+ TriggeredBy: {
+ id: string
+ name: string
+ description: string
+ }[]
IdentificationConfidence: {
/**
* Format: double
* @description The confidence score is a floating-point number between 0 and 1 that represents the probability of accurate identification.
*/
score: number
- /** @description The revision name of the method used to calculate the Confidence score. This field is only present for customers who opted in to an alternative calculation method. */
- revision?: string
+ /** @description The version name of the method used to calculate the Confidence score. This field is only present for customers who opted in to an alternative calculation method. */
+ version?: string
comment?: string
}
- IdentificationSeenAt: {
- /** Format: date-time */
- global: string | null
- /** Format: date-time */
- subscription: string | null
- }
- RawDeviceAttributeError: {
- name?: string
- message?: string
- }
- RawDeviceAttribute: {
- /** value */
- value?: unknown
- error?: components['schemas']['RawDeviceAttributeError']
- }
- /** @description It includes 35+ raw browser identification attributes to provide Fingerprint users with even more information than our standard visitor ID provides. This enables Fingerprint users to not have to run our open-source product in conjunction with Fingerprint Pro Plus and Enterprise to get those additional attributes.
- * Warning: The raw signals data can change at any moment as we improve the product. We cannot guarantee the internal shape of raw device attributes to be stable, so typical semantic versioning rules do not apply here. Use this data with caution without assuming a specific structure beyond the generic type provided here.
- * */
- RawDeviceAttributes: {
- [key: string]: components['schemas']['RawDeviceAttribute']
- }
- /** @description Contains information about the SDK used to perform the request. */
- SDK: {
- /** @description Platform of the SDK. */
- platform: string
- /** @description SDK version string. */
- version: string
- }
Identification: {
/** @description String of 20 characters that uniquely identifies the visitor's browser or mobile device. */
- visitorId: string
- /** @description Unique identifier of the user's request. */
- requestId: string
- browserDetails: components['schemas']['BrowserDetails']
- /** @description Flag if user used incognito session. */
- incognito: boolean
- /** @description IP address of the requesting browser or bot. */
- ip: string
- /** @description This field is **deprecated** and will not return a result for **applications created after January 23rd, 2024**. Please use the [IP Geolocation Smart signal](https://dev.fingerprint.com/docs/smart-signals-overview#ip-geolocation) for geolocation information. */
- ipLocation?: components['schemas']['DeprecatedGeolocation']
- /** @description A customer-provided id that was sent with the request. */
- linkedId?: string
- /** @description Field is `true` if you have previously set the `suspect` flag for this event using the [Server API Update event endpoint](https://dev.fingerprint.com/reference/updateevent). */
- suspect?: boolean
+ visitor_id: string
+ confidence?: components['schemas']['IdentificationConfidence']
+ /** @description Attribute represents if a visitor had been identified before. */
+ visitor_found: boolean
/**
* Format: int64
- * @description Timestamp of the event with millisecond precision in Unix time.
+ * @description Unix epoch time milliseconds timestamp indicating the time at which this visitor ID was first seen. example: `1758069706642` - Corresponding to Wed Sep 17 2025 00:41:46 GMT+0000
+ *
*/
- timestamp: number
+ first_seen_at?: number
/**
- * Format: date-time
- * @description Time expressed according to ISO 8601 in UTC format, when the request from the JS agent was made. We recommend to treat requests that are older than 2 minutes as malicious. Otherwise, request replay attacks are possible.
+ * Format: int64
+ * @description Unix epoch time milliseconds timestamp indicating the time at which this visitor ID was last seen. example: `1758069706642` - Corresponding to Wed Sep 17 2025 00:41:46 GMT+0000
+ *
*/
- time: string
- /** @description Page URL from which the request was sent. */
- url: string
- /** @description A customer-provided value or an object that was sent with identification request. */
- tag: components['schemas']['Tag']
- confidence?: components['schemas']['IdentificationConfidence']
+ last_seen_at?: number
+ }
+ /** @description A supplementary browser identifier that prioritizes coverage over precision. The High Recall ID algorithm matches more generously, i.e., this identifier will remain the same even when there are subtle differences between two requests. This algorithm does not create as many new visitor IDs as the standard algorithms do, but there could be an increase in false-positive identification. */
+ SupplementaryIDHighRecall: {
+ /** @description String of 20 characters that uniquely identifies the visitor's browser or mobile device. */
+ visitor_id: string
/** @description Attribute represents if a visitor had been identified before. */
- visitorFound: boolean
- firstSeenAt: components['schemas']['IdentificationSeenAt']
- lastSeenAt: components['schemas']['IdentificationSeenAt']
- /** @description It includes 35+ raw browser identification attributes to provide Fingerprint users with even more information than our standard visitor ID provides. This enables Fingerprint users to not have to run our open-source product in conjunction with Fingerprint Pro Plus and Enterprise to get those additional attributes.
- * Warning: The raw signals data can change at any moment as we improve the product. We cannot guarantee the internal shape of raw device attributes to be stable, so typical semantic versioning rules do not apply here. Use this data with caution without assuming a specific structure beyond the generic type provided here.
- * */
- components?: components['schemas']['RawDeviceAttributes']
- /** @description `true` if we determined that this payload was replayed, `false` otherwise.
- * */
- replayed: boolean
- /** @description Contains information about the SDK used to perform the request. */
- sdk?: components['schemas']['SDK']
- /** @description Environment ID associated with the event */
- environmentId?: string
+ visitor_found: boolean
+ confidence?: components['schemas']['IdentificationConfidence']
+ /**
+ * Format: int64
+ * @description Unix epoch time milliseconds timestamp indicating the time at which this ID was first seen. example: `1758069706642` - Corresponding to Wed Sep 17 2025 00:41:46 GMT+0000
+ *
+ */
+ first_seen_at?: number
+ /**
+ * Format: int64
+ * @description Unix epoch time milliseconds timestamp indicating the time at which this ID was last seen. example: `1758069706642` - Corresponding to Wed Sep 17 2025 00:41:46 GMT+0000
+ *
+ */
+ last_seen_at?: number
}
- /**
- * @description Error code:
- * * `RequestCannotBeParsed` - the query parameters or JSON payload contains some errors
- * that prevented us from parsing it (wrong type/surpassed limits).
- * * `TokenRequired` - `Auth-API-Key` header is missing or empty.
- * * `TokenNotFound` - no Fingerprint application found for specified secret key.
- * * `SubscriptionNotActive` - Fingerprint application is not active.
- * * `WrongRegion` - server and application region differ.
- * * `FeatureNotEnabled` - this feature (for example, Delete API) is not enabled for your application.
- * * `RequestNotFound` - the specified request ID was not found. It never existed, expired, or it has been deleted.
- * * `VisitorNotFound` - The specified visitor ID was not found. It never existed or it may have already been deleted.
- * * `TooManyRequests` - the limit on secret API key requests per second has been exceeded.
- * * `429 Too Many Requests` - the limit on secret API key requests per second has been exceeded.
- * * `StateNotReady` - The event specified with request id is
- * not ready for updates yet. Try again.
- * This error happens in rare cases when update API is called immediately
- * after receiving the request id on the client. In case you need to send
- * information right away, we recommend using the JS agent API instead.
- * * `Failed` - internal server error.
- *
- * @enum {string}
- */
- ErrorCode:
- | 'RequestCannotBeParsed'
- | 'TokenRequired'
- | 'TokenNotFound'
- | 'SubscriptionNotActive'
- | 'WrongRegion'
- | 'FeatureNotEnabled'
- | 'RequestNotFound'
- | 'VisitorNotFound'
- | 'TooManyRequests'
- | '429 Too Many Requests'
- | 'StateNotReady'
- | 'Failed'
- Error: {
- /** @description Error code:
- * * `RequestCannotBeParsed` - the query parameters or JSON payload contains some errors
- * that prevented us from parsing it (wrong type/surpassed limits).
- * * `TokenRequired` - `Auth-API-Key` header is missing or empty.
- * * `TokenNotFound` - no Fingerprint application found for specified secret key.
- * * `SubscriptionNotActive` - Fingerprint application is not active.
- * * `WrongRegion` - server and application region differ.
- * * `FeatureNotEnabled` - this feature (for example, Delete API) is not enabled for your application.
- * * `RequestNotFound` - the specified request ID was not found. It never existed, expired, or it has been deleted.
- * * `VisitorNotFound` - The specified visitor ID was not found. It never existed or it may have already been deleted.
- * * `TooManyRequests` - the limit on secret API key requests per second has been exceeded.
- * * `429 Too Many Requests` - the limit on secret API key requests per second has been exceeded.
- * * `StateNotReady` - The event specified with request id is
- * not ready for updates yet. Try again.
- * This error happens in rare cases when update API is called immediately
- * after receiving the request id on the client. In case you need to send
- * information right away, we recommend using the JS agent API instead.
- * * `Failed` - internal server error.
- * */
- code: components['schemas']['ErrorCode']
- message: string
+ /** @description A customer-provided value or an object that was sent with the identification request or updated later. */
+ Tags: {
+ [key: string]: unknown
}
- ProductIdentification: {
- data?: components['schemas']['Identification']
- error?: components['schemas']['Error']
+ /** @description Page URL from which the request was sent. For example `https://example.com/`
+ * */
+ Url: string
+ /** @description Bundle Id of the iOS application integrated with the Fingerprint SDK for the event. For example: `com.foo.app`
+ * */
+ BundleId: string
+ /** @description Package name of the Android application integrated with the Fingerprint SDK for the event. For example: `com.foo.app`
+ * */
+ PackageName: string
+ /** @description IP address of the requesting browser or bot. */
+ IpAddress: string
+ /** @description User Agent of the client, for example: `Mozilla/5.0 (Windows NT 6.1; Win64; x64) ....`
+ * */
+ UserAgent: string
+ BrowserDetails: {
+ browser_name: string
+ browser_major_version: string
+ browser_full_version: string
+ os: string
+ os_version: string
+ device: string
+ }
+ /** @description Proximity ID represents a fixed geographical zone in a discrete global grid within which the device is observed.
+ * */
+ Proximity: {
+ /** @description A stable privacy-preserving identifier for a given proximity zone.
+ * */
+ id: string
+ /**
+ * Format: int32
+ * @description The radius of the proximity zone’s precision level, in meters.
+ *
+ * @enum {integer}
+ */
+ precision_radius: 10 | 25 | 65 | 175 | 450 | 1200 | 3300 | 8500 | 22500
+ /**
+ * Format: float
+ * @description A value between `0` and `1` representing the likelihood that the true device location lies within the mapped proximity zone.
+ * * Scores closer to `1` indicate high confidence that the location is inside the mapped proximity zone.
+ * * Scores closer to `0` indicate lower confidence, suggesting the true location may fall in an adjacent zone.
+ *
+ */
+ confidence: number
}
/**
* @description Bot detection result:
- * * `notDetected` - the visitor is not a bot
+ * * `not_detected` - the visitor is not a bot
* * `good` - good bot detected, such as Google bot, Baidu Spider, AlexaBot and so on
* * `bad` - bad bot detected, such as Selenium, Puppeteer, Playwright, headless browsers, and so on
*
* @enum {string}
*/
- BotdBotResult: 'notDetected' | 'good' | 'bad'
- /** @description Stores bot detection result */
- BotdBot: {
- /** @description Bot detection result:
- * * `notDetected` - the visitor is not a bot
- * * `good` - good bot detected, such as Google bot, Baidu Spider, AlexaBot and so on
- * * `bad` - bad bot detected, such as Selenium, Puppeteer, Playwright, headless browsers, and so on
- * */
- result: components['schemas']['BotdBotResult']
- type?: string
- }
- /** @description Contains all the information from Bot Detection product */
- Botd: {
- /** @description Stores bot detection result */
- bot: components['schemas']['BotdBot']
- /** @description A customer-provided value or an object that was sent with identification request. */
- meta?: components['schemas']['Tag']
- /** @description A customer-provided id that was sent with the request. */
- linkedId?: string
- /** @description Page URL from which the request was sent. */
- url: string
- /** @description IP address of the requesting browser or bot. */
- ip: string
- /**
- * Format: date-time
- * @description Time in UTC when the request from the JS agent was made. We recommend to treat requests that are older than 2 minutes as malicious. Otherwise, request replay attacks are possible.
- */
- time: string
- userAgent: string
- /** @description Unique identifier of the user's request. */
- requestId: string
- }
- ProductBotd: {
- /** @description Contains all the information from Bot Detection product */
- data?: components['schemas']['Botd']
- error?: components['schemas']['Error']
- }
- RootApps: {
- /** @description Android specific root management apps detection. There are 2 values:
- * * `true` - Root Management Apps detected (e.g. Magisk).
- * * `false` - No Root Management Apps detected or the client isn't Android.
- * */
- result: boolean
- }
- ProductRootApps: {
- data?: components['schemas']['RootApps']
- error?: components['schemas']['Error']
- }
- Emulator: {
- /** @description Android specific emulator detection. There are 2 values:
- * * `true` - Emulated environment detected (e.g. launch inside of AVD).
- * * `false` - No signs of emulated environment detected or the client is not Android.
- * */
- result: boolean
- }
- ProductEmulator: {
- data?: components['schemas']['Emulator']
- error?: components['schemas']['Error']
+ BotResult: 'not_detected' | 'good' | 'bad'
+ /** @description Additional classification of the bot type if detected.
+ * */
+ BotType: string
+ /** @description Android specific cloned application detection. There are 2 values: * `true` - Presence of app cloners work detected (e.g. fully cloned application found or launch of it inside of a not main working profile detected). * `false` - No signs of cloned application detected or the client is not Android.
+ * */
+ ClonedApp: boolean
+ /** @description `true` if the browser is Chrome with DevTools open or Firefox with Developer Tools open, `false` otherwise.
+ * */
+ DeveloperTools: boolean
+ /** @description Android specific emulator detection. There are 2 values:
+ * * `true` - Emulated environment detected (e.g. launch inside of AVD).
+ * * `false` - No signs of emulated environment detected or the client is not Android.
+ * */
+ Emulator: boolean
+ /**
+ * Format: int64
+ * @description The time of the most recent factory reset that happened on the **mobile device** is expressed as Unix epoch time. When a factory reset cannot be detected on the mobile device or when the request is initiated from a browser, this field will correspond to the *epoch* time (i.e 1 Jan 1970 UTC) as a value of 0. See [Factory Reset Detection](https://dev.fingerprint.com/docs/smart-signals-overview#factory-reset-detection) to learn more about this Smart Signal.
+ *
+ */
+ FactoryReset: number
+ /** @description [Frida](https://frida.re/docs/) detection for Android and iOS devices. There are 2 values:
+ * * `true` - Frida detected
+ * * `false` - No signs of Frida or the client is not a mobile device.
+ * */
+ Frida: boolean
+ IPBlockList: {
+ /** @description IP address was part of a known email spam attack (SMTP). */
+ email_spam?: boolean
+ /** @description IP address was part of a known network attack (SSH/HTTPS). */
+ attack_source?: boolean
+ /** @description IP address was part of known TOR network activity. */
+ tor_node?: boolean
}
Geolocation: {
/** @description The IP address is likely to be within this radius (in km) of the specified location. */
- accuracyRadius?: number
+ accuracy_radius?: number
/** Format: double */
latitude?: number
/** Format: double */
longitude?: number
- postalCode?: string
+ postal_code?: string
/** Format: timezone */
timezone?: string
- city?: components['schemas']['GeolocationCity']
- country?: components['schemas']['GeolocationCountry']
- continent?: components['schemas']['GeolocationContinent']
- subdivisions?: components['schemas']['GeolocationSubdivisions']
- }
- IPInfoASN: {
- asn: string
- name: string
- network: string
- }
- IPInfoDataCenter: {
- result: boolean
- name: string
+ city_name?: string
+ country_code?: string
+ country_name?: string
+ continent_code?: string
+ continent_name?: string
+ subdivisions?: {
+ iso_code: string
+ name: string
+ }[]
}
IPInfoV4: {
/** Format: ipv4 */
address: string
- geolocation: components['schemas']['Geolocation']
- asn?: components['schemas']['IPInfoASN']
- datacenter?: components['schemas']['IPInfoDataCenter']
+ geolocation?: components['schemas']['Geolocation']
+ asn?: string
+ asn_name?: string
+ asn_network?: string
+ datacenter_result?: boolean
+ datacenter_name?: string
}
IPInfoV6: {
/** Format: ipv6 */
address: string
- geolocation: components['schemas']['Geolocation']
- asn?: components['schemas']['IPInfoASN']
- datacenter?: components['schemas']['IPInfoDataCenter']
+ geolocation?: components['schemas']['Geolocation']
+ asn?: string
+ asn_name?: string
+ asn_network?: string
+ datacenter_result?: boolean
+ datacenter_name?: string
}
/** @description Details about the request IP address. Has separate fields for v4 and v6 IP address versions. */
IPInfo: {
v4?: components['schemas']['IPInfoV4']
v6?: components['schemas']['IPInfoV6']
}
- ProductIPInfo: {
- /** @description Details about the request IP address. Has separate fields for v4 and v6 IP address versions. */
- data?: components['schemas']['IPInfo']
- error?: components['schemas']['Error']
- }
- IPBlocklistDetails: {
- /** @description IP address was part of a known email spam attack (SMTP). */
- emailSpam: boolean
- /** @description IP address was part of a known network attack (SSH/HTTPS). */
- attackSource: boolean
- }
- IPBlocklist: {
- /** @description `true` if request IP address is part of any database that we use to search for known malicious actors, `false` otherwise.
- * */
- result: boolean
- details: components['schemas']['IPBlocklistDetails']
- }
- ProductIPBlocklist: {
- data?: components['schemas']['IPBlocklist']
- error?: components['schemas']['Error']
- }
- Tor: {
- /** @description `true` if the request IP address is a known tor exit node, `false` otherwise.
- * */
- result: boolean
- }
- ProductTor: {
- data?: components['schemas']['Tor']
- error?: components['schemas']['Error']
- }
- /**
- * @description A confidence rating for the VPN detection result — "low", "medium", or "high". Depends on the combination of results returned from all VPN detection methods.
- * @enum {string}
- */
- VPNConfidence: 'low' | 'medium' | 'high'
- VPNMethods: {
- /** @description The browser timezone doesn't match the timezone inferred from the request IP address. */
- timezoneMismatch: boolean
- /** @description Request IP address is owned and used by a public VPN service provider. */
- publicVPN: boolean
- /** @description This method applies to mobile devices only. Indicates the result of additional methods used to detect a VPN in mobile devices. */
- auxiliaryMobile: boolean
- /** @description The browser runs on a different operating system than the operating system inferred from the request network signature. */
- osMismatch: boolean
- /** @description Request IP address belongs to a relay service provider, indicating the use of relay services like [Apple Private relay](https://support.apple.com/en-us/102602) or [Cloudflare Warp](https://developers.cloudflare.com/warp-client/).
- *
- * * Like VPNs, relay services anonymize the visitor's true IP address.
- * * Unlike traditional VPNs, relay services don't let visitors spoof their location by choosing an exit node in a different country.
- *
- * This field allows you to differentiate VPN users and relay service users in your fraud prevention logic.
- * */
- relay: boolean
- }
- VPN: {
- /** @description VPN or other anonymizing service has been used when sending the request. */
- result: boolean
- /** @description A confidence rating for the VPN detection result — "low", "medium", or "high". Depends on the combination of results returned from all VPN detection methods. */
- confidence: components['schemas']['VPNConfidence']
- /** @description Local timezone which is used in timezoneMismatch method. */
- originTimezone: string
- /** @description Country of the request (only for Android SDK version >= 2.4.0, ISO 3166 format or unknown). */
- originCountry: string
- methods: components['schemas']['VPNMethods']
- }
- ProductVPN: {
- data?: components['schemas']['VPN']
- error?: components['schemas']['Error']
- }
+ /** @description IP address was used by a public proxy provider or belonged to a known recent residential proxy
+ * */
+ Proxy: boolean
/**
- * @description Confidence level of the proxy detection.
- * If a proxy is not detected, confidence is "high".
- * If it's detected, can be "low", "medium", or "high".
+ * @description Confidence level of the proxy detection. If a proxy is not detected, confidence is "high". If it's detected, can be "low", "medium", or "high".
*
* @enum {string}
*/
ProxyConfidence: 'low' | 'medium' | 'high'
- /** @description Proxy detection details (present if proxy is detected) */
+ /** @description Proxy detection details (present if `proxy` is `true`) */
ProxyDetails: {
/**
* @description Residential proxies use real user IP addresses to appear as legitimate traffic,
@@ -570,746 +386,390 @@ export interface components {
*
* @enum {string}
*/
- proxyType: 'residential' | 'data_center'
+ proxy_type: 'residential' | 'data_center'
/**
- * Format: date-time
- * @description ISO 8601 formatted timestamp in UTC with hourly resolution
- * of when this IP was last seen as a proxy when available.
+ * Format: int64
+ * @description Unix millisecond timestamp with hourly resolution of when this IP was last seen as a proxy
*
*/
- lastSeenAt?: string
- } | null
- Proxy: {
- /** @description IP address was used by a public proxy provider or belonged to a known recent residential proxy
- * */
- result: boolean
- /** @description Confidence level of the proxy detection.
- * If a proxy is not detected, confidence is "high".
- * If it's detected, can be "low", "medium", or "high".
- * */
- confidence: components['schemas']['ProxyConfidence']
- /** @description Proxy detection details (present if proxy is detected) */
- details?: components['schemas']['ProxyDetails']
- }
- ProductProxy: {
- data?: components['schemas']['Proxy']
- error?: components['schemas']['Error']
- }
- Incognito: {
- /** @description `true` if we detected incognito mode used in the browser, `false` otherwise.
- * */
- result: boolean
+ last_seen_at?: number
}
- ProductIncognito: {
- data?: components['schemas']['Incognito']
- error?: components['schemas']['Error']
- }
- Tampering: {
- /** @description Indicates if an identification request from a browser or an Android SDK has been tampered with. Not supported in the iOS SDK, is always `false` for iOS requests.
- * * `true` - If the request meets either of the following conditions:
- * * Contains anomalous browser or device attributes that could not have been legitimately produced by the JavaScript agent or the Android SDK (see `anomalyScore`).
- * * Originated from an anti-detect browser like Incognition (see `antiDetectBrowser`).
- * * `false` - If the request is considered genuine or was generated by the iOS SDK.
- * */
- result: boolean
+ /** @description `true` if we detected incognito mode used in the browser, `false` otherwise.
+ * */
+ Incognito: boolean
+ /** @description iOS specific jailbreak detection. There are 2 values:
+ * * `true` - Jailbreak detected.
+ * * `false` - No signs of jailbreak or the client is not iOS.
+ * */
+ Jailbroken: boolean
+ /** @description Flag indicating whether the request came from a mobile device with location spoofing enabled. */
+ LocationSpoofing: boolean
+ /** @description * `true` - When requests made from your users' mobile devices to Fingerprint servers have been intercepted and potentially modified.
+ * * `false` - Otherwise or when the request originated from a browser.
+ * See [MitM Attack Detection](https://dev.fingerprint.com/docs/smart-signals-reference#mitm-attack-detection) to learn more about this Smart Signal.
+ * */
+ MitMAttack: boolean
+ /** @description `true` if the request is from a privacy aware browser (e.g. Tor) or from a browser in which fingerprinting is blocked. Otherwise `false`.
+ * */
+ PrivacySettings: boolean
+ /** @description Android specific root management apps detection. There are 2 values:
+ * * `true` - Root Management Apps detected (e.g. Magisk).
+ * * `false` - No Root Management Apps detected or the client isn't Android.
+ * */
+ RootApps: boolean
+ /** @description Suspect Score is an easy way to integrate Smart Signals into your fraud protection work flow. It is a weighted representation of all Smart Signals present in the payload that helps identify suspicious activity. The value range is [0; S] where S is sum of all Smart Signals weights. See more details here: https://dev.fingerprint.com/docs/suspect-score
+ * */
+ SuspectScore: number
+ /** @description Flag indicating browser tampering was detected. This happens when either:
+ * * There are inconsistencies in the browser configuration that cross internal tampering thresholds (see `tampering_details.anomaly_score`).
+ * * The browser signature resembles an "anti-detect" browser specifically designed to evade fingerprinting (see `tampering_details.anti_detect_browser`).
+ * */
+ Tampering: boolean
+ TamperingDetails: {
/**
* Format: double
- * @description A score that indicates the extent of anomalous data in the request. This field applies to requests originating from **both** browsers and Android SDKs.
- * * Values above `0.5` indicate that the request has been tampered with.
- * * Values below `0.5` indicate that the request is genuine.
+ * @description Confidence score (`0.0 - 1.0`) for tampering detection:
+ * * Values above `0.5` indicate tampering.
+ * * Values below `0.5` indicate genuine browsers.
*
*/
- anomalyScore: number
- /** @description Anti-detect browsers try to evade identification by masking or manipulating their fingerprint to imitate legitimate browser configurations. This field does not apply to requests originating from mobile SDKs.
- * * `true` - The browser resembles a known anti-detect browser, for example, Incognition.
- * * `false` - The browser does not resemble an anti-detect browser or the request originates from a mobile SDK.
+ anomaly_score?: number
+ /** @description True if the identified browser resembles an "anti-detect" browser, such as Incognition, which attempts to evade identification by manipulating its fingerprint.
* */
- antiDetectBrowser: boolean
+ anti_detect_browser?: boolean
}
- ProductTampering: {
- data?: components['schemas']['Tampering']
- error?: components['schemas']['Error']
- }
- ClonedApp: {
- /** @description Android specific cloned application detection. There are 2 values:
- * * `true` - Presence of app cloners work detected (e.g. fully cloned application found or launch of it inside of a not main working profile detected).
- * * `false` - No signs of cloned application detected or the client is not Android.
+ /** @description Is absent if the velocity data could not be generated for the visitor Id.
+ * */
+ VelocityData: {
+ /** @description Count for the last 5 minutes of velocity data, from the time of the event.
* */
- result: boolean
- }
- ProductClonedApp: {
- data?: components['schemas']['ClonedApp']
- error?: components['schemas']['Error']
- }
- FactoryReset: {
- /**
- * Format: date-time
- * @description Indicates the time (in UTC) of the most recent factory reset that happened on the **mobile device**.
- * When a factory reset cannot be detected on the mobile device or when the request is initiated from a browser, this field will correspond to the *epoch* time (i.e 1 Jan 1970 UTC).
- * See [Factory Reset Detection](https://dev.fingerprint.com/docs/smart-signals-overview#factory-reset-detection) to learn more about this Smart Signal.
- *
- */
- time: string
- /**
- * Format: int64
- * @description This field is just another representation of the value in the `time` field.
- * The time of the most recent factory reset that happened on the **mobile device** is expressed as Unix epoch time.
- *
- */
- timestamp: number
- }
- ProductFactoryReset: {
- data?: components['schemas']['FactoryReset']
- error?: components['schemas']['Error']
- }
- Jailbroken: {
- /** @description iOS specific jailbreak detection. There are 2 values:
- * * `true` - Jailbreak detected.
- * * `false` - No signs of jailbreak or the client is not iOS.
+ '5_minutes': number
+ /** @description Count for the last 1 hour of velocity data, from the time of the event.
* */
- result: boolean
- }
- ProductJailbroken: {
- data?: components['schemas']['Jailbroken']
- error?: components['schemas']['Error']
- }
- Frida: {
- /** @description [Frida](https://frida.re/docs/) detection for Android and iOS devices. There are 2 values:
- * * `true` - Frida detected
- * * `false` - No signs of Frida or the client is not a mobile device.
+ '1_hour': number
+ /** @description The `24_hours` interval of `distinct_ip`, `distinct_linked_id`, `distinct_country`, `distinct_ip_by_linked_id` and `distinct_visitor_id_by_linked_id` will be omitted if the number of `events` for the visitor Id in the last 24 hours (`events.['24_hours']`) is higher than 20.000.
* */
- result: boolean
- }
- ProductFrida: {
- data?: components['schemas']['Frida']
- error?: components['schemas']['Error']
+ '24_hours'?: number
}
- PrivacySettings: {
- /** @description `true` if the request is from a privacy aware browser (e.g. Tor) or from a browser in which fingerprinting is blocked. Otherwise `false`.
+ /** @description Sums key data points for a specific `visitor_id`, `ip_address` and `linked_id` at three distinct time
+ * intervals: 5 minutes, 1 hour, and 24 hours as follows:
+ *
+ * - Number of distinct IP addresses associated to the visitor Id.
+ * - Number of distinct linked Ids associated with the visitor Id.
+ * - Number of distinct countries associated with the visitor Id.
+ * - Number of identification events associated with the visitor Id.
+ * - Number of identification events associated with the detected IP address.
+ * - Number of distinct IP addresses associated with the provided linked Id.
+ * - Number of distinct visitor Ids associated with the provided linked Id.
+ *
+ * The `24h` interval of `distinct_ip`, `distinct_linked_id`, `distinct_country`,
+ * `distinct_ip_by_linked_id` and `distinct_visitor_id_by_linked_id` will be omitted
+ * if the number of `events` for the visitor Id in the last 24
+ * hours (`events.['24h']`) is higher than 20.000.
+ *
+ * All will not necessarily be returned in a response, some may be omitted if the
+ * associated event does not have the required data, such as a linked_id.
+ * */
+ Velocity: {
+ /** @description Is absent if the velocity data could not be generated for the visitor Id.
* */
- result: boolean
- }
- ProductPrivacySettings: {
- data?: components['schemas']['PrivacySettings']
- error?: components['schemas']['Error']
- }
- VirtualMachine: {
- /** @description `true` if the request came from a browser running inside a virtual machine (e.g. VMWare), `false` otherwise.
+ distinct_ip?: components['schemas']['VelocityData']
+ /** @description Is absent if the velocity data could not be generated for the visitor Id.
* */
- result: boolean
- }
- ProductVirtualMachine: {
- data?: components['schemas']['VirtualMachine']
- error?: components['schemas']['Error']
- }
- ProductRawDeviceAttributes: {
- /** @description It includes 35+ raw browser identification attributes to provide Fingerprint users with even more information than our standard visitor ID provides. This enables Fingerprint users to not have to run our open-source product in conjunction with Fingerprint Pro Plus and Enterprise to get those additional attributes.
- * Warning: The raw signals data can change at any moment as we improve the product. We cannot guarantee the internal shape of raw device attributes to be stable, so typical semantic versioning rules do not apply here. Use this data with caution without assuming a specific structure beyond the generic type provided here.
+ distinct_linked_id?: components['schemas']['VelocityData']
+ /** @description Is absent if the velocity data could not be generated for the visitor Id.
* */
- data?: components['schemas']['RawDeviceAttributes']
- error?: components['schemas']['Error']
- }
- HighActivity: {
- /** @description Flag indicating if the request came from a high-activity visitor. */
- result: boolean
- /**
- * Format: int64
- * @description Number of requests from the same visitor in the previous day.
- */
- dailyRequests?: number
- }
- ProductHighActivity: {
- data?: components['schemas']['HighActivity']
- error?: components['schemas']['Error']
- }
- LocationSpoofing: {
- /** @description Flag indicating whether the request came from a mobile device with location spoofing enabled. */
- result: boolean
- }
- ProductLocationSpoofing: {
- data?: components['schemas']['LocationSpoofing']
- error?: components['schemas']['Error']
- }
- SuspectScore: {
- /** @description Suspect Score is an easy way to integrate Smart Signals into your fraud protection work flow. It is a weighted representation of all Smart Signals present in the payload that helps identify suspicious activity. The value range is [0; S] where S is sum of all Smart Signals weights. See more details here: https://dev.fingerprint.com/docs/suspect-score
+ distinct_country?: components['schemas']['VelocityData']
+ /** @description Is absent if the velocity data could not be generated for the visitor Id.
* */
- result: number
- }
- ProductSuspectScore: {
- data?: components['schemas']['SuspectScore']
- error?: components['schemas']['Error']
- }
- /**
- * @deprecated
- * @description This signal is deprecated.
- *
- */
- RemoteControl: {
- /** @description `true` if the request came from a machine being remotely controlled (e.g. TeamViewer), `false` otherwise.
+ events?: components['schemas']['VelocityData']
+ /** @description Is absent if the velocity data could not be generated for the visitor Id.
+ * */
+ ip_events?: components['schemas']['VelocityData']
+ /** @description Is absent if the velocity data could not be generated for the visitor Id.
+ * */
+ distinct_ip_by_linked_id?: components['schemas']['VelocityData']
+ /** @description Is absent if the velocity data could not be generated for the visitor Id.
* */
- result: boolean
+ distinct_visitor_id_by_linked_id?: components['schemas']['VelocityData']
}
+ /** @description `true` if the request came from a browser running inside a virtual machine (e.g. VMWare), `false` otherwise.
+ * */
+ VirtualMachine: boolean
+ /** @description VPN or other anonymizing service has been used when sending the request.
+ * */
+ Vpn: boolean
/**
- * @deprecated
- * @description This product is deprecated.
- *
+ * @description A confidence rating for the VPN detection result — "low", "medium", or "high". Depends on the combination of results returned from all VPN detection methods.
+ * @enum {string}
*/
- ProductRemoteControl: {
- /** @description This signal is deprecated.
- * */
- data?: components['schemas']['RemoteControl']
- error?: components['schemas']['Error']
- }
- /** @description Is absent if the velocity data could not be generated for the visitor ID.
+ VpnConfidence: 'low' | 'medium' | 'high'
+ /** @description Local timezone which is used in timezone_mismatch method.
* */
- VelocityIntervals: {
- '5m': number
- '1h': number
- /** @description The `24h` interval of `distinctIp`, `distinctLinkedId`, `distinctCountry`, `distinctIpByLinkedId` and `distinctVisitorIdByLinkedId` will be omitted if the number of `events`` for the visitor ID in the last 24 hours (`events.intervals.['24h']`) is higher than 20.000.
- * */
- '24h'?: number
- }
- VelocityData: {
- /** @description Is absent if the velocity data could not be generated for the visitor ID.
- * */
- intervals?: components['schemas']['VelocityIntervals']
- }
- /** @description Sums key data points for a specific `visitorId`, `ipAddress` and `linkedId` at three distinct time
- * intervals: 5 minutes, 1 hour, and 24 hours as follows:
- *
- * - Number of distinct IP addresses associated to the visitor ID.
- * - Number of distinct linked IDs associated with the visitor ID.
- * - Number of distinct countries associated with the visitor ID.
- * - Number of identification events associated with the visitor ID.
- * - Number of identification events associated with the detected IP address.
- * - Number of distinct IP addresses associated with the provided linked ID.
- * - Number of distinct visitor IDs associated with the provided linked ID.
- *
- * The `24h` interval of `distinctIp`, `distinctLinkedId`, `distinctCountry`,
- * `distinctIpByLinkedId` and `distinctVisitorIdByLinkedId` will be omitted
- * if the number of `events` for the visitor ID in the last 24
- * hours (`events.intervals.['24h']`) is higher than 20.000.
+ VpnOriginTimezone: string
+ /** @description Country of the request (only for Android SDK version >= 2.4.0, ISO 3166 format or unknown).
* */
- Velocity: {
- distinctIp: components['schemas']['VelocityData']
- distinctLinkedId: components['schemas']['VelocityData']
- distinctCountry: components['schemas']['VelocityData']
- events: components['schemas']['VelocityData']
- ipEvents: components['schemas']['VelocityData']
- distinctIpByLinkedId: components['schemas']['VelocityData']
- distinctVisitorIdByLinkedId: components['schemas']['VelocityData']
- }
- ProductVelocity: {
- /** @description Sums key data points for a specific `visitorId`, `ipAddress` and `linkedId` at three distinct time
- * intervals: 5 minutes, 1 hour, and 24 hours as follows:
+ VpnOriginCountry: string
+ VpnMethods: {
+ /** @description The browser timezone doesn't match the timezone inferred from the request IP address. */
+ timezone_mismatch?: boolean
+ /** @description Request IP address is owned and used by a public VPN service provider. */
+ public_vpn?: boolean
+ /** @description This method applies to mobile devices only. Indicates the result of additional methods used to detect a VPN in mobile devices. */
+ auxiliary_mobile?: boolean
+ /** @description The browser runs on a different operating system than the operating system inferred from the request network signature. */
+ os_mismatch?: boolean
+ /** @description Request IP address belongs to a relay service provider, indicating the use of relay services like [Apple Private relay](https://support.apple.com/en-us/102602) or [Cloudflare Warp](https://developers.cloudflare.com/warp-client/).
*
- * - Number of distinct IP addresses associated to the visitor ID.
- * - Number of distinct linked IDs associated with the visitor ID.
- * - Number of distinct countries associated with the visitor ID.
- * - Number of identification events associated with the visitor ID.
- * - Number of identification events associated with the detected IP address.
- * - Number of distinct IP addresses associated with the provided linked ID.
- * - Number of distinct visitor IDs associated with the provided linked ID.
+ * * Like VPNs, relay services anonymize the visitor's true IP address.
+ * * Unlike traditional VPNs, relay services don't let visitors spoof their location by choosing an exit node in a different country.
*
- * The `24h` interval of `distinctIp`, `distinctLinkedId`, `distinctCountry`,
- * `distinctIpByLinkedId` and `distinctVisitorIdByLinkedId` will be omitted
- * if the number of `events` for the visitor ID in the last 24
- * hours (`events.intervals.['24h']`) is higher than 20.000.
+ * This field allows you to differentiate VPN users and relay service users in your fraud prevention logic.
* */
- data?: components['schemas']['Velocity']
- error?: components['schemas']['Error']
+ relay?: boolean
}
- DeveloperTools: {
- /** @description `true` if the browser is Chrome with DevTools open or Firefox with Developer Tools open, `false` otherwise.
+ /** @description Contains results from Fingerprint Identification and all active Smart Signals. */
+ Event: {
+ /** @description Unique identifier of the user's request. The first portion of the event_id is a unix epoch milliseconds timestamp For example: `1758130560902.8tRtrH`
* */
- result: boolean
- }
- ProductDeveloperTools: {
- data?: components['schemas']['DeveloperTools']
- error?: components['schemas']['Error']
- }
- MitMAttack: {
- /** @description * `true` - When requests made from your users' mobile devices to Fingerprint servers have been intercepted and potentially modified.
- * * `false` - Otherwise or when the request originated from a browser.
- * See [MitM Attack Detection](https://dev.fingerprint.com/docs/smart-signals-reference#mitm-attack-detection) to learn more about this Smart Signal.
+ event_id?: components['schemas']['EventId']
+ /** @description Timestamp of the event with millisecond precision in Unix time. */
+ timestamp?: components['schemas']['Timestamp']
+ /** @description A customer-provided id that was sent with the request. */
+ linked_id?: components['schemas']['LinkedId']
+ /** @description Environment Id of the event. For example: `ae_47abaca3db2c7c43`
* */
- result: boolean
- }
- ProductMitMAttack: {
- data?: components['schemas']['MitMAttack']
- error?: components['schemas']['Error']
- }
- /** @description Proximity ID represents a fixed geographical zone in a discrete global grid within which the device is observed.
- * */
- Proximity: {
- /** @description A stable privacy-preserving identifier for a given proximity zone.
+ environment_id?: components['schemas']['EnvironmentId']
+ /** @description Field is `true` if you have previously set the `suspect` flag for this event using the [Server API Update event endpoint](https://dev.fingerprint.com/reference/updateevent). */
+ suspect?: components['schemas']['Suspect']
+ /** @description Contains information about the SDK used to perform the request. */
+ sdk?: components['schemas']['SDK']
+ /** @description `true` if we determined that this payload was replayed, `false` otherwise.
* */
- id: string
- /**
- * Format: int32
- * @description The radius of the proximity zone’s precision level, in meters.
- *
- * @enum {integer}
- */
- precisionRadius: 10 | 25 | 65 | 175 | 450 | 1200 | 3300 | 8500 | 22500
- /**
- * Format: float
- * @description A value between `0` and `1` representing the likelihood that the true device location lies within the mapped proximity zone.
- * * Scores closer to `1` indicate high confidence that the location is inside the mapped proximity zone.
- * * Scores closer to `0` indicate lower confidence, suggesting the true location may fall in an adjacent zone.
- *
- */
- confidence: number
- }
- ProductProximity: {
- /** @description Proximity ID represents a fixed geographical zone in a discrete global grid within which the device is observed.
+ replayed?: components['schemas']['Replayed']
+ identification?: components['schemas']['Identification']
+ /** @description A supplementary browser identifier that prioritizes coverage over precision. The High Recall ID algorithm matches more generously, i.e., this identifier will remain the same even when there are subtle differences between two requests. This algorithm does not create as many new visitor IDs as the standard algorithms do, but there could be an increase in false-positive identification. */
+ supplementary_id_high_recall?: components['schemas']['SupplementaryIDHighRecall']
+ /** @description A customer-provided value or an object that was sent with the identification request or updated later. */
+ tags?: components['schemas']['Tags']
+ /** @description Page URL from which the request was sent. For example `https://example.com/`
* */
- data?: components['schemas']['Proximity']
- error?: components['schemas']['Error']
- }
- /** @description Contains all information about the request identified by `requestId`, depending on the pricing plan (Pro, Pro Plus, Enterprise) */
- Products: {
- identification?: components['schemas']['ProductIdentification']
- botd?: components['schemas']['ProductBotd']
- rootApps?: components['schemas']['ProductRootApps']
- emulator?: components['schemas']['ProductEmulator']
- ipInfo?: components['schemas']['ProductIPInfo']
- ipBlocklist?: components['schemas']['ProductIPBlocklist']
- tor?: components['schemas']['ProductTor']
- vpn?: components['schemas']['ProductVPN']
- proxy?: components['schemas']['ProductProxy']
- incognito?: components['schemas']['ProductIncognito']
- tampering?: components['schemas']['ProductTampering']
- clonedApp?: components['schemas']['ProductClonedApp']
- factoryReset?: components['schemas']['ProductFactoryReset']
- jailbroken?: components['schemas']['ProductJailbroken']
- frida?: components['schemas']['ProductFrida']
- privacySettings?: components['schemas']['ProductPrivacySettings']
- virtualMachine?: components['schemas']['ProductVirtualMachine']
- rawDeviceAttributes?: components['schemas']['ProductRawDeviceAttributes']
- highActivity?: components['schemas']['ProductHighActivity']
- locationSpoofing?: components['schemas']['ProductLocationSpoofing']
- suspectScore?: components['schemas']['ProductSuspectScore']
- /** @description This product is deprecated.
+ url?: components['schemas']['Url']
+ /** @description Bundle Id of the iOS application integrated with the Fingerprint SDK for the event. For example: `com.foo.app`
* */
- remoteControl?: components['schemas']['ProductRemoteControl']
- velocity?: components['schemas']['ProductVelocity']
- developerTools?: components['schemas']['ProductDeveloperTools']
- mitmAttack?: components['schemas']['ProductMitMAttack']
- proximity?: components['schemas']['ProductProximity']
- }
- /** @description Contains results from all activated products - Fingerprint Pro, Bot Detection, and others. */
- EventsGetResponse: {
- /** @description Contains all information about the request identified by `requestId`, depending on the pricing plan (Pro, Pro Plus, Enterprise) */
- products: components['schemas']['Products']
- }
- ErrorResponse: {
- error: components['schemas']['Error']
- }
- EventsUpdateRequest: {
- /** @description LinkedID value to assign to the existing event */
- linkedId?: string
- /** @description A customer-provided value or an object that was sent with identification request. */
- tag?: components['schemas']['Tag']
- /** @description Suspect flag indicating observed suspicious or fraudulent event */
- suspect?: boolean
- }
- /** @description Contains a list of all identification events matching the specified search criteria. */
- SearchEventsResponse: {
- events?: {
- /** @description Contains all information about the request identified by `requestId`, depending on the pricing plan (Pro, Pro Plus, Enterprise) */
- products: components['schemas']['Products']
- }[]
- /** @description Use this value in the `pagination_key` parameter to request the next page of search results. */
- paginationKey?: string
- }
- Visit: {
- /** @description Unique identifier of the user's request. */
- requestId: string
- browserDetails: components['schemas']['BrowserDetails']
- /** @description Flag if user used incognito session. */
- incognito: boolean
+ bundle_id?: components['schemas']['BundleId']
+ /** @description Package name of the Android application integrated with the Fingerprint SDK for the event. For example: `com.foo.app`
+ * */
+ package_name?: components['schemas']['PackageName']
/** @description IP address of the requesting browser or bot. */
- ip: string
- /** @description This field is **deprecated** and will not return a result for **applications created after January 23rd, 2024**. Please use the [IP Geolocation Smart signal](https://dev.fingerprint.com/docs/smart-signals-overview#ip-geolocation) for geolocation information. */
- ipLocation?: components['schemas']['DeprecatedGeolocation']
- /** @description A customer-provided id that was sent with the request. */
- linkedId?: string
- /**
- * Format: int64
- * @description Timestamp of the event with millisecond precision in Unix time.
- */
- timestamp: number
- /**
- * Format: date-time
- * @description Time expressed according to ISO 8601 in UTC format, when the request from the client agent was made. We recommend to treat requests that are older than 2 minutes as malicious. Otherwise, request replay attacks are possible.
- */
- time: string
- /** @description Page URL from which the request was sent. */
- url: string
- /** @description A customer-provided value or an object that was sent with identification request. */
- tag: components['schemas']['Tag']
- confidence?: components['schemas']['IdentificationConfidence']
- /** @description Attribute represents if a visitor had been identified before. */
- visitorFound: boolean
- firstSeenAt: components['schemas']['IdentificationSeenAt']
- lastSeenAt: components['schemas']['IdentificationSeenAt']
- /** @description It includes 35+ raw browser identification attributes to provide Fingerprint users with even more information than our standard visitor ID provides. This enables Fingerprint users to not have to run our open-source product in conjunction with Fingerprint Pro Plus and Enterprise to get those additional attributes.
- * Warning: The raw signals data can change at any moment as we improve the product. We cannot guarantee the internal shape of raw device attributes to be stable, so typical semantic versioning rules do not apply here. Use this data with caution without assuming a specific structure beyond the generic type provided here.
+ ip_address?: components['schemas']['IpAddress']
+ /** @description User Agent of the client, for example: `Mozilla/5.0 (Windows NT 6.1; Win64; x64) ....`
* */
- components?: components['schemas']['RawDeviceAttributes']
- }
- /** @description Pagination-related fields `lastTimestamp` and `paginationKey` are included if you use a pagination parameter like `limit` or `before` and there is more data available on the next page. */
- VisitorsGetResponse: {
- visitorId: string
- visits: components['schemas']['Visit'][]
- /**
- * Format: int64
- * @deprecated
- * @description ⚠️ Deprecated paging attribute, please use `paginationKey` instead. Timestamp of the last visit in the current page of results.
- *
- */
- lastTimestamp?: number
- /** @description Request ID of the last visit in the current page of results. Use this value in the following request as the `paginationKey` parameter to get the next page of results. */
- paginationKey?: string
- }
- ErrorPlainResponse: {
- error: string
- }
- RelatedVisitor: {
- /** @description Visitor ID of a browser that originates from the same mobile device as the input visitor ID. */
- visitorId: string
- }
- RelatedVisitorsResponse: {
- relatedVisitors: components['schemas']['RelatedVisitor'][]
- }
- WebhookRootApps: {
- /** @description Android specific root management apps detection. There are 2 values:
- * * `true` - Root Management Apps detected (e.g. Magisk).
- * * `false` - No Root Management Apps detected or the client isn't Android.
+ user_agent?: components['schemas']['UserAgent']
+ browser_details?: components['schemas']['BrowserDetails']
+ /** @description Proximity ID represents a fixed geographical zone in a discrete global grid within which the device is observed.
+ * */
+ proximity?: components['schemas']['Proximity']
+ /** @description Bot detection result:
+ * * `not_detected` - the visitor is not a bot
+ * * `good` - good bot detected, such as Google bot, Baidu Spider, AlexaBot and so on
+ * * `bad` - bad bot detected, such as Selenium, Puppeteer, Playwright, headless browsers, and so on
+ * */
+ bot?: components['schemas']['BotResult']
+ /** @description Additional classification of the bot type if detected.
+ * */
+ bot_type?: components['schemas']['BotType']
+ /** @description Android specific cloned application detection. There are 2 values: * `true` - Presence of app cloners work detected (e.g. fully cloned application found or launch of it inside of a not main working profile detected). * `false` - No signs of cloned application detected or the client is not Android.
+ * */
+ cloned_app?: components['schemas']['ClonedApp']
+ /** @description `true` if the browser is Chrome with DevTools open or Firefox with Developer Tools open, `false` otherwise.
* */
- result?: boolean
- }
- WebhookEmulator: {
+ developer_tools?: components['schemas']['DeveloperTools']
/** @description Android specific emulator detection. There are 2 values:
- * * `true` - Emulated environment detected (e.g. launch inside of AVD).
- * * `false` - No signs of emulated environment detected or the client is not Android.
+ * * `true` - Emulated environment detected (e.g. launch inside of AVD).
+ * * `false` - No signs of emulated environment detected or the client is not Android.
* */
- result?: boolean
- }
- /** @description Details about the request IP address. Has separate fields for v4 and v6 IP address versions. */
- WebhookIPInfo: {
- v4?: components['schemas']['IPInfoV4']
- v6?: components['schemas']['IPInfoV6']
- }
- WebhookIPBlocklist: {
- /** @description `true` if request IP address is part of any database that we use to search for known malicious actors, `false` otherwise.
+ emulator?: components['schemas']['Emulator']
+ /** @description The time of the most recent factory reset that happened on the **mobile device** is expressed as Unix epoch time. When a factory reset cannot be detected on the mobile device or when the request is initiated from a browser, this field will correspond to the *epoch* time (i.e 1 Jan 1970 UTC) as a value of 0. See [Factory Reset Detection](https://dev.fingerprint.com/docs/smart-signals-overview#factory-reset-detection) to learn more about this Smart Signal.
* */
- result?: boolean
- details?: components['schemas']['IPBlocklistDetails']
- }
- WebhookTor: {
- /** @description `true` if the request IP address is a known tor exit node, `false` otherwise.
+ factory_reset_timestamp?: components['schemas']['FactoryReset']
+ /** @description [Frida](https://frida.re/docs/) detection for Android and iOS devices. There are 2 values:
+ * * `true` - Frida detected
+ * * `false` - No signs of Frida or the client is not a mobile device.
* */
- result?: boolean
- }
- WebhookVPN: {
- /** @description VPN or other anonymizing service has been used when sending the request. */
- result?: boolean
- /** @description A confidence rating for the VPN detection result — "low", "medium", or "high". Depends on the combination of results returned from all VPN detection methods. */
- confidence?: components['schemas']['VPNConfidence']
- /** @description Local timezone which is used in timezoneMismatch method. */
- originTimezone?: string
- /** @description Country of the request (only for Android SDK version >= 2.4.0, ISO 3166 format or unknown). */
- originCountry?: string
- methods?: components['schemas']['VPNMethods']
- }
- WebhookProxy: {
+ frida?: components['schemas']['Frida']
+ ip_blocklist?: components['schemas']['IPBlockList']
+ /** @description Details about the request IP address. Has separate fields for v4 and v6 IP address versions. */
+ ip_info?: components['schemas']['IPInfo']
/** @description IP address was used by a public proxy provider or belonged to a known recent residential proxy
* */
- result?: boolean
- /** @description Confidence level of the proxy detection.
- * If a proxy is not detected, confidence is "high".
- * If it's detected, can be "low", "medium", or "high".
+ proxy?: components['schemas']['Proxy']
+ /** @description Confidence level of the proxy detection. If a proxy is not detected, confidence is "high". If it's detected, can be "low", "medium", or "high".
* */
- confidence?: components['schemas']['ProxyConfidence']
- /** @description Proxy detection details (present if proxy is detected) */
- details?: components['schemas']['ProxyDetails']
- }
- WebhookTampering: {
- /** @description Indicates if an identification request from a browser or an Android SDK has been tampered with. Not supported in the iOS SDK, is always `false` for iOS requests.
- * * `true` - If the request meets either of the following conditions:
- * * Contains anomalous browser or device attributes that could not have been legitimately produced by the JavaScript agent or the Android SDK (see `anomalyScore`).
- * * Originated from an anti-detect browser like Incognition (see `antiDetectBrowser`).
- * * `false` - If the request is considered genuine or was generated by the iOS SDK.
+ proxy_confidence?: components['schemas']['ProxyConfidence']
+ /** @description Proxy detection details (present if `proxy` is `true`) */
+ proxy_details?: components['schemas']['ProxyDetails']
+ /** @description `true` if we detected incognito mode used in the browser, `false` otherwise.
* */
- result?: boolean
- /**
- * Format: double
- * @description A score that indicates the extent of anomalous data in the request. This field applies to requests originating from **both** browsers and Android SDKs.
- * * Values above `0.5` indicate that the request has been tampered with.
- * * Values below `0.5` indicate that the request is genuine.
- *
- */
- anomalyScore?: number
- /** @description Anti-detect browsers try to evade identification by masking or manipulating their fingerprint to imitate legitimate browser configurations. This field does not apply to requests originating from mobile SDKs.
- * * `true` - The browser resembles a known anti-detect browser, for example, Incognition.
- * * `false` - The browser does not resemble an anti-detect browser or the request originates from a mobile SDK.
+ incognito?: components['schemas']['Incognito']
+ /** @description iOS specific jailbreak detection. There are 2 values:
+ * * `true` - Jailbreak detected.
+ * * `false` - No signs of jailbreak or the client is not iOS.
* */
- antiDetectBrowser?: boolean
- }
- WebhookClonedApp: {
- /** @description Android specific cloned application detection. There are 2 values:
- * * `true` - Presence of app cloners work detected (e.g. fully cloned application found or launch of it inside of a not main working profile detected).
- * * `false` - No signs of cloned application detected or the client is not Android.
+ jailbroken?: components['schemas']['Jailbroken']
+ /** @description Flag indicating whether the request came from a mobile device with location spoofing enabled. */
+ location_spoofing?: components['schemas']['LocationSpoofing']
+ /** @description * `true` - When requests made from your users' mobile devices to Fingerprint servers have been intercepted and potentially modified.
+ * * `false` - Otherwise or when the request originated from a browser.
+ * See [MitM Attack Detection](https://dev.fingerprint.com/docs/smart-signals-reference#mitm-attack-detection) to learn more about this Smart Signal.
* */
- result?: boolean
- }
- WebhookFactoryReset: {
- /**
- * Format: date-time
- * @description Indicates the time (in UTC) of the most recent factory reset that happened on the **mobile device**.
- * When a factory reset cannot be detected on the mobile device or when the request is initiated from a browser, this field will correspond to the *epoch* time (i.e 1 Jan 1970 UTC).
- * See [Factory Reset Detection](https://dev.fingerprint.com/docs/smart-signals-overview#factory-reset-detection) to learn more about this Smart Signal.
+ mitm_attack?: components['schemas']['MitMAttack']
+ /** @description `true` if the request is from a privacy aware browser (e.g. Tor) or from a browser in which fingerprinting is blocked. Otherwise `false`.
+ * */
+ privacy_settings?: components['schemas']['PrivacySettings']
+ /** @description Android specific root management apps detection. There are 2 values:
+ * * `true` - Root Management Apps detected (e.g. Magisk).
+ * * `false` - No Root Management Apps detected or the client isn't Android.
+ * */
+ root_apps?: components['schemas']['RootApps']
+ /** @description Suspect Score is an easy way to integrate Smart Signals into your fraud protection work flow. It is a weighted representation of all Smart Signals present in the payload that helps identify suspicious activity. The value range is [0; S] where S is sum of all Smart Signals weights. See more details here: https://dev.fingerprint.com/docs/suspect-score
+ * */
+ suspect_score?: components['schemas']['SuspectScore']
+ /** @description Flag indicating browser tampering was detected. This happens when either:
+ * * There are inconsistencies in the browser configuration that cross internal tampering thresholds (see `tampering_details.anomaly_score`).
+ * * The browser signature resembles an "anti-detect" browser specifically designed to evade fingerprinting (see `tampering_details.anti_detect_browser`).
+ * */
+ tampering?: components['schemas']['Tampering']
+ tampering_details?: components['schemas']['TamperingDetails']
+ /** @description Sums key data points for a specific `visitor_id`, `ip_address` and `linked_id` at three distinct time
+ * intervals: 5 minutes, 1 hour, and 24 hours as follows:
*
- */
- time?: string
- /**
- * Format: int64
- * @description This field is just another representation of the value in the `time` field.
- * The time of the most recent factory reset that happened on the **mobile device** is expressed as Unix epoch time.
+ * - Number of distinct IP addresses associated to the visitor Id.
+ * - Number of distinct linked Ids associated with the visitor Id.
+ * - Number of distinct countries associated with the visitor Id.
+ * - Number of identification events associated with the visitor Id.
+ * - Number of identification events associated with the detected IP address.
+ * - Number of distinct IP addresses associated with the provided linked Id.
+ * - Number of distinct visitor Ids associated with the provided linked Id.
*
- */
- timestamp?: number
- }
- WebhookJailbroken: {
- /** @description iOS specific jailbreak detection. There are 2 values:
- * * `true` - Jailbreak detected.
- * * `false` - No signs of jailbreak or the client is not iOS.
+ * The `24h` interval of `distinct_ip`, `distinct_linked_id`, `distinct_country`,
+ * `distinct_ip_by_linked_id` and `distinct_visitor_id_by_linked_id` will be omitted
+ * if the number of `events` for the visitor Id in the last 24
+ * hours (`events.['24h']`) is higher than 20.000.
+ *
+ * All will not necessarily be returned in a response, some may be omitted if the
+ * associated event does not have the required data, such as a linked_id.
* */
- result?: boolean
- }
- WebhookFrida: {
- /** @description [Frida](https://frida.re/docs/) detection for Android and iOS devices. There are 2 values:
- * * `true` - Frida detected
- * * `false` - No signs of Frida or the client is not a mobile device.
+ velocity?: components['schemas']['Velocity']
+ /** @description `true` if the request came from a browser running inside a virtual machine (e.g. VMWare), `false` otherwise.
* */
- result?: boolean
- }
- WebhookPrivacySettings: {
- /** @description `true` if the request is from a privacy aware browser (e.g. Tor) or from a browser in which fingerprinting is blocked. Otherwise `false`.
+ virtual_machine?: components['schemas']['VirtualMachine']
+ /** @description VPN or other anonymizing service has been used when sending the request.
* */
- result?: boolean
- }
- WebhookVirtualMachine: {
- /** @description `true` if the request came from a browser running inside a virtual machine (e.g. VMWare), `false` otherwise.
+ vpn?: components['schemas']['Vpn']
+ /** @description A confidence rating for the VPN detection result — "low", "medium", or "high". Depends on the combination of results returned from all VPN detection methods. */
+ vpn_confidence?: components['schemas']['VpnConfidence']
+ /** @description Local timezone which is used in timezone_mismatch method.
* */
- result?: boolean
- }
- /** @description It includes 35+ raw browser identification attributes to provide Fingerprint users with even more information than our standard visitor ID provides. This enables Fingerprint users to not have to run our open-source product in conjunction with Fingerprint Pro Plus and Enterprise to get those additional attributes.
- * Warning: The raw signals data can change at any moment as we improve the product. We cannot guarantee the internal shape of raw device attributes to be stable, so typical semantic versioning rules do not apply here. Use this data with caution without assuming a specific structure beyond the generic type provided here.
- * */
- WebhookRawDeviceAttributes: {
- [key: string]: components['schemas']['RawDeviceAttribute']
- }
- WebhookHighActivity: {
- /** @description Flag indicating if the request came from a high-activity visitor. */
- result: boolean
- /**
- * Format: int64
- * @description Number of requests from the same visitor in the previous day.
- */
- dailyRequests?: number
- }
- WebhookLocationSpoofing: {
- /** @description Flag indicating whether the request came from a mobile device with location spoofing enabled. */
- result?: boolean
- }
- WebhookSuspectScore: {
- /** @description Suspect Score is an easy way to integrate Smart Signals into your fraud protection work flow. It is a weighted representation of all Smart Signals present in the payload that helps identify suspicious activity. The value range is [0; S] where S is sum of all Smart Signals weights. See more details here: https://dev.fingerprint.com/docs/suspect-score
+ vpn_origin_timezone?: components['schemas']['VpnOriginTimezone']
+ /** @description Country of the request (only for Android SDK version >= 2.4.0, ISO 3166 format or unknown).
* */
- result?: number
+ vpn_origin_country?: components['schemas']['VpnOriginCountry']
+ vpn_methods?: components['schemas']['VpnMethods']
}
/**
- * @deprecated
- * @description This signal is deprecated.
+ * @description Error code:
+ * * `request_cannot_be_parsed` - The query parameters or JSON payload contains some errors
+ * that prevented us from parsing it (wrong type/surpassed limits).
+ * * `secret_api_key_required` - secret API key in header is missing or empty.
+ * * `secret_api_key_not_found` - No Fingerprint application found for specified secret API key.
+ * * `public_api_key_required` - public API key in header is missing or empty.
+ * * `public_api_key_not_found` - No Fingerprint application found for specified public API key.
+ * * `subscription_not_active` - Fingerprint application is not active.
+ * * `wrong_region` - Server and application region differ.
+ * * `feature_not_enabled` - This feature (for example, Delete API) is not enabled for your application.
+ * * `request_not_found` - The specified event ID was not found. It never existed, expired, or it has been deleted.
+ * * `visitor_not_found` - The specified visitor ID was not found. It never existed or it may have already been deleted.
+ * * `too_many_requests` - The limit on secret API key requests per second has been exceeded.
+ * * `state_not_ready` - The event specified with event ID is
+ * not ready for updates yet. Try again.
+ * This error happens in rare cases when update API is called immediately
+ * after receiving the event ID on the client. In case you need to send
+ * information right away, we recommend using the JS agent API instead.
+ * * `failed` - Internal server error.
+ * * `event_not_found` - The specified event ID was not found. It never existed, expired, or it has been deleted.
+ * * `missing_module` - The request is invalid because it is missing a required module.
+ * * `payload_too_large` - The request payload is too large and cannot be processed.
*
+ * @enum {string}
*/
- WebhookRemoteControl: {
- /** @description `true` if the request came from a machine being remotely controlled (e.g. TeamViewer), `false` otherwise.
- * */
- result?: boolean
- }
- /** @description Sums key data points for a specific `visitorId`, `ipAddress` and `linkedId` at three distinct time
- * intervals: 5 minutes, 1 hour, and 24 hours as follows:
- *
- * - Number of distinct IP addresses associated to the visitor ID.
- * - Number of distinct linked IDs associated with the visitor ID.
- * - Number of distinct countries associated with the visitor ID.
- * - Number of identification events associated with the visitor ID.
- * - Number of identification events associated with the detected IP address.
- * - Number of distinct IP addresses associated with the provided linked ID.
- * - Number of distinct visitor IDs associated with the provided linked ID.
- *
- * The `24h` interval of `distinctIp`, `distinctLinkedId`, `distinctCountry`,
- * `distinctIpByLinkedId` and `distinctVisitorIdByLinkedId` will be omitted
- * if the number of `events` for the visitor ID in the last 24
- * hours (`events.intervals.['24h']`) is higher than 20.000.
- * */
- WebhookVelocity: {
- distinctIp?: components['schemas']['VelocityData']
- distinctLinkedId?: components['schemas']['VelocityData']
- distinctCountry?: components['schemas']['VelocityData']
- events?: components['schemas']['VelocityData']
- ipEvents?: components['schemas']['VelocityData']
- distinctIpByLinkedId?: components['schemas']['VelocityData']
- distinctVisitorIdByLinkedId?: components['schemas']['VelocityData']
- }
- WebhookDeveloperTools: {
- /** @description `true` if the browser is Chrome with DevTools open or Firefox with Developer Tools open, `false` otherwise.
- * */
- result?: boolean
- }
- WebhookMitMAttack: {
- /** @description * `true` - When requests made from your users' mobile devices to Fingerprint servers have been intercepted and potentially modified.
- * * `false` - Otherwise or when the request originated from a browser.
- * See [MitM Attack Detection](https://dev.fingerprint.com/docs/smart-signals-overview#mitm-attack-detection) to learn more about this Smart Signal.
+ ErrorCode:
+ | 'request_cannot_be_parsed'
+ | 'secret_api_key_required'
+ | 'secret_api_key_not_found'
+ | 'public_api_key_required'
+ | 'public_api_key_not_found'
+ | 'subscription_not_active'
+ | 'wrong_region'
+ | 'feature_not_enabled'
+ | 'request_not_found'
+ | 'visitor_not_found'
+ | 'too_many_requests'
+ | 'state_not_ready'
+ | 'failed'
+ | 'event_not_found'
+ | 'missing_module'
+ | 'payload_too_large'
+ Error: {
+ /** @description Error code:
+ * * `request_cannot_be_parsed` - The query parameters or JSON payload contains some errors
+ * that prevented us from parsing it (wrong type/surpassed limits).
+ * * `secret_api_key_required` - secret API key in header is missing or empty.
+ * * `secret_api_key_not_found` - No Fingerprint application found for specified secret API key.
+ * * `public_api_key_required` - public API key in header is missing or empty.
+ * * `public_api_key_not_found` - No Fingerprint application found for specified public API key.
+ * * `subscription_not_active` - Fingerprint application is not active.
+ * * `wrong_region` - Server and application region differ.
+ * * `feature_not_enabled` - This feature (for example, Delete API) is not enabled for your application.
+ * * `request_not_found` - The specified event ID was not found. It never existed, expired, or it has been deleted.
+ * * `visitor_not_found` - The specified visitor ID was not found. It never existed or it may have already been deleted.
+ * * `too_many_requests` - The limit on secret API key requests per second has been exceeded.
+ * * `state_not_ready` - The event specified with event ID is
+ * not ready for updates yet. Try again.
+ * This error happens in rare cases when update API is called immediately
+ * after receiving the event ID on the client. In case you need to send
+ * information right away, we recommend using the JS agent API instead.
+ * * `failed` - Internal server error.
+ * * `event_not_found` - The specified event ID was not found. It never existed, expired, or it has been deleted.
+ * * `missing_module` - The request is invalid because it is missing a required module.
+ * * `payload_too_large` - The request payload is too large and cannot be processed.
* */
- result?: boolean
- }
- SupplementaryID: {
- /** @description String of 20 characters that uniquely identifies the visitor's browser or mobile device. */
- visitorId?: string
- /** @description Attribute represents if a visitor had been identified before. */
- visitorFound?: boolean
- confidence?: components['schemas']['IdentificationConfidence']
- firstSeenAt?: components['schemas']['IdentificationSeenAt']
- lastSeenAt?: components['schemas']['IdentificationSeenAt']
+ code: components['schemas']['ErrorCode']
+ message: string
}
- /** @description Other identities that have been established for a given Visitor. */
- WebhookSupplementaryIDs: {
- standard: components['schemas']['SupplementaryID']
- highRecall: components['schemas']['SupplementaryID']
+ ErrorResponse: {
+ error: components['schemas']['Error']
}
- /** @description Proximity ID represents a fixed geographical zone in a discrete global grid within which the device is observed.
- * */
- WebhookProximity: {
- /** @description A stable privacy-preserving identifier for a given proximity zone.
- * */
- id: string
- /**
- * Format: int32
- * @description The radius of the proximity zone’s precision level, in meters.
- *
- * @enum {integer}
- */
- precisionRadius: 10 | 25 | 65 | 175 | 450 | 1200 | 3300 | 8500 | 22500
- /**
- * Format: float
- * @description A value between `0` and `1` representing the likelihood that the true device location lies within the mapped proximity zone.
- * * Scores closer to `1` indicate high confidence that the location is inside the mapped proximity zone.
- * * Scores closer to `0` indicate lower confidence, suggesting the true location may fall in an adjacent zone.
- *
- */
- confidence: number
+ EventUpdate: {
+ /** @description Linked Id value to assign to the existing event */
+ linked_id?: string
+ /** @description A customer-provided value or an object that was sent with the identification request or updated later. */
+ tags?: {
+ [key: string]: unknown
+ }
+ /** @description Suspect flag indicating observed suspicious or fraudulent event */
+ suspect?: boolean
}
- Webhook: {
- /** @description Unique identifier of the user's request. */
- requestId: string
- /** @description Page URL from which the request was sent. */
- url: string
- /** @description IP address of the requesting browser or bot. */
- ip: string
- /** @description Environment ID of the event. */
- environmentId?: string
- /** @description A customer-provided value or an object that was sent with identification request. */
- tag?: components['schemas']['Tag']
- /**
- * Format: date-time
- * @description Time expressed according to ISO 8601 in UTC format, when the request from the JS agent was made. We recommend to treat requests that are older than 2 minutes as malicious. Otherwise, request replay attacks are possible.
- */
- time: string
+ /** @description Contains a list of all identification events matching the specified search criteria. */
+ EventSearch: {
+ events: components['schemas']['Event'][]
+ /** @description Use this value in the `pagination_key` parameter to request the next page of search results. */
+ pagination_key?: string
/**
* Format: int64
- * @description Timestamp of the event with millisecond precision in Unix time.
+ * @description This value represents the total number of events matching the search query, up to the limit provided in the `total_hits` query parameter. Only present if the `total_hits` query parameter was provided.
*/
- timestamp: number
- /** @description This field is **deprecated** and will not return a result for **applications created after January 23rd, 2024**. Please use the [IP Geolocation Smart signal](https://dev.fingerprint.com/docs/smart-signals-overview#ip-geolocation) for geolocation information. */
- ipLocation?: components['schemas']['DeprecatedGeolocation']
- /** @description A customer-provided id that was sent with the request. */
- linkedId?: string
- /** @description String of 20 characters that uniquely identifies the visitor's browser or mobile device. */
- visitorId?: string
- /** @description Attribute represents if a visitor had been identified before. */
- visitorFound?: boolean
- confidence?: components['schemas']['IdentificationConfidence']
- firstSeenAt?: components['schemas']['IdentificationSeenAt']
- lastSeenAt?: components['schemas']['IdentificationSeenAt']
- browserDetails?: components['schemas']['BrowserDetails']
- /** @description Flag if user used incognito session. */
- incognito?: boolean
- clientReferrer?: string
- /** @description It includes 35+ raw browser identification attributes to provide Fingerprint users with even more information than our standard visitor ID provides. This enables Fingerprint users to not have to run our open-source product in conjunction with Fingerprint Pro Plus and Enterprise to get those additional attributes.
- * Warning: The raw signals data can change at any moment as we improve the product. We cannot guarantee the internal shape of raw device attributes to be stable, so typical semantic versioning rules do not apply here. Use this data with caution without assuming a specific structure beyond the generic type provided here.
- * */
- components?: components['schemas']['RawDeviceAttributes']
- /** @description Stores bot detection result */
- bot?: components['schemas']['BotdBot']
- userAgent?: string
- rootApps?: components['schemas']['WebhookRootApps']
- emulator?: components['schemas']['WebhookEmulator']
- /** @description Details about the request IP address. Has separate fields for v4 and v6 IP address versions. */
- ipInfo?: components['schemas']['WebhookIPInfo']
- ipBlocklist?: components['schemas']['WebhookIPBlocklist']
- tor?: components['schemas']['WebhookTor']
- vpn?: components['schemas']['WebhookVPN']
- proxy?: components['schemas']['WebhookProxy']
- tampering?: components['schemas']['WebhookTampering']
- clonedApp?: components['schemas']['WebhookClonedApp']
- factoryReset?: components['schemas']['WebhookFactoryReset']
- jailbroken?: components['schemas']['WebhookJailbroken']
- frida?: components['schemas']['WebhookFrida']
- privacySettings?: components['schemas']['WebhookPrivacySettings']
- virtualMachine?: components['schemas']['WebhookVirtualMachine']
- /** @description It includes 35+ raw browser identification attributes to provide Fingerprint users with even more information than our standard visitor ID provides. This enables Fingerprint users to not have to run our open-source product in conjunction with Fingerprint Pro Plus and Enterprise to get those additional attributes.
- * Warning: The raw signals data can change at any moment as we improve the product. We cannot guarantee the internal shape of raw device attributes to be stable, so typical semantic versioning rules do not apply here. Use this data with caution without assuming a specific structure beyond the generic type provided here.
- * */
- rawDeviceAttributes?: components['schemas']['WebhookRawDeviceAttributes']
- highActivity?: components['schemas']['WebhookHighActivity']
- locationSpoofing?: components['schemas']['WebhookLocationSpoofing']
- suspectScore?: components['schemas']['WebhookSuspectScore']
- /** @description This signal is deprecated.
- * */
- remoteControl?: components['schemas']['WebhookRemoteControl']
- /** @description Sums key data points for a specific `visitorId`, `ipAddress` and `linkedId` at three distinct time
- * intervals: 5 minutes, 1 hour, and 24 hours as follows:
- *
- * - Number of distinct IP addresses associated to the visitor ID.
- * - Number of distinct linked IDs associated with the visitor ID.
- * - Number of distinct countries associated with the visitor ID.
- * - Number of identification events associated with the visitor ID.
- * - Number of identification events associated with the detected IP address.
- * - Number of distinct IP addresses associated with the provided linked ID.
- * - Number of distinct visitor IDs associated with the provided linked ID.
- *
- * The `24h` interval of `distinctIp`, `distinctLinkedId`, `distinctCountry`,
- * `distinctIpByLinkedId` and `distinctVisitorIdByLinkedId` will be omitted
- * if the number of `events` for the visitor ID in the last 24
- * hours (`events.intervals.['24h']`) is higher than 20.000.
- * */
- velocity?: components['schemas']['WebhookVelocity']
- developerTools?: components['schemas']['WebhookDeveloperTools']
- mitmAttack?: components['schemas']['WebhookMitMAttack']
- /** @description `true` if we determined that this payload was replayed, `false` otherwise.
- * */
- replayed?: boolean
- /** @description Contains information about the SDK used to perform the request. */
- sdk: components['schemas']['SDK']
- /** @description Other identities that have been established for a given Visitor. */
- supplementaryIds?: components['schemas']['WebhookSupplementaryIDs']
- /** @description Proximity ID represents a fixed geographical zone in a discrete global grid within which the device is observed.
- * */
- proximity?: components['schemas']['WebhookProximity']
+ total_hits?: number
}
}
responses: never
@@ -1325,8 +785,8 @@ export interface operations {
query?: never
header?: never
path: {
- /** @description The unique [identifier](https://dev.fingerprint.com/reference/get-function#requestid) of each identification request. */
- request_id: string
+ /** @description The unique [identifier](https://dev.fingerprint.com/reference/get-function#requestid) of each identification request (`requestId` can be used in its place). */
+ event_id: string
}
cookie?: never
}
@@ -1338,7 +798,16 @@ export interface operations {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['EventsGetResponse']
+ 'application/json': components['schemas']['Event']
+ }
+ }
+ /** @description Bad request. The event Id provided is not valid. */
+ 400: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponse']
}
}
/** @description Forbidden. Access to this API is denied. */
@@ -1350,7 +819,7 @@ export interface operations {
'application/json': components['schemas']['ErrorResponse']
}
}
- /** @description Not found. The request ID cannot be found in this application's data. */
+ /** @description Not found. The event Id cannot be found in this application's data. */
404: {
headers: {
[name: string]: unknown
@@ -1359,6 +828,15 @@ export interface operations {
'application/json': components['schemas']['ErrorResponse']
}
}
+ /** @description Application error. */
+ 500: {
+ headers: {
+ [name: string]: unknown
+ }
+ content: {
+ 'application/json': components['schemas']['ErrorResponse']
+ }
+ }
}
}
updateEvent: {
@@ -1366,14 +844,14 @@ export interface operations {
query?: never
header?: never
path: {
- /** @description The unique event [identifier](https://dev.fingerprint.com/reference/get-function#requestid). */
- request_id: string
+ /** @description The unique event [identifier](https://dev.fingerprint.com/reference/get-function#event_id). */
+ event_id: string
}
cookie?: never
}
requestBody: {
content: {
- 'application/json': components['schemas']['EventsUpdateRequest']
+ 'application/json': components['schemas']['EventUpdate']
}
}
responses: {
@@ -1402,7 +880,7 @@ export interface operations {
'application/json': components['schemas']['ErrorResponse']
}
}
- /** @description Not found. The request ID cannot be found in this application's data. */
+ /** @description Not found. The event Id cannot be found in this application's data. */
404: {
headers: {
[name: string]: unknown
@@ -1424,19 +902,19 @@ export interface operations {
}
searchEvents: {
parameters: {
- query: {
+ query?: {
/** @description Limit the number of events returned.
* */
- limit: number
+ limit?: number
/** @description 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:
+ * When more results are available (e.g., you requested up to 100 results for your query using `limit`, but there are more than 100 events total matching your request), the `pagination_key` field 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`
+ * 1. First request, returning most recent 200 events: `GET api-base-url/events?limit=100`
+ * 2. Use `response.pagination_key` to get the next page of results: `GET api-base-url/events?limit=100&pagination_key=1740815825085`
* */
pagination_key?: string
- /** @description Unique [visitor identifier](https://dev.fingerprint.com/reference/get-function#visitorid) issued by Fingerprint Pro.
+ /** @description Unique [visitor identifier](https://dev.fingerprint.com/reference/get-function#visitorid) issued by Fingerprint Identification and all active Smart Signals.
* Filter for events matching this `visitor_id`.
* */
visitor_id?: string
@@ -1445,18 +923,24 @@ export interface operations {
* `good` - events where a good bot was detected.
* `bad` - events where a bad bot was detected.
* `none` - events where no bot was detected.
- * > Note: When using this parameter, only events with the `products.botd.data.bot.result` property set to a valid value are returned. Events without a `products.botd` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `botd.bot` property set to a valid value are returned. Events without a `botd` Smart Signal result are left out of the response.
* */
bot?: 'all' | 'good' | 'bad' | 'none'
- /** @description 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
+ /** @description Filter events by IP address or IP range (if CIDR notation is used). If CIDR notation is not used, a /32 for IPv4 or /128 for IPv6 is assumed.
+ * Examples of range based queries: 10.0.0.0/24, 192.168.0.1/32
* */
ip_address?: string
/** @description 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.
+ * 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.
* */
linked_id?: string
+ /** @description Filter events by the URL (`url` property) associated with the event.
+ * */
+ url?: string
+ /** @description Filter events by the origin field of the event. Origin could be the website domain or mobile app bundle ID (eg: com.foo.bar)
+ * */
+ origin?: string
/** @description Filter events with a timestamp greater than the start time, in Unix time (milliseconds).
* */
start?: number
@@ -1471,108 +955,95 @@ export interface operations {
* */
suspect?: boolean
/** @description Filter events by VPN Detection result.
- * > Note: When using this parameter, only events with the `products.vpn.data.result` property set to `true` or `false` are returned. Events without a `products.vpn` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `vpn` property set to `true` or `false` are returned. Events without a `vpn` Smart Signal result are left out of the response.
* */
vpn?: boolean
/** @description Filter events by Virtual Machine Detection result.
- * > Note: When using this parameter, only events with the `products.virtualMachine.data.result` property set to `true` or `false` are returned. Events without a `products.virtualMachine` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `virtual_machine` property set to `true` or `false` are returned. Events without a `virtual_machine` Smart Signal result are left out of the response.
* */
virtual_machine?: boolean
- /** @description Filter events by Tampering Detection result.
- * > Note: When using this parameter, only events with the `products.tampering.data.result` property set to `true` or `false` are returned. Events without a `products.tampering` Smart Signal result are left out of the response.
+ /** @description Filter events by Browser Tampering Detection result.
+ * > Note: When using this parameter, only events with the `tampering.result` property set to `true` or `false` are returned. Events without a `tampering` Smart Signal result are left out of the response.
* */
tampering?: boolean
/** @description Filter events by Anti-detect Browser Detection result.
- * > Note: When using this parameter, only events with the `products.tampering.data.antiDetectBrowser` property set to `true` or `false` are returned. Events without a `products.tampering` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `tampering.anti_detect_browser` property set to `true` or `false` are returned. Events without a `tampering` Smart Signal result are left out of the response.
* */
anti_detect_browser?: boolean
/** @description Filter events by Browser Incognito Detection result.
- * > Note: When using this parameter, only events with the `products.incognito.data.result` property set to `true` or `false` are returned. Events without a `products.incognito` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `incognito` property set to `true` or `false` are returned. Events without an `incognito` Smart Signal result are left out of the response.
* */
incognito?: boolean
/** @description Filter events by Privacy Settings Detection result.
- * > Note: When using this parameter, only events with the `products.privacySettings.data.result` property set to `true` or `false` are returned. Events without a `products.privacySettings` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `privacy_settings` property set to `true` or `false` are returned. Events without a `privacy_settings` Smart Signal result are left out of the response.
* */
privacy_settings?: boolean
/** @description Filter events by Jailbroken Device Detection result.
- * > Note: When using this parameter, only events with the `products.jailbroken.data.result` property set to `true` or `false` are returned. Events without a `products.jailbroken` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `jailbroken` property set to `true` or `false` are returned. Events without a `jailbroken` Smart Signal result are left out of the response.
* */
jailbroken?: boolean
/** @description Filter events by Frida Detection result.
- * > Note: When using this parameter, only events with the `products.frida.data.result` property set to `true` or `false` are returned. Events without a `products.frida` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `frida` property set to `true` or `false` are returned. Events without a `frida` Smart Signal result are left out of the response.
* */
frida?: boolean
/** @description Filter events by Factory Reset Detection result.
- * > Note: When using this parameter, only events with the `products.factoryReset.data.result` property set to `true` or `false` are returned. Events without a `products.factoryReset` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with a `factory_reset` time. Events without a `factory_reset` Smart Signal result are left out of the response.
* */
factory_reset?: boolean
/** @description Filter events by Cloned App Detection result.
- * > Note: When using this parameter, only events with the `products.clonedApp.data.result` property set to `true` or `false` are returned. Events without a `products.clonedApp` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `cloned_app` property set to `true` or `false` are returned. Events without a `cloned_app` Smart Signal result are left out of the response.
* */
cloned_app?: boolean
/** @description Filter events by Android Emulator Detection result.
- * > Note: When using this parameter, only events with the `products.emulator.data.result` property set to `true` or `false` are returned. Events without a `products.emulator` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `emulator` property set to `true` or `false` are returned. Events without an `emulator` Smart Signal result are left out of the response.
* */
emulator?: boolean
/** @description Filter events by Rooted Device Detection result.
- * > Note: When using this parameter, only events with the `products.rootApps.data.result` property set to `true` or `false` are returned. Events without a `products.rootApps` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `root_apps` property set to `true` or `false` are returned. Events without a `root_apps` Smart Signal result are left out of the response.
* */
root_apps?: boolean
/** @description Filter events by VPN Detection result confidence level.
* `high` - events with high VPN Detection confidence.
* `medium` - events with medium VPN Detection confidence.
* `low` - events with low VPN Detection confidence.
- * > Note: When using this parameter, only events with the `products.vpn.data.confidence` property set to a valid value are returned. Events without a `products.vpn` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `vpn.confidence` property set to a valid value are returned. Events without a `vpn` Smart Signal result are left out of the response.
* */
- vpn_confidence?: 'high' | 'medium' | 'low'
+ vpn_confidence?: 'high,' | 'medium' | 'low'
/** @description Filter events with Suspect Score result above a provided minimum threshold.
- * > Note: When using this parameter, only events where the `products.suspectScore.data.result` property set to a value exceeding your threshold are returned. Events without a `products.suspectScore` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events where the `suspect_score` property set to a value exceeding your threshold are returned. Events without a `suspect_score` Smart Signal result are left out of the response.
* */
min_suspect_score?: number
- /** @description Filter events by IP Blocklist Detection result.
- * > Note: When using this parameter, only events with the `products.ipBlocklist.data.result` property set to `true` or `false` are returned. Events without a `products.ipBlocklist` Smart Signal result are left out of the response.
- * */
- ip_blocklist?: boolean
- /** @description Filter events by Datacenter Detection result.
- * > Note: When using this parameter, only events with the `products.ipInfo.data.v4.datacenter.result` or `products.ipInfo.data.v6.datacenter.result` property set to `true` or `false` are returned. Events without a `products.ipInfo` Smart Signal result are left out of the response.
- * */
- datacenter?: boolean
/** @description Filter events by Developer Tools detection result.
- * > Note: When using this parameter, only events with the `products.developerTools.data.result` property set to `true` or `false` are returned. Events without a `products.developerTools` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `developer_tools` property set to `true` or `false` are returned. Events without a `developer_tools` Smart Signal result are left out of the response.
* */
developer_tools?: boolean
/** @description Filter events by Location Spoofing detection result.
- * > Note: When using this parameter, only events with the `products.locationSpoofing.data.result` property set to `true` or `false` are returned. Events without a `products.locationSpoofing` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `location_spoofing` property set to `true` or `false` are returned. Events without a `location_spoofing` Smart Signal result are left out of the response.
* */
location_spoofing?: boolean
/** @description Filter events by MITM (Man-in-the-Middle) Attack detection result.
- * > Note: When using this parameter, only events with the `products.mitmAttack.data.result` property set to `true` or `false` are returned. Events without a `products.mitmAttack` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `mitm_attack` property set to `true` or `false` are returned. Events without a `mitm_attack` Smart Signal result are left out of the response.
* */
mitm_attack?: boolean
/** @description Filter events by Proxy detection result.
- * > Note: When using this parameter, only events with the `products.proxy.data.result` property set to `true` or `false` are returned. Events without a `products.proxy` Smart Signal result are left out of the response.
+ * > Note: When using this parameter, only events with the `proxy` property set to `true` or `false` are returned. Events without a `proxy` Smart Signal result are left out of the response.
* */
proxy?: boolean
- /** @description Filter events by a specific SDK version associated with the identification event. Example: `3.11.14`
+ /** @description Filter events by a specific SDK version associated with the identification event (`sdk.version` property). Example: `3.11.14`
* */
sdk_version?: string
- /** @description Filter events by the SDK Platform associated with the identification event.
- * `js` - JavaScript agent (Web).
+ /** @description Filter events by the SDK Platform associated with the identification event (`sdk.platform` property) .
+ * `js` - Javascript agent (Web).
* `ios` - Apple iOS based devices.
* `android` - Android based devices.
* */
sdk_platform?: 'js' | 'android' | 'ios'
- /** @description Filter for events by providing one or more environment IDs.
+ /** @description Filter for events by providing one or more environment IDs (`environment_id` property).
* */
environment?: string[]
- /** @description Filter events by the most precise Proximity ID provided by default.
- * > Note: When using this parameter, only events with the `products.proximity.id` property matching the provided ID are returned. Events without a `products.proximity` result are left out of the response.
+ /** @description When set, the response will include a `total_hits` property with a count of total query matches across all pages, up to the specified limit.
* */
- proximity_id?: string
- /** @description Filter events by Proximity Radius.
- * > Note: When using this parameter, only events with the `products.proximity.precisionRadius` property set to a valid value are returned. Events without a `products.proximity` result are left out of the response.
- * */
- proximity_precision_radius?: 10 | 25 | 65 | 175 | 450 | 1200 | 3300 | 8500 | 22500
+ total_hits?: number
}
header?: never
path?: never
@@ -1586,7 +1057,7 @@ export interface operations {
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['SearchEventsResponse']
+ 'application/json': components['schemas']['EventSearch']
}
}
/** @description Bad request. One or more supplied search parameters are invalid, or a required parameter is missing. */
@@ -1607,89 +1078,13 @@ export interface operations {
'application/json': components['schemas']['ErrorResponse']
}
}
- }
- }
- getVisits: {
- parameters: {
- query?: {
- /** @description Filter visits by `requestId`.
- *
- * Every identification request has a unique identifier associated with it called `requestId`. This identifier is returned to the client in the identification [result](https://dev.fingerprint.com/reference/get-function#requestid). When you filter visits by `requestId`, only one visit will be returned.
- * */
- request_id?: string
- /** @description Filter visits by your custom identifier.
- *
- * You can use [`linkedId`](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.
- * */
- linked_id?: string
- /** @description 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.
- * */
- limit?: number
- /** @description 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.
- * */
- paginationKey?: string
- /**
- * @deprecated
- * @description ⚠️ Deprecated pagination method, please use `paginationKey` instead. Timestamp (in milliseconds since epoch) used to paginate results.
- *
- */
- before?: number
- }
- header?: never
- path: {
- /** @description Unique [visitor identifier](https://dev.fingerprint.com/reference/get-function#visitorid) issued by Fingerprint Pro. */
- visitor_id: string
- }
- cookie?: never
- }
- requestBody?: never
- responses: {
- /** @description OK. */
- 200: {
- headers: {
- [name: string]: unknown
- }
- content: {
- 'application/json': components['schemas']['VisitorsGetResponse']
- }
- }
- /** @description Bad request. The visitor ID or query parameters are missing or in the wrong format. */
- 400: {
- headers: {
- [name: string]: unknown
- }
- content: {
- 'application/json': components['schemas']['ErrorPlainResponse']
- }
- }
- /** @description Forbidden. Access to this API is denied. */
- 403: {
- headers: {
- [name: string]: unknown
- }
- content: {
- 'application/json': components['schemas']['ErrorPlainResponse']
- }
- }
- /** @description Too Many Requests. The request is throttled. */
- 429: {
+ /** @description Application error. */
+ 500: {
headers: {
- /** @description Indicates how many seconds you should wait before attempting the next request. */
- 'Retry-After'?: number
[name: string]: unknown
}
content: {
- 'application/json': components['schemas']['ErrorPlainResponse']
+ 'application/json': components['schemas']['ErrorResponse']
}
}
}
@@ -1751,62 +1146,27 @@ export interface operations {
}
}
}
- getRelatedVisitors: {
+ postEventWebhook: {
parameters: {
- query: {
- /** @description The [visitor ID](https://dev.fingerprint.com/reference/get-function#visitorid) for which you want to find the other visitor IDs that originated from the same mobile device. */
- visitor_id: string
- }
+ query?: never
header?: never
path?: never
cookie?: never
}
- requestBody?: never
+ /** @description If configured, a Webhook event will be posted to the provided endpoint. The webhook has the same data as our `/v4/events` endpoint.
+ * */
+ requestBody: {
+ content: {
+ 'application/json': components['schemas']['Event']
+ }
+ }
responses: {
- /** @description OK. */
+ /** @description Return a 200 status to indicate that the data was received successfully */
200: {
headers: {
[name: string]: unknown
}
- content: {
- 'application/json': components['schemas']['RelatedVisitorsResponse']
- }
- }
- /** @description Bad request. The visitor ID parameter is missing or in the wrong format. */
- 400: {
- headers: {
- [name: string]: unknown
- }
- content: {
- 'application/json': components['schemas']['ErrorResponse']
- }
- }
- /** @description Forbidden. Access to this API is denied. */
- 403: {
- headers: {
- [name: string]: unknown
- }
- content: {
- 'application/json': components['schemas']['ErrorResponse']
- }
- }
- /** @description Not found. The visitor ID cannot be found in this application's data. */
- 404: {
- headers: {
- [name: string]: unknown
- }
- content: {
- 'application/json': components['schemas']['ErrorResponse']
- }
- }
- /** @description Too Many Requests. The request is throttled. */
- 429: {
- headers: {
- [name: string]: unknown
- }
- content: {
- 'application/json': components['schemas']['ErrorResponse']
- }
+ content?: never
}
}
}
diff --git a/src/serverApiClient.ts b/src/serverApiClient.ts
index 3d947d1d..52cc8fa4 100644
--- a/src/serverApiClient.ts
+++ b/src/serverApiClient.ts
@@ -1,17 +1,12 @@
import { getRequestPath } from './urlUtils'
import {
- AuthenticationMode,
EventsGetResponse,
- EventsUpdateRequest,
+ EventUpdate,
FingerprintApi,
Options,
Region,
- RelatedVisitorsFilter,
- RelatedVisitorsResponse,
SearchEventsFilter,
SearchEventsResponse,
- VisitorHistoryFilter,
- VisitorsResponse,
} from './types'
import { copyResponseJson } from './responseUtils'
import { handleErrorResponse } from './errors/handleErrorResponse'
@@ -21,12 +16,8 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
public readonly apiKey: string
- public readonly authenticationMode: AuthenticationMode
-
protected readonly fetch: typeof fetch
- protected static readonly DEFAULT_RETRY_AFTER = 1
-
/**
* FingerprintJS server API client used to fetch data from FingerprintJS
* @constructor
@@ -41,7 +32,6 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
// region or authentication mode to be specified as a string or an enum value.
// The resulting JS from using the enum value or the string is identical.
this.region = (options.region as Region) ?? Region.Global
- this.authenticationMode = (options.authenticationMode as AuthenticationMode) ?? AuthenticationMode.AuthHeader // Default auth mode is AuthHeader
this.apiKey = options.apiKey
this.fetch = options.fetch ?? fetch
@@ -50,14 +40,14 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
/**
* Retrieves a specific identification event with the information from each activated product — Identification and all active [Smart signals](https://dev.fingerprint.com/docs/smart-signals-overview).
*
- * @param requestId - identifier of the event
+ * @param eventId - identifier of the event
*
* @returns {Promise} - promise with event response. For more information, see the [Server API documentation](https://dev.fingerprint.com/reference/getevent).
*
* @example
* ```javascript
* client
- * .getEvent('')
+ * .getEvent('')
* .then((result) => console.log(result))
* .catch((error) => {
* if (error instanceof RequestError) {
@@ -68,24 +58,23 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
* })
* ```
* */
- public async getEvent(requestId: string): Promise {
- if (!requestId) {
- throw new TypeError('requestId is not set')
+ public async getEvent(eventId: string): Promise {
+ if (!eventId) {
+ throw new TypeError('eventId is not set')
}
const url = getRequestPath({
- path: '/events/{request_id}',
+ path: '/events/{event_id}',
region: this.region,
- apiKey: this.getQueryApiKey(),
- pathParams: [requestId],
+ pathParams: [eventId],
method: 'get',
})
- const headers = this.getHeaders()
-
const response = await this.fetch(url, {
method: 'GET',
- headers,
+ headers: {
+ Authorization: `Bearer ${this.apiKey}`,
+ },
})
const jsonResponse = await copyResponseJson(response)
@@ -98,15 +87,15 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
}
/**
- * Update an event with a given request ID
- * @description Change information in existing events specified by `requestId` or *flag suspicious events*.
+ * Update an event with a given event ID
+ * @description Change information in existing events specified by `eventId` or *flag suspicious events*.
*
* When an event is created, it is assigned `linkedId` and `tag` submitted through the JS agent parameters. This information might not be available on the client so the Server API allows for updating the attributes after the fact.
*
* **Warning** It's not possible to update events older than 10 days.
*
* @param body - Data to update the event with.
- * @param requestId The unique event [identifier](https://dev.fingerprint.com/docs/js-agent#requestid).
+ * @param eventId The unique event [identifier](https://dev.fingerprint.com/docs/js-agent#eventid).
*
* @return {Promise}
*
@@ -118,7 +107,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
* }
*
* client
- * .updateEvent(body, '')
+ * .updateEvent(body, '')
* .then(() => {
* // Event was successfully updated
* })
@@ -135,27 +124,28 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
* })
* ```
*/
- public async updateEvent(body: EventsUpdateRequest, requestId: string): Promise {
+ public async updateEvent(body: EventUpdate, eventId: string): Promise {
if (!body) {
throw new TypeError('body is not set')
}
- if (!requestId) {
- throw new TypeError('requestId is not set')
+ if (!eventId) {
+ throw new TypeError('eventId is not set')
}
const url = getRequestPath({
- path: '/events/{request_id}',
+ path: '/events/{event_id}',
region: this.region,
- apiKey: this.getQueryApiKey(),
- pathParams: [requestId],
+ pathParams: [eventId],
method: 'put',
})
- const headers = this.getHeaders()
const response = await this.fetch(url, {
- method: 'PUT',
- headers,
+ method: 'PATCH',
+ headers: {
+ Accept: 'application/json',
+ Authorization: `Bearer ${this.apiKey}`,
+ },
body: JSON.stringify(body),
})
@@ -206,16 +196,15 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
const url = getRequestPath({
path: '/visitors/{visitor_id}',
region: this.region,
- apiKey: this.getQueryApiKey(),
pathParams: [visitorId],
method: 'delete',
})
- const headers = this.getHeaders()
-
const response = await this.fetch(url, {
method: 'DELETE',
- headers,
+ headers: {
+ Authorization: `Bearer ${this.apiKey}`,
+ },
})
if (response.status === 200) {
@@ -227,13 +216,6 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
handleErrorResponse(jsonResponse, response)
}
- /**
- * @deprecated Please use {@link FingerprintJsServerApiClient.getVisits} instead
- * */
- public async getVisitorHistory(visitorId: string, filter?: VisitorHistoryFilter): Promise {
- return this.getVisits(visitorId, filter)
- }
-
/**
* Search for identification events, including Smart Signals, using
* multiple filtering criteria. If you don't provide `start` or `end`
@@ -272,16 +254,16 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
* */
async searchEvents(filter: SearchEventsFilter): Promise {
const url = getRequestPath({
- path: '/events/search',
+ path: '/events',
region: this.region,
- apiKey: this.getQueryApiKey(),
method: 'get',
queryParams: filter,
})
- const headers = this.getHeaders()
const response = await this.fetch(url, {
method: 'GET',
- headers,
+ headers: {
+ Authorization: `Bearer ${this.apiKey}`,
+ },
})
const jsonResponse = await copyResponseJson(response)
@@ -292,129 +274,4 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
handleErrorResponse(jsonResponse, response)
}
-
- /**
- * Retrieves event history for the specific visitor using the given filter, returns a promise with visitor history response.
- *
- * @param {string} visitorId - Identifier of the visitor
- * @param {VisitorHistoryFilter} filter - Visitor history filter
- * @param {string} filter.limit - limit scanned results
- * @param {string} filter.request_id - filter visits by `requestId`.
- * @param {string} filter.linked_id - filter visits by your custom identifier.
- * @param {string} filter.paginationKey - 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.
- * @example
- * ```javascript
- * client
- * .getVisits('', { limit: 1 })
- * .then((visitorHistory) => {
- * console.log(visitorHistory)
- * })
- * .catch((error) => {
- * if (error instanceof RequestError) {
- * console.log(error.statusCode, error.message)
- * // Access raw response in error
- * console.log(error.response)
- *
- * if(error instanceof TooManyRequestsError) {
- * retryLater(error.retryAfter) // Needs to be implemented on your side
- * }
- * }
- * })
- * ```
- */
- public async getVisits(visitorId: string, filter?: VisitorHistoryFilter): Promise {
- if (!visitorId) {
- throw TypeError('VisitorId is not set')
- }
-
- const url = getRequestPath({
- path: '/visitors/{visitor_id}',
- region: this.region,
- apiKey: this.getQueryApiKey(),
- pathParams: [visitorId],
- method: 'get',
- queryParams: filter,
- })
- const headers = this.getHeaders()
-
- const response = await this.fetch(url, {
- method: 'GET',
- headers,
- })
-
- const jsonResponse = await copyResponseJson(response)
-
- if (response.status === 200) {
- return jsonResponse as VisitorsResponse
- }
-
- handleErrorResponse(jsonResponse, response)
- }
-
- /**
- * Related visitors API lets you link web visits and in-app browser visits that originated from the same mobile device.
- * It searches the past 6 months of identification events to find the visitor IDs that belong to the same mobile device as the given visitor ID.
- * ⚠️ Please note that this API is not enabled by default and is billable separately. ⚠️
- * If you would like to use Related visitors API, please contact our [support team](https://fingerprint.com/support).
- * To learn more, see [Related visitors API reference](https://dev.fingerprint.com/reference/related-visitors-api).
- *
- * @param {RelatedVisitorsFilter} filter - Related visitors filter
- * @param {string} filter.visitorId - The [visitor ID](https://dev.fingerprint.com/docs/js-agent#visitorid) for which you want to find the other visitor IDs that originated from the same mobile device.
- *
- * @example
- * ```javascript
- * client
- * .getRelatedVisitors({ visitor_id: '' })
- * .then((relatedVisits) => {
- * console.log(relatedVisits)
- * })
- * .catch((error) => {
- * if (error instanceof RequestError) {
- * console.log(error.statusCode, error.message)
- * // Access raw response in error
- * console.log(error.response)
- *
- * if(error instanceof TooManyRequestsError) {
- * retryLater(error.retryAfter) // Needs to be implemented on your side
- * }
- * }
- * })
- * ```
- */
- async getRelatedVisitors(filter: RelatedVisitorsFilter): Promise {
- const url = getRequestPath({
- path: '/related-visitors',
- region: this.region,
- apiKey: this.getQueryApiKey(),
- method: 'get',
- queryParams: filter,
- })
- const headers = this.getHeaders()
-
- const response = await this.fetch(url, {
- method: 'GET',
- headers,
- })
-
- const jsonResponse = await copyResponseJson(response)
-
- if (response.status === 200) {
- return jsonResponse as RelatedVisitorsResponse
- }
-
- handleErrorResponse(jsonResponse, response)
- }
-
- private getHeaders() {
- return this.authenticationMode === AuthenticationMode.AuthHeader ? { 'Auth-API-Key': this.apiKey } : undefined
- }
-
- private getQueryApiKey() {
- return this.authenticationMode === AuthenticationMode.QueryParameter ? this.apiKey : undefined
- }
}
diff --git a/src/types.ts b/src/types.ts
index f684676f..854acc9d 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -6,11 +6,6 @@ export enum Region {
Global = 'Global',
}
-export enum AuthenticationMode {
- AuthHeader = 'AuthHeader',
- QueryParameter = 'QueryParameter',
-}
-
/**
* Options for FingerprintJS server API client
*/
@@ -23,11 +18,6 @@ export interface Options {
* Region of the FingerprintJS service server
*/
region?: Region | `${Region}`
- /**
- * Authentication mode
- * Optional, default value is AuthHeader
- */
- authenticationMode?: AuthenticationMode | `${AuthenticationMode}`
/**
* Optional fetch implementation
@@ -38,31 +28,26 @@ export interface Options {
/**
* More info: https://dev.fingerprintjs.com/docs/server-api#query-parameters
*/
+/*
export type VisitorHistoryFilter = paths['/visitors/{visitor_id}']['get']['parameters']['query']
+*/
-export type ErrorPlainResponse = components['schemas']['ErrorPlainResponse']
export type ErrorResponse = components['schemas']['ErrorResponse']
-export type SearchEventsFilter = paths['/events/search']['get']['parameters']['query']
-export type SearchEventsResponse = paths['/events/search']['get']['responses']['200']['content']['application/json']
+export type SearchEventsFilter = paths['/events']['get']['parameters']['query']
+export type SearchEventsResponse = components['schemas']['EventSearch']
/**
* More info: https://dev.fingerprintjs.com/docs/server-api#response
*/
-export type VisitorsResponse = paths['/visitors/{visitor_id}']['get']['responses']['200']['content']['application/json']
-
-export type EventsGetResponse = paths['/events/{request_id}']['get']['responses']['200']['content']['application/json']
-
-export type RelatedVisitorsResponse =
- paths['/related-visitors']['get']['responses']['200']['content']['application/json']
-export type RelatedVisitorsFilter = paths['/related-visitors']['get']['parameters']['query']
+export type EventsGetResponse = paths['/events/{event_id}']['get']['responses']['200']['content']['application/json']
/**
* More info: https://dev.fingerprintjs.com/docs/webhooks#identification-webhook-object-format
*/
-export type Webhook = components['schemas']['Webhook']
+export type Event = components['schemas']['Event']
-export type EventsUpdateRequest = components['schemas']['EventsUpdateRequest']
+export type EventUpdate = components['schemas']['EventUpdate']
// Extract just the `path` parameters as a tuple of strings
type ExtractPathParamStrings = Path extends { parameters: { path: infer P } }
@@ -78,6 +63,10 @@ export type ExtractQueryParams = Path extends { parameters: { query?: infe
: Q // Otherwise, it's required
: never // If no query parameters, return never
+type WebhookOperationIds = 'postEventWebhook'
+
+type ClientOperationKeys = Exclude
+
// Utility type to extract request body from an operation (for POST, PUT, etc.)
type ExtractRequestBody = Path extends { requestBody: { content: { 'application/json': infer B } } } ? B : never
@@ -90,7 +79,7 @@ type ExtractResponse = Path extends { responses: { 200: { content: { 'appl
type ApiMethodArgs = [
// If method has body, extract it as first parameter
...(ExtractRequestBody extends never ? [] : [body: ExtractRequestBody]),
- // Next are path params, e.g. for path "/events/{request_id}" it will be one string parameter,
+ // Next are path params, e.g. for path "/events/{event_id}" it will be one string parameter,
...ExtractPathParamStrings,
// Last parameter will be the query params, if any
...(ExtractQueryParams extends never ? [] : [params: ExtractQueryParams]),
@@ -101,5 +90,5 @@ type ApiMethod = (
) => Promise>
export type FingerprintApi = {
- [Path in keyof operations]: ApiMethod
+ [Operation in ClientOperationKeys]: ApiMethod
}
diff --git a/src/urlUtils.ts b/src/urlUtils.ts
index 5c07864c..400c4227 100644
--- a/src/urlUtils.ts
+++ b/src/urlUtils.ts
@@ -2,6 +2,8 @@ import { ExtractQueryParams, Region } from './types'
import { version } from '../package.json'
import { paths } from './generatedApiTypes'
+const apiVersion = 'v4'
+
const euRegionUrl = 'https://eu.api.fpjs.io/'
const apRegionUrl = 'https://ap.api.fpjs.io/'
const globalRegionUrl = 'https://api.fpjs.io/'
@@ -90,7 +92,6 @@ type QueryParams =
type GetRequestPathOptions = {
path: Path
method: Method
- apiKey?: string
region: Region
} & PathParams &
QueryParams
@@ -104,7 +105,6 @@ type GetRequestPathOptions} options
* @param {Path} options.path - The path of the API endpoint
* @param {string[]} [options.pathParams] - Path parameters to be replaced in the path
- * @param {string} [options.apiKey] - API key to be included in the query string
* @param {QueryParams["queryParams"]} [options.queryParams] - Query string
* parameters to be appended to the URL
* @param {Region} options.region - The region of the API endpoint
@@ -116,7 +116,6 @@ type GetRequestPathOptions({
path,
pathParams,
- apiKey,
queryParams,
region,
// method mention here so that it can be referenced in JSDoc
@@ -127,7 +126,7 @@ export function getRequestPath match[1])
// Step 2: Replace the placeholders with provided pathParams
- let formattedPath: string = path
+ let formattedPath: string = `${apiVersion}${path}`
placeholders.forEach((placeholder, index) => {
if (pathParams?.[index]) {
formattedPath = formattedPath.replace(`{${placeholder}}`, pathParams[index])
@@ -140,9 +139,6 @@ export function getRequestPath ts2) {
@@ -73,7 +81,7 @@ async function main() {
const recent = await getRecentEvents(client, start, end)
const [firstEvent] = recent.events
- await fetchEventAndVisitorDetails(client, firstEvent)
+ await fetchEventAndVisitorDetails(client, firstEvent, start, end)
await validateOldestOrder(client, start, end)
diff --git a/tests/mocked-responses-tests/castVisitorWebhookTest.spec.ts b/tests/mocked-responses-tests/castVisitorWebhookTest.spec.ts
deleted file mode 100644
index 96dbfee7..00000000
--- a/tests/mocked-responses-tests/castVisitorWebhookTest.spec.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { Webhook } from '../../src/types'
-import visitWebhookBody from './mocked-responses-data/webhook.json'
-
-describe('[Mocked body] Cast visitor webhook', () => {
- test('with sample request body', async () => {
- const visit = visitWebhookBody as Webhook
-
- // Assertion just to use the `visit` variable. The goal of this test is to assume that Typescript won't throw an error here.
- expect(visit).toBeTruthy()
- })
-})
diff --git a/tests/mocked-responses-tests/castWebhookEventTest.spec.ts b/tests/mocked-responses-tests/castWebhookEventTest.spec.ts
new file mode 100644
index 00000000..0b1c2299
--- /dev/null
+++ b/tests/mocked-responses-tests/castWebhookEventTest.spec.ts
@@ -0,0 +1,11 @@
+import { Event } from '../../src'
+import eventWebhookBody from './mocked-responses-data/webhook/webhook_event.json'
+
+describe('[Mocked body] Cast webhook event', () => {
+ test('with sample request body', async () => {
+ const event = eventWebhookBody as Event
+
+ // Assertion just to use the `event` variable. The goal of this test is to assume that Typescript won't throw an error here.
+ expect(event).toBeTruthy()
+ })
+})
diff --git a/tests/mocked-responses-tests/deleteVisitorDataTests.spec.ts b/tests/mocked-responses-tests/deleteVisitorDataTests.spec.ts
index b7d184e3..e609f557 100644
--- a/tests/mocked-responses-tests/deleteVisitorDataTests.spec.ts
+++ b/tests/mocked-responses-tests/deleteVisitorDataTests.spec.ts
@@ -7,7 +7,7 @@ import {
SdkError,
TooManyRequestsError,
} from '../../src'
-import Error404 from './mocked-responses-data/errors/404_request_not_found.json'
+import Error404 from './mocked-responses-data/errors/404_visitor_not_found.json'
import Error403 from './mocked-responses-data/errors/403_feature_not_enabled.json'
import Error400 from './mocked-responses-data/errors/400_visitor_id_invalid.json'
import Error429 from './mocked-responses-data/errors/429_too_many_requests.json'
@@ -30,9 +30,9 @@ describe('[Mocked response] Delete visitor data', () => {
expect(response).toBeUndefined()
expect(mockFetch).toHaveBeenCalledWith(
- `https://eu.api.fpjs.io/visitors/${existingVisitorId}?ii=${encodeURIComponent(getIntegrationInfo())}`,
+ `https://eu.api.fpjs.io/v4/visitors/${existingVisitorId}?ii=${encodeURIComponent(getIntegrationInfo())}`,
{
- headers: { 'Auth-API-Key': 'dummy_api_key' },
+ headers: { Authorization: `Bearer ${apiKey}` },
method: 'DELETE',
}
)
diff --git a/tests/mocked-responses-tests/getEventTests.spec.ts b/tests/mocked-responses-tests/getEventTests.spec.ts
index c3fe2ef7..bb58e384 100644
--- a/tests/mocked-responses-tests/getEventTests.spec.ts
+++ b/tests/mocked-responses-tests/getEventTests.spec.ts
@@ -1,54 +1,41 @@
-import { ErrorResponse, Region } from '../../src/types'
-import { FingerprintJsServerApiClient } from '../../src/serverApiClient'
-import getEventResponse from './mocked-responses-data/get_event_200.json'
-import getEventWithExtraFieldsResponse from './mocked-responses-data/get_event_200_extra_fields.json'
-import getEventAllErrorsResponse from './mocked-responses-data/get_event_200_all_errors.json'
-import { RequestError, SdkError } from '../../src/errors/apiErrors'
-import { getIntegrationInfo } from '../../src'
+import {
+ ErrorResponse,
+ FingerprintJsServerApiClient,
+ getIntegrationInfo,
+ Region,
+ RequestError,
+ SdkError,
+} from '../../src'
+import getEventResponse from './mocked-responses-data/events/get_event_200.json'
jest.spyOn(global, 'fetch')
const mockFetch = fetch as unknown as jest.Mock
describe('[Mocked response] Get Event', () => {
const apiKey = 'dummy_api_key'
- const existingRequestId = '1626550679751.cVc5Pm'
+ const existingEventId = '1626550679751.cVc5Pm'
const client = new FingerprintJsServerApiClient({ region: Region.EU, apiKey })
- test('with request_id', async () => {
+ test('with event_id', async () => {
mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getEventResponse))))
- const response = await client.getEvent(existingRequestId)
+ const response = await client.getEvent(existingEventId)
expect(mockFetch).toHaveBeenCalledWith(
- `https://eu.api.fpjs.io/events/${existingRequestId}?ii=${encodeURIComponent(getIntegrationInfo())}`,
+ `https://eu.api.fpjs.io/v4/events/${existingEventId}?ii=${encodeURIComponent(getIntegrationInfo())}`,
{
- headers: { 'Auth-API-Key': 'dummy_api_key' },
+ headers: { Authorization: `Bearer ${apiKey}` },
method: 'GET',
}
)
expect(response).toEqual(getEventResponse)
})
- test('with additional signals', async () => {
- mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getEventWithExtraFieldsResponse))))
-
- const response = await client.getEvent(existingRequestId)
- expect(response).toEqual(getEventWithExtraFieldsResponse)
- })
-
- test('with all signals with failed error', async () => {
- mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getEventAllErrorsResponse))))
-
- const response = await client.getEvent(existingRequestId)
-
- expect(response).toEqual(getEventAllErrorsResponse)
- })
-
test('403 error', async () => {
const errorInfo = {
error: {
- code: 'TokenRequired',
+ code: 'secret_api_key_required',
message: 'secret key is required',
},
} satisfies ErrorResponse
@@ -56,7 +43,7 @@ describe('[Mocked response] Get Event', () => {
status: 403,
})
mockFetch.mockReturnValue(Promise.resolve(mockResponse))
- await expect(client.getEvent(existingRequestId)).rejects.toThrow(
+ await expect(client.getEvent(existingEventId)).rejects.toThrow(
RequestError.fromErrorResponse(errorInfo, mockResponse)
)
})
@@ -64,7 +51,7 @@ describe('[Mocked response] Get Event', () => {
test('404 error', async () => {
const errorInfo = {
error: {
- code: 'RequestNotFound',
+ code: 'request_not_found',
message: 'request id is not found',
},
} satisfies ErrorResponse
@@ -72,24 +59,23 @@ describe('[Mocked response] Get Event', () => {
status: 404,
})
mockFetch.mockReturnValue(Promise.resolve(mockResponse))
- await expect(client.getEvent(existingRequestId)).rejects.toThrow(
+ await expect(client.getEvent(existingEventId)).rejects.toThrow(
RequestError.fromErrorResponse(errorInfo, mockResponse)
)
})
- test('Error with bad shape', async () => {
- const errorInfo = 'Some text instead of shaped object'
+ test('Error with unknown', async () => {
const mockResponse = new Response(
JSON.stringify({
- error: errorInfo,
+ error: 'Unexpected error format',
}),
{
status: 404,
}
)
mockFetch.mockReturnValue(Promise.resolve(mockResponse))
- await expect(client.getEvent(existingRequestId)).rejects.toThrow(RequestError)
- await expect(client.getEvent(existingRequestId)).rejects.toThrow('Some text instead of shaped object')
+ await expect(client.getEvent(existingEventId)).rejects.toThrow(RequestError)
+ await expect(client.getEvent(existingEventId)).rejects.toThrow('Unknown error')
})
test('Error with bad JSON', async () => {
@@ -98,7 +84,7 @@ describe('[Mocked response] Get Event', () => {
})
mockFetch.mockReturnValue(Promise.resolve(mockResponse))
- await expect(client.getEvent(existingRequestId)).rejects.toMatchObject(
+ await expect(client.getEvent(existingEventId)).rejects.toMatchObject(
new SdkError(
'Failed to parse JSON response',
mockResponse,
diff --git a/tests/mocked-responses-tests/getRelatedVisitorsTests.spec.ts b/tests/mocked-responses-tests/getRelatedVisitorsTests.spec.ts
deleted file mode 100644
index d543904a..00000000
--- a/tests/mocked-responses-tests/getRelatedVisitorsTests.spec.ts
+++ /dev/null
@@ -1,146 +0,0 @@
-import { ErrorResponse, Region } from '../../src/types'
-import { FingerprintJsServerApiClient } from '../../src/serverApiClient'
-import getRelatedVisitors from './mocked-responses-data/related-visitors/get_related_visitors_200.json'
-import { RequestError, SdkError, TooManyRequestsError } from '../../src/errors/apiErrors'
-import { getIntegrationInfo } from '../../src'
-
-jest.spyOn(global, 'fetch')
-
-const mockFetch = fetch as unknown as jest.Mock
-
-describe('[Mocked response] Get related Visitors', () => {
- const apiKey = 'dummy_api_key'
- const existingVisitorId = 'TaDnMBz9XCpZNuSzFUqP'
-
- const client = new FingerprintJsServerApiClient({ region: Region.EU, apiKey: apiKey })
-
- test('without filter', async () => {
- mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getRelatedVisitors))))
-
- const response = await client.getRelatedVisitors({
- visitor_id: existingVisitorId,
- })
- expect(response).toEqual(getRelatedVisitors)
- expect(mockFetch).toHaveBeenCalledWith(
- `https://eu.api.fpjs.io/related-visitors?visitor_id=${existingVisitorId}&ii=${encodeURIComponent(getIntegrationInfo())}`,
- {
- headers: { 'Auth-API-Key': 'dummy_api_key' },
- method: 'GET',
- }
- )
- })
-
- test('400 error', async () => {
- const error = {
- error: {
- message: 'Forbidden',
- code: 'RequestCannotBeParsed',
- },
- } satisfies ErrorResponse
- const mockResponse = new Response(JSON.stringify(error), {
- status: 400,
- })
- mockFetch.mockReturnValue(Promise.resolve(mockResponse))
- await expect(
- client.getRelatedVisitors({
- visitor_id: existingVisitorId,
- })
- ).rejects.toThrow(RequestError.fromErrorResponse(error, mockResponse))
- })
-
- test('403 error', async () => {
- const error = {
- error: {
- message: 'secret key is required',
- code: 'TokenRequired',
- },
- } satisfies ErrorResponse
- const mockResponse = new Response(JSON.stringify(error), {
- status: 403,
- })
- mockFetch.mockReturnValue(Promise.resolve(mockResponse))
- await expect(
- client.getRelatedVisitors({
- visitor_id: existingVisitorId,
- })
- ).rejects.toThrow(RequestError.fromErrorResponse(error, mockResponse))
- })
-
- test('404 error', async () => {
- const error = {
- error: {
- message: 'request id is not found',
- code: 'RequestNotFound',
- },
- } satisfies ErrorResponse
- const mockResponse = new Response(JSON.stringify(error), {
- status: 404,
- })
- mockFetch.mockReturnValue(Promise.resolve(mockResponse))
- await expect(
- client.getRelatedVisitors({
- visitor_id: existingVisitorId,
- })
- ).rejects.toThrow(RequestError.fromErrorResponse(error, mockResponse))
- })
-
- test('429 error', async () => {
- const error = {
- error: {
- message: 'Too Many Requests',
- code: 'TooManyRequests',
- },
- } satisfies ErrorResponse
- const mockResponse = new Response(JSON.stringify(error), {
- status: 429,
- headers: { 'Retry-after': '10' },
- })
- mockFetch.mockReturnValue(Promise.resolve(mockResponse))
-
- const expectedError = new TooManyRequestsError(error, mockResponse)
- await expect(
- client.getRelatedVisitors({
- visitor_id: existingVisitorId,
- })
- ).rejects.toThrow(expectedError)
- expect(expectedError.retryAfter).toEqual(10)
- })
-
- test('429 error with empty retry-after header', async () => {
- const error = {
- error: {
- message: 'Too Many Requests',
- code: 'TooManyRequests',
- },
- } satisfies ErrorResponse
- const mockResponse = new Response(JSON.stringify(error), {
- status: 429,
- })
- mockFetch.mockReturnValue(Promise.resolve(mockResponse))
- const expectedError = new TooManyRequestsError(error, mockResponse)
- await expect(
- client.getRelatedVisitors({
- visitor_id: existingVisitorId,
- })
- ).rejects.toThrow(expectedError)
- expect(expectedError.retryAfter).toEqual(0)
- })
-
- test('Error with bad JSON', async () => {
- const mockResponse = new Response('(Some bad JSON)', {
- status: 404,
- })
- mockFetch.mockReturnValue(Promise.resolve(mockResponse))
- await expect(
- client.getRelatedVisitors({
- visitor_id: existingVisitorId,
- })
- ).rejects.toMatchObject(
- new SdkError(
- 'Failed to parse JSON response',
- mockResponse,
- new SyntaxError('Unexpected token \'(\', "(Some bad JSON)" is not valid JSON')
- )
- )
- })
-})
diff --git a/tests/mocked-responses-tests/getVisitorsTests.spec.ts b/tests/mocked-responses-tests/getVisitorsTests.spec.ts
deleted file mode 100644
index 1f3eee29..00000000
--- a/tests/mocked-responses-tests/getVisitorsTests.spec.ts
+++ /dev/null
@@ -1,148 +0,0 @@
-import { ErrorPlainResponse, Region, VisitorHistoryFilter } from '../../src/types'
-import { FingerprintJsServerApiClient } from '../../src/serverApiClient'
-import getVisits from './mocked-responses-data/get_visitors_200_limit_1.json'
-import { RequestError, SdkError, TooManyRequestsError } from '../../src/errors/apiErrors'
-import { getIntegrationInfo } from '../../src'
-
-jest.spyOn(global, 'fetch')
-
-const mockFetch = fetch as unknown as jest.Mock
-
-describe('[Mocked response] Get Visitors', () => {
- const apiKey = 'dummy_api_key'
- const existingVisitorId = 'TaDnMBz9XCpZNuSzFUqP'
- const existingRequestId = '1626550679751.cVc5Pm'
- const existingLinkedId = 'makma'
-
- const client = new FingerprintJsServerApiClient({ region: Region.EU, apiKey: apiKey })
-
- test('without filter', async () => {
- mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getVisits))))
-
- const response = await client.getVisits(existingVisitorId)
- expect(response).toEqual(getVisits)
- expect(mockFetch).toHaveBeenCalledWith(
- `https://eu.api.fpjs.io/visitors/${existingVisitorId}?ii=${encodeURIComponent(getIntegrationInfo())}`,
- {
- headers: { 'Auth-API-Key': 'dummy_api_key' },
- method: 'GET',
- }
- )
- })
-
- test('with request_id filter', async () => {
- mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getVisits))))
-
- const filter: VisitorHistoryFilter = { request_id: existingRequestId }
- const response = await client.getVisits(existingVisitorId, filter)
- expect(mockFetch).toHaveBeenCalledWith(
- `https://eu.api.fpjs.io/visitors/${existingVisitorId}?request_id=${existingRequestId}&ii=${encodeURIComponent(getIntegrationInfo())}`,
- {
- headers: { 'Auth-API-Key': 'dummy_api_key' },
- method: 'GET',
- }
- )
- expect(response).toEqual(getVisits)
- })
-
- test('with request_id and linked_id filter', async () => {
- mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getVisits))))
-
- const filter: VisitorHistoryFilter = {
- request_id: existingRequestId,
- linked_id: existingLinkedId,
- }
- const response = await client.getVisits(existingVisitorId, filter)
- expect(mockFetch).toHaveBeenCalledWith(
- `https://eu.api.fpjs.io/visitors/${existingVisitorId}?request_id=${existingRequestId}&linked_id=${existingLinkedId}&ii=${encodeURIComponent(getIntegrationInfo())}`,
- {
- headers: { 'Auth-API-Key': 'dummy_api_key' },
- method: 'GET',
- }
- )
- expect(response).toEqual(getVisits)
- })
-
- test('with linked_id and limit filter', async () => {
- mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getVisits))))
-
- const filter: VisitorHistoryFilter = { linked_id: existingLinkedId, limit: 5 }
- const response = await client.getVisits(existingVisitorId, filter)
- expect(mockFetch).toHaveBeenCalledWith(
- `https://eu.api.fpjs.io/visitors/${existingVisitorId}?linked_id=${existingLinkedId}&limit=5&ii=${encodeURIComponent(getIntegrationInfo())}`,
- {
- headers: { 'Auth-API-Key': 'dummy_api_key' },
- method: 'GET',
- }
- )
- expect(response).toEqual(getVisits)
- })
-
- test('with limit and before', async () => {
- mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getVisits))))
-
- const filter: VisitorHistoryFilter = { limit: 4, before: 1626538505244 }
- const response = await client.getVisits(existingVisitorId, filter)
- expect(mockFetch).toHaveBeenCalledWith(
- `https://eu.api.fpjs.io/visitors/${existingVisitorId}?limit=4&before=1626538505244&ii=${encodeURIComponent(getIntegrationInfo())}`,
- {
- headers: { 'Auth-API-Key': 'dummy_api_key' },
- method: 'GET',
- }
- )
- expect(response).toEqual(getVisits)
- })
-
- test('403 error', async () => {
- const error = {
- error: 'Forbidden',
- } satisfies ErrorPlainResponse
- const mockResponse = new Response(JSON.stringify(error), {
- status: 403,
- })
- mockFetch.mockReturnValue(Promise.resolve(mockResponse))
- await expect(client.getVisits(existingVisitorId)).rejects.toThrow(RequestError.fromPlainError(error, mockResponse))
- })
-
- test('429 error', async () => {
- const error = {
- error: 'Too Many Requests',
- }
- const mockResponse = new Response(JSON.stringify(error), {
- status: 429,
- headers: { 'Retry-after': '10' },
- })
- mockFetch.mockReturnValue(Promise.resolve(mockResponse))
-
- const expectedError = TooManyRequestsError.fromPlain(error, mockResponse)
- await expect(client.getVisits(existingVisitorId)).rejects.toThrow(expectedError)
- expect(expectedError.retryAfter).toEqual(10)
- })
-
- test('429 error with empty retry-after header', async () => {
- const error = {
- error: 'Too Many Requests',
- } satisfies ErrorPlainResponse
- const mockResponse = new Response(JSON.stringify(error), {
- status: 429,
- })
- mockFetch.mockReturnValue(Promise.resolve(mockResponse))
- const expectedError = TooManyRequestsError.fromPlain(error, mockResponse)
- await expect(client.getVisits(existingVisitorId)).rejects.toThrow(expectedError)
- expect(expectedError.retryAfter).toEqual(0)
- })
-
- test('Error with bad JSON', async () => {
- const mockResponse = new Response('(Some bad JSON)', {
- status: 404,
- })
- mockFetch.mockReturnValue(Promise.resolve(mockResponse))
- await expect(client.getVisits(existingVisitorId)).rejects.toMatchObject(
- new SdkError(
- 'Failed to parse JSON response',
- mockResponse,
- new SyntaxError('Unexpected token \'(\', "(Some bad JSON)" is not valid JSON')
- )
- )
- })
-})
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/400_bot_type_invalid.json b/tests/mocked-responses-tests/mocked-responses-data/errors/400_bot_type_invalid.json
deleted file mode 100644
index 8dd65266..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/400_bot_type_invalid.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "error": {
- "code": "RequestCannotBeParsed",
- "message": "invalid bot type"
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/400_end_time_invalid.json b/tests/mocked-responses-tests/mocked-responses-data/errors/400_end_time_invalid.json
deleted file mode 100644
index 88654093..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/400_end_time_invalid.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "error": {
- "code": "RequestCannotBeParsed",
- "message": "invalid end time"
- }
-}
\ No newline at end of file
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/400_ip_address_invalid.json b/tests/mocked-responses-tests/mocked-responses-data/errors/400_ip_address_invalid.json
deleted file mode 100644
index 5969bab6..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/400_ip_address_invalid.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "error": {
- "code": "RequestCannotBeParsed",
- "message": "invalid ip address"
- }
-}
\ No newline at end of file
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/400_limit_invalid.json b/tests/mocked-responses-tests/mocked-responses-data/errors/400_limit_invalid.json
deleted file mode 100644
index 46297eb4..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/400_limit_invalid.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "error": {
- "code": "RequestCannotBeParsed",
- "message": "invalid limit"
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/400_linked_id_invalid.json b/tests/mocked-responses-tests/mocked-responses-data/errors/400_linked_id_invalid.json
deleted file mode 100644
index 72de54e0..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/400_linked_id_invalid.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "error": {
- "code": "RequestCannotBeParsed",
- "message": "linked_id can't be greater than 256 characters long"
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/400_pagination_key_invalid.json b/tests/mocked-responses-tests/mocked-responses-data/errors/400_pagination_key_invalid.json
deleted file mode 100644
index df559f9a..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/400_pagination_key_invalid.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "error": {
- "code": "RequestCannotBeParsed",
- "message": "invalid pagination key"
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/400_request_body_invalid.json b/tests/mocked-responses-tests/mocked-responses-data/errors/400_request_body_invalid.json
index ce56deff..c71fae96 100644
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/400_request_body_invalid.json
+++ b/tests/mocked-responses-tests/mocked-responses-data/errors/400_request_body_invalid.json
@@ -1,6 +1,6 @@
{
"error": {
- "code": "RequestCannotBeParsed",
+ "code": "request_cannot_be_parsed",
"message": "request body is not valid"
}
}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/400_reverse_invalid.json b/tests/mocked-responses-tests/mocked-responses-data/errors/400_reverse_invalid.json
deleted file mode 100644
index 540800fa..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/400_reverse_invalid.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "error": {
- "code": "RequestCannotBeParsed",
- "message": "invalid reverse param"
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/400_start_time_invalid.json b/tests/mocked-responses-tests/mocked-responses-data/errors/400_start_time_invalid.json
deleted file mode 100644
index 5d93f929..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/400_start_time_invalid.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "error": {
- "code": "RequestCannotBeParsed",
- "message": "invalid start time"
- }
-}
\ No newline at end of file
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/400_visitor_id_invalid.json b/tests/mocked-responses-tests/mocked-responses-data/errors/400_visitor_id_invalid.json
index c204c568..ae7a3596 100644
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/400_visitor_id_invalid.json
+++ b/tests/mocked-responses-tests/mocked-responses-data/errors/400_visitor_id_invalid.json
@@ -1,6 +1,6 @@
{
"error": {
- "code": "RequestCannotBeParsed",
+ "code": "request_cannot_be_parsed",
"message": "invalid visitor id"
}
}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/400_visitor_id_required.json b/tests/mocked-responses-tests/mocked-responses-data/errors/400_visitor_id_required.json
deleted file mode 100644
index 6c5801a0..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/400_visitor_id_required.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "error": {
- "code": "RequestCannotBeParsed",
- "message": "visitor id is required"
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/403_feature_not_enabled.json b/tests/mocked-responses-tests/mocked-responses-data/errors/403_feature_not_enabled.json
index 9820a568..1478d51d 100644
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/403_feature_not_enabled.json
+++ b/tests/mocked-responses-tests/mocked-responses-data/errors/403_feature_not_enabled.json
@@ -1,6 +1,6 @@
{
"error": {
- "code": "FeatureNotEnabled",
+ "code": "feature_not_enabled",
"message": "feature not enabled"
}
}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/403_subscription_not_active.json b/tests/mocked-responses-tests/mocked-responses-data/errors/403_subscription_not_active.json
deleted file mode 100644
index 3deac898..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/403_subscription_not_active.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "error": {
- "code": "SubscriptionNotActive",
- "message": "forbidden"
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/403_token_not_found.json b/tests/mocked-responses-tests/mocked-responses-data/errors/403_token_not_found.json
deleted file mode 100644
index 3936b530..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/403_token_not_found.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "error": {
- "code": "TokenNotFound",
- "message": "secret key is not found"
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/403_token_required.json b/tests/mocked-responses-tests/mocked-responses-data/errors/403_token_required.json
deleted file mode 100644
index 544d8714..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/403_token_required.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "error": {
- "code": "TokenRequired",
- "message": "secret key is required"
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/403_wrong_region.json b/tests/mocked-responses-tests/mocked-responses-data/errors/403_wrong_region.json
deleted file mode 100644
index 8acc9e01..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/403_wrong_region.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "error": {
- "code": "WrongRegion",
- "message": "wrong region"
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/404_event_not_found.json b/tests/mocked-responses-tests/mocked-responses-data/errors/404_event_not_found.json
new file mode 100644
index 00000000..f7f7e542
--- /dev/null
+++ b/tests/mocked-responses-tests/mocked-responses-data/errors/404_event_not_found.json
@@ -0,0 +1,6 @@
+{
+ "error": {
+ "code": "event_not_found",
+ "message": "event id not found"
+ }
+}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/404_request_not_found.json b/tests/mocked-responses-tests/mocked-responses-data/errors/404_request_not_found.json
deleted file mode 100644
index 389b351c..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/404_request_not_found.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "error": {
- "code": "RequestNotFound",
- "message": "request id is not found"
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/404_visitor_not_found.json b/tests/mocked-responses-tests/mocked-responses-data/errors/404_visitor_not_found.json
index 11da4f3d..e4076f4f 100644
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/404_visitor_not_found.json
+++ b/tests/mocked-responses-tests/mocked-responses-data/errors/404_visitor_not_found.json
@@ -1,6 +1,6 @@
{
"error": {
- "code": "VisitorNotFound",
+ "code": "visitor_not_found",
"message": "visitor not found"
}
}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/409_state_not_ready.json b/tests/mocked-responses-tests/mocked-responses-data/errors/409_state_not_ready.json
index 36e6dde3..4ba3ac53 100644
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/409_state_not_ready.json
+++ b/tests/mocked-responses-tests/mocked-responses-data/errors/409_state_not_ready.json
@@ -1,6 +1,6 @@
{
"error": {
- "code": "StateNotReady",
+ "code": "state_not_ready",
"message": "resource is not mutable yet, try again"
}
}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/errors/429_too_many_requests.json b/tests/mocked-responses-tests/mocked-responses-data/errors/429_too_many_requests.json
index e38639aa..bbbc7c41 100644
--- a/tests/mocked-responses-tests/mocked-responses-data/errors/429_too_many_requests.json
+++ b/tests/mocked-responses-tests/mocked-responses-data/errors/429_too_many_requests.json
@@ -1,6 +1,6 @@
{
"error": {
- "code": "TooManyRequests",
+ "code": "too_many_requests",
"message": "too many requests"
}
}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/events/get_event_200.json b/tests/mocked-responses-tests/mocked-responses-data/events/get_event_200.json
new file mode 100644
index 00000000..5cb733e5
--- /dev/null
+++ b/tests/mocked-responses-tests/mocked-responses-data/events/get_event_200.json
@@ -0,0 +1,178 @@
+{
+ "linked_id": "somelinkedId",
+ "tags": {},
+ "timestamp": 1708102555327,
+ "event_id": "1708102555327.NLOjmg",
+ "url": "https://www.example.com/login?hope{this{works[!",
+ "ip_address": "61.127.217.15",
+ "user_agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) ....",
+ "browser_details": {
+ "browser_name": "Chrome",
+ "browser_major_version": "74",
+ "browser_full_version": "74.0.3729",
+ "os": "Windows",
+ "os_version": "7",
+ "device": "Other"
+ },
+ "identification": {
+ "visitor_id": "Ibk1527CUFmcnjLwIs4A9",
+ "confidence": {
+ "score": 0.97,
+ "version": "1.1"
+ },
+ "visitor_found": false,
+ "first_seen_at": 1708102555327,
+ "last_seen_at": 1708102555327
+ },
+ "supplementary_id_high_recall": {
+ "visitor_id": "3HNey93AkBW6CRbxV6xP",
+ "visitor_found": true,
+ "confidence": {
+ "score": 0.97,
+ "version": "1.1"
+ },
+ "first_seen_at": 1708102555327,
+ "last_seen_at": 1708102555327
+ },
+ "bot": "not_detected",
+ "root_apps": false,
+ "emulator": false,
+ "ip_info": {
+ "v4": {
+ "address": "94.142.239.124",
+ "geolocation": {
+ "accuracy_radius": 20,
+ "latitude": 50.05,
+ "longitude": 14.4,
+ "postal_code": "150 00",
+ "timezone": "Europe/Prague",
+ "city_name": "Prague",
+ "country_code": "CZ",
+ "country_name": "Czechia",
+ "continent_code": "EU",
+ "continent_name": "Europe",
+ "subdivisions": [
+ {
+ "iso_code": "10",
+ "name": "Hlavni mesto Praha"
+ }
+ ]
+ },
+ "asn": "7922",
+ "asn_name": "COMCAST-7922",
+ "asn_network": "73.136.0.0/13",
+ "datacenter_result": true,
+ "datacenter_name": "DediPath"
+ },
+ "v6": {
+ "address": "2001:db8:3333:4444:5555:6666:7777:8888",
+ "geolocation": {
+ "accuracy_radius": 5,
+ "latitude": 49.982,
+ "longitude": 36.2566,
+ "postal_code": "10112",
+ "timezone": "Europe/Berlin",
+ "city_name": "Berlin",
+ "country_code": "DE",
+ "country_name": "Germany",
+ "continent_code": "EU",
+ "continent_name": "Europe",
+ "subdivisions": [
+ {
+ "iso_code": "BE",
+ "name": "Land Berlin"
+ }
+ ]
+ },
+ "asn": "6805",
+ "asn_name": "Telefonica Germany",
+ "asn_network": "2a02:3100::/24",
+ "datacenter_result": false,
+ "datacenter_name": ""
+ }
+ },
+ "ip_blocklist": {
+ "email_spam": false,
+ "attack_source": false,
+ "tor_node": false
+ },
+ "proxy": true,
+ "proxy_confidence": "low",
+ "proxy_details": {
+ "proxy_type": "residential",
+ "last_seen_at": 1708102555327
+ },
+ "vpn": false,
+ "vpn_confidence": "high",
+ "vpn_origin_timezone": "Europe/Berlin",
+ "vpn_origin_country": "unknown",
+ "vpn_methods": {
+ "timezone_mismatch": false,
+ "public_vpn": false,
+ "auxiliary_mobile": false,
+ "os_mismatch": false,
+ "relay": false
+ },
+ "incognito": false,
+ "tampering": false,
+ "tampering_details" : {
+ "anomaly_score": 0.1955,
+ "anti_detect_browser": false
+ },
+ "cloned_app": false,
+ "factory_reset_timestamp": 0,
+ "jailbroken": false,
+ "frida": false,
+ "privacy_settings": false,
+ "virtual_machine": false,
+ "location_spoofing": false,
+ "velocity": {
+ "distinct_ip": {
+ "5_minutes": 1,
+ "1_hour": 1,
+ "24_hours": 1
+ },
+ "distinct_country": {
+ "5_minutes": 1,
+ "1_hour": 2,
+ "24_hours": 2
+ },
+ "events": {
+ "5_minutes": 1,
+ "1_hour": 5,
+ "24_hours": 5
+ },
+ "ip_events": {
+ "5_minutes": 1,
+ "1_hour": 5,
+ "24_hours": 5
+ },
+ "distinct_ip_by_linked_id": {
+ "5_minutes": 1,
+ "1_hour": 5,
+ "24_hours": 5
+ },
+ "distinct_visitor_id_by_linked_id": {
+ "5_minutes": 1,
+ "1_hour": 5,
+ "24_hours": 5
+ }
+ },
+ "developer_tools": false,
+ "mitm_attack": false,
+ "sdk": {
+ "platform": "js",
+ "version": "3.11.10",
+ "integrations": [
+ {
+ "name": "fingerprint-pro-react",
+ "version": "3.11.10",
+ "subintegration": {
+ "name": "preact",
+ "version": "10.21.0"
+ }
+ }
+ ]
+ },
+ "replayed": false
+}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/events/search/get_event_search_200.json b/tests/mocked-responses-tests/mocked-responses-data/events/search/get_event_search_200.json
new file mode 100644
index 00000000..f72e99d1
--- /dev/null
+++ b/tests/mocked-responses-tests/mocked-responses-data/events/search/get_event_search_200.json
@@ -0,0 +1,183 @@
+{
+ "events": [
+ {
+ "linked_id": "somelinkedId",
+ "tags": {},
+ "timestamp": 1708102555327,
+ "event_id": "1708102555327.NLOjmg",
+ "url": "https://www.example.com/login?hope{this{works[!",
+ "ip_address": "61.127.217.15",
+ "user_agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) ....",
+ "browser_details": {
+ "browser_name": "Chrome",
+ "browser_major_version": "74",
+ "browser_full_version": "74.0.3729",
+ "os": "Windows",
+ "os_version": "7",
+ "device": "Other"
+ },
+ "identification": {
+ "visitor_id": "Ibk1527CUFmcnjLwIs4A9",
+ "confidence": {
+ "score": 0.97,
+ "version": "1.1"
+ },
+ "visitor_found": false,
+ "first_seen_at": 1708102555327,
+ "last_seen_at": 1708102555327
+ },
+ "supplementary_id_high_recall": {
+ "visitor_id": "3HNey93AkBW6CRbxV6xP",
+ "visitor_found": true,
+ "confidence": {
+ "score": 0.97,
+ "version": "1.1"
+ },
+ "first_seen_at": 1708102555327,
+ "last_seen_at": 1708102555327
+ },
+ "bot": "not_detected",
+ "root_apps": false,
+ "emulator": false,
+ "ip_info": {
+ "v4": {
+ "address": "94.142.239.124",
+ "geolocation": {
+ "accuracy_radius": 20,
+ "latitude": 50.05,
+ "longitude": 14.4,
+ "postal_code": "150 00",
+ "timezone": "Europe/Prague",
+ "city_name": "Prague",
+ "country_code": "CZ",
+ "country_name": "Czechia",
+ "continent_code": "EU",
+ "continent_name": "Europe",
+ "subdivisions": [
+ {
+ "iso_code": "10",
+ "name": "Hlavni mesto Praha"
+ }
+ ]
+ },
+ "asn": "7922",
+ "asn_name": "COMCAST-7922",
+ "asn_network": "73.136.0.0/13",
+ "datacenter_result": true,
+ "datacenter_name": "DediPath"
+ },
+ "v6": {
+ "address": "2001:db8:3333:4444:5555:6666:7777:8888",
+ "geolocation": {
+ "accuracy_radius": 5,
+ "latitude": 49.982,
+ "longitude": 36.2566,
+ "postal_code": "10112",
+ "timezone": "Europe/Berlin",
+ "city_name": "Berlin",
+ "country_code": "DE",
+ "country_name": "Germany",
+ "continent_code": "EU",
+ "continent_name": "Europe",
+ "subdivisions": [
+ {
+ "iso_code": "BE",
+ "name": "Land Berlin"
+ }
+ ]
+ },
+ "asn": "6805",
+ "asn_name": "Telefonica Germany",
+ "asn_network": "2a02:3100::/24",
+ "datacenter_result": false,
+ "datacenter_name": ""
+ }
+ },
+ "ip_blocklist": {
+ "email_spam": false,
+ "attack_source": false,
+ "tor_node": false
+ },
+ "proxy": true,
+ "proxy_confidence": "low",
+ "proxy_details": {
+ "proxy_type": "residential",
+ "last_seen_at": 1708102555327
+ },
+ "vpn": false,
+ "vpn_confidence": "high",
+ "vpn_origin_timezone": "Europe/Berlin",
+ "vpn_origin_country": "unknown",
+ "vpn_methods": {
+ "timezone_mismatch": false,
+ "public_vpn": false,
+ "auxiliary_mobile": false,
+ "os_mismatch": false,
+ "relay": false
+ },
+ "incognito": false,
+ "tampering": false,
+ "tampering_details": {
+ "anomaly_score": 0.1955,
+ "anti_detect_browser": false
+ },
+ "cloned_app": false,
+ "factory_reset_timestamp": 0,
+ "jailbroken": false,
+ "frida": false,
+ "privacy_settings": false,
+ "virtual_machine": false,
+ "location_spoofing": false,
+ "velocity": {
+ "distinct_ip": {
+ "5_minutes": 1,
+ "1_hour": 1,
+ "24_hours": 1
+ },
+ "distinct_country": {
+ "5_minutes": 1,
+ "1_hour": 2,
+ "24_hours": 2
+ },
+ "events": {
+ "5_minutes": 1,
+ "1_hour": 5,
+ "24_hours": 5
+ },
+ "ip_events": {
+ "5_minutes": 1,
+ "1_hour": 5,
+ "24_hours": 5
+ },
+ "distinct_ip_by_linked_id": {
+ "5_minutes": 1,
+ "1_hour": 5,
+ "24_hours": 5
+ },
+ "distinct_visitor_id_by_linked_id": {
+ "5_minutes": 1,
+ "1_hour": 5,
+ "24_hours": 5
+ }
+ },
+ "developer_tools": false,
+ "mitm_attack": false,
+ "sdk": {
+ "platform": "js",
+ "version": "3.11.10",
+ "integrations": [
+ {
+ "name": "fingerprint-pro-react",
+ "version": "3.11.10",
+ "subintegration": {
+ "name": "preact",
+ "version": "10.21.0"
+ }
+ }
+ ]
+ },
+ "replayed": false
+ }
+ ],
+ "pagination_key": "1708102555327"
+}
\ No newline at end of file
diff --git a/tests/mocked-responses-tests/mocked-responses-data/get_event_200.json b/tests/mocked-responses-tests/mocked-responses-data/get_event_200.json
deleted file mode 100644
index 7560b9a6..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/get_event_200.json
+++ /dev/null
@@ -1,354 +0,0 @@
-{
- "products": {
- "identification": {
- "data": {
- "visitorId": "Ibk1527CUFmcnjLwIs4A9",
- "requestId": "1708102555327.NLOjmg",
- "incognito": true,
- "linkedId": "somelinkedId",
- "tag": {},
- "time": "2019-05-21T16:40:13Z",
- "timestamp": 1582299576512,
- "url": "https://www.example.com/login?hope{this{works[!",
- "ip": "61.127.217.15",
- "ipLocation": {
- "accuracyRadius": 10,
- "latitude": 49.982,
- "longitude": 36.2566,
- "postalCode": "61202",
- "timezone": "Europe/Dusseldorf",
- "city": {
- "name": "Dusseldorf"
- },
- "country": {
- "code": "DE",
- "name": "Germany"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "63",
- "name": "North Rhine-Westphalia"
- }
- ]
- },
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "74",
- "browserFullVersion": "74.0.3729",
- "os": "Windows",
- "osVersion": "7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) ...."
- },
- "confidence": {
- "score": 0.97
- },
- "visitorFound": false,
- "firstSeenAt": {
- "global": "2022-03-16T11:26:45.362Z",
- "subscription": "2022-03-16T11:31:01.101Z"
- },
- "lastSeenAt": {
- "global": null,
- "subscription": null
- },
- "sdk": {
- "platform": "js",
- "version": "3.11.10"
- },
- "replayed": false
- }
- },
- "botd": {
- "data": {
- "bot": {
- "result": "notDetected"
- },
- "url": "https://www.example.com/login?hope{this{works}[!",
- "ip": "61.127.217.15",
- "time": "2019-05-21T16:40:13Z",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 YaBrowser/24.1.0.0 Safari/537.36",
- "requestId": "1708102555327.NLOjmg"
- }
- },
- "rootApps": {
- "data": {
- "result": false
- }
- },
- "emulator": {
- "data": {
- "result": false
- }
- },
- "ipInfo": {
- "data": {
- "v4": {
- "address": "94.142.239.124",
- "geolocation": {
- "accuracyRadius": 20,
- "latitude": 50.05,
- "longitude": 14.4,
- "postalCode": "150 00",
- "timezone": "Europe/Prague",
- "city": {
- "name": "Prague"
- },
- "country": {
- "code": "CZ",
- "name": "Czechia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "10",
- "name": "Hlavni mesto Praha"
- }
- ]
- },
- "asn": {
- "asn": "7922",
- "name": "COMCAST-7922",
- "network": "73.136.0.0/13"
- },
- "datacenter": {
- "result": true,
- "name": "DediPath"
- }
- },
- "v6": {
- "address": "2001:db8:3333:4444:5555:6666:7777:8888",
- "geolocation": {
- "accuracyRadius": 5,
- "latitude": 49.982,
- "longitude": 36.2566,
- "postalCode": "10112",
- "timezone": "Europe/Berlin",
- "city": {
- "name": "Berlin"
- },
- "country": {
- "code": "DE",
- "name": "Germany"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "BE",
- "name": "Land Berlin"
- }
- ]
- },
- "asn": {
- "asn": "6805",
- "name": "Telefonica Germany",
- "network": "2a02:3100::/24"
- },
- "datacenter": {
- "result": false,
- "name": ""
- }
- }
- }
- },
- "ipBlocklist": {
- "data": {
- "result": false,
- "details": {
- "emailSpam": false,
- "attackSource": false
- }
- }
- },
- "tor": {
- "data": {
- "result": false
- }
- },
- "vpn": {
- "data": {
- "result": false,
- "confidence": "high",
- "originTimezone": "Europe/Berlin",
- "originCountry": "unknown",
- "methods": {
- "timezoneMismatch": false,
- "publicVPN": false,
- "auxiliaryMobile": false,
- "osMismatch": false,
- "relay": false
- }
- }
- },
- "proxy": {
- "data": {
- "result": true,
- "confidence": "high",
- "details": {
- "proxyType": "residential",
- "lastSeenAt": "2025-08-12T13:00:00Z"
- }
- }
- },
- "incognito": {
- "data": {
- "result": false
- }
- },
- "tampering": {
- "data": {
- "result": false,
- "anomalyScore": 0.1955,
- "antiDetectBrowser": false
- }
- },
- "clonedApp": {
- "data": {
- "result": false
- }
- },
- "factoryReset": {
- "data": {
- "time": "1970-01-01T00:00:00Z",
- "timestamp": 0
- }
- },
- "jailbroken": {
- "data": {
- "result": false
- }
- },
- "frida": {
- "data": {
- "result": false
- }
- },
- "privacySettings": {
- "data": {
- "result": false
- }
- },
- "virtualMachine": {
- "data": {
- "result": false
- }
- },
- "rawDeviceAttributes": {
- "data": {
- "architecture": {
- "value": 127
- },
- "audio": {
- "value": 35.73832903057337
- },
- "canvas": {
- "value": {
- "Winding": true,
- "Geometry": "4dce9d6017c3e0c052a77252f29f2b1c",
- "Text": "dd2474a56ff78c1de3e7a07070ba3b7d"
- }
- },
- "colorDepth": {
- "value": 30
- },
- "colorGamut": {
- "value": "p3"
- },
- "contrast": {
- "value": 0
- },
- "cookiesEnabled": {
- "value": true
- },
- "cpuClass": {},
- "fonts": {
- "value": ["Arial Unicode MS", "Gill Sans", "Helvetica Neue", "Menlo"]
- }
- }
- },
- "highActivity": {
- "data": {
- "result": false
- }
- },
- "locationSpoofing": {
- "data": {
- "result": false
- }
- },
- "velocity": {
- "data": {
- "distinctIp": {
- "intervals": {
- "5m": 1,
- "1h": 1,
- "24h": 1
- }
- },
- "distinctLinkedId": {},
- "distinctCountry": {
- "intervals": {
- "5m": 1,
- "1h": 2,
- "24h": 2
- }
- },
- "events": {
- "intervals": {
- "5m": 1,
- "1h": 5,
- "24h": 5
- }
- },
- "ipEvents": {
- "intervals": {
- "5m": 1,
- "1h": 5,
- "24h": 5
- }
- },
- "distinctIpByLinkedId": {
- "intervals": {
- "5m": 1,
- "1h": 5,
- "24h": 5
- }
- },
- "distinctVisitorIdByLinkedId": {
- "intervals": {
- "5m": 1,
- "1h": 5,
- "24h": 5
- }
- }
- }
- },
- "developerTools": {
- "data": {
- "result": false
- }
- },
- "mitmAttack": {
- "data": {
- "result": false
- }
- },
- "proximity": {
- "data": {
- "id": "w1aTfd4MCvl",
- "precisionRadius": 10,
- "confidence": 0.95
- }
- }
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/get_event_200_all_errors.json b/tests/mocked-responses-tests/mocked-responses-data/get_event_200_all_errors.json
deleted file mode 100644
index 15ea2037..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/get_event_200_all_errors.json
+++ /dev/null
@@ -1,164 +0,0 @@
-{
- "products": {
- "identification": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "botd": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "ipInfo": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "incognito": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "rootApps": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "clonedApp": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "factoryReset": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "jailbroken": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "frida": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "emulator": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "ipBlocklist": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "tor": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "vpn": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "proxy": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "privacySettings": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "virtualMachine": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "tampering": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "rawDeviceAttributes": {
- "data": {
- "audio": {
- "error": {
- "name": "Error",
- "message": "internal server error"
- }
- },
- "canvas": {
- "error": {
- "name": "Error",
- "message": "internal server error"
- }
- }
- }
- },
- "locationSpoofing": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "highActivity": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "suspectScore": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "velocity": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "developerTools": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "mitmAttack": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "proximity": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- }
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/get_event_200_botd_failed_error.json b/tests/mocked-responses-tests/mocked-responses-data/get_event_200_botd_failed_error.json
deleted file mode 100644
index 0afa5b79..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/get_event_200_botd_failed_error.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "products": {
- "identification": {
- "data": {
- "visitorId": "Ibk1527CUFmcnjLwIs4A9",
- "requestId": "0KSh65EnVoB85JBmloQK",
- "incognito": true,
- "linkedId": "somelinkedId",
- "time": "2019-05-21T16:40:13Z",
- "tag": {},
- "timestamp": 1582299576512,
- "url": "https://www.example.com/login",
- "ip": "61.127.217.15",
- "ipLocation": {
- "accuracyRadius": 10,
- "latitude": 49.982,
- "longitude": 36.2566,
- "postalCode": "61202",
- "timezone": "Europe/Dusseldorf",
- "city": {
- "name": "Dusseldorf"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "country": {
- "code": "DE",
- "name": "Germany"
- },
- "subdivisions": [
- {
- "isoCode": "63",
- "name": "North Rhine-Westphalia"
- }
- ]
- },
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "74",
- "browserFullVersion": "74.0.3729",
- "os": "Windows",
- "osVersion": "7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) ...."
- },
- "confidence": {
- "score": 0.97
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-03-16T11:26:45.362Z",
- "subscription": "2022-03-16T11:31:01.101Z"
- },
- "lastSeenAt": {
- "global": "2022-03-16T11:28:34.023Z",
- "subscription": null
- },
- "replayed": false
- }
- },
- "botd": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- }
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/get_event_200_extra_fields.json b/tests/mocked-responses-tests/mocked-responses-data/get_event_200_extra_fields.json
deleted file mode 100644
index 5a56a1c7..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/get_event_200_extra_fields.json
+++ /dev/null
@@ -1,91 +0,0 @@
-{
- "products": {
- "identification": {
- "data": {
- "visitorId": "Ibk1527CUFmcnjLwIs4A9",
- "requestId": "0KSh65EnVoB85JBmloQK",
- "incognito": true,
- "linkedId": "somelinkedId",
- "tag": {},
- "time": "2019-05-21T16:40:13Z",
- "timestamp": 1582299576512,
- "url": "https://www.example.com/login",
- "ip": "61.127.217.15",
- "ipLocation": {
- "accuracyRadius": 10,
- "latitude": 49.982,
- "longitude": 36.2566,
- "postalCode": "61202",
- "timezone": "Europe/Dusseldorf",
- "city": {
- "name": "Dusseldorf"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "country": {
- "code": "DE",
- "name": "Germany"
- },
- "subdivisions": [
- {
- "isoCode": "63",
- "name": "North Rhine-Westphalia"
- }
- ]
- },
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "74",
- "browserFullVersion": "74.0.3729",
- "os": "Windows",
- "osVersion": "7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) ...."
- },
- "confidence": {
- "score": 0.97,
- "revision": "v1.1"
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-03-16T11:26:45.362Z",
- "subscription": "2022-03-16T11:31:01.101Z"
- },
- "lastSeenAt": {
- "global": "2022-03-16T11:28:34.023Z",
- "subscription": null
- },
- "replayed": false
- }
- },
- "botd": {
- "data": {
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 YaBrowser/24.1.0.0 Safari/537.36",
- "requestId": "1708102555327.NLOjmg",
- "bot": {
- "result": "notDetected"
- },
- "url": "https://www.example.com/login",
- "ip": "61.127.217.15",
- "time": "2019-05-21T16:40:13Z"
- }
- },
- "product3": {
- "data": {
- "result": false
- }
- },
- "product4": {
- "data": {
- "result": true,
- "details": {
- "detail1": true,
- "detail2": "detail description",
- "detail3": 42
- }
- }
- }
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/get_event_200_identification_failed_error.json b/tests/mocked-responses-tests/mocked-responses-data/get_event_200_identification_failed_error.json
deleted file mode 100644
index 4739f36e..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/get_event_200_identification_failed_error.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "products": {
- "identification": {
- "error": {
- "code": "Failed",
- "message": "internal server error"
- }
- },
- "botd": {
- "data": {
- "bot": {
- "result": "bad",
- "type": "headlessChrome"
- },
- "url": "https://example.com/login",
- "ip": "94.60.143.223",
- "time": "2024-02-23T10:20:25.287Z",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/121.0.6167.57 Safari/537.36",
- "requestId": "1708683625245.tuJ4nD"
- }
- }
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/get_event_200_too_many_requests_error.json b/tests/mocked-responses-tests/mocked-responses-data/get_event_200_too_many_requests_error.json
deleted file mode 100644
index 138aae72..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/get_event_200_too_many_requests_error.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "products": {
- "identification": {
- "error": {
- "code": "429 Too Many Requests",
- "message": "too many requests"
- }
- },
- "botd": {
- "error": {
- "code": "TooManyRequests",
- "message": "too many requests"
- }
- }
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/get_event_200_with_broken_format.json b/tests/mocked-responses-tests/mocked-responses-data/get_event_200_with_broken_format.json
deleted file mode 100644
index 58081140..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/get_event_200_with_broken_format.json
+++ /dev/null
@@ -1,301 +0,0 @@
-{
- "products": {
- "identification": {
- "data": {
- "visitorId": "Ibk1527CUFmcnjLwIs4A9",
- "requestId": "1708102555327.NLOjmg",
- "incognito": true,
- "linkedId": {
- "broken": "format"
- },
- "tag": {},
- "time": "2019-05-21T16:40:13Z",
- "timestamp": 1582299576512,
- "url": "https://www.example.com/login?hope{this{works[!",
- "ip": "61.127.217.15",
- "ipLocation": {
- "accuracyRadius": 10,
- "latitude": 49.982,
- "longitude": 36.2566,
- "postalCode": "61202",
- "timezone": "Europe/Dusseldorf",
- "city": {
- "name": "Dusseldorf"
- },
- "country": {
- "code": "DE",
- "name": "Germany"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "63",
- "name": "North Rhine-Westphalia"
- }
- ]
- },
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "74",
- "browserFullVersion": "74.0.3729",
- "os": "Windows",
- "osVersion": "7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) ...."
- },
- "confidence": {
- "score": 0.97
- },
- "visitorFound": false,
- "firstSeenAt": {
- "global": "2022-03-16T11:26:45.362Z",
- "subscription": "2022-03-16T11:31:01.101Z"
- },
- "lastSeenAt": {
- "global": null,
- "subscription": null
- },
- "replayed": false
- }
- },
- "botd": {
- "data": {
- "bot": {
- "result": "notDetected"
- },
- "url": "https://www.example.com/login?hope{this{works}[!",
- "ip": "61.127.217.15",
- "time": "2019-05-21T16:40:13Z",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 YaBrowser/24.1.0.0 Safari/537.36",
- "requestId": "1708102555327.NLOjmg"
- }
- },
- "rootApps": {
- "data": {
- "result": false
- }
- },
- "emulator": {
- "data": {
- "result": false
- }
- },
- "ipInfo": {
- "data": {
- "v4": {
- "address": "94.142.239.124",
- "geolocation": {
- "accuracyRadius": 20,
- "latitude": 50.05,
- "longitude": 14.4,
- "postalCode": "150 00",
- "timezone": "Europe/Prague",
- "city": {
- "name": "Prague"
- },
- "country": {
- "code": "CZ",
- "name": "Czechia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "10",
- "name": "Hlavni mesto Praha"
- }
- ]
- },
- "asn": {
- "asn": "7922",
- "name": "COMCAST-7922",
- "network": "73.136.0.0/13"
- },
- "datacenter": {
- "result": true,
- "name": "DediPath"
- }
- },
- "v6": {
- "address": "2001:db8:3333:4444:5555:6666:7777:8888",
- "geolocation": {
- "accuracyRadius": 5,
- "latitude": 49.982,
- "longitude": 36.2566,
- "postalCode": "10112",
- "timezone": "Europe/Berlin",
- "city": {
- "name": "Berlin"
- },
- "country": {
- "code": "DE",
- "name": "Germany"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "BE",
- "name": "Land Berlin"
- }
- ]
- },
- "asn": {
- "asn": "6805",
- "name": "Telefonica Germany",
- "network": "2a02:3100::/24"
- },
- "datacenter": {
- "result": false,
- "name": ""
- }
- }
- }
- },
- "ipBlocklist": {
- "data": {
- "result": false,
- "details": {
- "emailSpam": false,
- "attackSource": false
- }
- }
- },
- "tor": {
- "data": {
- "result": false
- }
- },
- "vpn": {
- "data": {
- "result": false,
- "originTimezone": "Europe/Berlin",
- "originCountry": "unknown",
- "methods": {
- "timezoneMismatch": false,
- "publicVPN": false,
- "auxiliaryMobile": false
- }
- }
- },
- "proxy": {
- "data": {
- "result": true,
- "confidence": "high",
- "details": {
- "proxyType": "residential",
- "lastSeenAt": "2025-08-12T13:00:00Z"
- }
- }
- },
- "incognito": {
- "data": {
- "result": false
- }
- },
- "tampering": {
- "data": {
- "result": false,
- "anomalyScore": 0.1955
- }
- },
- "clonedApp": {
- "data": {
- "result": false
- }
- },
- "factoryReset": {
- "data": {
- "time": "1970-01-01T00:00:00Z",
- "timestamp": 0
- }
- },
- "jailbroken": {
- "data": {
- "result": false
- }
- },
- "frida": {
- "data": {
- "result": false
- }
- },
- "privacySettings": {
- "data": {
- "result": false
- }
- },
- "virtualMachine": {
- "data": {
- "result": false
- }
- },
- "rawDeviceAttributes": {
- "data": {
- "architecture": {
- "value": 127
- },
- "audio": {
- "value": 35.73832903057337
- },
- "canvas": {
- "value": {
- "Winding": true,
- "Geometry": "4dce9d6017c3e0c052a77252f29f2b1c",
- "Text": "dd2474a56ff78c1de3e7a07070ba3b7d"
- }
- },
- "colorDepth": {
- "value": 30
- },
- "colorGamut": {
- "value": "p3"
- },
- "contrast": {
- "value": 0
- },
- "cookiesEnabled": {
- "value": true
- },
- "cpuClass": {},
- "fonts": {
- "value": [
- "Arial Unicode MS",
- "Gill Sans",
- "Helvetica Neue",
- "Menlo"
- ]
- }
- }
- },
- "highActivity": {
- "data": {
- "result": false
- }
- },
- "locationSpoofing": {
- "data": {
- "result": false
- }
- },
- "mitmAttack": {
- "data": {
- "result": false
- }
- },
- "proximity": {
- "data": {
- "id": "w1aTfd4MCvl",
- "precisionRadius": 10,
- "confidence": 0.95
- }
- }
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/get_event_200_with_unknown_field.json b/tests/mocked-responses-tests/mocked-responses-data/get_event_200_with_unknown_field.json
deleted file mode 100644
index 6af6ad63..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/get_event_200_with_unknown_field.json
+++ /dev/null
@@ -1,299 +0,0 @@
-{
- "unknown": "field",
- "products": {
- "unknown": "field",
- "identification": {
- "unknown": "field",
- "data": {
- "unknown": "field",
- "visitorId": "Ibk1527CUFmcnjLwIs4A9",
- "requestId": "1708102555327.NLOjmg",
- "incognito": true,
- "linkedId": "somelinkedId",
- "tag": {},
- "time": "2019-05-21T16:40:13Z",
- "timestamp": 1582299576512,
- "url": "https://www.example.com/login?hope{this{works[!",
- "ip": "61.127.217.15",
- "ipLocation": {
- "accuracyRadius": 10,
- "latitude": 49.982,
- "longitude": 36.2566,
- "postalCode": "61202",
- "timezone": "Europe/Dusseldorf",
- "city": {
- "name": "Dusseldorf"
- },
- "country": {
- "code": "DE",
- "name": "Germany"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "63",
- "name": "North Rhine-Westphalia"
- }
- ]
- },
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "74",
- "browserFullVersion": "74.0.3729",
- "os": "Windows",
- "osVersion": "7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) ...."
- },
- "confidence": {
- "score": 0.97
- },
- "visitorFound": false,
- "firstSeenAt": {
- "global": "2022-03-16T11:26:45.362Z",
- "subscription": "2022-03-16T11:31:01.101Z"
- },
- "lastSeenAt": {
- "global": null,
- "subscription": null
- },
- "replayed": false
- }
- },
- "botd": {
- "data": {
- "bot": {
- "result": "notDetected"
- },
- "url": "https://www.example.com/login?hope{this{works}[!",
- "ip": "61.127.217.15",
- "time": "2019-05-21T16:40:13Z",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 YaBrowser/24.1.0.0 Safari/537.36",
- "requestId": "1708102555327.NLOjmg"
- }
- },
- "rootApps": {
- "data": {
- "result": false
- }
- },
- "emulator": {
- "data": {
- "result": false
- }
- },
- "ipInfo": {
- "data": {
- "v4": {
- "address": "94.142.239.124",
- "geolocation": {
- "accuracyRadius": 20,
- "latitude": 50.05,
- "longitude": 14.4,
- "postalCode": "150 00",
- "timezone": "Europe/Prague",
- "city": {
- "name": "Prague"
- },
- "country": {
- "code": "CZ",
- "name": "Czechia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "10",
- "name": "Hlavni mesto Praha"
- }
- ]
- },
- "asn": {
- "asn": "7922",
- "name": "COMCAST-7922",
- "network": "73.136.0.0/13"
- },
- "datacenter": {
- "result": true,
- "name": "DediPath"
- }
- },
- "v6": {
- "address": "2001:db8:3333:4444:5555:6666:7777:8888",
- "geolocation": {
- "accuracyRadius": 5,
- "latitude": 49.982,
- "longitude": 36.2566,
- "postalCode": "10112",
- "timezone": "Europe/Berlin",
- "city": {
- "name": "Berlin"
- },
- "country": {
- "code": "DE",
- "name": "Germany"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "BE",
- "name": "Land Berlin"
- }
- ]
- },
- "asn": {
- "asn": "6805",
- "name": "Telefonica Germany",
- "network": "2a02:3100::/24"
- },
- "datacenter": {
- "result": false,
- "name": ""
- }
- }
- }
- },
- "ipBlocklist": {
- "data": {
- "result": false,
- "details": {
- "emailSpam": false,
- "attackSource": false
- }
- }
- },
- "tor": {
- "data": {
- "result": false
- }
- },
- "vpn": {
- "data": {
- "result": false,
- "originTimezone": "Europe/Berlin",
- "originCountry": "unknown",
- "methods": {
- "timezoneMismatch": false,
- "publicVPN": false,
- "auxiliaryMobile": false
- }
- }
- },
- "proxy": {
- "data": {
- "result": false,
- "confidence": "high"
- }
- },
- "incognito": {
- "data": {
- "result": false
- }
- },
- "tampering": {
- "data": {
- "result": false,
- "anomalyScore": 0.1955
- }
- },
- "clonedApp": {
- "data": {
- "result": false
- }
- },
- "factoryReset": {
- "data": {
- "time": "1970-01-01T00:00:00Z",
- "timestamp": 0
- }
- },
- "jailbroken": {
- "data": {
- "result": false
- }
- },
- "frida": {
- "data": {
- "result": false
- }
- },
- "privacySettings": {
- "data": {
- "result": false
- }
- },
- "virtualMachine": {
- "data": {
- "result": false
- }
- },
- "rawDeviceAttributes": {
- "data": {
- "architecture": {
- "value": 127
- },
- "audio": {
- "value": 35.73832903057337
- },
- "canvas": {
- "value": {
- "Winding": true,
- "Geometry": "4dce9d6017c3e0c052a77252f29f2b1c",
- "Text": "dd2474a56ff78c1de3e7a07070ba3b7d"
- }
- },
- "colorDepth": {
- "value": 30
- },
- "colorGamut": {
- "value": "p3"
- },
- "contrast": {
- "value": 0
- },
- "cookiesEnabled": {
- "value": true
- },
- "cpuClass": {},
- "fonts": {
- "value": [
- "Arial Unicode MS",
- "Gill Sans",
- "Helvetica Neue",
- "Menlo"
- ]
- }
- }
- },
- "highActivity": {
- "data": {
- "result": false
- }
- },
- "locationSpoofing": {
- "data": {
- "result": false
- }
- },
- "mitmAttack": {
- "data": {
- "result": false
- }
- },
- "proximity": {
- "data": {
- "id": "w1aTfd4MCvl",
- "precisionRadius": 10,
- "confidence": 0.95
- }
- }
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/get_event_search_200.json b/tests/mocked-responses-tests/mocked-responses-data/get_event_search_200.json
deleted file mode 100644
index 27b7848d..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/get_event_search_200.json
+++ /dev/null
@@ -1,354 +0,0 @@
-{
- "events": [
- {
- "products": {
- "identification": {
- "data": {
- "visitorId": "Ibk1527CUFmcnjLwIs4A9",
- "requestId": "1708102555327.NLOjmg",
- "incognito": true,
- "linkedId": "somelinkedId",
- "tag": {},
- "time": "2019-05-21T16:40:13Z",
- "timestamp": 1582299576512,
- "url": "https://www.example.com/login?hope{this{works[!",
- "ip": "61.127.217.15",
- "ipLocation": {
- "accuracyRadius": 10,
- "latitude": 49.982,
- "longitude": 36.2566,
- "postalCode": "61202",
- "timezone": "Europe/Dusseldorf",
- "city": {
- "name": "Dusseldorf"
- },
- "country": {
- "code": "DE",
- "name": "Germany"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "63",
- "name": "North Rhine-Westphalia"
- }
- ]
- },
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "74",
- "browserFullVersion": "74.0.3729",
- "os": "Windows",
- "osVersion": "7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) ...."
- },
- "confidence": {
- "score": 0.97
- },
- "visitorFound": false,
- "firstSeenAt": {
- "global": "2022-03-16T11:26:45.362Z",
- "subscription": "2022-03-16T11:31:01.101Z"
- },
- "lastSeenAt": {
- "global": null,
- "subscription": null
- },
- "replayed": false
- }
- },
- "botd": {
- "data": {
- "bot": {
- "result": "notDetected"
- },
- "url": "https://www.example.com/login?hope{this{works}[!",
- "ip": "61.127.217.15",
- "time": "2019-05-21T16:40:13Z",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 YaBrowser/24.1.0.0 Safari/537.36",
- "requestId": "1708102555327.NLOjmg"
- }
- },
- "rootApps": {
- "data": {
- "result": false
- }
- },
- "emulator": {
- "data": {
- "result": false
- }
- },
- "ipInfo": {
- "data": {
- "v4": {
- "address": "94.142.239.124",
- "geolocation": {
- "accuracyRadius": 20,
- "latitude": 50.05,
- "longitude": 14.4,
- "postalCode": "150 00",
- "timezone": "Europe/Prague",
- "city": {
- "name": "Prague"
- },
- "country": {
- "code": "CZ",
- "name": "Czechia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "10",
- "name": "Hlavni mesto Praha"
- }
- ]
- },
- "asn": {
- "asn": "7922",
- "name": "COMCAST-7922",
- "network": "73.136.0.0/13"
- },
- "datacenter": {
- "result": true,
- "name": "DediPath"
- }
- },
- "v6": {
- "address": "2001:db8:3333:4444:5555:6666:7777:8888",
- "geolocation": {
- "accuracyRadius": 5,
- "latitude": 49.982,
- "longitude": 36.2566,
- "postalCode": "10112",
- "timezone": "Europe/Berlin",
- "city": {
- "name": "Berlin"
- },
- "country": {
- "code": "DE",
- "name": "Germany"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "BE",
- "name": "Land Berlin"
- }
- ]
- },
- "asn": {
- "asn": "6805",
- "name": "Telefonica Germany",
- "network": "2a02:3100::/24"
- },
- "datacenter": {
- "result": false,
- "name": ""
- }
- }
- }
- },
- "ipBlocklist": {
- "data": {
- "result": false,
- "details": {
- "emailSpam": false,
- "attackSource": false
- }
- }
- },
- "tor": {
- "data": {
- "result": false
- }
- },
- "vpn": {
- "data": {
- "result": false,
- "confidence": "high",
- "originTimezone": "Europe/Berlin",
- "originCountry": "unknown",
- "methods": {
- "timezoneMismatch": false,
- "publicVPN": false,
- "auxiliaryMobile": false,
- "osMismatch": false,
- "relay": false
- }
- }
- },
- "proxy": {
- "data": {
- "result": false,
- "confidence": "high",
- "details": {
- "proxyType": "residential",
- "lastSeenAt": "2025-08-12T13:00:00Z"
- }
- }
- },
- "incognito": {
- "data": {
- "result": false
- }
- },
- "tampering": {
- "data": {
- "result": false,
- "anomalyScore": 0.1955,
- "antiDetectBrowser": false
- }
- },
- "clonedApp": {
- "data": {
- "result": false
- }
- },
- "factoryReset": {
- "data": {
- "time": "1970-01-01T00:00:00Z",
- "timestamp": 0
- }
- },
- "jailbroken": {
- "data": {
- "result": false
- }
- },
- "frida": {
- "data": {
- "result": false
- }
- },
- "privacySettings": {
- "data": {
- "result": false
- }
- },
- "virtualMachine": {
- "data": {
- "result": false
- }
- },
- "rawDeviceAttributes": {
- "data": {
- "architecture": {
- "value": 127
- },
- "audio": {
- "value": 35.73832903057337
- },
- "canvas": {
- "value": {
- "Winding": true,
- "Geometry": "4dce9d6017c3e0c052a77252f29f2b1c",
- "Text": "dd2474a56ff78c1de3e7a07070ba3b7d"
- }
- },
- "colorDepth": {
- "value": 30
- },
- "colorGamut": {
- "value": "p3"
- },
- "contrast": {
- "value": 0
- },
- "cookiesEnabled": {
- "value": true
- },
- "cpuClass": {},
- "fonts": {
- "value": ["Arial Unicode MS", "Gill Sans", "Helvetica Neue", "Menlo"]
- }
- }
- },
- "highActivity": {
- "data": {
- "result": false
- }
- },
- "locationSpoofing": {
- "data": {
- "result": false
- }
- },
- "velocity": {
- "data": {
- "distinctIp": {
- "intervals": {
- "5m": 1,
- "1h": 1,
- "24h": 1
- }
- },
- "distinctLinkedId": {},
- "distinctCountry": {
- "intervals": {
- "5m": 1,
- "1h": 2,
- "24h": 2
- }
- },
- "events": {
- "intervals": {
- "5m": 1,
- "1h": 5,
- "24h": 5
- }
- },
- "ipEvents": {
- "intervals": {
- "5m": 1,
- "1h": 5,
- "24h": 5
- }
- },
- "distinctIpByLinkedId": {
- "intervals": {
- "5m": 1,
- "1h": 5,
- "24h": 5
- }
- },
- "distinctVisitorIdByLinkedId": {
- "intervals": {
- "5m": 1,
- "1h": 5,
- "24h": 5
- }
- }
- }
- },
- "developerTools": {
- "data": {
- "result": false
- }
- },
- "mitmAttack": {
- "data": {
- "result": false
- }
- },
- "proximity": {
- "data": {
- "id": "w1aTfd4MCvl",
- "precisionRadius": 10,
- "confidence": 0.95
- }
- }
- }}
- ],
- "paginationKey": "1655373953086"
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/get_visitors_200_limit_1.json b/tests/mocked-responses-tests/mocked-responses-data/get_visitors_200_limit_1.json
deleted file mode 100644
index f6357ea5..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/get_visitors_200_limit_1.json
+++ /dev/null
@@ -1,61 +0,0 @@
-{
- "visitorId": "AcxioeQKffpXF8iGQK3P",
- "visits": [
- {
- "requestId": "1655373953086.DDlfmP",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "102",
- "browserFullVersion": "102.0.5005",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
- },
- "incognito": false,
- "ip": "82.118.30.68",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 50.0805,
- "longitude": 14.467,
- "postalCode": "130 00",
- "timezone": "Europe/Prague",
- "city": {
- "name": "Prague"
- },
- "country": {
- "code": "CZ",
- "name": "Czechia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "10",
- "name": "Hlavni mesto Praha"
- }
- ]
- },
- "timestamp": 1655373953094,
- "time": "2022-06-16T10:05:53Z",
- "url": "https://dashboard.fingerprint.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-06-16T10:03:00.912Z",
- "subscription": "2022-06-16T10:03:00.912Z"
- }
- }
- ],
- "lastTimestamp": 1655373953086,
- "paginationKey": "1655373953086.DDlfmP"
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/get_visitors_200_limit_500.json b/tests/mocked-responses-tests/mocked-responses-data/get_visitors_200_limit_500.json
deleted file mode 100644
index 3e3aceb0..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/get_visitors_200_limit_500.json
+++ /dev/null
@@ -1,3030 +0,0 @@
-{
- "visitorId": "AcxioeQKffpXF8iGQK3P",
- "visits": [
- {
- "requestId": "1655373780901.HhjRFX",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "102",
- "browserFullVersion": "102.0.5005",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
- },
- "incognito": false,
- "ip": "188.242.36.107",
- "ipLocation": {
- "accuracyRadius": 5,
- "latitude": 59.8983,
- "longitude": 30.2618,
- "postalCode": "190924",
- "timezone": "Europe/Moscow",
- "city": {
- "name": "St Petersburg"
- },
- "country": {
- "code": "RU",
- "name": "Russia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "SPE",
- "name": "St.-Petersburg"
- }
- ]
- },
- "timestamp": 1655373780912,
- "time": "2022-06-16T10:03:00Z",
- "url": "https://fingerprint.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-06-16T05:27:30.578Z",
- "subscription": "2022-06-16T05:27:30.578Z"
- }
- },
- {
- "requestId": "1655357250568.vqejDF",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "102",
- "browserFullVersion": "102.0.5005",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
- },
- "incognito": false,
- "ip": "82.118.30.62",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 50.0805,
- "longitude": 14.467,
- "postalCode": "130 00",
- "timezone": "Europe/Prague",
- "city": {
- "name": "Prague"
- },
- "country": {
- "code": "CZ",
- "name": "Czechia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "10",
- "name": "Hlavni mesto Praha"
- }
- ]
- },
- "timestamp": 1655357250578,
- "time": "2022-06-16T05:27:30Z",
- "url": "https://fingerprint.com/",
- "tag": {},
- "confidence": {
- "score": 0.99
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-06-15T15:28:33.479Z",
- "subscription": "2022-06-15T15:28:33.479Z"
- }
- },
- {
- "requestId": "1655306913474.kFQsQx",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "102",
- "browserFullVersion": "102.0.5005",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
- },
- "incognito": false,
- "ip": "82.118.30.68",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 50.0805,
- "longitude": 14.467,
- "postalCode": "130 00",
- "timezone": "Europe/Prague",
- "city": {
- "name": "Prague"
- },
- "country": {
- "code": "CZ",
- "name": "Czechia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "10",
- "name": "Hlavni mesto Praha"
- }
- ]
- },
- "timestamp": 1655306913479,
- "time": "2022-06-15T15:28:33Z",
- "url": "https://fingerprint.com/",
- "tag": {},
- "confidence": {
- "score": 0.99
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-06-15T08:47:34.677Z",
- "subscription": "2022-06-15T08:47:34.677Z"
- }
- },
- {
- "requestId": "1655282854672.vz4ZlN",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "102",
- "browserFullVersion": "102.0.5005",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
- },
- "incognito": false,
- "ip": "82.118.30.91",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 50.0805,
- "longitude": 14.467,
- "postalCode": "130 00",
- "timezone": "Europe/Prague",
- "city": {
- "name": "Prague"
- },
- "country": {
- "code": "CZ",
- "name": "Czechia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "10",
- "name": "Hlavni mesto Praha"
- }
- ]
- },
- "timestamp": 1655282854677,
- "time": "2022-06-15T08:47:34Z",
- "url": "https://fingerprint.com/",
- "tag": {},
- "confidence": {
- "score": 0.99
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-06-14T14:19:42.753Z",
- "subscription": "2022-06-14T14:19:42.753Z"
- }
- },
- {
- "requestId": "1655216382743.RDRa4h",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "102",
- "browserFullVersion": "102.0.5005",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
- },
- "incognito": false,
- "ip": "188.242.36.107",
- "ipLocation": {
- "accuracyRadius": 5,
- "latitude": 59.8983,
- "longitude": 30.2618,
- "postalCode": "190924",
- "timezone": "Europe/Moscow",
- "city": {
- "name": "St Petersburg"
- },
- "country": {
- "code": "RU",
- "name": "Russia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "SPE",
- "name": "St.-Petersburg"
- }
- ]
- },
- "timestamp": 1655216382753,
- "time": "2022-06-14T14:19:42Z",
- "url": "https://fingerprint.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-06-13T07:53:19.878Z",
- "subscription": "2022-06-13T07:53:19.878Z"
- }
- },
- {
- "requestId": "1655106799870.C8m8hR",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "102",
- "browserFullVersion": "102.0.5005",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.137",
- "timestamp": 1655106799878,
- "time": "2022-06-13T07:53:19Z",
- "url": "https://fingerprint.com/",
- "tag": {},
- "confidence": {
- "score": 0.99
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-06-07T12:54:35.413Z",
- "subscription": "2022-06-07T12:54:35.413Z"
- }
- },
- {
- "requestId": "1654606475406.2uXCJx",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "102",
- "browserFullVersion": "102.0.5005",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
- },
- "incognito": false,
- "ip": "89.38.224.157",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 44.804,
- "longitude": 20.4651
- },
- "timestamp": 1654606475413,
- "time": "2022-06-07T12:54:35Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 0.99
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-06-07T09:37:57.43Z",
- "subscription": "2022-06-07T09:37:57.43Z"
- }
- },
- {
- "requestId": "1654594677423.pCHmKJ",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "102",
- "browserFullVersion": "102.0.5005",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
- },
- "incognito": false,
- "ip": "188.242.36.107",
- "ipLocation": {
- "timezone": "Europe/Moscow"
- },
- "timestamp": 1654594677430,
- "time": "2022-06-07T09:37:57Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 0.99
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-06-07T09:37:50.109Z",
- "subscription": "2022-06-07T09:37:50.109Z"
- }
- },
- {
- "requestId": "1654594670097.Lmodmj",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "102",
- "browserFullVersion": "102.0.5005",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
- },
- "incognito": false,
- "ip": "188.242.36.107",
- "ipLocation": {
- "accuracyRadius": 5,
- "latitude": 59.8983,
- "longitude": 30.2618,
- "postalCode": "190924",
- "timezone": "Europe/Moscow",
- "city": {
- "name": "St Petersburg"
- },
- "country": {
- "code": "RU",
- "name": "Russia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "SPE",
- "name": "St.-Petersburg"
- }
- ]
- },
- "timestamp": 1654594670109,
- "time": "2022-06-07T09:37:50Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 0.99
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-06-07T08:31:31.9Z",
- "subscription": "2022-06-07T08:31:31.9Z"
- }
- },
- {
- "requestId": "1654590691894.aCYqYE",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "102",
- "browserFullVersion": "102.0.5005",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
- },
- "incognito": false,
- "ip": "188.242.36.107",
- "ipLocation": {
- "accuracyRadius": 5,
- "latitude": 59.8983,
- "longitude": 30.2618,
- "postalCode": "190924",
- "timezone": "Europe/Moscow",
- "city": {
- "name": "St Petersburg"
- },
- "country": {
- "code": "RU",
- "name": "Russia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "SPE",
- "name": "St.-Petersburg"
- }
- ]
- },
- "timestamp": 1654590691900,
- "time": "2022-06-07T08:31:31Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 0.99
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-06-06T09:05:25.954Z",
- "subscription": "2022-06-06T09:05:25.954Z"
- }
- },
- {
- "requestId": "1654506325946.ijIwzu",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "102",
- "browserFullVersion": "102.0.5005",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
- },
- "incognito": false,
- "ip": "89.38.224.165",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 44.804,
- "longitude": 20.4651,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1654506325954,
- "time": "2022-06-06T09:05:25Z",
- "url": "https://fingerprintcom.netlify.app/blog/name-change/",
- "tag": {},
- "confidence": {
- "score": 0.99
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-06-02T16:58:53.635Z",
- "subscription": "2022-06-02T16:58:53.635Z"
- }
- },
- {
- "requestId": "1654189133629.0V1gtF",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "102",
- "browserFullVersion": "102.0.5005",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
- },
- "incognito": false,
- "ip": "89.38.224.165",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 44.804,
- "longitude": 20.4651,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1654189133635,
- "time": "2022-06-02T16:58:53Z",
- "url": "https://fingerprintcom.netlify.app/blog/name-change/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-06-02T16:58:51.483Z",
- "subscription": "2022-06-02T16:58:51.483Z"
- }
- },
- {
- "requestId": "1654189131472.r49Bbh",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "102",
- "browserFullVersion": "102.0.5005",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36"
- },
- "incognito": false,
- "ip": "89.38.224.165",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 44.804,
- "longitude": 20.4651,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1654189131483,
- "time": "2022-06-02T16:58:51Z",
- "url": "https://fingerprintcom.netlify.app/",
- "tag": {},
- "confidence": {
- "score": 0.95
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-05-27T14:52:26.624Z",
- "subscription": "2022-05-27T14:52:26.624Z"
- }
- },
- {
- "requestId": "1653663146617.o8KpJO",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "101",
- "browserFullVersion": "101.0.4951",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36"
- },
- "incognito": false,
- "ip": "89.38.224.165",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 44.804,
- "longitude": 20.4651,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1653663146624,
- "time": "2022-05-27T14:52:26Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-05-20T09:50:06.7Z",
- "subscription": "2022-05-20T09:50:06.7Z"
- }
- },
- {
- "requestId": "1653040206694.Q5Csig",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "101",
- "browserFullVersion": "101.0.4951",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36"
- },
- "incognito": false,
- "ip": "89.38.224.165",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 44.804,
- "longitude": 20.4651,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1653040206700,
- "time": "2022-05-20T09:50:06Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-05-19T16:27:38.029Z",
- "subscription": "2022-05-19T16:27:38.029Z"
- }
- },
- {
- "requestId": "1652977658020.xbfYhA",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "101",
- "browserFullVersion": "101.0.4951",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36"
- },
- "incognito": false,
- "ip": "89.38.224.165",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 44.804,
- "longitude": 20.4651,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1652977658029,
- "time": "2022-05-19T16:27:38Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-05-17T15:09:32.666Z",
- "subscription": "2022-05-17T15:09:32.666Z"
- }
- },
- {
- "requestId": "1652800172657.xA22Pd",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "101",
- "browserFullVersion": "101.0.4951",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36"
- },
- "incognito": false,
- "ip": "89.38.224.165",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 44.804,
- "longitude": 20.4651,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1652800172666,
- "time": "2022-05-17T15:09:32Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-05-17T14:18:17.631Z",
- "subscription": "2022-05-17T14:18:17.631Z"
- }
- },
- {
- "requestId": "1652797097626.faAMJO",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "101",
- "browserFullVersion": "101.0.4951",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36"
- },
- "incognito": false,
- "ip": "89.38.224.165",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 44.804,
- "longitude": 20.4651,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1652797097631,
- "time": "2022-05-17T14:18:17Z",
- "url": "https://fingerprintjs.com/careers/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-05-17T10:16:04.809Z",
- "subscription": "2022-05-17T10:16:04.809Z"
- }
- },
- {
- "requestId": "1652782564800.MWH0GO",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "101",
- "browserFullVersion": "101.0.4951",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36"
- },
- "incognito": false,
- "ip": "89.38.224.165",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 44.804,
- "longitude": 20.4651,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1652782564809,
- "time": "2022-05-17T10:16:04Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-05-16T06:47:01.511Z",
- "subscription": "2022-05-16T06:47:01.511Z"
- }
- },
- {
- "requestId": "1652683621505.1tOjuc",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "101",
- "browserFullVersion": "101.0.4951",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36"
- },
- "incognito": false,
- "ip": "217.150.54.233",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 59.8983,
- "longitude": 30.2618,
- "postalCode": "190924",
- "timezone": "Europe/Moscow",
- "city": {
- "name": "St Petersburg"
- },
- "country": {
- "code": "RU",
- "name": "Russia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "SPE",
- "name": "St.-Petersburg"
- }
- ]
- },
- "timestamp": 1652683621511,
- "time": "2022-05-16T06:47:01Z",
- "url": "https://fingerprintjs.com/products/bot-detection/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-05-16T06:45:49.586Z",
- "subscription": "2022-05-16T06:45:49.586Z"
- }
- },
- {
- "requestId": "1652683586557.67Faeg",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "101",
- "browserFullVersion": "101.0.4951",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36"
- },
- "incognito": true,
- "ip": "217.150.54.233",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 59.8983,
- "longitude": 30.2618,
- "postalCode": "190924",
- "timezone": "Europe/Moscow",
- "city": {
- "name": "St Petersburg"
- },
- "country": {
- "code": "RU",
- "name": "Russia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "SPE",
- "name": "St.-Petersburg"
- }
- ]
- },
- "timestamp": 1652683586562,
- "time": "2022-05-16T06:46:26Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 0.94
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-05-16T06:45:49.586Z",
- "subscription": "2022-05-16T06:45:49.586Z"
- }
- },
- {
- "requestId": "1652683549513.aVRqEP",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "101",
- "browserFullVersion": "101.0.4951",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36"
- },
- "incognito": false,
- "ip": "217.150.54.233",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 59.8983,
- "longitude": 30.2618,
- "postalCode": "190924",
- "timezone": "Europe/Moscow",
- "city": {
- "name": "St Petersburg"
- },
- "country": {
- "code": "RU",
- "name": "Russia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "SPE",
- "name": "St.-Petersburg"
- }
- ]
- },
- "timestamp": 1652683549586,
- "time": "2022-05-16T06:45:49Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-05-05T10:11:25.96Z",
- "subscription": "2022-05-05T10:11:25.96Z"
- }
- },
- {
- "requestId": "1651745485951.Oj68me",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "89.38.224.165",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 44.804,
- "longitude": 20.4651,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1651745485960,
- "time": "2022-05-05T10:11:25Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-05-05T09:33:40.155Z",
- "subscription": "2022-05-05T09:33:40.155Z"
- }
- },
- {
- "requestId": "1651743220004.W02rhx",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "89.38.224.165",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 44.804,
- "longitude": 20.4651,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1651743220155,
- "time": "2022-05-05T09:33:40Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-05-03T15:26:32.826Z",
- "subscription": "2022-05-03T15:26:32.826Z"
- }
- },
- {
- "requestId": "1651591592822.Is9u93",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "89.38.224.157",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 44.804,
- "longitude": 20.4651,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1651591592826,
- "time": "2022-05-03T15:26:32Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-29T13:23:37.049Z",
- "subscription": "2022-04-29T13:23:37.049Z"
- }
- },
- {
- "requestId": "1651238617044.rMVPGS",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "89.38.224.165",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 44.804,
- "longitude": 20.4651,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1651238617049,
- "time": "2022-04-29T13:23:37Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-29T10:37:53.333Z",
- "subscription": "2022-04-29T10:37:53.333Z"
- }
- },
- {
- "requestId": "1651228673329.QZI2Cu",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "188.242.36.107",
- "ipLocation": {
- "accuracyRadius": 5,
- "latitude": 59.8983,
- "longitude": 30.2618,
- "postalCode": "190924",
- "timezone": "Europe/Moscow",
- "city": {
- "name": "St Petersburg"
- },
- "country": {
- "code": "RU",
- "name": "Russia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "SPE",
- "name": "St.-Petersburg"
- }
- ]
- },
- "timestamp": 1651228673333,
- "time": "2022-04-29T10:37:53Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-28T13:58:06.323Z",
- "subscription": "2022-04-28T13:58:06.323Z"
- }
- },
- {
- "requestId": "1651154286221.YvuOCP",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "84.247.59.113",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 50.0971,
- "longitude": 8.5952,
- "postalCode": "65933",
- "timezone": "Europe/Berlin",
- "city": {
- "name": "Frankfurt am Main"
- },
- "country": {
- "code": "DE",
- "name": "Germany"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "HE",
- "name": "Hesse"
- }
- ]
- },
- "timestamp": 1651154286323,
- "time": "2022-04-28T13:58:06Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-28T12:16:02.564Z",
- "subscription": "2022-04-28T12:16:02.564Z"
- }
- },
- {
- "requestId": "1651148162556.dySgif",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "84.247.59.113",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 50.0971,
- "longitude": 8.5952,
- "postalCode": "65933",
- "timezone": "Europe/Berlin",
- "city": {
- "name": "Frankfurt am Main"
- },
- "country": {
- "code": "DE",
- "name": "Germany"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "HE",
- "name": "Hesse"
- }
- ]
- },
- "timestamp": 1651148162564,
- "time": "2022-04-28T12:16:02Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-28T11:57:13.267Z",
- "subscription": "2022-04-28T11:57:13.267Z"
- }
- },
- {
- "requestId": "1651147033260.SxmFvL",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "84.247.59.146",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 50.0971,
- "longitude": 8.5952,
- "postalCode": "65933",
- "timezone": "Europe/Berlin",
- "city": {
- "name": "Frankfurt am Main"
- },
- "country": {
- "code": "DE",
- "name": "Germany"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "HE",
- "name": "Hesse"
- }
- ]
- },
- "timestamp": 1651147033267,
- "time": "2022-04-28T11:57:13Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-28T11:57:06.24Z",
- "subscription": "2022-04-28T11:57:06.24Z"
- }
- },
- {
- "requestId": "1651147026139.aAZ8TO",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "84.247.59.146",
- "ipLocation": {
- "accuracyRadius": 20,
- "latitude": 50.0971,
- "longitude": 8.5952,
- "postalCode": "65933",
- "timezone": "Europe/Berlin",
- "city": {
- "name": "Frankfurt am Main"
- },
- "country": {
- "code": "DE",
- "name": "Germany"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "HE",
- "name": "Hesse"
- }
- ]
- },
- "timestamp": 1651147026240,
- "time": "2022-04-28T11:57:06Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-26T14:10:31.908Z",
- "subscription": "2022-04-26T14:10:31.908Z"
- }
- },
- {
- "requestId": "1650982231903.eG0b6v",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.105",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650982231908,
- "time": "2022-04-26T14:10:31Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-26T11:43:37.373Z",
- "subscription": "2022-04-26T11:43:37.373Z"
- }
- },
- {
- "requestId": "1650973417360.xupFFD",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.99",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650973417373,
- "time": "2022-04-26T11:43:37Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-26T11:43:30.111Z",
- "subscription": "2022-04-26T11:43:30.111Z"
- }
- },
- {
- "requestId": "1650973410104.AQD4qu",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.99",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650973410111,
- "time": "2022-04-26T11:43:30Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-26T11:22:34.148Z",
- "subscription": "2022-04-26T11:22:34.148Z"
- }
- },
- {
- "requestId": "1650972154133.lSWE8a",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.96",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650972154148,
- "time": "2022-04-26T11:22:34Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-26T11:22:03.83Z",
- "subscription": "2022-04-26T11:22:03.83Z"
- }
- },
- {
- "requestId": "1650972123824.xk8MUR",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.96",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650972123830,
- "time": "2022-04-26T11:22:03Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-25T09:46:15.458Z",
- "subscription": "2022-04-25T09:46:15.458Z"
- }
- },
- {
- "requestId": "1650879975452.kfuowM",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "188.242.36.107",
- "ipLocation": {
- "accuracyRadius": 5,
- "latitude": 59.8983,
- "longitude": 30.2618,
- "postalCode": "190924",
- "timezone": "Europe/Moscow",
- "city": {
- "name": "St Petersburg"
- },
- "country": {
- "code": "RU",
- "name": "Russia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "SPE",
- "name": "St.-Petersburg"
- }
- ]
- },
- "timestamp": 1650879975458,
- "time": "2022-04-25T09:46:15Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-22T16:51:44.816Z",
- "subscription": "2022-04-22T16:51:44.816Z"
- }
- },
- {
- "requestId": "1650646304808.xQbAju",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.227",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650646304816,
- "time": "2022-04-22T16:51:44Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-21T11:43:33.116Z",
- "subscription": "2022-04-21T11:43:33.116Z"
- }
- },
- {
- "requestId": "1650541413105.leAPLz",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.89",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650541413116,
- "time": "2022-04-21T11:43:33Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-20T17:11:54.717Z",
- "subscription": "2022-04-20T17:11:54.717Z"
- }
- },
- {
- "requestId": "1650474714710.M1IGsl",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.111",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650474714717,
- "time": "2022-04-20T17:11:54Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-20T17:11:47.217Z",
- "subscription": "2022-04-20T17:11:47.217Z"
- }
- },
- {
- "requestId": "1650474707211.CEUuZk",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.111",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650474707217,
- "time": "2022-04-20T17:11:47Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-20T17:11:12.076Z",
- "subscription": "2022-04-20T17:11:12.076Z"
- }
- },
- {
- "requestId": "1650474672071.Pz4WsK",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.111",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650474672076,
- "time": "2022-04-20T17:11:12Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-19T12:29:06.692Z",
- "subscription": "2022-04-19T12:29:06.692Z"
- }
- },
- {
- "requestId": "1650371346684.1d7sgv",
- "browserDetails": {
- "browserName": "Chrome Mobile",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Android",
- "osVersion": "6.0",
- "device": "Nexus 5",
- "userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Mobile Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.198",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650371346692,
- "time": "2022-04-19T12:29:06Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-19T12:29:02.15Z",
- "subscription": "2022-04-19T12:29:02.15Z"
- }
- },
- {
- "requestId": "1650371342145.oWyfRx",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.198",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650371342150,
- "time": "2022-04-19T12:29:02Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-19T11:35:14.729Z",
- "subscription": "2022-04-19T11:35:14.729Z"
- }
- },
- {
- "requestId": "1650368114723.YEXcHI",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.206",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650368114729,
- "time": "2022-04-19T11:35:14Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-19T11:13:33.107Z",
- "subscription": "2022-04-19T11:13:33.107Z"
- }
- },
- {
- "requestId": "1650366813101.SvUZC1",
- "browserDetails": {
- "browserName": "Chrome Mobile",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Android",
- "osVersion": "6.0",
- "device": "Nexus 5",
- "userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Mobile Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.204",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650366813107,
- "time": "2022-04-19T11:13:33Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-19T11:13:28.453Z",
- "subscription": "2022-04-19T11:13:28.453Z"
- }
- },
- {
- "requestId": "1650366808426.Hy6j7v",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.204",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650366808453,
- "time": "2022-04-19T11:13:28Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-19T11:07:05.19Z",
- "subscription": "2022-04-19T11:07:05.19Z"
- }
- },
- {
- "requestId": "1650366425184.xvYkdr",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.204",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650366425190,
- "time": "2022-04-19T11:07:05Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-19T11:07:00.483Z",
- "subscription": "2022-04-19T11:07:00.483Z"
- }
- },
- {
- "requestId": "1650366420377.VR5pDX",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.204",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650366420483,
- "time": "2022-04-19T11:07:00Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-19T10:37:45.279Z",
- "subscription": "2022-04-19T10:37:45.279Z"
- }
- },
- {
- "requestId": "1650364665274.qq31O4",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.172",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650364665279,
- "time": "2022-04-19T10:37:45Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-19T10:22:58.87Z",
- "subscription": "2022-04-19T10:22:58.87Z"
- }
- },
- {
- "requestId": "1650363778864.tsVBjO",
- "browserDetails": {
- "browserName": "Chrome Mobile",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Android",
- "osVersion": "6.0",
- "device": "Nexus 5",
- "userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Mobile Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.210",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650363778870,
- "time": "2022-04-19T10:22:58Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-19T10:22:46.894Z",
- "subscription": "2022-04-19T10:22:46.894Z"
- }
- },
- {
- "requestId": "1650363766889.KuVDpm",
- "browserDetails": {
- "browserName": "Chrome Mobile",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Android",
- "osVersion": "6.0",
- "device": "Nexus 5",
- "userAgent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Mobile Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.210",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650363766894,
- "time": "2022-04-19T10:22:46Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-19T10:07:01.528Z",
- "subscription": "2022-04-19T10:07:01.528Z"
- }
- },
- {
- "requestId": "1650362821521.dXH2Ce",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.180",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650362821528,
- "time": "2022-04-19T10:07:01Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-19T10:02:42.46Z",
- "subscription": "2022-04-19T10:02:42.46Z"
- }
- },
- {
- "requestId": "1650362562448.a5cPLU",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.180",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650362562460,
- "time": "2022-04-19T10:02:42Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-18T17:06:30.834Z",
- "subscription": "2022-04-18T17:06:30.834Z"
- }
- },
- {
- "requestId": "1650301590829.YXGX7h",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.195",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650301590834,
- "time": "2022-04-18T17:06:30Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-18T12:23:30.446Z",
- "subscription": "2022-04-18T12:23:30.446Z"
- }
- },
- {
- "requestId": "1650284610441.lJrX4M",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36"
- },
- "incognito": false,
- "ip": "45.86.200.179",
- "ipLocation": {
- "accuracyRadius": 1000,
- "latitude": 52.3824,
- "longitude": 4.8995,
- "timezone": "Europe/Amsterdam",
- "country": {
- "code": "NL",
- "name": "Netherlands"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- }
- },
- "timestamp": 1650284610446,
- "time": "2022-04-18T12:23:30Z",
- "url": "https://fingerprintjs.com/blog/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-04-06T14:53:00.526Z",
- "subscription": "2022-04-06T14:53:00.526Z"
- }
- },
- {
- "requestId": "1649256780522.WAXWf2",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36"
- },
- "incognito": false,
- "ip": "109.245.35.200",
- "ipLocation": {
- "accuracyRadius": 50,
- "latitude": 44.8166,
- "longitude": 20.4721,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1649256780526,
- "time": "2022-04-06T14:53:00Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-03-18T11:08:35.698Z",
- "subscription": "2022-03-18T11:08:35.698Z"
- }
- },
- {
- "requestId": "1649256780520.RRC4PR",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "100",
- "browserFullVersion": "100.0.4896",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36"
- },
- "incognito": false,
- "ip": "109.245.35.200",
- "ipLocation": {
- "accuracyRadius": 50,
- "latitude": 44.8166,
- "longitude": 20.4721,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1649256780525,
- "time": "2022-04-06T14:53:00Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-03-18T11:08:35.698Z",
- "subscription": "2022-03-18T11:08:35.698Z"
- }
- },
- {
- "requestId": "1647601715689.iocXfW",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "98",
- "browserFullVersion": "98.0.4758",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.109 Safari/537.36"
- },
- "incognito": false,
- "ip": "178.223.21.183",
- "ipLocation": {
- "accuracyRadius": 50,
- "latitude": 44.8166,
- "longitude": 20.4721,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1647601715698,
- "time": "2022-03-18T11:08:35Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-03-16T08:21:23.62Z",
- "subscription": "2022-03-16T08:21:23.62Z"
- }
- },
- {
- "requestId": "1647418883615.Vck2NA",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "98",
- "browserFullVersion": "98.0.4758",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.109 Safari/537.36"
- },
- "incognito": false,
- "ip": "87.116.165.97",
- "ipLocation": {
- "accuracyRadius": 50,
- "latitude": 44.8166,
- "longitude": 20.4721,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1647418883620,
- "time": "2022-03-16T08:21:23Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-03-16T08:21:18.398Z",
- "subscription": "2022-03-16T08:21:18.398Z"
- }
- },
- {
- "requestId": "1647418878391.NZDmht",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "98",
- "browserFullVersion": "98.0.4758",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.109 Safari/537.36"
- },
- "incognito": false,
- "ip": "87.116.165.97",
- "ipLocation": {
- "accuracyRadius": 50,
- "latitude": 44.8166,
- "longitude": 20.4721,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1647418878398,
- "time": "2022-03-16T08:21:18Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-03-15T11:46:51.858Z",
- "subscription": "2022-03-15T11:46:51.858Z"
- }
- },
- {
- "requestId": "1647344811836.RvNkL5",
- "browserDetails": {
- "browserName": "Chrome",
- "browserMajorVersion": "98",
- "browserFullVersion": "98.0.4758",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "device": "Other",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.109 Safari/537.36"
- },
- "incognito": false,
- "ip": "87.116.165.97",
- "ipLocation": {
- "accuracyRadius": 50,
- "latitude": 44.8166,
- "longitude": 20.4721,
- "timezone": "Europe/Belgrade",
- "city": {
- "name": "Belgrade"
- },
- "country": {
- "code": "RS",
- "name": "Serbia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "00",
- "name": "Belgrade"
- }
- ]
- },
- "timestamp": 1647344811858,
- "time": "2022-03-15T11:46:51Z",
- "url": "https://fingerprintjs.com/",
- "tag": {},
- "confidence": {
- "score": 1
- },
- "visitorFound": true,
- "firstSeenAt": {
- "global": "2022-02-04T11:31:20Z",
- "subscription": "2022-02-04T11:31:20Z"
- },
- "lastSeenAt": {
- "global": "2022-03-08T12:33:05.677Z",
- "subscription": "2022-03-08T12:33:05.677Z"
- }
- }
- ]
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/get_visitors_400_bad_request.json b/tests/mocked-responses-tests/mocked-responses-data/get_visitors_400_bad_request.json
deleted file mode 100644
index c2b6e295..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/get_visitors_400_bad_request.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "error": "bad request"
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/get_visitors_403_forbidden.json b/tests/mocked-responses-tests/mocked-responses-data/get_visitors_403_forbidden.json
deleted file mode 100644
index 8a886d18..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/get_visitors_403_forbidden.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "error": "Forbidden (HTTP 403)"
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/get_visitors_429_too_many_requests.json b/tests/mocked-responses-tests/mocked-responses-data/get_visitors_429_too_many_requests.json
deleted file mode 100644
index 00d00f2e..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/get_visitors_429_too_many_requests.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "error": "too many requests"
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/related-visitors/get_related_visitors_200.json b/tests/mocked-responses-tests/mocked-responses-data/related-visitors/get_related_visitors_200.json
deleted file mode 100644
index 7a46a69e..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/related-visitors/get_related_visitors_200.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "relatedVisitors": [
- {
- "visitorId": "NtCUJGceWX9RpvSbhvOm"
- },
- {
- "visitorId": "25ee02iZwGxeyT0jMNkZ"
- }
- ]
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/related-visitors/get_related_visitors_200_empty.json b/tests/mocked-responses-tests/mocked-responses-data/related-visitors/get_related_visitors_200_empty.json
deleted file mode 100644
index 6c9b02c1..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/related-visitors/get_related_visitors_200_empty.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "relatedVisitors": []
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/update_event_multiple_fields_request.json b/tests/mocked-responses-tests/mocked-responses-data/update_event_multiple_fields_request.json
deleted file mode 100644
index f85d2e75..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/update_event_multiple_fields_request.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "linkedId": "myNewLinkedId",
- "tag": {
- "myTag": "myNewValue"
- },
- "suspect": true
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/update_event_one_field_request.json b/tests/mocked-responses-tests/mocked-responses-data/update_event_one_field_request.json
deleted file mode 100644
index 0ebd1549..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/update_event_one_field_request.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "linkedId": "myNewLinkedId"
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/webhook.json b/tests/mocked-responses-tests/mocked-responses-data/webhook.json
deleted file mode 100644
index 1180fcdc..00000000
--- a/tests/mocked-responses-tests/mocked-responses-data/webhook.json
+++ /dev/null
@@ -1,293 +0,0 @@
-{
- "requestId": "Px6VxbRC6WBkA39yeNH3",
- "url": "https://banking.example.com/signup",
- "ip": "216.3.128.12",
- "tag": {
- "requestType": "signup",
- "yourCustomId": 45321
- },
- "time": "2019-10-12T07:20:50.52Z",
- "timestamp": 1554910997788,
- "ipLocation": {
- "accuracyRadius": 1,
- "city": {
- "name": "Bolingbrook"
- },
- "continent": {
- "code": "NA",
- "name": "North America"
- },
- "country": {
- "code": "US",
- "name": "United States"
- },
- "latitude": 41.12933,
- "longitude": -88.9954,
- "postalCode": "60547",
- "subdivisions": [
- {
- "isoCode": "IL",
- "name": "Illinois"
- }
- ],
- "timezone": "America/Chicago"
- },
- "linkedId": "any-string",
- "visitorId": "3HNey93AkBW6CRbxV6xP",
- "visitorFound": true,
- "confidence": {
- "score": 0.97
- },
- "firstSeenAt": {
- "global": "2022-03-16T11:26:45.362Z",
- "subscription": "2022-03-16T11:31:01.101Z"
- },
- "lastSeenAt": {
- "global": "2022-03-16T11:28:34.023Z",
- "subscription": null
- },
- "browserDetails": {
- "browserName": "Chrome",
- "browserFullVersion": "73.0.3683.86",
- "browserMajorVersion": "73",
- "os": "Mac OS X",
- "osVersion": "10.14.3",
- "device": "Other",
- "userAgent": "(Macintosh; Intel Mac OS X 10_14_3) Chrome/73.0.3683.86"
- },
- "incognito": false,
- "clientReferrer": "https://google.com?search=banking+services",
- "bot": {
- "result": "bad",
- "type": "selenium"
- },
- "userAgent": "(Macintosh; Intel Mac OS X 10_14_3) Chrome/73.0.3683.86",
- "rootApps": {
- "result": false
- },
- "emulator": {
- "result": false
- },
- "ipInfo": {
- "v4": {
- "address": "94.142.239.124",
- "geolocation": {
- "accuracyRadius": 20,
- "latitude": 50.05,
- "longitude": 14.4,
- "postalCode": "150 00",
- "timezone": "Europe/Prague",
- "city": {
- "name": "Prague"
- },
- "country": {
- "code": "CZ",
- "name": "Czechia"
- },
- "continent": {
- "code": "EU",
- "name": "Europe"
- },
- "subdivisions": [
- {
- "isoCode": "10",
- "name": "Hlavni mesto Praha"
- }
- ]
- },
- "asn": {
- "asn": "7922",
- "name": "COMCAST-7922",
- "network": "73.136.0.0/13"
- },
- "datacenter": {
- "result": true,
- "name": "DediPath"
- }
- }
- },
- "ipBlocklist": {
- "result": false,
- "details": {
- "emailSpam": false,
- "attackSource": false
- }
- },
- "tor": {
- "result": false
- },
- "vpn": {
- "result": false,
- "confidence": "high",
- "originTimezone": "Europe/Berlin",
- "originCountry": "unknown",
- "methods": {
- "timezoneMismatch": false,
- "publicVPN": false,
- "auxiliaryMobile": false,
- "osMismatch": false,
- "relay": false
- }
- },
- "proxy": {
- "result": true,
- "confidence": "high",
- "details": {
- "proxyType": "residential",
- "lastSeenAt": "2025-08-12T13:00:00Z"
- }
- },
- "tampering": {
- "result": false,
- "anomalyScore": 0,
- "antiDetectBrowser": false
- },
- "clonedApp": {
- "result": false
- },
- "factoryReset": {
- "time": "1970-01-01T00:00:00Z",
- "timestamp": 0
- },
- "jailbroken": {
- "result": false
- },
- "frida": {
- "result": false
- },
- "privacySettings": {
- "result": false
- },
- "virtualMachine": {
- "result": false
- },
- "rawDeviceAttributes": {
- "architecture": {
- "value": 127
- },
- "audio": {
- "value": 35.73832903057337
- },
- "canvas": {
- "value": {
- "Winding": true,
- "Geometry": "4dce9d6017c3e0c052a77252f29f2b1c",
- "Text": "dd2474a56ff78c1de3e7a07070ba3b7d"
- }
- },
- "colorDepth": {
- "value": 30
- },
- "colorGamut": {
- "value": "srgb"
- },
- "contrast": {
- "value": 0
- },
- "cookiesEnabled": {
- "value": true
- }
- },
- "highActivity": {
- "result": false
- },
- "locationSpoofing": {
- "result": true
- },
- "suspectScore": {
- "result": 0
- },
- "velocity": {
- "distinctIp": {
- "intervals": {
- "5m": 1,
- "1h": 1,
- "24h": 1
- }
- },
- "distinctLinkedId": {},
- "distinctCountry": {
- "intervals": {
- "5m": 1,
- "1h": 2,
- "24h": 2
- }
- },
- "events": {
- "intervals": {
- "5m": 1,
- "1h": 5,
- "24h": 5
- }
- },
- "ipEvents": {
- "intervals": {
- "5m": 1,
- "1h": 5,
- "24h": 5
- }
- },
- "distinctIpByLinkedId": {
- "intervals": {
- "5m": 1,
- "1h": 5,
- "24h": 5
- }
- },
- "distinctVisitorIdByLinkedId": {
- "intervals": {
- "5m": 1,
- "1h": 5,
- "24h": 5
- }
- }
- },
- "developerTools": {
- "result": false
- },
- "mitmAttack": {
- "result": false
- },
- "sdk": {
- "platform": "js",
- "version": "3.11.10"
- },
- "replayed": false,
- "supplementaryIds": {
- "standard": {
- "visitorId": "3HNey93AkBW6CRbxV6xP",
- "visitorFound": true,
- "confidence": {
- "score": 0.97
- },
- "firstSeenAt": {
- "global": "2022-03-16T11:26:45.362Z",
- "subscription": "2022-03-16T11:31:01.101Z"
- },
- "lastSeenAt": {
- "global": "2022-03-16T11:28:34.023Z",
- "subscription": "2022-03-16T11:28:34.023Z"
- }
- },
- "highRecall": {
- "visitorId": "3HNey93AkBW6CRbxV6xP",
- "visitorFound": true,
- "confidence": {
- "score": 0.97
- },
- "firstSeenAt": {
- "global": "2022-03-16T11:26:45.362Z",
- "subscription": "2022-03-16T11:31:01.101Z"
- },
- "lastSeenAt": {
- "global": "2022-03-16T11:28:34.023Z",
- "subscription": "2022-03-16T11:28:34.023Z"
- }
- }
- },
- "proximity": {
- "id": "w1aTfd4MCvl",
- "precisionRadius": 10,
- "confidence": 0.95
- }
-}
diff --git a/tests/mocked-responses-tests/mocked-responses-data/webhook/webhook_event.json b/tests/mocked-responses-tests/mocked-responses-data/webhook/webhook_event.json
new file mode 100644
index 00000000..09c15380
--- /dev/null
+++ b/tests/mocked-responses-tests/mocked-responses-data/webhook/webhook_event.json
@@ -0,0 +1,178 @@
+{
+ "linked_id": "somelinkedId",
+ "tags": {},
+ "timestamp": 1708102555327,
+ "event_id": "1708102555327.NLOjmg",
+ "url": "https://www.example.com/login?hope{this{works[!",
+ "ip_address": "61.127.217.15",
+ "user_agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) ....",
+ "browser_details": {
+ "browser_name": "Chrome",
+ "browser_major_version": "74",
+ "browser_full_version": "74.0.3729",
+ "os": "Windows",
+ "os_version": "7",
+ "device": "Other"
+ },
+ "identification": {
+ "visitor_id": "Ibk1527CUFmcnjLwIs4A9",
+ "confidence": {
+ "score": 0.97,
+ "version": "1.1"
+ },
+ "visitor_found": false,
+ "first_seen_at": 1708102555327,
+ "last_seen_at": 1708102555327
+ },
+ "supplementary_id_high_recall": {
+ "visitor_id": "3HNey93AkBW6CRbxV6xP",
+ "visitor_found": true,
+ "confidence": {
+ "score": 0.97,
+ "version": "1.1"
+ },
+ "first_seen_at": 1708102555327,
+ "last_seen_at": 1708102555327
+ },
+ "bot": "not_detected",
+ "root_apps": false,
+ "emulator": false,
+ "ip_info": {
+ "v4": {
+ "address": "94.142.239.124",
+ "geolocation": {
+ "accuracy_radius": 20,
+ "latitude": 50.05,
+ "longitude": 14.4,
+ "postal_code": "150 00",
+ "timezone": "Europe/Prague",
+ "city_name": "Prague",
+ "country_code": "CZ",
+ "country_name": "Czechia",
+ "continent_code": "EU",
+ "continent_name": "Europe",
+ "subdivisions": [
+ {
+ "iso_code": "10",
+ "name": "Hlavni mesto Praha"
+ }
+ ]
+ },
+ "asn": "7922",
+ "asn_name": "COMCAST-7922",
+ "asn_network": "73.136.0.0/13",
+ "datacenter_result": true,
+ "datacenter_name": "DediPath"
+ },
+ "v6": {
+ "address": "2001:db8:3333:4444:5555:6666:7777:8888",
+ "geolocation": {
+ "accuracy_radius": 5,
+ "latitude": 49.982,
+ "longitude": 36.2566,
+ "postal_code": "10112",
+ "timezone": "Europe/Berlin",
+ "city_name": "Berlin",
+ "country_code": "DE",
+ "country_name": "Germany",
+ "continent_code": "EU",
+ "continent_name": "Europe",
+ "subdivisions": [
+ {
+ "iso_code": "BE",
+ "name": "Land Berlin"
+ }
+ ]
+ },
+ "asn": "6805",
+ "asn_name": "Telefonica Germany",
+ "asn_network": "2a02:3100::/24",
+ "datacenter_result": false,
+ "datacenter_name": ""
+ }
+ },
+ "ip_blocklist": {
+ "email_spam": false,
+ "attack_source": false,
+ "tor_node": false
+ },
+ "proxy": true,
+ "proxy_confidence": "low",
+ "proxy_details": {
+ "proxy_type": "residential",
+ "last_seen_at": 1708102555327
+ },
+ "vpn": false,
+ "vpn_confidence": "high",
+ "vpn_origin_timezone": "Europe/Berlin",
+ "vpn_origin_country": "unknown",
+ "vpn_methods": {
+ "timezone_mismatch": false,
+ "public_vpn": false,
+ "auxiliary_mobile": false,
+ "os_mismatch": false,
+ "relay": false
+ },
+ "incognito": false,
+ "tampering": false,
+ "tampering_details": {
+ "anomaly_score": 0.1955,
+ "anti_detect_browser": false
+ },
+ "cloned_app": false,
+ "factory_reset_timestamp": 0,
+ "jailbroken": false,
+ "frida": false,
+ "privacy_settings": false,
+ "virtual_machine": false,
+ "location_spoofing": false,
+ "velocity": {
+ "distinct_ip": {
+ "5_minutes": 1,
+ "1_hour": 1,
+ "24_hours": 1
+ },
+ "distinct_country": {
+ "5_minutes": 1,
+ "1_hour": 2,
+ "24_hours": 2
+ },
+ "events": {
+ "5_minutes": 1,
+ "1_hour": 5,
+ "24_hours": 5
+ },
+ "ip_events": {
+ "5_minutes": 1,
+ "1_hour": 5,
+ "24_hours": 5
+ },
+ "distinct_ip_by_linked_id": {
+ "5_minutes": 1,
+ "1_hour": 5,
+ "24_hours": 5
+ },
+ "distinct_visitor_id_by_linked_id": {
+ "5_minutes": 1,
+ "1_hour": 5,
+ "24_hours": 5
+ }
+ },
+ "developer_tools": false,
+ "mitm_attack": false,
+ "sdk": {
+ "platform": "js",
+ "version": "3.11.10",
+ "integrations": [
+ {
+ "name": "fingerprint-pro-react",
+ "version": "3.11.10",
+ "subintegration": {
+ "name": "preact",
+ "version": "10.21.0"
+ }
+ }
+ ]
+ },
+ "replayed": false
+}
\ No newline at end of file
diff --git a/tests/mocked-responses-tests/searchEventsTests.spec.ts b/tests/mocked-responses-tests/searchEventsTests.spec.ts
index 3667a0f4..9fa83169 100644
--- a/tests/mocked-responses-tests/searchEventsTests.spec.ts
+++ b/tests/mocked-responses-tests/searchEventsTests.spec.ts
@@ -1,5 +1,11 @@
-import { ErrorResponse, FingerprintJsServerApiClient, getIntegrationInfo, RequestError } from '../../src'
-import getEventsSearch from './mocked-responses-data/get_event_search_200.json'
+import {
+ ErrorResponse,
+ FingerprintJsServerApiClient,
+ getIntegrationInfo,
+ RequestError,
+ SearchEventsFilter,
+} from '../../src'
+import getEventsSearch from './mocked-responses-data/events/search/get_event_search_200.json'
jest.spyOn(global, 'fetch')
@@ -12,14 +18,16 @@ describe('[Mocked response] Search Events', () => {
test('without filter', async () => {
mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getEventsSearch))))
+ const limit = 10
+
const response = await client.searchEvents({
- limit: 10,
+ limit,
})
expect(response).toEqual(getEventsSearch)
expect(mockFetch).toHaveBeenCalledWith(
- `https://api.fpjs.io/events/search?limit=10&ii=${encodeURIComponent(getIntegrationInfo())}`,
+ `https://api.fpjs.io/v4/events?limit=${limit}&ii=${encodeURIComponent(getIntegrationInfo())}`,
{
- headers: { 'Auth-API-Key': apiKey },
+ headers: { Authorization: `Bearer ${apiKey}` },
method: 'GET',
}
)
@@ -28,16 +36,18 @@ describe('[Mocked response] Search Events', () => {
test('with filter params passed as undefined', async () => {
mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getEventsSearch))))
+ const limit = 10
+
const response = await client.searchEvents({
- limit: 10,
+ limit,
ip_address: undefined,
visitor_id: undefined,
})
expect(response).toEqual(getEventsSearch)
expect(mockFetch).toHaveBeenCalledWith(
- `https://api.fpjs.io/events/search?limit=10&ii=${encodeURIComponent(getIntegrationInfo())}`,
+ `https://api.fpjs.io/v4/events?limit=${limit}&ii=${encodeURIComponent(getIntegrationInfo())}`,
{
- headers: { 'Auth-API-Key': apiKey },
+ headers: { Authorization: `Bearer ${apiKey}` },
method: 'GET',
}
)
@@ -46,16 +56,20 @@ describe('[Mocked response] Search Events', () => {
test('with partial filter', async () => {
mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getEventsSearch))))
+ const limit = 10
+ const bot = 'good'
+ const visitorId = 'visitor_id'
+
const response = await client.searchEvents({
- limit: 10,
- bot: 'good',
- visitor_id: 'visitor_id',
+ limit,
+ bot,
+ visitor_id: visitorId,
})
expect(response).toEqual(getEventsSearch)
expect(mockFetch).toHaveBeenCalledWith(
- `https://api.fpjs.io/events/search?limit=10&bot=good&visitor_id=visitor_id&ii=${encodeURIComponent(getIntegrationInfo())}`,
+ `https://api.fpjs.io/v4/events?limit=${limit}&bot=${bot}&visitor_id=${visitorId}&ii=${encodeURIComponent(getIntegrationInfo())}`,
{
- headers: { 'Auth-API-Key': apiKey },
+ headers: { Authorization: `Bearer ${apiKey}` },
method: 'GET',
}
)
@@ -64,7 +78,7 @@ describe('[Mocked response] Search Events', () => {
test('with all possible filters', async () => {
mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getEventsSearch))))
- const response = await client.searchEvents({
+ const filters: SearchEventsFilter = {
limit: 10,
bot: 'all',
visitor_id: 'visitor_id',
@@ -88,39 +102,49 @@ describe('[Mocked response] Search Events', () => {
vpn_confidence: 'medium',
emulator: true,
incognito: true,
- ip_blocklist: true,
- datacenter: true,
developer_tools: true,
location_spoofing: true,
mitm_attack: true,
proxy: true,
sdk_version: 'testSdkVersion',
sdk_platform: 'js',
- environment: ['env1', 'env2', ''], // Cannot add null or undefined here because environment expects string or string array
- proximity_id: 'testProximityId',
- proximity_precision_radius: 10,
- })
+ environment: ['env1', 'env2', ''],
+ }
+
+ const response = await client.searchEvents(filters)
expect(response).toEqual(getEventsSearch)
- expect(mockFetch).toHaveBeenCalledWith(
- `https://api.fpjs.io/events/search?limit=10&bot=all&visitor_id=visitor_id&ip_address=${encodeURIComponent(
- '192.168.0.1/32'
- )}&linked_id=linked_id&start=1620000000000&end=1630000000000&reverse=true&suspect=false&anti_detect_browser=true&cloned_app=true&factory_reset=true&frida=true&jailbroken=true&min_suspect_score=0.5&privacy_settings=true&root_apps=true&tampering=true&virtual_machine=true&vpn=true&vpn_confidence=medium&emulator=true&incognito=true&ip_blocklist=true&datacenter=true&developer_tools=true&location_spoofing=true&mitm_attack=true&proxy=true&sdk_version=testSdkVersion&sdk_platform=js&environment%5B%5D=env1&environment%5B%5D=env2&environment%5B%5D=&proximity_id=testProximityId&proximity_precision_radius=10&ii=${encodeURIComponent(
- getIntegrationInfo()
- )}`,
- {
- headers: { 'Auth-API-Key': apiKey },
- method: 'GET',
+ const baseUrl = 'https://api.fpjs.io/v4/events'
+ const queryParams = new URLSearchParams()
+ for (const [key, value] of Object.entries(filters)) {
+ if (value === undefined || value === null) {
+ continue
}
- )
+
+ if (Array.isArray(value)) {
+ for (const v of value) {
+ queryParams.append(`${key}[]`, String(v))
+ }
+ } else {
+ queryParams.set(key, String(value))
+ }
+ }
+ queryParams.set('ii', getIntegrationInfo())
+
+ const expectedUrl = `${baseUrl}?${queryParams.toString()}`
+
+ expect(mockFetch).toHaveBeenCalledWith(expectedUrl, {
+ headers: { Authorization: `Bearer ${apiKey}` },
+ method: 'GET',
+ })
})
test('400 error', async () => {
const error = {
error: {
+ code: 'request_cannot_be_parsed',
message: 'Forbidden',
- code: 'RequestCannotBeParsed',
},
} satisfies ErrorResponse
const mockResponse = new Response(JSON.stringify(error), {
@@ -137,8 +161,8 @@ describe('[Mocked response] Search Events', () => {
test('403 error', async () => {
const error = {
error: {
+ code: 'secret_api_key_required',
message: 'secret key is required',
- code: 'TokenRequired',
},
} satisfies ErrorResponse
const mockResponse = new Response(JSON.stringify(error), {
diff --git a/tests/mocked-responses-tests/updateEventTests.spec.ts b/tests/mocked-responses-tests/updateEventTests.spec.ts
index 5809154d..7e9380d3 100644
--- a/tests/mocked-responses-tests/updateEventTests.spec.ts
+++ b/tests/mocked-responses-tests/updateEventTests.spec.ts
@@ -1,9 +1,15 @@
-import { ErrorResponse, FingerprintJsServerApiClient, getIntegrationInfo, Region, RequestError } from '../../src'
-import Error404 from './mocked-responses-data/errors/404_request_not_found.json'
+import {
+ ErrorResponse,
+ FingerprintJsServerApiClient,
+ getIntegrationInfo,
+ Region,
+ RequestError,
+ SdkError,
+} from '../../src'
+import Error404 from './mocked-responses-data/errors/404_event_not_found.json'
import Error403 from './mocked-responses-data/errors/403_feature_not_enabled.json'
import Error400 from './mocked-responses-data/errors/400_request_body_invalid.json'
import Error409 from './mocked-responses-data/errors/409_state_not_ready.json'
-import { SdkError } from '../../src/errors/apiErrors'
jest.spyOn(global, 'fetch')
@@ -12,18 +18,18 @@ const mockFetch = fetch as unknown as jest.Mock
describe('[Mocked response] Update event', () => {
const apiKey = 'dummy_api_key'
- const existingVisitorId = 'TaDnMBz9XCpZNuSzFUqP'
+ const existingEventId = 'TaDnMBz9XCpZNuSzFUqP'
const client = new FingerprintJsServerApiClient({ region: Region.EU, apiKey })
- test('with visitorId', async () => {
+ test('with eventId', async () => {
mockFetch.mockReturnValue(Promise.resolve(new Response()))
const body = {
linkedId: 'linked_id',
suspect: true,
}
- const response = await client.updateEvent(body, existingVisitorId)
+ const response = await client.updateEvent(body, existingEventId)
expect(response).toBeUndefined()
@@ -32,9 +38,9 @@ describe('[Mocked response] Update event', () => {
expect(JSON.parse(bodyFromCall)).toEqual(body)
expect(mockFetch).toHaveBeenCalledWith(
- `https://eu.api.fpjs.io/events/${existingVisitorId}?ii=${encodeURIComponent(getIntegrationInfo())}`,
+ `https://eu.api.fpjs.io/v4/events/${existingEventId}?ii=${encodeURIComponent(getIntegrationInfo())}`,
{
- headers: { 'Auth-API-Key': 'dummy_api_key' },
+ headers: { Authorization: `Bearer ${apiKey}` },
method: 'PUT',
body: JSON.stringify(body),
}
@@ -51,7 +57,7 @@ describe('[Mocked response] Update event', () => {
linkedId: 'linked_id',
suspect: true,
}
- await expect(client.updateEvent(body, existingVisitorId)).rejects.toThrow(
+ await expect(client.updateEvent(body, existingEventId)).rejects.toThrow(
RequestError.fromErrorResponse(Error404 as ErrorResponse, mockResponse)
)
})
@@ -66,7 +72,7 @@ describe('[Mocked response] Update event', () => {
linkedId: 'linked_id',
suspect: true,
}
- await expect(client.updateEvent(body, existingVisitorId)).rejects.toThrow(
+ await expect(client.updateEvent(body, existingEventId)).rejects.toThrow(
RequestError.fromErrorResponse(Error403 as ErrorResponse, mockResponse)
)
})
@@ -81,7 +87,7 @@ describe('[Mocked response] Update event', () => {
linkedId: 'linked_id',
suspect: true,
}
- await expect(client.updateEvent(body, existingVisitorId)).rejects.toThrow(
+ await expect(client.updateEvent(body, existingEventId)).rejects.toThrow(
RequestError.fromErrorResponse(Error400 as ErrorResponse, mockResponse)
)
})
@@ -96,7 +102,7 @@ describe('[Mocked response] Update event', () => {
linkedId: 'linked_id',
suspect: true,
}
- await expect(client.updateEvent(body, existingVisitorId)).rejects.toThrow(
+ await expect(client.updateEvent(body, existingEventId)).rejects.toThrow(
RequestError.fromErrorResponse(Error409 as ErrorResponse, mockResponse)
)
})
@@ -111,7 +117,7 @@ describe('[Mocked response] Update event', () => {
linkedId: 'linked_id',
suspect: true,
}
- await expect(client.updateEvent(body, existingVisitorId)).rejects.toMatchObject(
+ await expect(client.updateEvent(body, existingEventId)).rejects.toMatchObject(
new SdkError(
'Failed to parse JSON response',
mockResponse,
@@ -121,10 +127,9 @@ describe('[Mocked response] Update event', () => {
})
test('Error with bad shape', async () => {
- const errorInfo = 'Some text instead of shaped object'
const mockResponse = new Response(
JSON.stringify({
- error: errorInfo,
+ error: 'Unexpected error format',
}),
{
status: 404,
@@ -137,7 +142,7 @@ describe('[Mocked response] Update event', () => {
linkedId: 'linked_id',
suspect: true,
}
- await expect(client.updateEvent(body, existingVisitorId)).rejects.toThrow(RequestError)
- await expect(client.updateEvent(body, existingVisitorId)).rejects.toThrow('Some text instead of shaped object')
+ await expect(client.updateEvent(body, existingEventId)).rejects.toThrow(RequestError)
+ await expect(client.updateEvent(body, existingEventId)).rejects.toThrow('Unknown error')
})
})
diff --git a/tests/unit-tests/serverApiClientTests.spec.ts b/tests/unit-tests/serverApiClientTests.spec.ts
index 15c3389c..58a135b4 100644
--- a/tests/unit-tests/serverApiClientTests.spec.ts
+++ b/tests/unit-tests/serverApiClientTests.spec.ts
@@ -1,4 +1,4 @@
-import { RequestError, FingerprintJsServerApiClient, Region, AuthenticationMode } from '../../src'
+import { RequestError, FingerprintJsServerApiClient, Region } from '../../src'
describe('ServerApiClient', () => {
it('should support passing custom fetch implementation', async () => {
@@ -10,7 +10,7 @@ describe('ServerApiClient', () => {
region: Region.Global,
})
- await client.getVisits('visitorId')
+ await client.getEvent('eventId')
expect(mockFetch).toHaveBeenCalledTimes(1)
})
@@ -22,6 +22,7 @@ describe('ServerApiClient', () => {
message: 'feature not enabled',
},
}
+
const mockFetch = jest.fn().mockResolvedValue(new Response(JSON.stringify(responseBody), { status: 403 }))
const client = new FingerprintJsServerApiClient({
@@ -57,46 +58,25 @@ describe('ServerApiClient', () => {
expect(client).toBeTruthy()
})
- it('should support using a string constant for AuthenticationMode.AuthHeader', async () => {
+ it('should support using a string constant for Authorization header', async () => {
const mockFetch = jest.fn().mockResolvedValue(new Response(JSON.stringify({})))
+ const apiKey = 'test'
+
const client = new FingerprintJsServerApiClient({
fetch: mockFetch,
- apiKey: 'test',
+ apiKey,
region: Region.Global,
- authenticationMode: 'AuthHeader',
})
- await client.getVisits('visitorId')
+ await client.getEvent('eventId')
expect(mockFetch).toHaveBeenCalledTimes(1)
- expect(mockFetch).toHaveBeenCalledWith(expect.not.stringContaining('api_key=test'), {
+ expect(mockFetch).toHaveBeenCalledWith(expect.anything(), {
method: 'GET',
headers: {
- 'Auth-API-Key': 'test',
+ Authorization: `Bearer ${apiKey}`,
},
})
})
-
- it.each([['QueryParameter' as keyof typeof AuthenticationMode], [AuthenticationMode.QueryParameter]])(
- 'should put the API key in the query parameters for AuthenticationMode.QueryParameter',
- async (authenticationMode) => {
- const mockFetch = jest.fn().mockResolvedValue(new Response(JSON.stringify({})))
-
- const client = new FingerprintJsServerApiClient({
- fetch: mockFetch,
- apiKey: 'test',
- region: Region.Global,
- authenticationMode,
- })
-
- await client.getVisits('visitorId')
-
- expect(mockFetch).toHaveBeenCalledTimes(1)
- expect(mockFetch).toHaveBeenCalledWith(expect.stringMatching(/.*\?.*api_key=test.*$/), {
- method: 'GET',
- headers: undefined,
- })
- }
- )
})
diff --git a/tests/unit-tests/urlUtilsTests.spec.ts b/tests/unit-tests/urlUtilsTests.spec.ts
index 7ce8cfc8..ecf3ddba 100644
--- a/tests/unit-tests/urlUtilsTests.spec.ts
+++ b/tests/unit-tests/urlUtilsTests.spec.ts
@@ -1,43 +1,29 @@
-import { Region, VisitorHistoryFilter } from '../../src/types'
-import { getRequestPath } from '../../src/urlUtils'
+import { Region, getRequestPath, SearchEventsFilter } from '../../src'
import { version } from '../../package.json'
const visitorId = 'TaDnMBz9XCpZNuSzFUqP'
-const requestId = '1626550679751.cVc5Pm'
+const eventId = '1626550679751.cVc5Pm'
const ii = `ii=fingerprint-pro-server-node-sdk%2F${version}`
describe('Get Event path', () => {
- it('returns correct path without api key', () => {
+ it('returns correct path', () => {
const url = getRequestPath({
- path: '/events/{request_id}',
+ path: '/events/{event_id}',
method: 'get',
- pathParams: [requestId],
+ pathParams: [eventId],
region: Region.Global,
})
- const expectedPath = `https://api.fpjs.io/events/${requestId}?${ii}`
-
- expect(url).toEqual(expectedPath)
- })
-
- it('returns correct path with api key', () => {
- const apiKey = 'test-api-key'
- const url = getRequestPath({
- path: '/events/{request_id}',
- method: 'get',
- pathParams: [requestId],
- apiKey,
- region: Region.Global,
- })
- const expectedPath = `https://api.fpjs.io/events/${requestId}?${ii}&api_key=${apiKey}`
+ const expectedPath = `https://api.fpjs.io/v4/events/${eventId}?${ii}`
expect(url).toEqual(expectedPath)
})
})
-describe('Get Visitors path', () => {
- const linkedId = 'makma'
+describe('Get Event Search path', () => {
+ const linkedId = 'linkedId'
const limit = 10
- const before = 1626538505244
+ const end = 1626538505244
+ const start = 1626538505241
const paginationKey = '1683900801733.Ogvu1j'
test('eu region without filter', async () => {
@@ -47,7 +33,7 @@ describe('Get Visitors path', () => {
pathParams: [visitorId],
region: Region.EU,
})
- const expectedPath = `https://eu.api.fpjs.io/visitors/TaDnMBz9XCpZNuSzFUqP?${ii}`
+ const expectedPath = `https://eu.api.fpjs.io/v4/visitors/TaDnMBz9XCpZNuSzFUqP?${ii}`
expect(actualPath).toEqual(expectedPath)
})
@@ -58,7 +44,7 @@ describe('Get Visitors path', () => {
pathParams: [visitorId],
region: Region.AP,
})
- const expectedPath = `https://ap.api.fpjs.io/visitors/TaDnMBz9XCpZNuSzFUqP?${ii}`
+ const expectedPath = `https://ap.api.fpjs.io/v4/visitors/TaDnMBz9XCpZNuSzFUqP?${ii}`
expect(actualPath).toEqual(expectedPath)
})
@@ -85,120 +71,86 @@ describe('Get Visitors path', () => {
).toThrowError('Unsupported region')
})
- test('eu region with request_id filter', async () => {
- const filter: VisitorHistoryFilter = { request_id: requestId }
- const actualPath = getRequestPath({
- path: '/visitors/{visitor_id}',
- method: 'get',
- queryParams: filter,
- pathParams: [visitorId],
- region: Region.EU,
- })
- const expectedPath = `https://eu.api.fpjs.io/visitors/TaDnMBz9XCpZNuSzFUqP?request_id=1626550679751.cVc5Pm&${ii}`
- expect(actualPath).toEqual(expectedPath)
- })
-
- test('eu region with request_id linked_id filters', async () => {
- const filter: VisitorHistoryFilter = { request_id: requestId, linked_id: linkedId }
+ test('eu region with linked_id filters', async () => {
+ const filter: SearchEventsFilter = { linked_id: linkedId }
const actualPath = getRequestPath({
- path: '/visitors/{visitor_id}',
+ path: '/events',
method: 'get',
queryParams: filter,
- pathParams: [visitorId],
region: Region.EU,
})
- const expectedPath = `https://eu.api.fpjs.io/visitors/TaDnMBz9XCpZNuSzFUqP?request_id=1626550679751.cVc5Pm&linked_id=makma&${ii}`
+ const expectedPath = `https://eu.api.fpjs.io/v4/events?linked_id=${linkedId}&${ii}`
expect(actualPath).toEqual(expectedPath)
})
- test('eu region with request_id, linked_id, limit, before filters', async () => {
- const filter: VisitorHistoryFilter = {
- request_id: requestId,
+ test('eu region with linked_id, limit, start, end filters', async () => {
+ const filter: SearchEventsFilter = {
linked_id: linkedId,
limit,
- before,
+ start,
+ end,
}
const actualPath = getRequestPath({
- path: '/visitors/{visitor_id}',
+ path: '/events',
method: 'get',
queryParams: filter,
- pathParams: [visitorId],
region: Region.EU,
})
- const expectedPath = `https://eu.api.fpjs.io/visitors/TaDnMBz9XCpZNuSzFUqP?request_id=1626550679751.cVc5Pm&linked_id=makma&limit=10&before=1626538505244&${ii}`
+ const expectedPath = `https://eu.api.fpjs.io/v4/events?linked_id=${linkedId}&limit=${limit}&start=${start}&end=${end}&${ii}`
expect(actualPath).toEqual(expectedPath)
})
- test('eu region with request_id, linked_id, limit, paginationKey filters', async () => {
- const filter: VisitorHistoryFilter = {
- request_id: requestId,
+ test('eu region with linked_id, limit, paginationKey filters', async () => {
+ const filter: SearchEventsFilter = {
linked_id: linkedId,
limit,
- paginationKey,
+ pagination_key: paginationKey,
}
const actualPath = getRequestPath({
- path: '/visitors/{visitor_id}',
+ path: '/events',
method: 'get',
queryParams: filter,
- pathParams: [visitorId],
region: Region.EU,
})
- const expectedPath = `https://eu.api.fpjs.io/visitors/TaDnMBz9XCpZNuSzFUqP?request_id=1626550679751.cVc5Pm&linked_id=makma&limit=10&paginationKey=1683900801733.Ogvu1j&${ii}`
+ const expectedPath = `https://eu.api.fpjs.io/v4/events?linked_id=${linkedId}&limit=${limit}&pagination_key=${paginationKey}&${ii}`
expect(actualPath).toEqual(expectedPath)
})
test('global region without filter', async () => {
const actualPath = getRequestPath({
- path: '/visitors/{visitor_id}',
- method: 'get',
- pathParams: [visitorId],
- region: Region.Global,
- })
- const expectedPath = `https://api.fpjs.io/visitors/TaDnMBz9XCpZNuSzFUqP?${ii}`
- expect(actualPath).toEqual(expectedPath)
- })
-
- test('global region with request_id filter', async () => {
- const filter: VisitorHistoryFilter = { request_id: requestId }
- const actualPath = getRequestPath({
- path: '/visitors/{visitor_id}',
+ path: '/events',
method: 'get',
- pathParams: [visitorId],
region: Region.Global,
- queryParams: filter,
})
- const expectedPath = `https://api.fpjs.io/visitors/TaDnMBz9XCpZNuSzFUqP?request_id=1626550679751.cVc5Pm&${ii}`
+ const expectedPath = `https://api.fpjs.io/v4/events?${ii}`
expect(actualPath).toEqual(expectedPath)
})
- test('global region with request_id linked_id filters', async () => {
- const filter: VisitorHistoryFilter = { request_id: requestId, linked_id: linkedId }
+ test('global region with linked_id filters', async () => {
+ const filter: SearchEventsFilter = { linked_id: linkedId }
const actualPath = getRequestPath({
- path: '/visitors/{visitor_id}',
+ path: '/events',
method: 'get',
- pathParams: [visitorId],
queryParams: filter,
region: Region.Global,
})
- const expectedPath = `https://api.fpjs.io/visitors/TaDnMBz9XCpZNuSzFUqP?request_id=1626550679751.cVc5Pm&linked_id=makma&${ii}`
+ const expectedPath = `https://api.fpjs.io/v4/events?linked_id=${linkedId}&${ii}`
expect(actualPath).toEqual(expectedPath)
})
- test('global region with request_id, linked_id, limit, paginationKey filters', async () => {
- const filter: VisitorHistoryFilter = {
- request_id: requestId,
+ test('global region with linked_id, limit, paginationKey filters', async () => {
+ const filter: SearchEventsFilter = {
linked_id: linkedId,
limit,
- paginationKey,
+ pagination_key: paginationKey,
}
const actualPath = getRequestPath({
- path: '/visitors/{visitor_id}',
+ path: '/events',
method: 'get',
- pathParams: [visitorId],
region: Region.Global,
queryParams: filter,
})
- const expectedPath = `https://api.fpjs.io/visitors/TaDnMBz9XCpZNuSzFUqP?request_id=1626550679751.cVc5Pm&linked_id=makma&limit=10&paginationKey=1683900801733.Ogvu1j&${ii}`
+ const expectedPath = `https://api.fpjs.io/v4/events?linked_id=${linkedId}&limit=${limit}&pagination_key=${paginationKey}&${ii}`
expect(actualPath).toEqual(expectedPath)
})
})
@@ -211,7 +163,7 @@ describe('Delete visitor path', () => {
pathParams: [visitorId],
region: Region.EU,
})
- const expectedPath = `https://eu.api.fpjs.io/visitors/TaDnMBz9XCpZNuSzFUqP?${ii}`
+ const expectedPath = `https://eu.api.fpjs.io/v4/visitors/TaDnMBz9XCpZNuSzFUqP?${ii}`
expect(actualPath).toEqual(expectedPath)
})
@@ -222,7 +174,7 @@ describe('Delete visitor path', () => {
pathParams: [visitorId],
region: Region.AP,
})
- const expectedPath = `https://ap.api.fpjs.io/visitors/TaDnMBz9XCpZNuSzFUqP?${ii}`
+ const expectedPath = `https://ap.api.fpjs.io/v4/visitors/TaDnMBz9XCpZNuSzFUqP?${ii}`
expect(actualPath).toEqual(expectedPath)
})
@@ -233,7 +185,7 @@ describe('Delete visitor path', () => {
pathParams: [visitorId],
region: Region.Global,
})
- const expectedPath = `https://api.fpjs.io/visitors/TaDnMBz9XCpZNuSzFUqP?${ii}`
+ const expectedPath = `https://api.fpjs.io/v4/visitors/TaDnMBz9XCpZNuSzFUqP?${ii}`
expect(actualPath).toEqual(expectedPath)
})
})
From 42cd278d9e7fdcb8867adb288d80124527b409b5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Tue, 14 Oct 2025 15:26:41 +0300
Subject: [PATCH 02/29] feat: remove accept header for updateEvent
Remove `Accept: application/json` testing header for `updateEvent`
function.
Related-Task: INTER-1488
---
src/serverApiClient.ts | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/serverApiClient.ts b/src/serverApiClient.ts
index 52cc8fa4..2ab5fe09 100644
--- a/src/serverApiClient.ts
+++ b/src/serverApiClient.ts
@@ -143,7 +143,6 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
const response = await this.fetch(url, {
method: 'PATCH',
headers: {
- Accept: 'application/json',
Authorization: `Bearer ${this.apiKey}`,
},
body: JSON.stringify(body),
From a9286111c11c7d97b1ff10e5b43ce2283b49a111 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Tue, 14 Oct 2025 15:27:18 +0300
Subject: [PATCH 03/29] test: fix update event test expected method
Fix updateEventTests test expected method to `PATCH`.
Related-Task: INTER-1488
---
tests/mocked-responses-tests/updateEventTests.spec.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/mocked-responses-tests/updateEventTests.spec.ts b/tests/mocked-responses-tests/updateEventTests.spec.ts
index 7e9380d3..ea5f7718 100644
--- a/tests/mocked-responses-tests/updateEventTests.spec.ts
+++ b/tests/mocked-responses-tests/updateEventTests.spec.ts
@@ -26,7 +26,7 @@ describe('[Mocked response] Update event', () => {
mockFetch.mockReturnValue(Promise.resolve(new Response()))
const body = {
- linkedId: 'linked_id',
+ linked_id: 'linked_id',
suspect: true,
}
const response = await client.updateEvent(body, existingEventId)
@@ -41,7 +41,7 @@ describe('[Mocked response] Update event', () => {
`https://eu.api.fpjs.io/v4/events/${existingEventId}?ii=${encodeURIComponent(getIntegrationInfo())}`,
{
headers: { Authorization: `Bearer ${apiKey}` },
- method: 'PUT',
+ method: 'PATCH',
body: JSON.stringify(body),
}
)
From 558c352e15cfaf898337d56086998c67d6a42778 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Tue, 14 Oct 2025 16:02:58 +0300
Subject: [PATCH 04/29] chore: remove unnecessary commented line
Removed unnecessary commented line.
Related-Task: INTER-1488
---
src/types.ts | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/src/types.ts b/src/types.ts
index 854acc9d..76103400 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -25,15 +25,11 @@ export interface Options {
fetch?: typeof fetch
}
+export type ErrorResponse = components['schemas']['ErrorResponse']
+
/**
* More info: https://dev.fingerprintjs.com/docs/server-api#query-parameters
*/
-/*
-export type VisitorHistoryFilter = paths['/visitors/{visitor_id}']['get']['parameters']['query']
-*/
-
-export type ErrorResponse = components['schemas']['ErrorResponse']
-
export type SearchEventsFilter = paths['/events']['get']['parameters']['query']
export type SearchEventsResponse = components['schemas']['EventSearch']
From c6a02cde4d092933de9fd318444c2f7511bfebf5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 15 Oct 2025 15:05:43 +0300
Subject: [PATCH 05/29] docs: expand `searchEvents` JSDoc with new filters
Expands `searchEvents` JSDoc with new filters. Also its align parameter
names.
---
src/serverApiClient.ts | 42 ++++++++++++++++++++++++++++++++----------
1 file changed, 32 insertions(+), 10 deletions(-)
diff --git a/src/serverApiClient.ts b/src/serverApiClient.ts
index 2ab5fe09..848cab73 100644
--- a/src/serverApiClient.ts
+++ b/src/serverApiClient.ts
@@ -226,30 +226,52 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
*
* @param {SearchEventsFilter} filter - Events filter
* @param {number} filter.limit - Limit the number of events returned. Must be greater than 0.
- * @param {string|undefined} filter.visitorId - Unique [visitor identifier](https://dev.fingerprint.com/reference/get-function#visitorid) issued by Fingerprint Pro. Filter for events matching this `visitor_id`.
- * @param {string|undefined} filter.bot - Filter events by the bot detection result, specifically:
- * - events where any kind of bot was detected.
- * - events where a good bot was detected.
- * - events where a bad bot was detected.
- * - events where no bot was detected.
+ * @param {string|undefined} filter.pagination_key - Use `pagination_key` to get the next page of results.
+ * @param {string|undefined} filter.visitor_id - Unique [visitor identifier](https://dev.fingerprint.com/reference/get-function#visitorid) issued by Fingerprint Identification. Filter for events matching this `visitor_id`.
+ * @param {string|undefined} filter.bot - Filter events by the bot detection result, specifically:
+ * - events where any kind of bot was detected.
+ * - events where a good bot was detected.
+ * - events where a bad bot was detected.
+ * - events where no bot was detected.
*
- * Allowed values: `all`, `good`, `bad`, `none`.
+ * Allowed values: `all`, `good`, `bad`, `none`.
* @param {string|undefined} filter.ip_address - 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
- * @param {string|undefined} filter.linked_id - Filter events by your custom identifier.
- *
- *
+ * @param {string|undefined} filter.linked_id - 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.
+ * @param {string|undefined} filter.url - Filter events by the URL (`url` property) associated with the event.
+ * @param {string|undefined} filter.origin - Filter events by the origin field of the event. Origin could be the website domain or mobile app bundle ID (eg: com.foo.bar)
* @param {number|undefined} filter.start - Filter events with a timestamp greater than the start time, in Unix time (milliseconds).
* @param {number|undefined} filter.end - Filter events with a timestamp smaller than the end time, in Unix time (milliseconds).
* @param {boolean|undefined} filter.reverse - Sort events in reverse timestamp order.
* @param {boolean|undefined} filter.suspect - Filter events previously tagged as suspicious via the [Update API](https://dev.fingerprint.com/reference/updateevent).
+ * @param {boolean|undefined} filter.vpn - Filter events by VPN Detection result.
+ * @param {boolean|undefined} filter.virtual_machine - Filter events by Virtual Machine Detection result.
+ * @param {boolean|undefined} filter.tampering - Filter events by Browser Tampering Detection result.
+ * @param {boolean|undefined} filter.anti_detect_browser - Filter events by Anti-detect Browser Detection result.
+ * @param {boolean|undefined} filter.incognito - Filter events by Browser Incognito Detection result.
+ * @param {boolean|undefined} filter.privacy_settings - Filter events by Privacy Settings Detection result.
+ * @param {boolean|undefined} filter.jailbroken - Filter events by Jailbroken Device Detection result.
+ * @param {boolean|undefined} filter.frida - Filter events by Frida Detection result.
+ * @param {boolean|undefined} filter.factory_reset - Filter events by Factory Reset Detection result.
+ * @param {boolean|undefined} filter.cloned_app - Filter events by Cloned App Detection result.
+ * @param {boolean|undefined} filter.emulator - Filter events by Android Emulator Detection result.
+ * @param {boolean|undefined} filter.root_apps - Filter events by Rooted Device Detection result.
+ * @param {'high'|'medium'|'low'|undefined} filter.vpn_confidence - Filter events by VPN Detection result confidence level.
+ * @param {number|undefined} filter.min_suspect_score - Filter events with Suspect Score result above a provided minimum threshold.
+ * @param {boolean|undefined} filter.developer_tools - Filter events by Developer Tools detection result.
+ * @param {boolean|undefined} filter.location_spoofing - Filter events by Location Spoofing detection result.
+ * @param {boolean|undefined} filter.mitm_attack - Filter events by MITM (Man-in-the-Middle) Attack detection result.
+ * @param {boolean|undefined} filter.proxy - Filter events by Proxy detection result.
+ * @param {string|undefined} filter.sdk_version - Filter events by a specific SDK version associated with the identification event (`sdk.version` property).
+ * @param {string|undefined} filter.sdk_platform - Filter events by the SDK Platform associated with the identification event (`sdk.platform` property).
+ * @param {string[]|undefined} filter.environment - Filter for events by providing one or more environment IDs (`environment_id` property).
* */
async searchEvents(filter: SearchEventsFilter): Promise {
const url = getRequestPath({
From 696acb32e74eeb6637bd664d03fabf09c5338f73 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 15 Oct 2025 15:27:56 +0300
Subject: [PATCH 06/29] docs: fix example naming for error handling
---
readme.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index 9a20e0bb..e8d0481b 100644
--- a/readme.md
+++ b/readme.md
@@ -125,7 +125,7 @@ const client = new FingerprintJsServerApiClient({
// Handling getEvent errors
try {
- const event = await client.getEvent(requestId)
+ const event = await client.getEvent(eventId)
console.log(JSON.stringify(event, null, 2))
} catch (error) {
if (error instanceof RequestError) {
From 3840e16b62bc1c2fad57807c73f011cceafb494e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 15 Oct 2025 15:28:20 +0300
Subject: [PATCH 07/29] chore: update OpenAPI schema version
---
.schema-version | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.schema-version b/.schema-version
index a5db00c8..b105cea1 100644
--- a/.schema-version
+++ b/.schema-version
@@ -1 +1 @@
-v2.12.0
\ No newline at end of file
+v3.0.1
From ce2854dc064037cd7b2583cb076e671db58d0866 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 15 Oct 2025 15:39:40 +0300
Subject: [PATCH 08/29] chore: add changeset file for changes
---
.changeset/early-seas-look.md | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
create mode 100644 .changeset/early-seas-look.md
diff --git a/.changeset/early-seas-look.md b/.changeset/early-seas-look.md
new file mode 100644
index 00000000..814c9f1c
--- /dev/null
+++ b/.changeset/early-seas-look.md
@@ -0,0 +1,24 @@
+---
+'@fingerprint/fingerprint-server-sdk': major
+---
+
+**Server APIv3 -> Server APIv4 migration**
+
+- Switch all endpoints to `/v4/*`.
+- Remove `authenticationMode` option when initializing `FingerprintJsServerApiClient`.
+- Rename `request_id` to `event_id`.
+- Use snake_case fields when updating an event.
+- Use `PATCH` method when updating an event.
+- Examples, tests, and docs updated.
+
+**BREAKING CHANGES**
+- `authenticationMode` option removed.
+- Endpoints and method signatures changed.
+ - Use `eventId` instead of `requestId` when triggering `updateEvent()` function.
+ - Use `eventId` instead of `requestId` when triggering `getEvent()` function.
+- Removed `getVisits()` function.
+- Removed `getRelatedVisitors()` function.
+- Removed `VisitorHistoryFilter`, `ErrorPlainResponse`, `VisitorsResponse`, `RelatedVisitorsResponse`,
+`RelatedVisitorsFilter`, `Webhook`, `EventsUpdateRequest` types.
+- Use `tags` instead of `tag` for updating an event.
+- Response models changed.
From 41876b5d3ce052eb150348e204ed7b21393e79bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 15 Oct 2025 16:29:49 +0300
Subject: [PATCH 09/29] docs: update package name for badges
---
readme.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/readme.md b/readme.md
index e8d0481b..8a9d5cef 100644
--- a/readme.md
+++ b/readme.md
@@ -10,8 +10,8 @@
From 29e84971721d9dc7764312cf75e87f55b4f449d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 15 Oct 2025 16:30:18 +0300
Subject: [PATCH 10/29] docs: use correct package name for installation
---
readme.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/readme.md b/readme.md
index 8a9d5cef..74864633 100644
--- a/readme.md
+++ b/readme.md
@@ -55,16 +55,16 @@ Install the package using your favorite package manager:
- NPM:
```sh
- npm i @fingerprint/fingerprintjs-server-sdk
+ npm i @fingerprint/fingerprint-server-sdk
```
- Yarn:
```sh
- yarn add @fingerprint/fingerprintjs-server-sdk
+ yarn add @fingerprint/fingerprint-server-sdk
```
- pnpm:
```sh
- pnpm i @fingerprint/fingerprintjs-server-sdk
+ pnpm i @fingerprint/fingerprint-server-sdk
```
## Getting started
From 8e2343ed561ec38f442860c7d740c3e00eb536f4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 22 Oct 2025 13:06:25 +0300
Subject: [PATCH 11/29] chore: remove `getVisitorHistory` example file
Removes `example/getVisitorHistory.mjs` file because it's not a
different endpoint anymore.
Related-Task: INTER-1488
---
example/getVisitorHistory.mjs | 53 -----------------------------------
1 file changed, 53 deletions(-)
delete mode 100644 example/getVisitorHistory.mjs
diff --git a/example/getVisitorHistory.mjs b/example/getVisitorHistory.mjs
deleted file mode 100644
index 6438da9a..00000000
--- a/example/getVisitorHistory.mjs
+++ /dev/null
@@ -1,53 +0,0 @@
-import {
- FingerprintJsServerApiClient,
- Region,
- RequestError,
- TooManyRequestsError,
-} from '@fingerprint/fingerprint-server-sdk'
-import { config } from 'dotenv'
-config()
-
-const apiKey = process.env.API_KEY
-const visitorId = process.env.VISITOR_ID
-const envRegion = process.env.REGION
-
-if (!visitorId) {
- console.error('Visitor ID not defined')
- process.exit(1)
-}
-
-if (!apiKey) {
- console.error('API key not defined')
- process.exit(1)
-}
-
-let region = Region.Global
-if (envRegion === 'eu') {
- region = Region.EU
-} else if (envRegion === 'ap') {
- region = Region.AP
-}
-
-const client = new FingerprintJsServerApiClient({ region, apiKey })
-
-try {
- const visitorHistory = await client.searchEvents({ visitor_id: visitorId, limit: 10 })
- console.log(JSON.stringify(visitorHistory, null, 2))
-} catch (error) {
- if (error instanceof RequestError) {
- console.log(error.statusCode, error.message)
- if (error instanceof TooManyRequestsError) {
- retryLater(error.retryAfter) // Needs to be implemented on your side
- }
- } else {
- console.error('unknown error: ', error)
- }
- process.exit(1)
-}
-
-/**
- * @param {number} delay - How many seconds to wait before retrying
- */
-function retryLater(delay) {
- console.log(`Implement your own retry logic here and retry after ${delay} seconds`)
-}
From 174b14d350f0bc0157b94fe3bf2a80250f347020 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 22 Oct 2025 13:14:52 +0300
Subject: [PATCH 12/29] chore: ignore `fingerprint-server-sdk-smoke-tests`
Add `fingerprint-server-sdk-smoke-tests` to changeset ignore list.
Related-Task: INTER-1488
---
.changeset/config.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.changeset/config.json b/.changeset/config.json
index 401eea9e..339730c2 100644
--- a/.changeset/config.json
+++ b/.changeset/config.json
@@ -12,5 +12,5 @@
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
- "ignore": ["fingerprint-server-sdk-example"]
+ "ignore": ["fingerprint-server-sdk-example", "fingerprint-server-sdk-smoke-tests"]
}
From 385b01b7f9e49422bc3b5e4a4423b73c241a9766 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 22 Oct 2025 13:15:42 +0300
Subject: [PATCH 13/29] chore: changeset mention about package name change
Explicitly mention about package name change in changeset file.
Related-Task: INTER-1488
---
.changeset/loud-waves-drive.md | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 .changeset/loud-waves-drive.md
diff --git a/.changeset/loud-waves-drive.md b/.changeset/loud-waves-drive.md
new file mode 100644
index 00000000..d8c1702f
--- /dev/null
+++ b/.changeset/loud-waves-drive.md
@@ -0,0 +1,5 @@
+---
+'@fingerprint/fingerprint-server-sdk': major
+---
+
+change package name to `@fingerprint/fingerprint-server-sdk`
From ef98a926e47a29d24a667cf04f1aa851f900ff90 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 22 Oct 2025 13:17:46 +0300
Subject: [PATCH 14/29] fix: use correct method for updating event
Use correct `patch` method instead of `put` for updating an event.
Related-Task: INTER-1488
---
src/serverApiClient.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/serverApiClient.ts b/src/serverApiClient.ts
index 848cab73..6070e65c 100644
--- a/src/serverApiClient.ts
+++ b/src/serverApiClient.ts
@@ -137,7 +137,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
path: '/events/{event_id}',
region: this.region,
pathParams: [eventId],
- method: 'put',
+ method: 'patch',
})
const response = await this.fetch(url, {
From ba36af25d1340864a74e6853b0728579ce2015db Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 22 Oct 2025 13:22:07 +0300
Subject: [PATCH 15/29] fix: use response.ok for all success responses
Replace strict `response.status === 200` checks with `response.ok` in
fetch handlers.
Related-Task: INTER-1488
---
src/serverApiClient.ts | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/serverApiClient.ts b/src/serverApiClient.ts
index 6070e65c..eb07e466 100644
--- a/src/serverApiClient.ts
+++ b/src/serverApiClient.ts
@@ -79,7 +79,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
const jsonResponse = await copyResponseJson(response)
- if (response.status === 200) {
+ if (response.ok) {
return jsonResponse as EventsGetResponse
}
@@ -148,7 +148,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
body: JSON.stringify(body),
})
- if (response.status === 200) {
+ if (response.ok) {
return
}
@@ -206,7 +206,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
},
})
- if (response.status === 200) {
+ if (response.ok) {
return
}
@@ -289,7 +289,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
const jsonResponse = await copyResponseJson(response)
- if (response.status === 200) {
+ if (response.ok) {
return jsonResponse as SearchEventsResponse
}
From 4f21b239560808579cdea8a8dfef55e52fc84fe4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 22 Oct 2025 14:41:41 +0300
Subject: [PATCH 16/29] feat: simplify API requests with `callApi`
Added a new `callApi()` function to handle request building and `fetch`
usage in one place. Replaced all direct `fetch` calls with `callApi`.
Introduced `defaultHeaders` options to the client, it's include
`Authorization` header and allow extra headers and override of
`Authorization` header. Made `region` optional in `GetRequestPathOptions`
and it's default to `Region.Global` in `getRequestPath` function.
Related-Task: INTER-1488
---
src/serverApiClient.ts | 61 +++++++++++++++++++-----------------------
src/types.ts | 5 ++++
src/urlUtils.ts | 6 ++---
3 files changed, 35 insertions(+), 37 deletions(-)
diff --git a/src/serverApiClient.ts b/src/serverApiClient.ts
index eb07e466..2c292bfa 100644
--- a/src/serverApiClient.ts
+++ b/src/serverApiClient.ts
@@ -1,4 +1,4 @@
-import { getRequestPath } from './urlUtils'
+import { getRequestPath, GetRequestPathOptions } from './urlUtils'
import {
EventsGetResponse,
EventUpdate,
@@ -10,6 +10,7 @@ import {
} from './types'
import { copyResponseJson } from './responseUtils'
import { handleErrorResponse } from './errors/handleErrorResponse'
+import { paths } from './generatedApiTypes'
export class FingerprintJsServerApiClient implements FingerprintApi {
public readonly region: Region
@@ -18,6 +19,8 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
protected readonly fetch: typeof fetch
+ private readonly defaultHeaders: Record
+
/**
* FingerprintJS server API client used to fetch data from FingerprintJS
* @constructor
@@ -35,6 +38,11 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
this.apiKey = options.apiKey
this.fetch = options.fetch ?? fetch
+
+ this.defaultHeaders = {
+ Authorization: `Bearer ${this.apiKey}`,
+ ...options.defaultHeaders,
+ }
}
/**
@@ -63,20 +71,13 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
throw new TypeError('eventId is not set')
}
- const url = getRequestPath({
+ const response = await this.callApi({
path: '/events/{event_id}',
region: this.region,
pathParams: [eventId],
method: 'get',
})
- const response = await this.fetch(url, {
- method: 'GET',
- headers: {
- Authorization: `Bearer ${this.apiKey}`,
- },
- })
-
const jsonResponse = await copyResponseJson(response)
if (response.ok) {
@@ -133,21 +134,13 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
throw new TypeError('eventId is not set')
}
- const url = getRequestPath({
+ const response = await this.callApi({
path: '/events/{event_id}',
region: this.region,
pathParams: [eventId],
method: 'patch',
})
- const response = await this.fetch(url, {
- method: 'PATCH',
- headers: {
- Authorization: `Bearer ${this.apiKey}`,
- },
- body: JSON.stringify(body),
- })
-
if (response.ok) {
return
}
@@ -192,20 +185,13 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
throw TypeError('VisitorId is not set')
}
- const url = getRequestPath({
+ const response = await this.callApi({
path: '/visitors/{visitor_id}',
region: this.region,
pathParams: [visitorId],
method: 'delete',
})
- const response = await this.fetch(url, {
- method: 'DELETE',
- headers: {
- Authorization: `Bearer ${this.apiKey}`,
- },
- })
-
if (response.ok) {
return
}
@@ -274,18 +260,11 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
* @param {string[]|undefined} filter.environment - Filter for events by providing one or more environment IDs (`environment_id` property).
* */
async searchEvents(filter: SearchEventsFilter): Promise {
- const url = getRequestPath({
+ const response = await this.callApi({
path: '/events',
- region: this.region,
method: 'get',
queryParams: filter,
})
- const response = await this.fetch(url, {
- method: 'GET',
- headers: {
- Authorization: `Bearer ${this.apiKey}`,
- },
- })
const jsonResponse = await copyResponseJson(response)
@@ -295,4 +274,18 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
handleErrorResponse(jsonResponse, response)
}
+
+ private async callApi(
+ options: GetRequestPathOptions & { headers?: Record }
+ ) {
+ const url = getRequestPath(options)
+
+ return await this.fetch(url, {
+ method: options.method as string,
+ headers: {
+ ...this.defaultHeaders,
+ ...options.headers,
+ },
+ })
+ }
}
diff --git a/src/types.ts b/src/types.ts
index 76103400..a594b112 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -23,6 +23,11 @@ export interface Options {
* Optional fetch implementation
* */
fetch?: typeof fetch
+
+ /**
+ * Optional default headers
+ */
+ defaultHeaders?: Record
}
export type ErrorResponse = components['schemas']['ErrorResponse']
diff --git a/src/urlUtils.ts b/src/urlUtils.ts
index 400c4227..8229f8e9 100644
--- a/src/urlUtils.ts
+++ b/src/urlUtils.ts
@@ -89,10 +89,10 @@ type QueryParams =
queryParams?: ExtractQueryParams // Optional query params
}
-type GetRequestPathOptions = {
+export type GetRequestPathOptions = {
path: Path
method: Method
- region: Region
+ region?: Region
} & PathParams &
QueryParams
@@ -140,7 +140,7 @@ export function getRequestPath
Date: Wed, 22 Oct 2025 14:50:13 +0300
Subject: [PATCH 17/29] refactor: inline null checks in query serializer
Remove `isEmptyValue` helper function and use direct `== null` checks to
skip `undefined` or `null` values.
Related-Task: INTER-1488
---
src/urlUtils.ts | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/src/urlUtils.ts b/src/urlUtils.ts
index 8229f8e9..365f9c4c 100644
--- a/src/urlUtils.ts
+++ b/src/urlUtils.ts
@@ -19,23 +19,17 @@ export function getIntegrationInfo() {
return `fingerprint-pro-server-node-sdk/${version}`
}
-function isEmptyValue(value: any): boolean {
- return value === undefined || value === null
-}
-
function serializeQueryStringParams(params: QueryStringParameters): string {
const entries: [string, string][] = []
for (const [key, value] of Object.entries(params)) {
- // Use the helper for the main value
- if (isEmptyValue(value)) {
+ if (value == null) {
continue
}
if (Array.isArray(value)) {
for (const v of value) {
- // Also use the helper for each item in the array
- if (isEmptyValue(v)) {
+ if (v == null) {
continue
}
entries.push([`${key}[]`, String(v)])
From ba552dcf31b958ec81460e75ad181dc38b7d9133 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 22 Oct 2025 15:45:24 +0300
Subject: [PATCH 18/29] chore: use `EVENT_ID` placeholder example dotenv
Use correct `EVENT_ID` placeholder for the example `.env.example` dotenv
file.
Related-Task: INTER-1488
---
example/.env.example | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/example/.env.example b/example/.env.example
index 753f0fed..c48a2f10 100644
--- a/example/.env.example
+++ b/example/.env.example
@@ -1,6 +1,6 @@
API_KEY=
VISITOR_ID=
-EVENT_ID=
+EVENT_ID=
# "eu" or "ap", "us" is the default
REGION=
WEBHOOK_SIGNATURE_SECRET=
From 60156de23de179c3fc8f54fefc4cd6c40ca84ee6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 22 Oct 2025 15:48:03 +0300
Subject: [PATCH 19/29] feat: restrict allowed methods via `AllowedMethod`
Add `IsNever` and `NonNeverKeys` utility types to filter out `never`
type keys. Introduce and export `AllowedMethod` that excludes specific
`parameters` and any `never` type methods. Use this `AllowedMethod` type
for `GetRequestPathOptions` type and `getRequestPath` functions. Update
related signatures.
Related-Task: INTER-1488
---
src/serverApiClient.ts | 4 ++--
src/urlUtils.ts | 10 ++++++++--
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/src/serverApiClient.ts b/src/serverApiClient.ts
index 2c292bfa..5f10018f 100644
--- a/src/serverApiClient.ts
+++ b/src/serverApiClient.ts
@@ -1,4 +1,4 @@
-import { getRequestPath, GetRequestPathOptions } from './urlUtils'
+import { AllowedMethod, getRequestPath, GetRequestPathOptions } from './urlUtils'
import {
EventsGetResponse,
EventUpdate,
@@ -275,7 +275,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
handleErrorResponse(jsonResponse, response)
}
- private async callApi(
+ private async callApi>(
options: GetRequestPathOptions & { headers?: Record }
) {
const url = getRequestPath(options)
diff --git a/src/urlUtils.ts b/src/urlUtils.ts
index 365f9c4c..5922936a 100644
--- a/src/urlUtils.ts
+++ b/src/urlUtils.ts
@@ -83,7 +83,13 @@ type QueryParams =
queryParams?: ExtractQueryParams // Optional query params
}
-export type GetRequestPathOptions = {
+type IsNever = [Exclude] extends [never] ? true : false
+type NonNeverKeys = {
+ [Key in keyof Type]-?: IsNever extends true ? never : Key
+}[keyof Type]
+export type AllowedMethod = Exclude, 'parameters'>
+
+export type GetRequestPathOptions> = {
path: Path
method: Method
region?: Region
@@ -107,7 +113,7 @@ export type GetRequestPathOptions({
+export function getRequestPath>({
path,
pathParams,
queryParams,
From 297d67912872e555e0f6c4b0a38aa537155d26aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 22 Oct 2025 15:57:43 +0300
Subject: [PATCH 20/29] fix: normalize HTTP method casing (uppercase)
Use `options.method.toUpperCase()` when calling `fetch` to ensure
standard HTTP method casing and avoid test fails. Change `AllowedMethod`
to make a string literal union.
Related-Task: INTER-1488
---
src/serverApiClient.ts | 2 +-
src/urlUtils.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/serverApiClient.ts b/src/serverApiClient.ts
index 5f10018f..579a6d43 100644
--- a/src/serverApiClient.ts
+++ b/src/serverApiClient.ts
@@ -281,7 +281,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
const url = getRequestPath(options)
return await this.fetch(url, {
- method: options.method as string,
+ method: options.method.toUpperCase(),
headers: {
...this.defaultHeaders,
...options.headers,
diff --git a/src/urlUtils.ts b/src/urlUtils.ts
index 5922936a..fc1c477d 100644
--- a/src/urlUtils.ts
+++ b/src/urlUtils.ts
@@ -87,7 +87,7 @@ type IsNever = [Exclude] extends [never] ? true : false
type NonNeverKeys = {
[Key in keyof Type]-?: IsNever extends true ? never : Key
}[keyof Type]
-export type AllowedMethod = Exclude, 'parameters'>
+export type AllowedMethod = Extract, 'parameters'>, string>
export type GetRequestPathOptions> = {
path: Path
From 577660b70e0bd97b8a01f7f53abced998b405969 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 22 Oct 2025 16:08:03 +0300
Subject: [PATCH 21/29] feat: add body support to `callApi`
Extend `callApi` to accept an optional `body?: BodyInit` and forward it
to `fetch`. Fix `updateEvent` to send `body`.
Related-Task: INTER-1488
---
src/serverApiClient.ts | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/serverApiClient.ts b/src/serverApiClient.ts
index 579a6d43..802e9b7c 100644
--- a/src/serverApiClient.ts
+++ b/src/serverApiClient.ts
@@ -139,6 +139,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
region: this.region,
pathParams: [eventId],
method: 'patch',
+ body: JSON.stringify(body),
})
if (response.ok) {
@@ -276,7 +277,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
}
private async callApi>(
- options: GetRequestPathOptions & { headers?: Record }
+ options: GetRequestPathOptions & { headers?: Record; body?: BodyInit }
) {
const url = getRequestPath(options)
@@ -286,6 +287,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
...this.defaultHeaders,
...options.headers,
},
+ body: options.body,
})
}
}
From 6ff4e053c9bfba1f58c2f5708b5d19920d57ef61 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 22 Oct 2025 16:09:25 +0300
Subject: [PATCH 22/29] test: remove unnecessary visitor detail tests
Removed unnecessary visitor detail tests.
Related-Task: INTER-1488
---
tests/unit-tests/urlUtilsTests.spec.ts | 45 --------------------------
1 file changed, 45 deletions(-)
diff --git a/tests/unit-tests/urlUtilsTests.spec.ts b/tests/unit-tests/urlUtilsTests.spec.ts
index ecf3ddba..8eb4cbaf 100644
--- a/tests/unit-tests/urlUtilsTests.spec.ts
+++ b/tests/unit-tests/urlUtilsTests.spec.ts
@@ -26,51 +26,6 @@ describe('Get Event Search path', () => {
const start = 1626538505241
const paginationKey = '1683900801733.Ogvu1j'
- test('eu region without filter', async () => {
- const actualPath = getRequestPath({
- path: '/visitors/{visitor_id}',
- method: 'get',
- pathParams: [visitorId],
- region: Region.EU,
- })
- const expectedPath = `https://eu.api.fpjs.io/v4/visitors/TaDnMBz9XCpZNuSzFUqP?${ii}`
- expect(actualPath).toEqual(expectedPath)
- })
-
- test('ap region without filter', async () => {
- const actualPath = getRequestPath({
- path: '/visitors/{visitor_id}',
- method: 'get',
- pathParams: [visitorId],
- region: Region.AP,
- })
- const expectedPath = `https://ap.api.fpjs.io/v4/visitors/TaDnMBz9XCpZNuSzFUqP?${ii}`
- expect(actualPath).toEqual(expectedPath)
- })
-
- test('without path param', async () => {
- expect(() =>
- getRequestPath({
- path: '/visitors/{visitor_id}',
- method: 'get',
- pathParams: [],
- region: Region.AP,
- })
- ).toThrowError('Missing path parameter for visitor_id')
- })
-
- test('unsupported region', async () => {
- expect(() =>
- getRequestPath({
- path: '/visitors/{visitor_id}',
- method: 'get',
- pathParams: [visitorId],
- // @ts-expect-error
- region: 'INVALID',
- })
- ).toThrowError('Unsupported region')
- })
-
test('eu region with linked_id filters', async () => {
const filter: SearchEventsFilter = { linked_id: linkedId }
const actualPath = getRequestPath({
From a9d0af30fcdb601913634b2d264d1ea61839fc06 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 22 Oct 2025 17:28:42 +0300
Subject: [PATCH 23/29] chore: fix missing quote for linked_id
Fix missing quote for `linked_id` in `searchEvents.mjs` example file.
Related-Task: INTER-1488
---
example/searchEvents.mjs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/example/searchEvents.mjs b/example/searchEvents.mjs
index 8349a4f5..03c6016a 100644
--- a/example/searchEvents.mjs
+++ b/example/searchEvents.mjs
@@ -25,7 +25,7 @@ const filter = {
// bot: 'all',
// visitor_id: 'TaDnMBz9XCpZNuSzFUqP',
// ip_address: '192.168.0.1/32',
- // linked_id: ',
+ // linked_id: '',
//start: 1620000000000,
//end: 1630000000000,
//reverse: true,
From bfce2df7e16fb5face4f3e3dae185284086e0b24 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 22 Oct 2025 19:54:38 +0300
Subject: [PATCH 24/29] chore: remove redundant await keyword in callApi
Removed redundant `await` keyword in `callApi` function.
Related-Task: INTER-1488
---
src/serverApiClient.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/serverApiClient.ts b/src/serverApiClient.ts
index 802e9b7c..4b57136c 100644
--- a/src/serverApiClient.ts
+++ b/src/serverApiClient.ts
@@ -281,7 +281,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
) {
const url = getRequestPath(options)
- return await this.fetch(url, {
+ return this.fetch(url, {
method: options.method.toUpperCase(),
headers: {
...this.defaultHeaders,
From 0e4ff4e10c5693d004636b09777673b4eb24f456 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Thu, 23 Oct 2025 14:29:35 +0300
Subject: [PATCH 25/29] refactor: unify response handling and improve type
Centralize response parsing and error handling in `callApi` function.
Throw consistent `SdkError`, `RequestError`, or `TooManyRequestsError`
depends on the case. Added `SuccessJsonOrVoid` to
automatically resolve the potential/correct return type for success
responses. Simplify all public methods.
Related-Task: INTER-1488
---
src/serverApiClient.ts | 97 +++++++++++++++++++++---------------------
src/urlUtils.ts | 34 ++++++++++++++-
2 files changed, 82 insertions(+), 49 deletions(-)
diff --git a/src/serverApiClient.ts b/src/serverApiClient.ts
index 4b57136c..d3f1c85c 100644
--- a/src/serverApiClient.ts
+++ b/src/serverApiClient.ts
@@ -1,5 +1,6 @@
-import { AllowedMethod, getRequestPath, GetRequestPathOptions } from './urlUtils'
+import { AllowedMethod, getRequestPath, GetRequestPathOptions, SuccessJsonOrVoid } from './urlUtils'
import {
+ ErrorResponse,
EventsGetResponse,
EventUpdate,
FingerprintApi,
@@ -8,9 +9,9 @@ import {
SearchEventsFilter,
SearchEventsResponse,
} from './types'
-import { copyResponseJson } from './responseUtils'
-import { handleErrorResponse } from './errors/handleErrorResponse'
import { paths } from './generatedApiTypes'
+import { RequestError, SdkError, TooManyRequestsError } from './errors/apiErrors'
+import { toError } from './utils'
export class FingerprintJsServerApiClient implements FingerprintApi {
public readonly region: Region
@@ -71,20 +72,12 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
throw new TypeError('eventId is not set')
}
- const response = await this.callApi({
+ return this.callApi({
path: '/events/{event_id}',
region: this.region,
pathParams: [eventId],
method: 'get',
})
-
- const jsonResponse = await copyResponseJson(response)
-
- if (response.ok) {
- return jsonResponse as EventsGetResponse
- }
-
- handleErrorResponse(jsonResponse, response)
}
/**
@@ -134,21 +127,13 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
throw new TypeError('eventId is not set')
}
- const response = await this.callApi({
+ return this.callApi({
path: '/events/{event_id}',
region: this.region,
pathParams: [eventId],
method: 'patch',
body: JSON.stringify(body),
})
-
- if (response.ok) {
- return
- }
-
- const jsonResponse = await copyResponseJson(response)
-
- handleErrorResponse(jsonResponse, response)
}
/**
@@ -186,20 +171,12 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
throw TypeError('VisitorId is not set')
}
- const response = await this.callApi({
+ return this.callApi({
path: '/visitors/{visitor_id}',
region: this.region,
pathParams: [visitorId],
method: 'delete',
})
-
- if (response.ok) {
- return
- }
-
- const jsonResponse = await copyResponseJson(response)
-
- handleErrorResponse(jsonResponse, response)
}
/**
@@ -261,33 +238,57 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
* @param {string[]|undefined} filter.environment - Filter for events by providing one or more environment IDs (`environment_id` property).
* */
async searchEvents(filter: SearchEventsFilter): Promise {
- const response = await this.callApi({
+ return this.callApi({
path: '/events',
method: 'get',
queryParams: filter,
})
-
- const jsonResponse = await copyResponseJson(response)
-
- if (response.ok) {
- return jsonResponse as SearchEventsResponse
- }
-
- handleErrorResponse(jsonResponse, response)
}
private async callApi>(
options: GetRequestPathOptions & { headers?: Record; body?: BodyInit }
- ) {
+ ): Promise> {
const url = getRequestPath(options)
- return this.fetch(url, {
- method: options.method.toUpperCase(),
- headers: {
- ...this.defaultHeaders,
- ...options.headers,
- },
- body: options.body,
- })
+ let response: Response
+ try {
+ response = await this.fetch(url, {
+ method: options.method.toUpperCase(),
+ headers: {
+ ...this.defaultHeaders,
+ ...options.headers,
+ },
+ body: options.body,
+ })
+ } catch (e) {
+ throw new SdkError('Network or fetch error', undefined, e as Error)
+ }
+
+ const contentType = response.headers.get('content-type') ?? ''
+ const isJson = contentType.includes('application/json')
+
+ if (response.ok) {
+ if (!isJson || response.status === 204) {
+ return undefined as SuccessJsonOrVoid
+ }
+ let data
+ try {
+ data = await response.json()
+ } catch (e) {
+ throw new SdkError('Failed to parse JSON response', response, toError(e))
+ }
+ return data as SuccessJsonOrVoid
+ }
+
+ if (!isJson) {
+ throw new SdkError(`Non-JSON error response (status ${response.status})`)
+ }
+
+ // TODO: Use ErrorJson instead of ErrorResponse type. It requires generic error classes without error.message and error.code
+ const errPayload = (await response.json()) as ErrorResponse
+ if (response.status === 429) {
+ throw new TooManyRequestsError(errPayload, response)
+ }
+ throw new RequestError(errPayload.error.message, errPayload, response.status, errPayload.error.code, response)
}
}
diff --git a/src/urlUtils.ts b/src/urlUtils.ts
index fc1c477d..e66c3289 100644
--- a/src/urlUtils.ts
+++ b/src/urlUtils.ts
@@ -84,11 +84,43 @@ type QueryParams =
}
type IsNever = [Exclude] extends [never] ? true : false
-type NonNeverKeys = {
+export type NonNeverKeys = {
[Key in keyof Type]-?: IsNever extends true ? never : Key
}[keyof Type]
export type AllowedMethod = Extract, 'parameters'>, string>
+type JsonContentOf = Response extends { content: { 'application/json': infer T } } ? T : never
+
+type UnionJsonFromResponses = {
+ [StatusCode in keyof Response]: JsonContentOf
+}[keyof Response]
+
+type StartingWithSuccessCode = {
+ [StatusCode in keyof Response]: `${StatusCode & number}` extends `2${number}${number}` ? StatusCode : never
+}[keyof Response]
+
+type SuccessResponses = Pick, keyof Response>>
+type ErrorResponses = Omit, keyof Response>>
+
+type OperationOf> = paths[Path][Method]
+
+type ResponsesOf> =
+ OperationOf extends { responses: infer Response } ? Response : never
+
+type SuccessJson> = UnionJsonFromResponses<
+ SuccessResponses>
+>
+
+export type ErrorJson> = UnionJsonFromResponses<
+ ErrorResponses>
+>
+
+export type SuccessJsonOrVoid> = [
+ SuccessJson,
+] extends [never]
+ ? void
+ : SuccessJson
+
export type GetRequestPathOptions> = {
path: Path
method: Method
From bbf565bf6cb5695298d0896bf2ea8c7c1e81703b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Thu, 23 Oct 2025 15:02:23 +0300
Subject: [PATCH 26/29] refactor: simplify error handling
Removed `handleErrorResponse` and moved all error logic into `callApi`.
Exported `isErrorResponse` to detect valid error payloads. Added
`createResponse` helper for creating mock Response object with headers.
Related-Task: INTER-1488
---
src/errors/handleErrorResponse.ts | 15 +------------
src/serverApiClient.ts | 20 +++++++++++-------
.../getEventTests.spec.ts | 21 +++++++------------
.../searchEventsTests.spec.ts | 17 +++++++--------
tests/mocked-responses-tests/utils.ts | 7 +++++++
5 files changed, 35 insertions(+), 45 deletions(-)
create mode 100644 tests/mocked-responses-tests/utils.ts
diff --git a/src/errors/handleErrorResponse.ts b/src/errors/handleErrorResponse.ts
index 853b713a..6ef2a6f5 100644
--- a/src/errors/handleErrorResponse.ts
+++ b/src/errors/handleErrorResponse.ts
@@ -1,7 +1,6 @@
import { ErrorResponse } from '../types'
-import { RequestError, TooManyRequestsError } from './apiErrors'
-function isErrorResponse(value: unknown): value is ErrorResponse {
+export function isErrorResponse(value: unknown): value is ErrorResponse {
return Boolean(
value &&
typeof value === 'object' &&
@@ -12,15 +11,3 @@ function isErrorResponse(value: unknown): value is ErrorResponse {
'message' in value.error
)
}
-
-export function handleErrorResponse(json: any, response: Response): never {
- if (isErrorResponse(json)) {
- if (response.status === 429) {
- throw new TooManyRequestsError(json, response)
- }
-
- throw RequestError.fromErrorResponse(json, response)
- }
-
- throw RequestError.unknown(response)
-}
diff --git a/src/serverApiClient.ts b/src/serverApiClient.ts
index d3f1c85c..7b5262fa 100644
--- a/src/serverApiClient.ts
+++ b/src/serverApiClient.ts
@@ -1,6 +1,5 @@
import { AllowedMethod, getRequestPath, GetRequestPathOptions, SuccessJsonOrVoid } from './urlUtils'
import {
- ErrorResponse,
EventsGetResponse,
EventUpdate,
FingerprintApi,
@@ -12,6 +11,7 @@ import {
import { paths } from './generatedApiTypes'
import { RequestError, SdkError, TooManyRequestsError } from './errors/apiErrors'
import { toError } from './utils'
+import { isErrorResponse } from './errors/handleErrorResponse'
export class FingerprintJsServerApiClient implements FingerprintApi {
public readonly region: Region
@@ -273,22 +273,26 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
}
let data
try {
- data = await response.json()
+ data = await response.clone().json()
} catch (e) {
throw new SdkError('Failed to parse JSON response', response, toError(e))
}
return data as SuccessJsonOrVoid
}
- if (!isJson) {
- throw new SdkError(`Non-JSON error response (status ${response.status})`)
+ let errPayload
+ try {
+ // TODO: Use ErrorJson instead of ErrorResponse type. It requires generic error classes without error.message and error.code
+ errPayload = await response.clone().json()
+ } catch (e) {
+ throw new SdkError('Failed to parse JSON response', response, toError(e))
}
-
- // TODO: Use ErrorJson instead of ErrorResponse type. It requires generic error classes without error.message and error.code
- const errPayload = (await response.json()) as ErrorResponse
if (response.status === 429) {
throw new TooManyRequestsError(errPayload, response)
}
- throw new RequestError(errPayload.error.message, errPayload, response.status, errPayload.error.code, response)
+ if (isErrorResponse(errPayload)) {
+ throw new RequestError(errPayload.error.message, errPayload, response.status, errPayload.error.code, response)
+ }
+ throw RequestError.unknown(response)
}
}
diff --git a/tests/mocked-responses-tests/getEventTests.spec.ts b/tests/mocked-responses-tests/getEventTests.spec.ts
index bb58e384..b0ef3ea7 100644
--- a/tests/mocked-responses-tests/getEventTests.spec.ts
+++ b/tests/mocked-responses-tests/getEventTests.spec.ts
@@ -7,6 +7,7 @@ import {
SdkError,
} from '../../src'
import getEventResponse from './mocked-responses-data/events/get_event_200.json'
+import { createResponse } from './utils'
jest.spyOn(global, 'fetch')
@@ -18,7 +19,7 @@ describe('[Mocked response] Get Event', () => {
const client = new FingerprintJsServerApiClient({ region: Region.EU, apiKey })
test('with event_id', async () => {
- mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getEventResponse))))
+ mockFetch.mockReturnValue(Promise.resolve(createResponse(getEventResponse)))
const response = await client.getEvent(existingEventId)
@@ -39,9 +40,7 @@ describe('[Mocked response] Get Event', () => {
message: 'secret key is required',
},
} satisfies ErrorResponse
- const mockResponse = new Response(JSON.stringify(errorInfo), {
- status: 403,
- })
+ const mockResponse = createResponse(errorInfo, 403)
mockFetch.mockReturnValue(Promise.resolve(mockResponse))
await expect(client.getEvent(existingEventId)).rejects.toThrow(
RequestError.fromErrorResponse(errorInfo, mockResponse)
@@ -55,9 +54,7 @@ describe('[Mocked response] Get Event', () => {
message: 'request id is not found',
},
} satisfies ErrorResponse
- const mockResponse = new Response(JSON.stringify(errorInfo), {
- status: 404,
- })
+ const mockResponse = createResponse(errorInfo, 404)
mockFetch.mockReturnValue(Promise.resolve(mockResponse))
await expect(client.getEvent(existingEventId)).rejects.toThrow(
RequestError.fromErrorResponse(errorInfo, mockResponse)
@@ -65,13 +62,11 @@ describe('[Mocked response] Get Event', () => {
})
test('Error with unknown', async () => {
- const mockResponse = new Response(
- JSON.stringify({
- error: 'Unexpected error format',
- }),
+ const mockResponse = createResponse(
{
- status: 404,
- }
+ error: 'Unexpected error format',
+ },
+ 404
)
mockFetch.mockReturnValue(Promise.resolve(mockResponse))
await expect(client.getEvent(existingEventId)).rejects.toThrow(RequestError)
diff --git a/tests/mocked-responses-tests/searchEventsTests.spec.ts b/tests/mocked-responses-tests/searchEventsTests.spec.ts
index 9fa83169..8ee4edbc 100644
--- a/tests/mocked-responses-tests/searchEventsTests.spec.ts
+++ b/tests/mocked-responses-tests/searchEventsTests.spec.ts
@@ -6,6 +6,7 @@ import {
SearchEventsFilter,
} from '../../src'
import getEventsSearch from './mocked-responses-data/events/search/get_event_search_200.json'
+import { createResponse } from './utils'
jest.spyOn(global, 'fetch')
@@ -16,7 +17,7 @@ describe('[Mocked response] Search Events', () => {
const client = new FingerprintJsServerApiClient({ apiKey })
test('without filter', async () => {
- mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getEventsSearch))))
+ mockFetch.mockReturnValue(Promise.resolve(createResponse(getEventsSearch)))
const limit = 10
@@ -34,7 +35,7 @@ describe('[Mocked response] Search Events', () => {
})
test('with filter params passed as undefined', async () => {
- mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getEventsSearch))))
+ mockFetch.mockReturnValue(Promise.resolve(createResponse(getEventsSearch)))
const limit = 10
@@ -54,7 +55,7 @@ describe('[Mocked response] Search Events', () => {
})
test('with partial filter', async () => {
- mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getEventsSearch))))
+ mockFetch.mockReturnValue(Promise.resolve(createResponse(getEventsSearch)))
const limit = 10
const bot = 'good'
@@ -76,7 +77,7 @@ describe('[Mocked response] Search Events', () => {
})
test('with all possible filters', async () => {
- mockFetch.mockReturnValue(Promise.resolve(new Response(JSON.stringify(getEventsSearch))))
+ mockFetch.mockReturnValue(Promise.resolve(createResponse(getEventsSearch)))
const filters: SearchEventsFilter = {
limit: 10,
@@ -147,9 +148,7 @@ describe('[Mocked response] Search Events', () => {
message: 'Forbidden',
},
} satisfies ErrorResponse
- const mockResponse = new Response(JSON.stringify(error), {
- status: 400,
- })
+ const mockResponse = createResponse(error, 400)
mockFetch.mockReturnValue(Promise.resolve(mockResponse))
await expect(
client.searchEvents({
@@ -165,9 +164,7 @@ describe('[Mocked response] Search Events', () => {
message: 'secret key is required',
},
} satisfies ErrorResponse
- const mockResponse = new Response(JSON.stringify(error), {
- status: 403,
- })
+ const mockResponse = createResponse(error, 403)
mockFetch.mockReturnValue(Promise.resolve(mockResponse))
await expect(
client.searchEvents({
diff --git a/tests/mocked-responses-tests/utils.ts b/tests/mocked-responses-tests/utils.ts
new file mode 100644
index 00000000..d62a975c
--- /dev/null
+++ b/tests/mocked-responses-tests/utils.ts
@@ -0,0 +1,7 @@
+export const createResponse = (resp: object, status: number = 200) =>
+ new Response(JSON.stringify(resp), {
+ headers: {
+ 'content-type': 'application/json',
+ },
+ status,
+ })
From d967cf23286cf627038df103ec8dcbc071b03b85 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 29 Oct 2025 15:27:07 +0300
Subject: [PATCH 27/29] docs: fix webhook example and description
Fixes webhook example and description in the `readme.md` file.
Related-Task: INTER-1488
---
readme.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/readme.md b/readme.md
index 74864633..2ca790ed 100644
--- a/readme.md
+++ b/readme.md
@@ -142,12 +142,12 @@ try {
#### Webhook types
-When handling [Webhooks](https://dev.fingerprint.com/docs/webhooks) coming from Fingerprint, you can cast the payload as the built-in `VisitWebhook` type:
+When handling [Webhooks](https://dev.fingerprint.com/reference/posteventwebhook#/) coming from Fingerprint, you can cast the payload as the built-in `Event` type:
```ts
import { Event } from '@fingerprint/fingerprint-server-sdk'
-const visit = visitWebhookBody as unknown as Event
+const event = eventWebhookBody as unknown as Event
```
#### Webhook signature validation
From ed6fa0190bb12cd9075524d8e7932e5ddfae0ae9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 29 Oct 2025 15:28:42 +0300
Subject: [PATCH 28/29] feat: use Event type instead of EventsGetResponse
Use `Event` type instead of duplicated `EventsGetResponse` type. Update
sealedResults snapshot and example base64 sealed result value. Fix
reference links.
Related-Task: INTER-1488
---
src/sealedResults.ts | 13 +-
src/serverApiClient.ts | 17 +-
src/types.ts | 7 +-
.../__snapshots__/sealedResults.spec.ts.snap | 230 ++++++++++++------
tests/unit-tests/sealedResults.spec.ts | 2 +-
5 files changed, 171 insertions(+), 98 deletions(-)
diff --git a/src/sealedResults.ts b/src/sealedResults.ts
index 86f86aa3..60ae04e2 100644
--- a/src/sealedResults.ts
+++ b/src/sealedResults.ts
@@ -1,7 +1,7 @@
import { createDecipheriv } from 'crypto'
import { inflateRaw } from 'zlib'
import { promisify } from 'util'
-import { EventsGetResponse } from './types'
+import { Event } from './types'
import { UnsealAggregateError, UnsealError } from './errors/unsealError'
import { Buffer } from 'buffer'
@@ -18,14 +18,14 @@ export interface DecryptionKey {
const SEALED_HEADER = Buffer.from([0x9e, 0x85, 0xdc, 0xed])
-function isEventResponse(data: unknown): data is EventsGetResponse {
- return Boolean(data && typeof data === 'object' && 'products' in data)
+function isEventResponse(data: unknown): data is Event {
+ return Boolean(data && typeof data === 'object' && 'event_id' in data && 'timestamp' in data)
}
/**
* @private
* */
-export function parseEventsResponse(unsealed: string): EventsGetResponse {
+export function parseEventsResponse(unsealed: string): Event {
const json = JSON.parse(unsealed)
if (!isEventResponse(json)) {
@@ -42,10 +42,7 @@ export function parseEventsResponse(unsealed: string): EventsGetResponse {
* @throws UnsealAggregateError
* @throws Error
*/
-export async function unsealEventsResponse(
- sealedData: Buffer,
- decryptionKeys: DecryptionKey[]
-): Promise {
+export async function unsealEventsResponse(sealedData: Buffer, decryptionKeys: DecryptionKey[]): Promise {
const unsealed = await unseal(sealedData, decryptionKeys)
return parseEventsResponse(unsealed)
diff --git a/src/serverApiClient.ts b/src/serverApiClient.ts
index 7b5262fa..a5012d68 100644
--- a/src/serverApiClient.ts
+++ b/src/serverApiClient.ts
@@ -1,13 +1,5 @@
import { AllowedMethod, getRequestPath, GetRequestPathOptions, SuccessJsonOrVoid } from './urlUtils'
-import {
- EventsGetResponse,
- EventUpdate,
- FingerprintApi,
- Options,
- Region,
- SearchEventsFilter,
- SearchEventsResponse,
-} from './types'
+import { Event, EventUpdate, FingerprintApi, Options, Region, SearchEventsFilter, SearchEventsResponse } from './types'
import { paths } from './generatedApiTypes'
import { RequestError, SdkError, TooManyRequestsError } from './errors/apiErrors'
import { toError } from './utils'
@@ -51,7 +43,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
*
* @param eventId - identifier of the event
*
- * @returns {Promise} - promise with event response. For more information, see the [Server API documentation](https://dev.fingerprint.com/reference/getevent).
+ * @returns {Promise} - promise with event response. For more information, see the [Server API documentation](https://dev.fingerprint.com/reference/getevent).
*
* @example
* ```javascript
@@ -67,7 +59,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
* })
* ```
* */
- public async getEvent(eventId: string): Promise {
+ public async getEvent(eventId: string): Promise {
if (!eventId) {
throw new TypeError('eventId is not set')
}
@@ -89,7 +81,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
* **Warning** It's not possible to update events older than 10 days.
*
* @param body - Data to update the event with.
- * @param eventId The unique event [identifier](https://dev.fingerprint.com/docs/js-agent#eventid).
+ * @param eventId The unique event [identifier](https://dev.fingerprint.com/reference/js-agent-get-function#requestid).
*
* @return {Promise}
*
@@ -282,7 +274,6 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
let errPayload
try {
- // TODO: Use ErrorJson instead of ErrorResponse type. It requires generic error classes without error.message and error.code
errPayload = await response.clone().json()
} catch (e) {
throw new SdkError('Failed to parse JSON response', response, toError(e))
diff --git a/src/types.ts b/src/types.ts
index a594b112..3c7dca46 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -39,12 +39,7 @@ export type SearchEventsFilter = paths['/events']['get']['parameters']['query']
export type SearchEventsResponse = components['schemas']['EventSearch']
/**
- * More info: https://dev.fingerprintjs.com/docs/server-api#response
- */
-export type EventsGetResponse = paths['/events/{event_id}']['get']['responses']['200']['content']['application/json']
-
-/**
- * More info: https://dev.fingerprintjs.com/docs/webhooks#identification-webhook-object-format
+ * More info: https://dev.fingerprint.com/reference/server-api-v4-get-event
*/
export type Event = components['schemas']['Event']
diff --git a/tests/unit-tests/__snapshots__/sealedResults.spec.ts.snap b/tests/unit-tests/__snapshots__/sealedResults.spec.ts.snap
index 01e8165b..62912390 100644
--- a/tests/unit-tests/__snapshots__/sealedResults.spec.ts.snap
+++ b/tests/unit-tests/__snapshots__/sealedResults.spec.ts.snap
@@ -2,81 +2,171 @@
exports[`Unseal event response unseals sealed data using aes256gcm 1`] = `
{
- "products": {
- "botd": {
- "data": {
- "bot": {
- "result": "notDetected",
- },
- "ip": "::1",
- "meta": {
- "foo": "bar",
- },
- "requestId": "1703067132750.Z5hutJ",
- "time": "2023-12-20T10:12:13.894Z",
- "url": "http://localhost:8080/",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3 Safari/605.1.15",
- },
+ "bot": "not_detected",
+ "browser_details": {
+ "browser_full_version": "74.0.3729",
+ "browser_major_version": "74",
+ "browser_name": "Chrome",
+ "device": "Other",
+ "os": "Windows",
+ "os_version": "7",
+ },
+ "cloned_app": false,
+ "developer_tools": false,
+ "emulator": false,
+ "event_id": "1708102555327.NLOjmg",
+ "factory_reset_timestamp": 0,
+ "frida": false,
+ "identification": {
+ "confidence": {
+ "score": 0.97,
+ "version": "1.1",
},
- "identification": {
- "data": {
- "browserDetails": {
- "browserFullVersion": "17.3",
- "browserMajorVersion": "17",
- "browserName": "Safari",
- "device": "Other",
- "os": "Mac OS X",
- "osVersion": "10.15.7",
- "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3 Safari/605.1.15",
- },
- "confidence": {
- "score": 1,
- },
- "firstSeenAt": {
- "global": "2023-12-15T12:13:55.103Z",
- "subscription": "2023-12-15T12:13:55.103Z",
- },
- "incognito": false,
- "ip": "::1",
- "ipLocation": {
- "accuracyRadius": 1000,
- "city": {
- "name": "Stockholm",
- },
- "continent": {
- "code": "EU",
- "name": "Europe",
+ "first_seen_at": 1708102555327,
+ "last_seen_at": 1708102555327,
+ "visitor_found": false,
+ "visitor_id": "Ibk1527CUFmcnjLwIs4A9",
+ },
+ "incognito": false,
+ "ip_address": "61.127.217.15",
+ "ip_blocklist": {
+ "attack_source": false,
+ "email_spam": false,
+ "tor_node": false,
+ },
+ "ip_info": {
+ "v4": {
+ "address": "94.142.239.124",
+ "asn": "7922",
+ "asn_name": "COMCAST-7922",
+ "asn_network": "73.136.0.0/13",
+ "datacenter_name": "DediPath",
+ "datacenter_result": true,
+ "geolocation": {
+ "accuracy_radius": 20,
+ "city_name": "Prague",
+ "continent_code": "EU",
+ "continent_name": "Europe",
+ "country_code": "CZ",
+ "country_name": "Czechia",
+ "latitude": 50.05,
+ "longitude": 14.4,
+ "postal_code": "150 00",
+ "subdivisions": [
+ {
+ "iso_code": "10",
+ "name": "Hlavni mesto Praha",
},
- "country": {
- "code": "SE",
- "name": "Sweden",
+ ],
+ "timezone": "Europe/Prague",
+ },
+ },
+ "v6": {
+ "address": "2001:db8:3333:4444:5555:6666:7777:8888",
+ "asn": "6805",
+ "asn_name": "Telefonica Germany",
+ "asn_network": "2a02:3100::/24",
+ "datacenter_name": "",
+ "datacenter_result": false,
+ "geolocation": {
+ "accuracy_radius": 5,
+ "city_name": "Berlin",
+ "continent_code": "EU",
+ "continent_name": "Europe",
+ "country_code": "DE",
+ "country_name": "Germany",
+ "latitude": 49.982,
+ "longitude": 36.2566,
+ "postal_code": "10112",
+ "subdivisions": [
+ {
+ "iso_code": "BE",
+ "name": "Land Berlin",
},
- "latitude": 59.3241,
- "longitude": 18.0517,
- "postalCode": "100 05",
- "subdivisions": [
- {
- "isoCode": "AB",
- "name": "Stockholm County",
- },
- ],
- "timezone": "Europe/Stockholm",
- },
- "lastSeenAt": {
- "global": "2023-12-19T11:39:51.52Z",
- "subscription": "2023-12-19T11:39:51.52Z",
- },
- "requestId": "1703067132750.Z5hutJ",
- "tag": {
- "foo": "bar",
- },
- "time": "2023-12-20T10:12:16Z",
- "timestamp": 1703067136286,
- "url": "http://localhost:8080/",
- "visitorFound": true,
- "visitorId": "2ZEDCZEfOfXjEmMuE3tq",
+ ],
+ "timezone": "Europe/Berlin",
},
},
},
+ "jailbroken": false,
+ "linked_id": "somelinkedId",
+ "location_spoofing": false,
+ "mitm_attack": false,
+ "privacy_settings": false,
+ "proxy": true,
+ "proxy_confidence": "low",
+ "proxy_details": {
+ "last_seen_at": 1708102555327,
+ "proxy_type": "residential",
+ },
+ "replayed": false,
+ "root_apps": false,
+ "sdk": {
+ "platform": "js",
+ "version": "3.11.10",
+ },
+ "supplementary_id_high_recall": {
+ "confidence": {
+ "score": 0.97,
+ "version": "1.1",
+ },
+ "first_seen_at": 1708102555327,
+ "last_seen_at": 1708102555327,
+ "visitor_found": true,
+ "visitor_id": "3HNey93AkBW6CRbxV6xP",
+ },
+ "tags": {},
+ "tampering": false,
+ "tampering_details": {
+ "anomaly_score": 0.1955,
+ "anti_detect_browser": false,
+ },
+ "timestamp": 1708102555327,
+ "url": "https://www.example.com/login?hope{this{works[!",
+ "user_agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) ....",
+ "velocity": {
+ "distinct_country": {
+ "1_hour": 2,
+ "24_hours": 2,
+ "5_minutes": 1,
+ },
+ "distinct_ip": {
+ "1_hour": 1,
+ "24_hours": 1,
+ "5_minutes": 1,
+ },
+ "distinct_ip_by_linked_id": {
+ "1_hour": 5,
+ "24_hours": 5,
+ "5_minutes": 1,
+ },
+ "distinct_visitor_id_by_linked_id": {
+ "1_hour": 5,
+ "24_hours": 5,
+ "5_minutes": 1,
+ },
+ "events": {
+ "1_hour": 5,
+ "24_hours": 5,
+ "5_minutes": 1,
+ },
+ "ip_events": {
+ "1_hour": 5,
+ "24_hours": 5,
+ "5_minutes": 1,
+ },
+ },
+ "virtual_machine": false,
+ "vpn": false,
+ "vpn_confidence": "high",
+ "vpn_methods": {
+ "auxiliary_mobile": false,
+ "os_mismatch": false,
+ "public_vpn": false,
+ "relay": false,
+ "timezone_mismatch": false,
+ },
+ "vpn_origin_country": "unknown",
+ "vpn_origin_timezone": "Europe/Berlin",
}
`;
diff --git a/tests/unit-tests/sealedResults.spec.ts b/tests/unit-tests/sealedResults.spec.ts
index 620885c9..9eb5557e 100644
--- a/tests/unit-tests/sealedResults.spec.ts
+++ b/tests/unit-tests/sealedResults.spec.ts
@@ -16,7 +16,7 @@ describe('Parse events response', () => {
describe('Unseal event response', () => {
const sealedData = Buffer.from(
- 'noXc7SXO+mqeAGrvBMgObi/S0fXTpP3zupk8qFqsO/1zdtWCD169iLA3VkkZh9ICHpZ0oWRzqG0M9/TnCeKFohgBLqDp6O0zEfXOv6i5q++aucItznQdLwrKLP+O0blfb4dWVI8/aSbd4ELAZuJJxj9bCoVZ1vk+ShbUXCRZTD30OIEAr3eiG9aw00y1UZIqMgX6CkFlU9L9OnKLsNsyomPIaRHTmgVTI5kNhrnVNyNsnzt9rY7fUD52DQxJILVPrUJ1Q+qW7VyNslzGYBPG0DyYlKbRAomKJDQIkdj/Uwa6bhSTq4XYNVvbk5AJ/dGwvsVdOnkMT2Ipd67KwbKfw5bqQj/cw6bj8Cp2FD4Dy4Ud4daBpPRsCyxBM2jOjVz1B/lAyrOp8BweXOXYugwdPyEn38MBZ5oL4D38jIwR/QiVnMHpERh93jtgwh9Abza6i4/zZaDAbPhtZLXSM5ztdctv8bAb63CppLU541Kf4OaLO3QLvfLRXK2n8bwEwzVAqQ22dyzt6/vPiRbZ5akh8JB6QFXG0QJF9DejsIspKF3JvOKjG2edmC9o+GfL3hwDBiihYXCGY9lElZICAdt+7rZm5UxMx7STrVKy81xcvfaIp1BwGh/HyMsJnkE8IczzRFpLlHGYuNDxdLoBjiifrmHvOCUDcV8UvhSV+UAZtAVejdNGo5G/bz0NF21HUO4pVRPu6RqZIs/aX4hlm6iO/0Ru00ct8pfadUIgRcephTuFC2fHyZxNBC6NApRtLSNLfzYTTo/uSjgcu6rLWiNo5G7yfrM45RXjalFEFzk75Z/fu9lCJJa5uLFgDNKlU+IaFjArfXJCll3apbZp4/LNKiU35ZlB7ZmjDTrji1wLep8iRVVEGht/DW00MTok7Zn7Fv+MlxgWmbZB3BuezwTmXb/fNw==',
+ 'noXc7Xu7PIKu1tbMkMxLbQG4XU46Bv5dED98hqTkPYZnmb8PG81Q83Kpg541Vt4NQdkzfezDSVk8FP9ZzJ08L0MMb4S8bT78c10Op1LyKwZU6DGr1e3V+ZWcNzHVG1rPoL+eUHN6yR9MQp8/CmSUBQUPOOAUXdoqWohbfIGxoQIuQ5BtfpSJuYD6kTyswSi56wxzY/s24dMwgS2KnA81Y1pdi3ZVJKBdwGYGg4T5Dvcqu0GWv3sScKD9b4Tagfbe2m8nbXY/QtN770c7J1xo/TNXXdq4lyqaMyqIayHOwRBP58tNF8mACusm1pogOVIt456wIMetCGKxicPJr7m/Q02ONzhkMtzzXwgwriglGHfM7UbtTsCytCBP7J2vp0tEkHiq/X3qtuvSLJqNyRzwFJhgisKGftc5CIaT2VxVKKxkL/6Ws6FPm4sQB1UGtMCMftKpyb1lFzG9lwFkKvYN9+FGtvRM50mbrzz7ONDxbwykkxihAab36MIuk7dfhvnVLFAjrpuCkEFdWrtjVyWmM0xVeXpEUtP6Ijk5P+VuPZ1alV/JV1q4WvfrGMizEZbwbp6eQZg9mwKe4IX+FVi7sPF2S/CCLI/d90S5Yz6bBP9uiQ3pCVlYbVOkpwS0YQxnR+h5J50qodY7LuswNO5VlEgI0ztkjPQBr8koT4SM54X2z14tA2tKCxSv1psEL5HOk4IWN+9f3RVfDKBDruDiDd+BtZquhYLmOFat9K4h41NrPGAqv5tKmmJtx3llMs6LFHPKBlNlI5zgqE7T47xv2AWw5nqWM107t8lpRETIgJx+YN/Jv6byJSQm7afaeDtHXGceMPOKMziH1XgsiQiS56OsmyyRgaq5YCmMuaPw8gcgVa7RNZSafkP34aQBAuJOA3JFs5xcYcubKutD3h1mk697A8vwdtR/Gj0zTvuUnQ/9o3qHSLseAEIiY9/dS6WJnKXRKTonQi2F6DV9NTzFVQl99AH22jq6lIsjbEEKcq/ydFDUpgAq4lyp9nPBHuPXSojdG+1BWuUyjYykaqnLzzqKgRalGzeWmRHd2qeNw8Bz5OWYBw82C3gHRS2BB9VquIgEYktDvgJ5yRfDYkp8qgxHoYeR88ijccWgdvk+WH78OPdwqA7rqdAYcWqn9KNozoxuYddc0fnrHbgaWpanCmPp0gNEeb4r+i9FDGPSkgYBdyrEPHblsDN/Ad1dhLIHEDEtQyv13s6tDRgLVvhowrzqIM+5cm/abyTDhXzSYDfCw2Wf90cBOMsbQBB2N2YRqnrpA50PGp+0IwlPL7qZj1N4JGhvQD0ux8Ood6AiXpdguj7DMP+T0laHIjWee5/xGZB6g3EsCdOZJjVj7hSE/L3eV4No0WcLqJ5DPOgw+FnvQpxndCTc8DW83tNm624lm7scu0A499vEFj1dhtq5gUxsGcqzm09+Vk2V/d0sa77Xocqe3bcfS5lXc/pHrOc1qKlK8kTr2AYNwjeJJ14euuin361WBETd1I6n8eIs02HyBas09o9lT7Nq05jsnbxej6d0q6GH7IYusiBFTJaAZ6UXOV5i1NOcw9jaGyHms3M2N/b2cmXFYTIFZSjSfbqoI6YZF73sMPhEZqfZ5Jjq+ZLMC3A+yFPFJOW/0oolUGbcC8TBVmLi37Z9Wgc338w2Jf+I94SdViku',
'base64'
)
const validKey = Buffer.from('p2PA7MGy5tx56cnyJaFZMr96BCFwZeHjZV2EqMvTq53=', 'base64')
From c073aebe523db351a53ea0da5c3c6d4c092056be Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eray=20Ayd=C4=B1n?=
Date: Wed, 29 Oct 2025 15:30:07 +0300
Subject: [PATCH 29/29] refactor: remove unnecessary `ErrorJson` type
Removes unnecessary `ErrorJson` type from the project.
Related-Task: INTER-1488
---
src/urlUtils.ts | 5 -----
1 file changed, 5 deletions(-)
diff --git a/src/urlUtils.ts b/src/urlUtils.ts
index e66c3289..aa64dc85 100644
--- a/src/urlUtils.ts
+++ b/src/urlUtils.ts
@@ -100,7 +100,6 @@ type StartingWithSuccessCode = {
}[keyof Response]
type SuccessResponses = Pick, keyof Response>>
-type ErrorResponses = Omit, keyof Response>>
type OperationOf> = paths[Path][Method]
@@ -111,10 +110,6 @@ type SuccessJson> =
SuccessResponses>
>
-export type ErrorJson> = UnionJsonFromResponses<
- ErrorResponses>
->
-
export type SuccessJsonOrVoid> = [
SuccessJson,
] extends [never]