diff --git a/.gitattributes b/.gitattributes index 4691184..272e990 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,7 @@ # Shared test fixtures are compared byte for byte (webhook signatures): never rewrite them. src/test/resources/fixtures/** -text +generated/** linguist-generated +resources/shieldlabs-api.yaml linguist-generated +sync.sh text eol=lf +generate.sh text eol=lf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bf29b72..e76c9e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,3 +37,15 @@ jobs: - name: Compile the example against the installed SDK run: mvn -B -ntp -f examples/httpserver/pom.xml verify + + generated: + name: Generated API types + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 + with: + persist-credentials: false + - name: Rebuild generated files + run: ./generate.sh + - name: Fail if generated files drifted + run: git diff --exit-code diff --git a/CHANGELOG.md b/CHANGELOG.md index 72f5a73..b406c2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project are documented in this file. The format foll [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- `sync.sh` downloads the OpenAPI description and `generate.sh` rebuilds `generated/` from it. The supported client is unchanged. + ## [1.0.0] - 2026-09-30 ### Added diff --git a/README.md b/README.md index 1ab2b31..126dd48 100644 --- a/README.md +++ b/README.md @@ -335,6 +335,14 @@ Retries apply to GET requests only (every SDK call is a GET): exponential backof ## Development +Refresh the generated client when the API description changes. This does not replace the supported library in this repository. + +```bash +./sync.sh # download the current OpenAPI description into resources/ +./generate.sh # rebuild generated/ from that file +``` + + ```bash mvn verify # compile with -Xlint:all -Werror, tests, coverage, javadoc mvn install -DskipTests && mvn -f examples/httpserver/pom.xml verify diff --git a/config.json b/config.json new file mode 100644 index 0000000..c08ebdd --- /dev/null +++ b/config.json @@ -0,0 +1,19 @@ +{ + "groupId": "ai.shieldlabs", + "artifactId": "shieldlabs-generated", + "artifactVersion": "1.0.0", + "apiPackage": "ai.shieldlabs.generated.api", + "modelPackage": "ai.shieldlabs.generated.model", + "invokerPackage": "ai.shieldlabs.generated", + "library": "native", + "developerName": "ShieldLabs", + "developerEmail": "contact@shieldlabs.ai", + "developerOrganization": "ShieldLabs Inc.", + "developerOrganizationUrl": "https://shieldlabs.ai", + "licenseName": "MIT", + "licenseUrl": "https://opensource.org/licenses/MIT", + "scmConnection": "scm:git:https://github.com/ShieldLabs-ai/shieldlabs-java.git", + "scmDeveloperConnection": "scm:git:ssh://git@github.com/ShieldLabs-ai/shieldlabs-java.git", + "scmUrl": "https://github.com/ShieldLabs-ai/shieldlabs-java", + "hideGenerationTimestamp": true +} diff --git a/generate.sh b/generate.sh new file mode 100755 index 0000000..bf24bb9 --- /dev/null +++ b/generate.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd "$(dirname "${BASH_SOURCE[0]}")" + +if ! docker info >/dev/null 2>&1; then + echo "Docker is not running. Start Docker and run this script again." >&2 + exit 1 +fi + +generator="java" +image="openapitools/openapi-generator-cli:v7.23.0" +workdir="$(mktemp -d)" +trap 'rm -rf "$workdir"' EXIT + +python3 - "$PWD/resources/shieldlabs-api.yaml" "$workdir/spec.yaml" << 'PY' +import sys +from pathlib import Path + +source, dest = sys.argv[1:] +lines = Path(source).read_text().splitlines(keepends=True) +out = [] +i = 0 +while i < len(lines): + if lines[i].startswith(" description:"): + out.append(" description: Identification results and risk scoring for your backend.\n") + i += 1 + while i < len(lines) and not (lines[i].startswith(" ") and not lines[i].startswith(" ")): + i += 1 + continue + out.append(lines[i]) + i += 1 +Path(dest).write_text("".join(out)) +PY + +rm -rf generated +mkdir -p generated +cat > generated/.openapi-generator-ignore << 'IGN' +README.md +git_push.sh +.travis.yml +.gitignore +docs/ +test/ +api/openapi.yaml +.github/ +IGN + +docker run --rm -u "$(id -u):$(id -g)" \ + -v "$PWD":/local -v "$workdir":/work -w /local \ + "$image" generate \ + -i /work/spec.yaml \ + -g "$generator" \ + -o /local/generated \ + -c /local/config.json \ + --global-property apis,models,supportingFiles,modelTests=false,apiTests=false,modelDocs=false,apiDocs=false + +find generated \( -name README.md -o -name '*README.md' -o -name git_push.sh -o -name .travis.yml -o -name appveyor.yml -o -name .gitignore -o -name build.sbt -o -name '*.sln' \) -delete +rm -rf generated/docs generated/test generated/.github +find generated -type d -empty -delete + +if [ "$generator" = "go" ]; then + docker run --rm -u "$(id -u):$(id -g)" -v "$PWD/generated":/src -w /src golang:1.24-bookworm gofmt -w . + cat > generated/go.mod << 'MOD' +module github.com/ShieldLabs-ai/shieldlabs-go/generated + +go 1.23 +MOD +fi diff --git a/generated/.openapi-generator-ignore b/generated/.openapi-generator-ignore new file mode 100644 index 0000000..432ff52 --- /dev/null +++ b/generated/.openapi-generator-ignore @@ -0,0 +1,8 @@ +README.md +git_push.sh +.travis.yml +.gitignore +docs/ +test/ +api/openapi.yaml +.github/ diff --git a/generated/.openapi-generator/FILES b/generated/.openapi-generator/FILES new file mode 100644 index 0000000..753c3cf --- /dev/null +++ b/generated/.openapi-generator/FILES @@ -0,0 +1,39 @@ +build.gradle +build.sbt +gradle.properties +gradle/wrapper/gradle-wrapper.jar +gradle/wrapper/gradle-wrapper.properties +gradlew +gradlew.bat +pom.xml +settings.gradle +src/main/AndroidManifest.xml +src/main/java/ai/shieldlabs/generated/ApiClient.java +src/main/java/ai/shieldlabs/generated/ApiException.java +src/main/java/ai/shieldlabs/generated/ApiResponse.java +src/main/java/ai/shieldlabs/generated/Configuration.java +src/main/java/ai/shieldlabs/generated/JSON.java +src/main/java/ai/shieldlabs/generated/Pair.java +src/main/java/ai/shieldlabs/generated/RFC3339DateFormat.java +src/main/java/ai/shieldlabs/generated/RFC3339InstantDeserializer.java +src/main/java/ai/shieldlabs/generated/RFC3339JavaTimeModule.java +src/main/java/ai/shieldlabs/generated/ServerConfiguration.java +src/main/java/ai/shieldlabs/generated/ServerVariable.java +src/main/java/ai/shieldlabs/generated/api/HealthApi.java +src/main/java/ai/shieldlabs/generated/api/HistoryApiApi.java +src/main/java/ai/shieldlabs/generated/api/ManagementApiApi.java +src/main/java/ai/shieldlabs/generated/model/AbstractOpenApiSchema.java +src/main/java/ai/shieldlabs/generated/model/DetectionFlags.java +src/main/java/ai/shieldlabs/generated/model/DomainProfile.java +src/main/java/ai/shieldlabs/generated/model/ErrorBody.java +src/main/java/ai/shieldlabs/generated/model/HealthStatus.java +src/main/java/ai/shieldlabs/generated/model/HistoryPage.java +src/main/java/ai/shieldlabs/generated/model/HistoryRow.java +src/main/java/ai/shieldlabs/generated/model/IdentificationScoredData.java +src/main/java/ai/shieldlabs/generated/model/IdentificationScoredEvent.java +src/main/java/ai/shieldlabs/generated/model/IpInfo.java +src/main/java/ai/shieldlabs/generated/model/LegacySnapshot.java +src/main/java/ai/shieldlabs/generated/model/ScoreDetail.java +src/main/java/ai/shieldlabs/generated/model/Signal.java +src/main/java/ai/shieldlabs/generated/model/TrafficSource.java +src/main/java/ai/shieldlabs/generated/model/WebhookPingEvent.java diff --git a/generated/.openapi-generator/VERSION b/generated/.openapi-generator/VERSION new file mode 100644 index 0000000..14d6b5d --- /dev/null +++ b/generated/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.23.0 diff --git a/generated/build.gradle b/generated/build.gradle new file mode 100644 index 0000000..5093454 --- /dev/null +++ b/generated/build.gradle @@ -0,0 +1,113 @@ +apply plugin: 'idea' +apply plugin: 'eclipse' +apply plugin: 'com.diffplug.spotless' + +group = 'ai.shieldlabs' +version = '1.0.0' + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.diffplug.spotless:spotless-plugin-gradle:6.11.0' + } +} + +repositories { + mavenCentral() +} + +apply plugin: 'java' +apply plugin: 'maven-publish' + +sourceCompatibility = JavaVersion.VERSION_11 +targetCompatibility = JavaVersion.VERSION_11 + +// Some text from the schema is copy pasted into the source files as UTF-8 +// but the default still seems to be to use platform encoding +tasks.withType(JavaCompile) { + configure(options) { + options.encoding = 'UTF-8' + } +} +javadoc { + options.encoding = 'UTF-8' +} + +publishing { + publications { + maven(MavenPublication) { + artifactId = 'shieldlabs-generated' + from components.java + } + } +} + +task execute(type:JavaExec) { + main = System.getProperty('mainClass') + classpath = sourceSets.main.runtimeClasspath +} + +task sourcesJar(type: Jar, dependsOn: classes) { + archiveClassifier = 'sources' + from sourceSets.main.allSource +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + archiveClassifier = 'javadoc' + from javadoc.destinationDir +} + +artifacts { + archives sourcesJar + archives javadocJar +} + + +ext { + jackson_version = "2.21.1" + jackson_annotations_version = "2.21" + jakarta_annotation_version = "1.3.5" + beanvalidation_version = "2.0.2" + junit_version = "5.10.2" +} + +dependencies { + implementation "com.google.code.findbugs:jsr305:3.0.2" + implementation "com.fasterxml.jackson.core:jackson-core:$jackson_version" + implementation "com.fasterxml.jackson.core:jackson-annotations:$jackson_annotations_version" + implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version" + implementation "org.openapitools:jackson-databind-nullable:0.2.10" + implementation "jakarta.annotation:jakarta.annotation-api:$jakarta_annotation_version" + testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_version" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junit_version" +} + +test { + useJUnitPlatform() +} + +// Use spotless plugin to automatically format code, remove unused import, etc +// To apply changes directly to the file, run `gradlew spotlessApply` +// Ref: https://github.com/diffplug/spotless/tree/main/plugin-gradle +spotless { + // comment out below to run spotless as part of the `check` task + enforceCheck false + format 'misc', { + // define the files (e.g. '*.gradle', '*.md') to apply `misc` to + target '.gitignore' + // define the steps to apply to those files + trimTrailingWhitespace() + indentWithSpaces() // Takes an integer argument if you don't like 4 + endWithNewline() + } + java { + // don't need to set target, it is inferred from java + // apply a specific flavor of google-java-format + googleJavaFormat('1.8').aosp().reflowLongStrings() + removeUnusedImports() + importOrder() + } +} diff --git a/generated/gradle.properties b/generated/gradle.properties new file mode 100644 index 0000000..a340857 --- /dev/null +++ b/generated/gradle.properties @@ -0,0 +1,6 @@ +# This file is automatically generated by OpenAPI Generator (https://github.com/openAPITools/openapi-generator). +# To include other gradle properties as part of the code generation process, please use the `gradleProperties` option. +# +# Gradle properties reference: https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties +# For example, uncomment below to build for Android +#target = android diff --git a/generated/gradle/wrapper/gradle-wrapper.jar b/generated/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e644113 Binary files /dev/null and b/generated/gradle/wrapper/gradle-wrapper.jar differ diff --git a/generated/gradle/wrapper/gradle-wrapper.properties b/generated/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..b82aa23 --- /dev/null +++ b/generated/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/generated/gradlew b/generated/gradlew new file mode 100644 index 0000000..9d0ce63 --- /dev/null +++ b/generated/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while +APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path +[ -h "$app_path" ] +do +ls=$( ls -ld "$app_path" ) +link=${ls#*' -> '} +case $link in #( +/*) app_path=$link ;; #( +*) app_path=$APP_HOME$link ;; +esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { +echo "$*" +} >&2 + +die () { +echo +echo "$*" +echo +exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( +CYGWIN* ) cygwin=true ;; #( +Darwin* ) darwin=true ;; #( +MSYS* | MINGW* ) msys=true ;; #( +NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then +if [ -x "$JAVA_HOME/jre/sh/java" ] ; then +# IBM's JDK on AIX uses strange locations for the executables +JAVACMD=$JAVA_HOME/jre/sh/java +else +JAVACMD=$JAVA_HOME/bin/java +fi +if [ ! -x "$JAVACMD" ] ; then +die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi +else +JAVACMD=java +if ! command -v java >/dev/null 2>&1 +then +die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then +case $MAX_FD in #( +max*) +# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. +# shellcheck disable=SC2039,SC3045 +MAX_FD=$( ulimit -H -n ) || +warn "Could not query maximum file descriptor limit" +esac +case $MAX_FD in #( +'' | soft) :;; #( +*) +# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. +# shellcheck disable=SC2039,SC3045 +ulimit -n "$MAX_FD" || +warn "Could not set maximum file descriptor limit to $MAX_FD" +esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then +APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) +CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + +JAVACMD=$( cygpath --unix "$JAVACMD" ) + +# Now convert the arguments - kludge to limit ourselves to /bin/sh +for arg do +if +case $arg in #( +-*) false ;; # don't mess with options #( +/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath +[ -e "$t" ] ;; #( +*) false ;; +esac +then +arg=$( cygpath --path --ignore --mixed "$arg" ) +fi +# Roll the args list around exactly as many times as the number of +# args, so each arg winds up back in the position where it started, but +# possibly modified. +# +# NB: a `for` loop captures its iteration list before it begins, so +# changing the positional parameters here affects neither the number of +# iterations, nor the values presented in `arg`. +shift # remove old arg +set -- "$@" "$arg" # push replacement arg +done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ +"-Dorg.gradle.appname=$APP_BASE_NAME" \ +-classpath "$CLASSPATH" \ +org.gradle.wrapper.GradleWrapperMain \ +"$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then +die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( +printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | +xargs -n1 | +sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | +tr '\n' ' ' +)" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/generated/gradlew.bat b/generated/gradlew.bat new file mode 100644 index 0000000..25da30d --- /dev/null +++ b/generated/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/generated/pom.xml b/generated/pom.xml new file mode 100644 index 0000000..8745c28 --- /dev/null +++ b/generated/pom.xml @@ -0,0 +1,259 @@ + + 4.0.0 + ai.shieldlabs + shieldlabs-generated + jar + shieldlabs-generated + 1.0.0 + https://github.com/openapitools/openapi-generator + OpenAPI Java + + scm:git:https://github.com/ShieldLabs-ai/shieldlabs-java.git + scm:git:ssh://git@github.com/ShieldLabs-ai/shieldlabs-java.git + https://github.com/ShieldLabs-ai/shieldlabs-java + + + + + MIT + https://opensource.org/licenses/MIT + repo + + + + + + ShieldLabs + contact@shieldlabs.ai + ShieldLabs Inc. + https://shieldlabs.ai + + + + + + + maven-enforcer-plugin + 3.1.0 + + + enforce-maven + + enforce + + + + + 3 + + + 11 + + + + + + + + maven-surefire-plugin + 3.2.5 + + + conf/log4j.properties + + -Xms512m -Xmx1500m + methods + 10 + + + + maven-dependency-plugin + 3.3.0 + + + package + + copy-dependencies + + + ${project.build.directory}/lib + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.3.0 + + + + test-jar + + + + + + + + maven-compiler-plugin + 3.10.1 + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.4.1 + + + attach-javadocs + + jar + + + + + + maven-source-plugin + 3.2.1 + + + attach-sources + + jar-no-fork + + + + + + + com.diffplug.spotless + spotless-maven-plugin + ${spotless.version} + + + + + + + .gitignore + + + + + + true + 4 + + + + + + + + + + 1.8 + + true + + + + + + + + + + + + sign-artifacts + + + + maven-gpg-plugin + 3.0.1 + + + sign-artifacts + verify + + sign + + + + + + + + + + + + + + com.fasterxml.jackson.core + jackson-core + ${jackson-version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson-annotations-version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson-version} + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson-version} + + + org.openapitools + jackson-databind-nullable + ${jackson-databind-nullable-version} + + + + + com.google.code.findbugs + jsr305 + 3.0.2 + + + jakarta.annotation + jakarta.annotation-api + ${jakarta-annotation-version} + provided + + + + + org.junit.jupiter + junit-jupiter-api + ${junit-version} + test + + + + + UTF-8 + 11 + 11 + 2.21.1 + 2.21 + 0.2.10 + 1.3.5 + 2.0.2 + 5.10.2 + 2.27.2 + + diff --git a/generated/settings.gradle b/generated/settings.gradle new file mode 100644 index 0000000..b252be1 --- /dev/null +++ b/generated/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "shieldlabs-generated" \ No newline at end of file diff --git a/generated/src/main/AndroidManifest.xml b/generated/src/main/AndroidManifest.xml new file mode 100644 index 0000000..b8fd074 --- /dev/null +++ b/generated/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + + diff --git a/generated/src/main/java/ai/shieldlabs/generated/ApiClient.java b/generated/src/main/java/ai/shieldlabs/generated/ApiClient.java new file mode 100644 index 0000000..9b390ad --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/ApiClient.java @@ -0,0 +1,488 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package ai.shieldlabs.generated; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.openapitools.jackson.nullable.JsonNullableModule; + +import java.io.InputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpConnectTimeoutException; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.StringJoiner; +import java.util.function.Consumer; +import java.util.Optional; +import java.util.zip.GZIPInputStream; +import java.util.stream.Collectors; + +import static java.nio.charset.StandardCharsets.UTF_8; + +/** + * Configuration and utility class for API clients. + * + *

This class can be constructed and modified, then used to instantiate the + * various API classes. The API classes use the settings in this class to + * configure themselves, but otherwise do not store a link to this class.

+ * + *

This class is mutable and not synchronized, so it is not thread-safe. + * The API classes generated from this are immutable and thread-safe.

+ * + *

The setter methods of this class return the current object to facilitate + * a fluent style of configuration.

+ */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class ApiClient { + + protected HttpClient.Builder builder; + protected ObjectMapper mapper; + protected String scheme; + protected String host; + protected int port; + protected String basePath; + protected Consumer interceptor; + protected Consumer> responseInterceptor; + protected Consumer> asyncResponseInterceptor; + protected Duration readTimeout; + protected Duration connectTimeout; + + public static String valueToString(Object value) { + if (value == null) { + return ""; + } + if (value instanceof OffsetDateTime) { + return ((OffsetDateTime) value).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } + return value.toString(); + } + + /** + * URL encode a string in the UTF-8 encoding. + * + * @param s String to encode. + * @return URL-encoded representation of the input string. + */ + public static String urlEncode(String s) { + return URLEncoder.encode(s, UTF_8).replaceAll("\\+", "%20"); + } + + /** + * Convert a URL query name/value parameter to a list of encoded {@link Pair} + * objects. + * + *

The value can be null, in which case an empty list is returned.

+ * + * @param name The query name parameter. + * @param value The query value, which may not be a collection but may be + * null. + * @return A singleton list of the {@link Pair} objects representing the input + * parameters, which is encoded for use in a URL. If the value is null, an + * empty list is returned. + */ + public static List parameterToPairs(String name, Object value) { + if (name == null || name.isEmpty() || value == null) { + return Collections.emptyList(); + } + return Collections.singletonList(new Pair(urlEncode(name), urlEncode(valueToString(value)))); + } + + /** + * Convert a URL query name/collection parameter to a list of encoded + * {@link Pair} objects. + * + * @param collectionFormat The swagger collectionFormat string (csv, tsv, etc). + * @param name The query name parameter. + * @param values A collection of values for the given query name, which may be + * null. + * @return A list of {@link Pair} objects representing the input parameters, + * which is encoded for use in a URL. If the values collection is null, an + * empty list is returned. + */ + public static List parameterToPairs( + String collectionFormat, String name, Collection values) { + if (name == null || name.isEmpty() || values == null || values.isEmpty()) { + return Collections.emptyList(); + } + + // get the collection format (default: csv) + String format = collectionFormat == null || collectionFormat.isEmpty() ? "csv" : collectionFormat; + + // create the params based on the collection format + if ("multi".equals(format)) { + return values.stream() + .map(value -> new Pair(urlEncode(name), urlEncode(valueToString(value)))) + .collect(Collectors.toList()); + } + + String delimiter; + switch(format) { + case "csv": + delimiter = urlEncode(","); + break; + case "ssv": + delimiter = urlEncode(" "); + break; + case "tsv": + delimiter = urlEncode("\t"); + break; + case "pipes": + delimiter = urlEncode("|"); + break; + default: + throw new IllegalArgumentException("Illegal collection format: " + collectionFormat); + } + + StringJoiner joiner = new StringJoiner(delimiter); + for (Object value : values) { + joiner.add(urlEncode(valueToString(value))); + } + + return Collections.singletonList(new Pair(urlEncode(name), joiner.toString())); + } + + /** + * Create an instance of ApiClient. + */ + public ApiClient() { + this.builder = createDefaultHttpClientBuilder(); + this.mapper = createDefaultObjectMapper(); + updateBaseUri("https://account.shieldlabs.ai"); + interceptor = null; + readTimeout = null; + connectTimeout = null; + responseInterceptor = null; + asyncResponseInterceptor = null; + } + + /** + * Create an instance of ApiClient. + * + * @param builder Http client builder. + * @param mapper Object mapper. + * @param baseUri Base URI + */ + public ApiClient(HttpClient.Builder builder, ObjectMapper mapper, String baseUri) { + this.builder = builder; + this.mapper = mapper; + updateBaseUri(baseUri != null ? baseUri : "https://account.shieldlabs.ai"); + interceptor = null; + readTimeout = null; + connectTimeout = null; + responseInterceptor = null; + asyncResponseInterceptor = null; + } + + public static ObjectMapper createDefaultObjectMapper() { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false); + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); + mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); + mapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE); + mapper.registerModule(new JavaTimeModule()); + mapper.registerModule(new JsonNullableModule()); + mapper.registerModule(new RFC3339JavaTimeModule()); + return mapper; + } + + protected final String getDefaultBaseUri() { + return basePath; + } + + public static HttpClient.Builder createDefaultHttpClientBuilder() { + return HttpClient.newBuilder(); + } + + public final void updateBaseUri(String baseUri) { + URI uri = URI.create(baseUri); + scheme = uri.getScheme(); + host = uri.getHost(); + port = uri.getPort(); + basePath = uri.getRawPath(); + } + + /** + * Set a custom {@link HttpClient.Builder} object to use when creating the + * {@link HttpClient} that is used by the API client. + * + * @param builder Custom client builder. + * @return This object. + */ + public ApiClient setHttpClientBuilder(HttpClient.Builder builder) { + this.builder = builder; + return this; + } + + /** + * Get an {@link HttpClient} based on the current {@link HttpClient.Builder}. + * + *

The returned object is immutable and thread-safe.

+ * + * @return The HTTP client. + */ + public HttpClient getHttpClient() { + return builder.build(); + } + + /** + * Set a custom {@link ObjectMapper} to serialize and deserialize the request + * and response bodies. + * + * @param mapper Custom object mapper. + * @return This object. + */ + public ApiClient setObjectMapper(ObjectMapper mapper) { + this.mapper = mapper; + return this; + } + + /** + * Get a copy of the current {@link ObjectMapper}. + * + * @return A copy of the current object mapper. + */ + public ObjectMapper getObjectMapper() { + return mapper.copy(); + } + + /** + * Set a custom host name for the target service. + * + * @param host The host name of the target service. + * @return This object. + */ + public ApiClient setHost(String host) { + this.host = host; + return this; + } + + /** + * Set a custom port number for the target service. + * + * @param port The port of the target service. Set this to -1 to reset the + * value to the default for the scheme. + * @return This object. + */ + public ApiClient setPort(int port) { + this.port = port; + return this; + } + + /** + * Set a custom base path for the target service, for example '/v2'. + * + * @param basePath The base path against which the rest of the path is + * resolved. + * @return This object. + */ + public ApiClient setBasePath(String basePath) { + this.basePath = basePath; + return this; + } + + /** + * Get the base URI to resolve the endpoint paths against. + * + * @return The complete base URI that the rest of the API parameters are + * resolved against. + */ + public String getBaseUri() { + return scheme + "://" + host + (port == -1 ? "" : ":" + port) + basePath; + } + + /** + * Set a custom scheme for the target service, for example 'https'. + * + * @param scheme The scheme of the target service + * @return This object. + */ + public ApiClient setScheme(String scheme){ + this.scheme = scheme; + return this; + } + + /** + * Set a custom request interceptor. + * + *

A request interceptor is a mechanism for altering each request before it + * is sent. After the request has been fully configured but not yet built, the + * request builder is passed into this function for further modification, + * after which it is sent out.

+ * + *

This is useful for altering the requests in a custom manner, such as + * adding headers. It could also be used for logging and monitoring.

+ * + * @param interceptor A function invoked before creating each request. A value + * of null resets the interceptor to a no-op. + * @return This object. + */ + public ApiClient setRequestInterceptor(Consumer interceptor) { + this.interceptor = interceptor; + return this; + } + + /** + * Get the custom interceptor. + * + * @return The custom interceptor that was set, or null if there isn't any. + */ + public Consumer getRequestInterceptor() { + return interceptor; + } + + /** + * Set a custom response interceptor. + * + *

This is useful for logging, monitoring or extraction of header variables

+ * + * @param interceptor A function invoked before creating each request. A value + * of null resets the interceptor to a no-op. + * @return This object. + */ + public ApiClient setResponseInterceptor(Consumer> interceptor) { + this.responseInterceptor = interceptor; + return this; + } + + /** + * Get the custom response interceptor. + * + * @return The custom interceptor that was set, or null if there isn't any. + */ + public Consumer> getResponseInterceptor() { + return responseInterceptor; + } + + /** + * Set a custom async response interceptor. Use this interceptor when asyncNative is set to 'true'. + * + *

This is useful for logging, monitoring or extraction of header variables

+ * + * @param interceptor A function invoked before creating each request. A value + * of null resets the interceptor to a no-op. + * @return This object. + */ + public ApiClient setAsyncResponseInterceptor(Consumer> interceptor) { + this.asyncResponseInterceptor = interceptor; + return this; + } + + /** + * Get the custom async response interceptor. Use this interceptor when asyncNative is set to 'true'. + * + * @return The custom interceptor that was set, or null if there isn't any. + */ + public Consumer> getAsyncResponseInterceptor() { + return asyncResponseInterceptor; + } + + /** + * Set the read timeout for the http client. + * + *

This is the value used by default for each request, though it can be + * overridden on a per-request basis with a request interceptor.

+ * + * @param readTimeout The read timeout used by default by the http client. + * Setting this value to null resets the timeout to an + * effectively infinite value. + * @return This object. + */ + public ApiClient setReadTimeout(Duration readTimeout) { + this.readTimeout = readTimeout; + return this; + } + + /** + * Get the read timeout that was set. + * + * @return The read timeout, or null if no timeout was set. Null represents + * an infinite wait time. + */ + public Duration getReadTimeout() { + return readTimeout; + } + /** + * Sets the connect timeout (in milliseconds) for the http client. + * + *

In the case where a new connection needs to be established, if + * the connection cannot be established within the given {@code + * duration}, then {@link HttpClient#send(HttpRequest,BodyHandler) + * HttpClient::send} throws an {@link HttpConnectTimeoutException}, or + * {@link HttpClient#sendAsync(HttpRequest,BodyHandler) + * HttpClient::sendAsync} completes exceptionally with an + * {@code HttpConnectTimeoutException}. If a new connection does not + * need to be established, for example if a connection can be reused + * from a previous request, then this timeout duration has no effect. + * + * @param connectTimeout connection timeout in milliseconds + * + * @return This object. + */ + public ApiClient setConnectTimeout(Duration connectTimeout) { + this.connectTimeout = connectTimeout; + this.builder.connectTimeout(connectTimeout); + return this; + } + + /** + * Get connection timeout (in milliseconds). + * + * @return Timeout in milliseconds + */ + public Duration getConnectTimeout() { + return connectTimeout; + } + + /** + * Returns the response body InputStream, transparently decoding gzip-compressed + * payloads when the server sets {@code Content-Encoding: gzip}. + * + * @param response HTTP response whose body should be consumed + * @return Original or decompressed InputStream for the response body + * @throws IOException if the response body cannot be accessed or wrapping fails + */ + public static InputStream getResponseBody(HttpResponse response) throws IOException { + if (response == null) { + return null; + } + InputStream body = response.body(); + if (body == null) { + return null; + } + Optional encoding = response.headers().firstValue("Content-Encoding"); + if (encoding.isPresent()) { + for (String token : encoding.get().split(",")) { + if ("gzip".equalsIgnoreCase(token.trim())) { + return new GZIPInputStream(body, 8192); + } + } + } + return body; + } + +} diff --git a/generated/src/main/java/ai/shieldlabs/generated/ApiException.java b/generated/src/main/java/ai/shieldlabs/generated/ApiException.java new file mode 100644 index 0000000..1fa9c54 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/ApiException.java @@ -0,0 +1,92 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated; + +import java.net.http.HttpHeaders; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class ApiException extends Exception { + private static final long serialVersionUID = 1L; + + private int code = 0; + private HttpHeaders responseHeaders = null; + private String responseBody = null; + + public ApiException() {} + + public ApiException(Throwable throwable) { + super(throwable); + } + + public ApiException(String message) { + super(message); + } + + public ApiException(String message, Throwable throwable, int code, HttpHeaders responseHeaders, String responseBody) { + super(message, throwable); + this.code = code; + this.responseHeaders = responseHeaders; + this.responseBody = responseBody; + } + + public ApiException(String message, int code, HttpHeaders responseHeaders, String responseBody) { + this(message, (Throwable) null, code, responseHeaders, responseBody); + } + + public ApiException(String message, Throwable throwable, int code, HttpHeaders responseHeaders) { + this(message, throwable, code, responseHeaders, null); + } + + public ApiException(int code, HttpHeaders responseHeaders, String responseBody) { + this((String) null, (Throwable) null, code, responseHeaders, responseBody); + } + + public ApiException(int code, String message) { + super(message); + this.code = code; + } + + public ApiException(int code, String message, HttpHeaders responseHeaders, String responseBody) { + this(code, message); + this.responseHeaders = responseHeaders; + this.responseBody = responseBody; + } + + /** + * Get the HTTP status code. + * + * @return HTTP status code + */ + public int getCode() { + return code; + } + + /** + * Get the HTTP response headers. + * + * @return Headers as an HttpHeaders object + */ + public HttpHeaders getResponseHeaders() { + return responseHeaders; + } + + /** + * Get the HTTP response body. + * + * @return Response body in the form of string + */ + public String getResponseBody() { + return responseBody; + } +} diff --git a/generated/src/main/java/ai/shieldlabs/generated/ApiResponse.java b/generated/src/main/java/ai/shieldlabs/generated/ApiResponse.java new file mode 100644 index 0000000..0377d2d --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/ApiResponse.java @@ -0,0 +1,60 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated; + +import java.util.List; +import java.util.Map; + +/** + * API response returned by API call. + * + * @param The type of data that is deserialized from response body + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class ApiResponse { + final private int statusCode; + final private Map> headers; + final private T data; + + /** + * @param statusCode The status code of HTTP response + * @param headers The headers of HTTP response + */ + public ApiResponse(int statusCode, Map> headers) { + this(statusCode, headers, null); + } + + /** + * @param statusCode The status code of HTTP response + * @param headers The headers of HTTP response + * @param data The object deserialized from response bod + */ + public ApiResponse(int statusCode, Map> headers, T data) { + this.statusCode = statusCode; + this.headers = headers; + this.data = data; + } + + public int getStatusCode() { + return statusCode; + } + + public Map> getHeaders() { + return headers; + } + + public T getData() { + return data; + } +} diff --git a/generated/src/main/java/ai/shieldlabs/generated/Configuration.java b/generated/src/main/java/ai/shieldlabs/generated/Configuration.java new file mode 100644 index 0000000..1e11306 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/Configuration.java @@ -0,0 +1,63 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class Configuration { + public static final String VERSION = "1.0.0"; + + private static final AtomicReference defaultApiClient = new AtomicReference<>(); + private static volatile Supplier apiClientFactory = ApiClient::new; + + /** + * Get the default API client, which would be used when creating API instances without providing an API client. + * + * @return Default API client + */ + public static ApiClient getDefaultApiClient() { + ApiClient client = defaultApiClient.get(); + if (client == null) { + client = defaultApiClient.updateAndGet(val -> { + if (val != null) { // changed by another thread + return val; + } + return apiClientFactory.get(); + }); + } + return client; + } + + /** + * Set the default API client, which would be used when creating API instances without providing an API client. + * + * @param apiClient API client + */ + public static void setDefaultApiClient(ApiClient apiClient) { + defaultApiClient.set(apiClient); + } + + /** + * set the callback used to create new ApiClient objects + */ + public static void setApiClientFactory(Supplier factory) { + apiClientFactory = Objects.requireNonNull(factory); + } + + private Configuration() { + } +} \ No newline at end of file diff --git a/generated/src/main/java/ai/shieldlabs/generated/JSON.java b/generated/src/main/java/ai/shieldlabs/generated/JSON.java new file mode 100644 index 0000000..8c96371 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/JSON.java @@ -0,0 +1,264 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.json.JsonMapper; +import org.openapitools.jackson.nullable.JsonNullableModule; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import ai.shieldlabs.generated.model.*; + +import java.text.DateFormat; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class JSON { + private ObjectMapper mapper; + + public JSON() { + mapper = JsonMapper.builder() + .serializationInclusion(JsonInclude.Include.NON_NULL) + .disable(MapperFeature.ALLOW_COERCION_OF_SCALARS) + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .enable(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE) + .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING) + .enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING) + .defaultDateFormat(new RFC3339DateFormat()) + .addModule(new JavaTimeModule()) + .build(); + JsonNullableModule jnm = new JsonNullableModule(); + mapper.registerModule(jnm); + } + + /** + * Set the date format for JSON (de)serialization with Date properties. + * + * @param dateFormat Date format + */ + public void setDateFormat(DateFormat dateFormat) { + mapper.setDateFormat(dateFormat); + } + + /** + * Get the object mapper + * + * @return object mapper + */ + public ObjectMapper getMapper() { return mapper; } + + /** + * Returns the target model class that should be used to deserialize the input data. + * The discriminator mappings are used to determine the target model class. + * + * @param node The input data. + * @param modelClass The class that contains the discriminator mappings. + * + * @return the target model class. + */ + public static Class getClassForElement(JsonNode node, Class modelClass) { + ClassDiscriminatorMapping cdm = modelDiscriminators.get(modelClass); + if (cdm != null) { + return cdm.getClassForElement(node, new HashSet>()); + } + return null; + } + + /** + * Helper class to register the discriminator mappings. + */ + @javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") + private static class ClassDiscriminatorMapping { + // The model class name. + Class modelClass; + // The name of the discriminator property. + String discriminatorName; + // The discriminator mappings for a model class. + Map> discriminatorMappings; + + // Constructs a new class discriminator. + ClassDiscriminatorMapping(Class cls, String propertyName, Map> mappings) { + modelClass = cls; + discriminatorName = propertyName; + discriminatorMappings = new HashMap>(); + if (mappings != null) { + discriminatorMappings.putAll(mappings); + } + } + + // Return the name of the discriminator property for this model class. + String getDiscriminatorPropertyName() { + return discriminatorName; + } + + // Return the discriminator value or null if the discriminator is not + // present in the payload. + String getDiscriminatorValue(JsonNode node) { + // Determine the value of the discriminator property in the input data. + if (discriminatorName != null) { + // Get the value of the discriminator property, if present in the input payload. + node = node.get(discriminatorName); + if (node != null && node.isValueNode()) { + String discrValue = node.asText(); + if (discrValue != null) { + return discrValue; + } + } + } + return null; + } + + /** + * Returns the target model class that should be used to deserialize the input data. + * This function can be invoked for anyOf/oneOf composed models with discriminator mappings. + * The discriminator mappings are used to determine the target model class. + * + * @param node The input data. + * @param visitedClasses The set of classes that have already been visited. + * + * @return the target model class. + */ + Class getClassForElement(JsonNode node, Set> visitedClasses) { + if (visitedClasses.contains(modelClass)) { + // Class has already been visited. + return null; + } + // Determine the value of the discriminator property in the input data. + String discrValue = getDiscriminatorValue(node); + if (discrValue == null) { + return null; + } + Class cls = discriminatorMappings.get(discrValue); + // It may not be sufficient to return this cls directly because that target class + // may itself be a composed schema, possibly with its own discriminator. + visitedClasses.add(modelClass); + for (Class childClass : discriminatorMappings.values()) { + ClassDiscriminatorMapping childCdm = modelDiscriminators.get(childClass); + if (childCdm == null) { + continue; + } + if (!discriminatorName.equals(childCdm.discriminatorName)) { + discrValue = getDiscriminatorValue(node); + if (discrValue == null) { + continue; + } + } + if (childCdm != null) { + // Recursively traverse the discriminator mappings. + Class childDiscr = childCdm.getClassForElement(node, visitedClasses); + if (childDiscr != null) { + return childDiscr; + } + } + } + return cls; + } + } + + /** + * Returns true if inst is an instance of modelClass in the OpenAPI model hierarchy. + * + * The Java class hierarchy is not implemented the same way as the OpenAPI model hierarchy, + * so it's not possible to use the instanceof keyword. + * + * @param modelClass A OpenAPI model class. + * @param inst The instance object. + * @param visitedClasses The set of classes that have already been visited. + * + * @return true if inst is an instance of modelClass in the OpenAPI model hierarchy. + */ + public static boolean isInstanceOf(Class modelClass, Object inst, Set> visitedClasses) { + if (modelClass.isInstance(inst)) { + // This handles the 'allOf' use case with single parent inheritance. + return true; + } + if (visitedClasses.contains(modelClass)) { + // This is to prevent infinite recursion when the composed schemas have + // a circular dependency. + return false; + } + visitedClasses.add(modelClass); + + // Traverse the oneOf/anyOf composed schemas. + Map> descendants = modelDescendants.get(modelClass); + if (descendants != null) { + for (Class childType : descendants.values()) { + if (isInstanceOf(childType, inst, visitedClasses)) { + return true; + } + } + } + return false; + } + + /** + * A map of discriminators for all model classes. + */ + private static Map, ClassDiscriminatorMapping> modelDiscriminators = new HashMap<>(); + + /** + * A map of oneOf/anyOf descendants for each model class. + */ + private static Map, Map>> modelDescendants = new HashMap<>(); + + /** + * Register a model class discriminator. + * + * @param modelClass the model class + * @param discriminatorPropertyName the name of the discriminator property + * @param mappings a map with the discriminator mappings. + */ + public static void registerDiscriminator(Class modelClass, String discriminatorPropertyName, Map> mappings) { + ClassDiscriminatorMapping m = new ClassDiscriminatorMapping(modelClass, discriminatorPropertyName, mappings); + modelDiscriminators.put(modelClass, m); + } + + /** + * Register the oneOf/anyOf descendants of the modelClass. + * + * @param modelClass the model class + * @param descendants a map of oneOf/anyOf descendants. + */ + public static void registerDescendants(Class modelClass, Map> descendants) { + modelDescendants.put(modelClass, descendants); + } + + private static JSON json; + + static { + json = new JSON(); + } + + /** + * Get the default JSON instance. + * + * @return the default JSON instance + */ + public static JSON getDefault() { + return json; + } + + /** + * Set the default JSON instance. + * + * @param json JSON instance to be used + */ + public static void setDefault(JSON json) { + JSON.json = json; + } +} diff --git a/generated/src/main/java/ai/shieldlabs/generated/Pair.java b/generated/src/main/java/ai/shieldlabs/generated/Pair.java new file mode 100644 index 0000000..6b08cc3 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/Pair.java @@ -0,0 +1,37 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class Pair { + private final String name; + private final String value; + + public Pair(String name, String value) { + this.name = isValidString(name) ? name : ""; + this.value = isValidString(value) ? value : ""; + } + + public String getName() { + return this.name; + } + + public String getValue() { + return this.value; + } + + private static boolean isValidString(String arg) { + return arg != null; + } +} diff --git a/generated/src/main/java/ai/shieldlabs/generated/RFC3339DateFormat.java b/generated/src/main/java/ai/shieldlabs/generated/RFC3339DateFormat.java new file mode 100644 index 0000000..142de09 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/RFC3339DateFormat.java @@ -0,0 +1,57 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package ai.shieldlabs.generated; + +import java.text.DateFormat; +import java.text.FieldPosition; +import java.text.ParsePosition; +import java.util.Date; +import java.text.DecimalFormat; +import java.util.GregorianCalendar; +import java.util.TimeZone; +import com.fasterxml.jackson.databind.util.StdDateFormat; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class RFC3339DateFormat extends DateFormat { + private static final long serialVersionUID = 1L; + private static final TimeZone TIMEZONE_Z = TimeZone.getTimeZone("UTC"); + + private final StdDateFormat fmt = new StdDateFormat() + .withTimeZone(TIMEZONE_Z) + .withColonInTimeZone(true); + + public RFC3339DateFormat() { + this.calendar = new GregorianCalendar(); + this.numberFormat = new DecimalFormat(); + } + + @Override + public Date parse(String source) { + return parse(source, new ParsePosition(0)); + } + + @Override + public Date parse(String source, ParsePosition pos) { + return fmt.parse(source, pos); + } + + @Override + public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { + return fmt.format(date, toAppendTo, fieldPosition); + } + + @Override + public Object clone() { + return super.clone(); + } +} diff --git a/generated/src/main/java/ai/shieldlabs/generated/RFC3339InstantDeserializer.java b/generated/src/main/java/ai/shieldlabs/generated/RFC3339InstantDeserializer.java new file mode 100644 index 0000000..56b2a82 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/RFC3339InstantDeserializer.java @@ -0,0 +1,100 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package ai.shieldlabs.generated; + +import java.io.IOException; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.util.function.BiFunction; +import java.util.function.Function; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeFeature; +import com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class RFC3339InstantDeserializer extends InstantDeserializer { + private static final long serialVersionUID = 1L; + private final static boolean DEFAULT_NORMALIZE_ZONE_ID = JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID.enabledByDefault(); + private final static boolean DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS + = JavaTimeFeature.ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS.enabledByDefault(); + + public static final RFC3339InstantDeserializer INSTANT = new RFC3339InstantDeserializer<>( + Instant.class, DateTimeFormatter.ISO_INSTANT, + Instant::from, + a -> Instant.ofEpochMilli( a.value ), + a -> Instant.ofEpochSecond( a.integer, a.fraction ), + null, + true, // yes, replace zero offset with Z + DEFAULT_NORMALIZE_ZONE_ID, + DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS + ); + + public static final RFC3339InstantDeserializer OFFSET_DATE_TIME = new RFC3339InstantDeserializer<>( + OffsetDateTime.class, DateTimeFormatter.ISO_OFFSET_DATE_TIME, + OffsetDateTime::from, + a -> OffsetDateTime.ofInstant( Instant.ofEpochMilli( a.value ), a.zoneId ), + a -> OffsetDateTime.ofInstant( Instant.ofEpochSecond( a.integer, a.fraction ), a.zoneId ), + (d, z) -> ( d.isEqual( OffsetDateTime.MIN ) || d.isEqual( OffsetDateTime.MAX ) ? + d : + d.withOffsetSameInstant( z.getRules().getOffset( d.toLocalDateTime() ) ) ), + true, // yes, replace zero offset with Z + DEFAULT_NORMALIZE_ZONE_ID, + DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS + ); + + public static final RFC3339InstantDeserializer ZONED_DATE_TIME = new RFC3339InstantDeserializer<>( + ZonedDateTime.class, DateTimeFormatter.ISO_ZONED_DATE_TIME, + ZonedDateTime::from, + a -> ZonedDateTime.ofInstant( Instant.ofEpochMilli( a.value ), a.zoneId ), + a -> ZonedDateTime.ofInstant( Instant.ofEpochSecond( a.integer, a.fraction ), a.zoneId ), + ZonedDateTime::withZoneSameInstant, + false, // keep zero offset and Z separate since zones explicitly supported + DEFAULT_NORMALIZE_ZONE_ID, + DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS + ); + + protected RFC3339InstantDeserializer( + Class supportedType, + DateTimeFormatter formatter, + Function parsedToValue, + Function fromMilliseconds, + Function fromNanoseconds, + BiFunction adjust, + boolean replaceZeroOffsetAsZ, + boolean normalizeZoneId, + boolean readNumericStringsAsTimestamp) { + super( + supportedType, + formatter, + parsedToValue, + fromMilliseconds, + fromNanoseconds, + adjust, + replaceZeroOffsetAsZ, + normalizeZoneId, + readNumericStringsAsTimestamp + ); + } + + @Override + protected T _fromString(JsonParser p, DeserializationContext ctxt, String string0) throws IOException { + return super._fromString(p, ctxt, string0.replace( ' ', 'T' )); + } +} \ No newline at end of file diff --git a/generated/src/main/java/ai/shieldlabs/generated/RFC3339JavaTimeModule.java b/generated/src/main/java/ai/shieldlabs/generated/RFC3339JavaTimeModule.java new file mode 100644 index 0000000..f36fb00 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/RFC3339JavaTimeModule.java @@ -0,0 +1,39 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package ai.shieldlabs.generated; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; + +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.Module.SetupContext; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class RFC3339JavaTimeModule extends SimpleModule { + private static final long serialVersionUID = 1L; + + public RFC3339JavaTimeModule() { + super("RFC3339JavaTimeModule"); + } + + @Override + public void setupModule(SetupContext context) { + super.setupModule(context); + + addDeserializer(Instant.class, RFC3339InstantDeserializer.INSTANT); + addDeserializer(OffsetDateTime.class, RFC3339InstantDeserializer.OFFSET_DATE_TIME); + addDeserializer(ZonedDateTime.class, RFC3339InstantDeserializer.ZONED_DATE_TIME); + } + +} diff --git a/generated/src/main/java/ai/shieldlabs/generated/ServerConfiguration.java b/generated/src/main/java/ai/shieldlabs/generated/ServerConfiguration.java new file mode 100644 index 0000000..b8fba22 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/ServerConfiguration.java @@ -0,0 +1,72 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated; + +import java.util.Map; + +/** + * Representing a Server configuration. + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class ServerConfiguration { + public String URL; + public String description; + public Map variables; + + /** + * @param URL A URL to the target host. + * @param description A description of the host designated by the URL. + * @param variables A map between a variable name and its value. The value is used for substitution in the server's URL template. + */ + public ServerConfiguration(String URL, String description, Map variables) { + this.URL = URL; + this.description = description; + this.variables = variables; + } + + /** + * Format URL template using given variables. + * + * @param variables A map between a variable name and its value. + * @return Formatted URL. + */ + public String URL(Map variables) { + String url = this.URL; + + // go through variables and replace placeholders + for (Map.Entry variable: this.variables.entrySet()) { + String name = variable.getKey(); + ServerVariable serverVariable = variable.getValue(); + String value = serverVariable.defaultValue; + + if (variables != null && variables.containsKey(name)) { + value = variables.get(name); + if (serverVariable.enumValues.size() > 0 && !serverVariable.enumValues.contains(value)) { + throw new IllegalArgumentException("The variable " + name + " in the server URL has invalid value " + value + "."); + } + } + url = url.replace("{" + name + "}", value); + } + return url; + } + + /** + * Format URL template using default server variables. + * + * @return Formatted URL. + */ + public String URL() { + return URL(null); + } +} diff --git a/generated/src/main/java/ai/shieldlabs/generated/ServerVariable.java b/generated/src/main/java/ai/shieldlabs/generated/ServerVariable.java new file mode 100644 index 0000000..a9415c1 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/ServerVariable.java @@ -0,0 +1,37 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated; + +import java.util.HashSet; + +/** + * Representing a Server Variable for server URL template substitution. + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class ServerVariable { + public String description; + public String defaultValue; + public HashSet enumValues = null; + + /** + * @param description A description for the server variable. + * @param defaultValue The default value to use for substitution. + * @param enumValues An enumeration of string values to be used if the substitution options are from a limited set. + */ + public ServerVariable(String description, String defaultValue, HashSet enumValues) { + this.description = description; + this.defaultValue = defaultValue; + this.enumValues = enumValues; + } +} diff --git a/generated/src/main/java/ai/shieldlabs/generated/api/HealthApi.java b/generated/src/main/java/ai/shieldlabs/generated/api/HealthApi.java new file mode 100644 index 0000000..8725157 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/api/HealthApi.java @@ -0,0 +1,274 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package ai.shieldlabs.generated.api; + +import ai.shieldlabs.generated.ApiClient; +import ai.shieldlabs.generated.ApiException; +import ai.shieldlabs.generated.ApiResponse; +import ai.shieldlabs.generated.Configuration; +import ai.shieldlabs.generated.Pair; + +import ai.shieldlabs.generated.model.HealthStatus; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.net.http.HttpRequest; +import java.nio.channels.Channels; +import java.nio.channels.Pipe; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; + +import java.util.ArrayList; +import java.util.StringJoiner; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class HealthApi { + /** + * Utility class for extending HttpRequest.Builder functionality. + */ + private static class HttpRequestBuilderExtensions { + /** + * Adds additional headers to the provided HttpRequest.Builder. Useful for adding method/endpoint specific headers. + * + * @param builder the HttpRequest.Builder to which headers will be added + * @param headers a map of header names and values to add; may be null + * @return the same HttpRequest.Builder instance with the additional headers set + */ + static HttpRequest.Builder withAdditionalHeaders(HttpRequest.Builder builder, Map headers) { + if (headers != null) { + for (Map.Entry entry : headers.entrySet()) { + builder.header(entry.getKey(), entry.getValue()); + } + } + return builder; + } + } + private final HttpClient memberVarHttpClient; + private final ObjectMapper memberVarObjectMapper; + private final String memberVarBaseUri; + private final Consumer memberVarInterceptor; + private final Duration memberVarReadTimeout; + private final Consumer> memberVarResponseInterceptor; + private final Consumer> memberVarAsyncResponseInterceptor; + + public HealthApi() { + this(Configuration.getDefaultApiClient()); + } + + public HealthApi(ApiClient apiClient) { + memberVarHttpClient = apiClient.getHttpClient(); + memberVarObjectMapper = apiClient.getObjectMapper(); + memberVarBaseUri = apiClient.getBaseUri(); + memberVarInterceptor = apiClient.getRequestInterceptor(); + memberVarReadTimeout = apiClient.getReadTimeout(); + memberVarResponseInterceptor = apiClient.getResponseInterceptor(); + memberVarAsyncResponseInterceptor = apiClient.getAsyncResponseInterceptor(); + } + + + protected ApiException getApiException(String operationId, HttpResponse response) throws IOException { + InputStream responseBody = ApiClient.getResponseBody(response); + String body = null; + try { + body = responseBody == null ? null : new String(responseBody.readAllBytes()); + } finally { + if (responseBody != null) { + responseBody.close(); + } + } + String message = formatExceptionMessage(operationId, response.statusCode(), body); + return new ApiException(response.statusCode(), message, response.headers(), body); + } + + private String formatExceptionMessage(String operationId, int statusCode, String body) { + if (body == null || body.isEmpty()) { + body = "[no body]"; + } + return operationId + " call failed with: " + statusCode + " - " + body; + } + + /** + * Download file from the given response. + * + * @param response Response + * @return File + * @throws ApiException If fail to read file content from response and write to disk + */ + public File downloadFileFromResponse(HttpResponse response, InputStream responseBody) throws ApiException { + if (responseBody == null) { + throw new ApiException(new IOException("Response body is empty")); + } + try { + File file = prepareDownloadFile(response); + java.nio.file.Files.copy(responseBody, file.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING); + return file; + } catch (IOException e) { + throw new ApiException(e); + } + } + + /** + *

Prepare the file for download from the response.

+ * + * @param response a {@link java.net.http.HttpResponse} object. + * @return a {@link java.io.File} object. + * @throws java.io.IOException if any. + */ + private File prepareDownloadFile(HttpResponse response) throws IOException { + String filename = null; + java.util.Optional contentDisposition = response.headers().firstValue("Content-Disposition"); + if (contentDisposition.isPresent() && !"".equals(contentDisposition.get())) { + // Get filename from the Content-Disposition header. + java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?"); + java.util.regex.Matcher matcher = pattern.matcher(contentDisposition.get()); + if (matcher.find()) + filename = matcher.group(1); + } + File file = null; + if (filename != null) { + java.nio.file.Path tempDir = java.nio.file.Files.createTempDirectory("swagger-gen-native"); + java.nio.file.Path filePath = java.nio.file.Files.createFile(tempDir.resolve(filename)); + file = filePath.toFile(); + tempDir.toFile().deleteOnExit(); // best effort cleanup + file.deleteOnExit(); // best effort cleanup + } else { + file = java.nio.file.Files.createTempFile("download-", "").toFile(); + file.deleteOnExit(); // best effort cleanup + } + return file; + } + + /** + * Check service health + * Liveness check. Returns `{\"status\":\"ok\"}` while the service answers. Available on both API hosts: `https://account.shieldlabs.ai/health` for the History API and `https://api.shieldlabs.ai/health` for the Management API. No authentication, not rate limited, not billed. + * @return HealthStatus + * @throws ApiException if fails to make API call + */ + public HealthStatus getHealth() throws ApiException { + return getHealth(null); + } + + /** + * Check service health + * Liveness check. Returns `{\"status\":\"ok\"}` while the service answers. Available on both API hosts: `https://account.shieldlabs.ai/health` for the History API and `https://api.shieldlabs.ai/health` for the Management API. No authentication, not rate limited, not billed. + * @param headers Optional headers to include in the request + * @return HealthStatus + * @throws ApiException if fails to make API call + */ + public HealthStatus getHealth(Map headers) throws ApiException { + ApiResponse localVarResponse = getHealthWithHttpInfo(headers); + return localVarResponse.getData(); + } + + /** + * Check service health + * Liveness check. Returns `{\"status\":\"ok\"}` while the service answers. Available on both API hosts: `https://account.shieldlabs.ai/health` for the History API and `https://api.shieldlabs.ai/health` for the Management API. No authentication, not rate limited, not billed. + * @return ApiResponse<HealthStatus> + * @throws ApiException if fails to make API call + */ + public ApiResponse getHealthWithHttpInfo() throws ApiException { + return getHealthWithHttpInfo(null); + } + + /** + * Check service health + * Liveness check. Returns `{\"status\":\"ok\"}` while the service answers. Available on both API hosts: `https://account.shieldlabs.ai/health` for the History API and `https://api.shieldlabs.ai/health` for the Management API. No authentication, not rate limited, not billed. + * @param headers Optional headers to include in the request + * @return ApiResponse<HealthStatus> + * @throws ApiException if fails to make API call + */ + public ApiResponse getHealthWithHttpInfo(Map headers) throws ApiException { + HttpRequest.Builder localVarRequestBuilder = getHealthRequestBuilder(headers); + try { + HttpResponse localVarResponse = memberVarHttpClient.send( + localVarRequestBuilder.build(), + HttpResponse.BodyHandlers.ofInputStream()); + if (memberVarResponseInterceptor != null) { + memberVarResponseInterceptor.accept(localVarResponse); + } + InputStream localVarResponseBody = null; + try { + if (localVarResponse.statusCode()/ 100 != 2) { + throw getApiException("getHealth", localVarResponse); + } + localVarResponseBody = ApiClient.getResponseBody(localVarResponse); + if (localVarResponseBody == null) { + return new ApiResponse( + localVarResponse.statusCode(), + localVarResponse.headers().map(), + null + ); + } + + + + String responseBody = new String(localVarResponseBody.readAllBytes()); + HealthStatus responseValue = responseBody.isBlank()? null: memberVarObjectMapper.readValue(responseBody, new TypeReference() {}); + + + return new ApiResponse( + localVarResponse.statusCode(), + localVarResponse.headers().map(), + responseValue + ); + } finally { + if (localVarResponseBody != null) { + localVarResponseBody.close(); + } + } + } catch (IOException e) { + throw new ApiException(e); + } + catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new ApiException(e); + } + } + + private HttpRequest.Builder getHealthRequestBuilder(Map headers) throws ApiException { + + HttpRequest.Builder localVarRequestBuilder = HttpRequest.newBuilder(); + + String localVarPath = "/health"; + + localVarRequestBuilder.uri(URI.create(memberVarBaseUri + localVarPath)); + + localVarRequestBuilder.header("Accept", "application/json, text/plain, text/html"); + + localVarRequestBuilder.method("GET", HttpRequest.BodyPublishers.noBody()); + if (memberVarReadTimeout != null) { + localVarRequestBuilder.timeout(memberVarReadTimeout); + } + // Add custom headers if provided + localVarRequestBuilder = HttpRequestBuilderExtensions.withAdditionalHeaders(localVarRequestBuilder, headers); + if (memberVarInterceptor != null) { + memberVarInterceptor.accept(localVarRequestBuilder); + } + return localVarRequestBuilder; + } + +} diff --git a/generated/src/main/java/ai/shieldlabs/generated/api/HistoryApiApi.java b/generated/src/main/java/ai/shieldlabs/generated/api/HistoryApiApi.java new file mode 100644 index 0000000..60d1bce --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/api/HistoryApiApi.java @@ -0,0 +1,318 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package ai.shieldlabs.generated.api; + +import ai.shieldlabs.generated.ApiClient; +import ai.shieldlabs.generated.ApiException; +import ai.shieldlabs.generated.ApiResponse; +import ai.shieldlabs.generated.Configuration; +import ai.shieldlabs.generated.Pair; + +import ai.shieldlabs.generated.model.ErrorBody; +import ai.shieldlabs.generated.model.HistoryPage; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.net.http.HttpRequest; +import java.nio.channels.Channels; +import java.nio.channels.Pipe; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; + +import java.util.ArrayList; +import java.util.StringJoiner; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class HistoryApiApi { + /** + * Utility class for extending HttpRequest.Builder functionality. + */ + private static class HttpRequestBuilderExtensions { + /** + * Adds additional headers to the provided HttpRequest.Builder. Useful for adding method/endpoint specific headers. + * + * @param builder the HttpRequest.Builder to which headers will be added + * @param headers a map of header names and values to add; may be null + * @return the same HttpRequest.Builder instance with the additional headers set + */ + static HttpRequest.Builder withAdditionalHeaders(HttpRequest.Builder builder, Map headers) { + if (headers != null) { + for (Map.Entry entry : headers.entrySet()) { + builder.header(entry.getKey(), entry.getValue()); + } + } + return builder; + } + } + private final HttpClient memberVarHttpClient; + private final ObjectMapper memberVarObjectMapper; + private final String memberVarBaseUri; + private final Consumer memberVarInterceptor; + private final Duration memberVarReadTimeout; + private final Consumer> memberVarResponseInterceptor; + private final Consumer> memberVarAsyncResponseInterceptor; + + public HistoryApiApi() { + this(Configuration.getDefaultApiClient()); + } + + public HistoryApiApi(ApiClient apiClient) { + memberVarHttpClient = apiClient.getHttpClient(); + memberVarObjectMapper = apiClient.getObjectMapper(); + memberVarBaseUri = apiClient.getBaseUri(); + memberVarInterceptor = apiClient.getRequestInterceptor(); + memberVarReadTimeout = apiClient.getReadTimeout(); + memberVarResponseInterceptor = apiClient.getResponseInterceptor(); + memberVarAsyncResponseInterceptor = apiClient.getAsyncResponseInterceptor(); + } + + + protected ApiException getApiException(String operationId, HttpResponse response) throws IOException { + InputStream responseBody = ApiClient.getResponseBody(response); + String body = null; + try { + body = responseBody == null ? null : new String(responseBody.readAllBytes()); + } finally { + if (responseBody != null) { + responseBody.close(); + } + } + String message = formatExceptionMessage(operationId, response.statusCode(), body); + return new ApiException(response.statusCode(), message, response.headers(), body); + } + + private String formatExceptionMessage(String operationId, int statusCode, String body) { + if (body == null || body.isEmpty()) { + body = "[no body]"; + } + return operationId + " call failed with: " + statusCode + " - " + body; + } + + /** + * Download file from the given response. + * + * @param response Response + * @return File + * @throws ApiException If fail to read file content from response and write to disk + */ + public File downloadFileFromResponse(HttpResponse response, InputStream responseBody) throws ApiException { + if (responseBody == null) { + throw new ApiException(new IOException("Response body is empty")); + } + try { + File file = prepareDownloadFile(response); + java.nio.file.Files.copy(responseBody, file.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING); + return file; + } catch (IOException e) { + throw new ApiException(e); + } + } + + /** + *

Prepare the file for download from the response.

+ * + * @param response a {@link java.net.http.HttpResponse} object. + * @return a {@link java.io.File} object. + * @throws java.io.IOException if any. + */ + private File prepareDownloadFile(HttpResponse response) throws IOException { + String filename = null; + java.util.Optional contentDisposition = response.headers().firstValue("Content-Disposition"); + if (contentDisposition.isPresent() && !"".equals(contentDisposition.get())) { + // Get filename from the Content-Disposition header. + java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?"); + java.util.regex.Matcher matcher = pattern.matcher(contentDisposition.get()); + if (matcher.find()) + filename = matcher.group(1); + } + File file = null; + if (filename != null) { + java.nio.file.Path tempDir = java.nio.file.Files.createTempDirectory("swagger-gen-native"); + java.nio.file.Path filePath = java.nio.file.Files.createFile(tempDir.resolve(filename)); + file = filePath.toFile(); + tempDir.toFile().deleteOnExit(); // best effort cleanup + file.deleteOnExit(); // best effort cleanup + } else { + file = java.nio.file.Files.createTempFile("download-", "").toFile(); + file.deleteOnExit(); // best effort cleanup + } + return file; + } + + /** + * Search identifications + * Returns the identifications of your domain that match one identifier, newest first, together with the total number of matches. The Private API Key selects the domain; identifications from its subdomains are included (`domain` holds the host, `site_domain` the registered domain). **Read one verdict.** After a protected action, search by `request_id` with `limit=1`. The row appears about 1-3 seconds after the browser call and can be refined for up to about 10 seconds as follow-up network checks finish, so start the identification when the user begins the action (for example when the signup form opens), not when the form is submitted. An empty `data` array means \"not scored yet\", never \"clean\". Poll with backoff (first try at once, then wait 250 ms, 500 ms, 1 s, then steps of about 1.5 s) and treat a `429` inside that loop as \"wait longer\". The official server SDKs do this for you. **Account-level checks.** Search by `device_id`, `user_hid`, `visitor_id` or `ip` to see how many accounts share a device, how many devices one account uses, or what else came from one IP address. When you count accounts, skip rows whose `user_hid` is empty or one of the values that do not identify a user: `anonymous`, `fail`, `-1` and `unknown`. **Validate before sending.** The server does not validate the path: an unknown `search_type` returns the latest identifications of the whole domain unfiltered, a malformed UUID or IPv4 value returns `500`, and a `limit` outside 1-100 silently becomes 20. **Paging.** Page with `offset` while it is below `total`. Rows are ordered by `created_at` only, so paging while new identifications arrive can repeat or skip rows: deduplicate on `request_id`. **Latest state.** A row can be refined after the webhook was sent, for example when late network data re-scores it; its `ver` then increases. The History API always returns the latest version, which makes it the guaranteed read path. Reads are free: they do not use your included identifications. + * @param searchType Identifier to search by. Only these seven values are supported: - `request_id`: one identification (read a verdict); - `device_id`: every identification of one device; - `user_hid`: every identification of one account; - `visitor_id`: every identification of one visitor; - `ip`: every identification from one public IPv4 address; - `session_id`: every identification of one visit; - `cookie_id`: every identification with one browser cookie. The server does not reject other values: it ignores them and returns the latest identifications of the whole domain, so restrict the value on your side. (required) + * @param value Value of the identifier, validated on your side before sending: - `request_id`, `device_id`, `visitor_id`, `session_id`, `cookie_id`: a UUID of any version, the nil UUID included, matching `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`. Send it lowercase. - `ip`: a dotted IPv4 address. IPv6 addresses cannot be searched. - `user_hid`: the exact, case-sensitive User HID as one path segment, encoded the way the server reads it: send the characters `A-Z a-z 0-9 - . _ ~ $ & + , : ; = @` unescaped and percent-encode every other byte of the UTF-8 value as uppercase `%XX`, including `! ' ( ) *`, spaces and `%` itself. The server compares any other encoding literally, so `%40` instead of `@`, or lowercase hex digits, return an empty page instead of the matching rows. Many HTTP clients and generated clients escape `$ & + , : ; = @` in path values: build this path yourself when yours does. A User HID that contains `/` cannot be searched, and most HTTP clients cannot send `.` or `..` because they remove them as dot segments; the pattern rejects these values. Hex-encoded hashes need no escaping at all. The server does not validate the value: a malformed UUID or IPv4 address gets a `500`. (required) + * @param limit Maximum number of identifications to return, from 1 to 100. The server replaces any other value (and a non-numeric one) with 20 instead of clamping it, so validate it on your side. (optional, default to 20) + * @param offset Number of identifications to skip, for paging. The server treats negative or non-numeric values as 0. Rows are ordered by `created_at` only, so paging while new identifications arrive can repeat or skip rows: deduplicate on `request_id`. (optional, default to 0) + * @return HistoryPage + * @throws ApiException if fails to make API call + */ + public HistoryPage searchHistory(@javax.annotation.Nonnull String searchType, @javax.annotation.Nonnull String value, @javax.annotation.Nullable Integer limit, @javax.annotation.Nullable Integer offset) throws ApiException { + return searchHistory(searchType, value, limit, offset, null); + } + + /** + * Search identifications + * Returns the identifications of your domain that match one identifier, newest first, together with the total number of matches. The Private API Key selects the domain; identifications from its subdomains are included (`domain` holds the host, `site_domain` the registered domain). **Read one verdict.** After a protected action, search by `request_id` with `limit=1`. The row appears about 1-3 seconds after the browser call and can be refined for up to about 10 seconds as follow-up network checks finish, so start the identification when the user begins the action (for example when the signup form opens), not when the form is submitted. An empty `data` array means \"not scored yet\", never \"clean\". Poll with backoff (first try at once, then wait 250 ms, 500 ms, 1 s, then steps of about 1.5 s) and treat a `429` inside that loop as \"wait longer\". The official server SDKs do this for you. **Account-level checks.** Search by `device_id`, `user_hid`, `visitor_id` or `ip` to see how many accounts share a device, how many devices one account uses, or what else came from one IP address. When you count accounts, skip rows whose `user_hid` is empty or one of the values that do not identify a user: `anonymous`, `fail`, `-1` and `unknown`. **Validate before sending.** The server does not validate the path: an unknown `search_type` returns the latest identifications of the whole domain unfiltered, a malformed UUID or IPv4 value returns `500`, and a `limit` outside 1-100 silently becomes 20. **Paging.** Page with `offset` while it is below `total`. Rows are ordered by `created_at` only, so paging while new identifications arrive can repeat or skip rows: deduplicate on `request_id`. **Latest state.** A row can be refined after the webhook was sent, for example when late network data re-scores it; its `ver` then increases. The History API always returns the latest version, which makes it the guaranteed read path. Reads are free: they do not use your included identifications. + * @param searchType Identifier to search by. Only these seven values are supported: - `request_id`: one identification (read a verdict); - `device_id`: every identification of one device; - `user_hid`: every identification of one account; - `visitor_id`: every identification of one visitor; - `ip`: every identification from one public IPv4 address; - `session_id`: every identification of one visit; - `cookie_id`: every identification with one browser cookie. The server does not reject other values: it ignores them and returns the latest identifications of the whole domain, so restrict the value on your side. (required) + * @param value Value of the identifier, validated on your side before sending: - `request_id`, `device_id`, `visitor_id`, `session_id`, `cookie_id`: a UUID of any version, the nil UUID included, matching `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`. Send it lowercase. - `ip`: a dotted IPv4 address. IPv6 addresses cannot be searched. - `user_hid`: the exact, case-sensitive User HID as one path segment, encoded the way the server reads it: send the characters `A-Z a-z 0-9 - . _ ~ $ & + , : ; = @` unescaped and percent-encode every other byte of the UTF-8 value as uppercase `%XX`, including `! ' ( ) *`, spaces and `%` itself. The server compares any other encoding literally, so `%40` instead of `@`, or lowercase hex digits, return an empty page instead of the matching rows. Many HTTP clients and generated clients escape `$ & + , : ; = @` in path values: build this path yourself when yours does. A User HID that contains `/` cannot be searched, and most HTTP clients cannot send `.` or `..` because they remove them as dot segments; the pattern rejects these values. Hex-encoded hashes need no escaping at all. The server does not validate the value: a malformed UUID or IPv4 address gets a `500`. (required) + * @param limit Maximum number of identifications to return, from 1 to 100. The server replaces any other value (and a non-numeric one) with 20 instead of clamping it, so validate it on your side. (optional, default to 20) + * @param offset Number of identifications to skip, for paging. The server treats negative or non-numeric values as 0. Rows are ordered by `created_at` only, so paging while new identifications arrive can repeat or skip rows: deduplicate on `request_id`. (optional, default to 0) + * @param headers Optional headers to include in the request + * @return HistoryPage + * @throws ApiException if fails to make API call + */ + public HistoryPage searchHistory(@javax.annotation.Nonnull String searchType, @javax.annotation.Nonnull String value, @javax.annotation.Nullable Integer limit, @javax.annotation.Nullable Integer offset, Map headers) throws ApiException { + ApiResponse localVarResponse = searchHistoryWithHttpInfo(searchType, value, limit, offset, headers); + return localVarResponse.getData(); + } + + /** + * Search identifications + * Returns the identifications of your domain that match one identifier, newest first, together with the total number of matches. The Private API Key selects the domain; identifications from its subdomains are included (`domain` holds the host, `site_domain` the registered domain). **Read one verdict.** After a protected action, search by `request_id` with `limit=1`. The row appears about 1-3 seconds after the browser call and can be refined for up to about 10 seconds as follow-up network checks finish, so start the identification when the user begins the action (for example when the signup form opens), not when the form is submitted. An empty `data` array means \"not scored yet\", never \"clean\". Poll with backoff (first try at once, then wait 250 ms, 500 ms, 1 s, then steps of about 1.5 s) and treat a `429` inside that loop as \"wait longer\". The official server SDKs do this for you. **Account-level checks.** Search by `device_id`, `user_hid`, `visitor_id` or `ip` to see how many accounts share a device, how many devices one account uses, or what else came from one IP address. When you count accounts, skip rows whose `user_hid` is empty or one of the values that do not identify a user: `anonymous`, `fail`, `-1` and `unknown`. **Validate before sending.** The server does not validate the path: an unknown `search_type` returns the latest identifications of the whole domain unfiltered, a malformed UUID or IPv4 value returns `500`, and a `limit` outside 1-100 silently becomes 20. **Paging.** Page with `offset` while it is below `total`. Rows are ordered by `created_at` only, so paging while new identifications arrive can repeat or skip rows: deduplicate on `request_id`. **Latest state.** A row can be refined after the webhook was sent, for example when late network data re-scores it; its `ver` then increases. The History API always returns the latest version, which makes it the guaranteed read path. Reads are free: they do not use your included identifications. + * @param searchType Identifier to search by. Only these seven values are supported: - `request_id`: one identification (read a verdict); - `device_id`: every identification of one device; - `user_hid`: every identification of one account; - `visitor_id`: every identification of one visitor; - `ip`: every identification from one public IPv4 address; - `session_id`: every identification of one visit; - `cookie_id`: every identification with one browser cookie. The server does not reject other values: it ignores them and returns the latest identifications of the whole domain, so restrict the value on your side. (required) + * @param value Value of the identifier, validated on your side before sending: - `request_id`, `device_id`, `visitor_id`, `session_id`, `cookie_id`: a UUID of any version, the nil UUID included, matching `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`. Send it lowercase. - `ip`: a dotted IPv4 address. IPv6 addresses cannot be searched. - `user_hid`: the exact, case-sensitive User HID as one path segment, encoded the way the server reads it: send the characters `A-Z a-z 0-9 - . _ ~ $ & + , : ; = @` unescaped and percent-encode every other byte of the UTF-8 value as uppercase `%XX`, including `! ' ( ) *`, spaces and `%` itself. The server compares any other encoding literally, so `%40` instead of `@`, or lowercase hex digits, return an empty page instead of the matching rows. Many HTTP clients and generated clients escape `$ & + , : ; = @` in path values: build this path yourself when yours does. A User HID that contains `/` cannot be searched, and most HTTP clients cannot send `.` or `..` because they remove them as dot segments; the pattern rejects these values. Hex-encoded hashes need no escaping at all. The server does not validate the value: a malformed UUID or IPv4 address gets a `500`. (required) + * @param limit Maximum number of identifications to return, from 1 to 100. The server replaces any other value (and a non-numeric one) with 20 instead of clamping it, so validate it on your side. (optional, default to 20) + * @param offset Number of identifications to skip, for paging. The server treats negative or non-numeric values as 0. Rows are ordered by `created_at` only, so paging while new identifications arrive can repeat or skip rows: deduplicate on `request_id`. (optional, default to 0) + * @return ApiResponse<HistoryPage> + * @throws ApiException if fails to make API call + */ + public ApiResponse searchHistoryWithHttpInfo(@javax.annotation.Nonnull String searchType, @javax.annotation.Nonnull String value, @javax.annotation.Nullable Integer limit, @javax.annotation.Nullable Integer offset) throws ApiException { + return searchHistoryWithHttpInfo(searchType, value, limit, offset, null); + } + + /** + * Search identifications + * Returns the identifications of your domain that match one identifier, newest first, together with the total number of matches. The Private API Key selects the domain; identifications from its subdomains are included (`domain` holds the host, `site_domain` the registered domain). **Read one verdict.** After a protected action, search by `request_id` with `limit=1`. The row appears about 1-3 seconds after the browser call and can be refined for up to about 10 seconds as follow-up network checks finish, so start the identification when the user begins the action (for example when the signup form opens), not when the form is submitted. An empty `data` array means \"not scored yet\", never \"clean\". Poll with backoff (first try at once, then wait 250 ms, 500 ms, 1 s, then steps of about 1.5 s) and treat a `429` inside that loop as \"wait longer\". The official server SDKs do this for you. **Account-level checks.** Search by `device_id`, `user_hid`, `visitor_id` or `ip` to see how many accounts share a device, how many devices one account uses, or what else came from one IP address. When you count accounts, skip rows whose `user_hid` is empty or one of the values that do not identify a user: `anonymous`, `fail`, `-1` and `unknown`. **Validate before sending.** The server does not validate the path: an unknown `search_type` returns the latest identifications of the whole domain unfiltered, a malformed UUID or IPv4 value returns `500`, and a `limit` outside 1-100 silently becomes 20. **Paging.** Page with `offset` while it is below `total`. Rows are ordered by `created_at` only, so paging while new identifications arrive can repeat or skip rows: deduplicate on `request_id`. **Latest state.** A row can be refined after the webhook was sent, for example when late network data re-scores it; its `ver` then increases. The History API always returns the latest version, which makes it the guaranteed read path. Reads are free: they do not use your included identifications. + * @param searchType Identifier to search by. Only these seven values are supported: - `request_id`: one identification (read a verdict); - `device_id`: every identification of one device; - `user_hid`: every identification of one account; - `visitor_id`: every identification of one visitor; - `ip`: every identification from one public IPv4 address; - `session_id`: every identification of one visit; - `cookie_id`: every identification with one browser cookie. The server does not reject other values: it ignores them and returns the latest identifications of the whole domain, so restrict the value on your side. (required) + * @param value Value of the identifier, validated on your side before sending: - `request_id`, `device_id`, `visitor_id`, `session_id`, `cookie_id`: a UUID of any version, the nil UUID included, matching `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`. Send it lowercase. - `ip`: a dotted IPv4 address. IPv6 addresses cannot be searched. - `user_hid`: the exact, case-sensitive User HID as one path segment, encoded the way the server reads it: send the characters `A-Z a-z 0-9 - . _ ~ $ & + , : ; = @` unescaped and percent-encode every other byte of the UTF-8 value as uppercase `%XX`, including `! ' ( ) *`, spaces and `%` itself. The server compares any other encoding literally, so `%40` instead of `@`, or lowercase hex digits, return an empty page instead of the matching rows. Many HTTP clients and generated clients escape `$ & + , : ; = @` in path values: build this path yourself when yours does. A User HID that contains `/` cannot be searched, and most HTTP clients cannot send `.` or `..` because they remove them as dot segments; the pattern rejects these values. Hex-encoded hashes need no escaping at all. The server does not validate the value: a malformed UUID or IPv4 address gets a `500`. (required) + * @param limit Maximum number of identifications to return, from 1 to 100. The server replaces any other value (and a non-numeric one) with 20 instead of clamping it, so validate it on your side. (optional, default to 20) + * @param offset Number of identifications to skip, for paging. The server treats negative or non-numeric values as 0. Rows are ordered by `created_at` only, so paging while new identifications arrive can repeat or skip rows: deduplicate on `request_id`. (optional, default to 0) + * @param headers Optional headers to include in the request + * @return ApiResponse<HistoryPage> + * @throws ApiException if fails to make API call + */ + public ApiResponse searchHistoryWithHttpInfo(@javax.annotation.Nonnull String searchType, @javax.annotation.Nonnull String value, @javax.annotation.Nullable Integer limit, @javax.annotation.Nullable Integer offset, Map headers) throws ApiException { + HttpRequest.Builder localVarRequestBuilder = searchHistoryRequestBuilder(searchType, value, limit, offset, headers); + try { + HttpResponse localVarResponse = memberVarHttpClient.send( + localVarRequestBuilder.build(), + HttpResponse.BodyHandlers.ofInputStream()); + if (memberVarResponseInterceptor != null) { + memberVarResponseInterceptor.accept(localVarResponse); + } + InputStream localVarResponseBody = null; + try { + if (localVarResponse.statusCode()/ 100 != 2) { + throw getApiException("searchHistory", localVarResponse); + } + localVarResponseBody = ApiClient.getResponseBody(localVarResponse); + if (localVarResponseBody == null) { + return new ApiResponse( + localVarResponse.statusCode(), + localVarResponse.headers().map(), + null + ); + } + + + + String responseBody = new String(localVarResponseBody.readAllBytes()); + HistoryPage responseValue = responseBody.isBlank()? null: memberVarObjectMapper.readValue(responseBody, new TypeReference() {}); + + + return new ApiResponse( + localVarResponse.statusCode(), + localVarResponse.headers().map(), + responseValue + ); + } finally { + if (localVarResponseBody != null) { + localVarResponseBody.close(); + } + } + } catch (IOException e) { + throw new ApiException(e); + } + catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new ApiException(e); + } + } + + private HttpRequest.Builder searchHistoryRequestBuilder(@javax.annotation.Nonnull String searchType, @javax.annotation.Nonnull String value, @javax.annotation.Nullable Integer limit, @javax.annotation.Nullable Integer offset, Map headers) throws ApiException { + // verify the required parameter 'searchType' is set + if (searchType == null) { + throw new ApiException(400, "Missing the required parameter 'searchType' when calling searchHistory"); + } + // verify the required parameter 'value' is set + if (value == null) { + throw new ApiException(400, "Missing the required parameter 'value' when calling searchHistory"); + } + + HttpRequest.Builder localVarRequestBuilder = HttpRequest.newBuilder(); + + String localVarPath = "/api/v1/history/{search_type}/{value}" + .replace("{search_type}", ApiClient.urlEncode(searchType.toString())) + .replace("{value}", ApiClient.urlEncode(value.toString())); + + List localVarQueryParams = new ArrayList<>(); + StringJoiner localVarQueryStringJoiner = new StringJoiner("&"); + String localVarQueryParameterBaseName; + localVarQueryParameterBaseName = "limit"; + localVarQueryParams.addAll(ApiClient.parameterToPairs("limit", limit)); + localVarQueryParameterBaseName = "offset"; + localVarQueryParams.addAll(ApiClient.parameterToPairs("offset", offset)); + + if (!localVarQueryParams.isEmpty() || localVarQueryStringJoiner.length() != 0) { + StringJoiner queryJoiner = new StringJoiner("&"); + localVarQueryParams.forEach(p -> queryJoiner.add(p.getName() + '=' + p.getValue())); + if (localVarQueryStringJoiner.length() != 0) { + queryJoiner.add(localVarQueryStringJoiner.toString()); + } + localVarRequestBuilder.uri(URI.create(memberVarBaseUri + localVarPath + '?' + queryJoiner.toString())); + } else { + localVarRequestBuilder.uri(URI.create(memberVarBaseUri + localVarPath)); + } + + localVarRequestBuilder.header("Accept", "application/json, text/plain, text/html"); + + localVarRequestBuilder.method("GET", HttpRequest.BodyPublishers.noBody()); + if (memberVarReadTimeout != null) { + localVarRequestBuilder.timeout(memberVarReadTimeout); + } + // Add custom headers if provided + localVarRequestBuilder = HttpRequestBuilderExtensions.withAdditionalHeaders(localVarRequestBuilder, headers); + if (memberVarInterceptor != null) { + memberVarInterceptor.accept(localVarRequestBuilder); + } + return localVarRequestBuilder; + } + +} diff --git a/generated/src/main/java/ai/shieldlabs/generated/api/ManagementApiApi.java b/generated/src/main/java/ai/shieldlabs/generated/api/ManagementApiApi.java new file mode 100644 index 0000000..28da8f2 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/api/ManagementApiApi.java @@ -0,0 +1,452 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +package ai.shieldlabs.generated.api; + +import ai.shieldlabs.generated.ApiClient; +import ai.shieldlabs.generated.ApiException; +import ai.shieldlabs.generated.ApiResponse; +import ai.shieldlabs.generated.Configuration; +import ai.shieldlabs.generated.Pair; + +import ai.shieldlabs.generated.model.DomainProfile; +import ai.shieldlabs.generated.model.ErrorBody; +import ai.shieldlabs.generated.model.LegacySnapshot; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.net.http.HttpRequest; +import java.nio.channels.Channels; +import java.nio.channels.Pipe; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; + +import java.util.ArrayList; +import java.util.StringJoiner; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class ManagementApiApi { + /** + * Utility class for extending HttpRequest.Builder functionality. + */ + private static class HttpRequestBuilderExtensions { + /** + * Adds additional headers to the provided HttpRequest.Builder. Useful for adding method/endpoint specific headers. + * + * @param builder the HttpRequest.Builder to which headers will be added + * @param headers a map of header names and values to add; may be null + * @return the same HttpRequest.Builder instance with the additional headers set + */ + static HttpRequest.Builder withAdditionalHeaders(HttpRequest.Builder builder, Map headers) { + if (headers != null) { + for (Map.Entry entry : headers.entrySet()) { + builder.header(entry.getKey(), entry.getValue()); + } + } + return builder; + } + } + private final HttpClient memberVarHttpClient; + private final ObjectMapper memberVarObjectMapper; + private final String memberVarBaseUri; + private final Consumer memberVarInterceptor; + private final Duration memberVarReadTimeout; + private final Consumer> memberVarResponseInterceptor; + private final Consumer> memberVarAsyncResponseInterceptor; + + public ManagementApiApi() { + this(Configuration.getDefaultApiClient()); + } + + public ManagementApiApi(ApiClient apiClient) { + memberVarHttpClient = apiClient.getHttpClient(); + memberVarObjectMapper = apiClient.getObjectMapper(); + memberVarBaseUri = apiClient.getBaseUri(); + memberVarInterceptor = apiClient.getRequestInterceptor(); + memberVarReadTimeout = apiClient.getReadTimeout(); + memberVarResponseInterceptor = apiClient.getResponseInterceptor(); + memberVarAsyncResponseInterceptor = apiClient.getAsyncResponseInterceptor(); + } + + + protected ApiException getApiException(String operationId, HttpResponse response) throws IOException { + InputStream responseBody = ApiClient.getResponseBody(response); + String body = null; + try { + body = responseBody == null ? null : new String(responseBody.readAllBytes()); + } finally { + if (responseBody != null) { + responseBody.close(); + } + } + String message = formatExceptionMessage(operationId, response.statusCode(), body); + return new ApiException(response.statusCode(), message, response.headers(), body); + } + + private String formatExceptionMessage(String operationId, int statusCode, String body) { + if (body == null || body.isEmpty()) { + body = "[no body]"; + } + return operationId + " call failed with: " + statusCode + " - " + body; + } + + /** + * Download file from the given response. + * + * @param response Response + * @return File + * @throws ApiException If fail to read file content from response and write to disk + */ + public File downloadFileFromResponse(HttpResponse response, InputStream responseBody) throws ApiException { + if (responseBody == null) { + throw new ApiException(new IOException("Response body is empty")); + } + try { + File file = prepareDownloadFile(response); + java.nio.file.Files.copy(responseBody, file.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING); + return file; + } catch (IOException e) { + throw new ApiException(e); + } + } + + /** + *

Prepare the file for download from the response.

+ * + * @param response a {@link java.net.http.HttpResponse} object. + * @return a {@link java.io.File} object. + * @throws java.io.IOException if any. + */ + private File prepareDownloadFile(HttpResponse response) throws IOException { + String filename = null; + java.util.Optional contentDisposition = response.headers().firstValue("Content-Disposition"); + if (contentDisposition.isPresent() && !"".equals(contentDisposition.get())) { + // Get filename from the Content-Disposition header. + java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?"); + java.util.regex.Matcher matcher = pattern.matcher(contentDisposition.get()); + if (matcher.find()) + filename = matcher.group(1); + } + File file = null; + if (filename != null) { + java.nio.file.Path tempDir = java.nio.file.Files.createTempDirectory("swagger-gen-native"); + java.nio.file.Path filePath = java.nio.file.Files.createFile(tempDir.resolve(filename)); + file = filePath.toFile(); + tempDir.toFile().deleteOnExit(); // best effort cleanup + file.deleteOnExit(); // best effort cleanup + } else { + file = java.nio.file.Files.createTempFile("download-", "").toFile(); + file.deleteOnExit(); // best effort cleanup + } + return file; + } + + /** + * Get the domain profile + * Returns the registered domain, the remaining included identifications of the account and the masked keys. **Credentials.** Send the Secret Key as a Bearer token and the registered domain in `X-Shield-Domain`. The domain is matched exactly: send it lowercase, without scheme, path, trailing slash or a leading `www.`. **Rate limit.** 15 requests per minute per client IP. The request that goes over the limit starts a 10-minute block during which every request to the Management API gets `429`. Call this endpoint sparingly, cache the profile, and never retry a `429`. `Weight` can be negative when the account is over its included volume. The call is free. + * @param xShieldDomain Your registered domain. The server matches it exactly against the domain registered in the analytics dashboard, so send it normalized: lowercase, without scheme, path, trailing slash or a leading `www.` (`https://www.Example.com/` becomes `example.com`). A missing or wrong value gets a `401` with an empty body. (required) + * @return DomainProfile + * @throws ApiException if fails to make API call + */ + public DomainProfile getDomainProfile(@javax.annotation.Nonnull String xShieldDomain) throws ApiException { + return getDomainProfile(xShieldDomain, null); + } + + /** + * Get the domain profile + * Returns the registered domain, the remaining included identifications of the account and the masked keys. **Credentials.** Send the Secret Key as a Bearer token and the registered domain in `X-Shield-Domain`. The domain is matched exactly: send it lowercase, without scheme, path, trailing slash or a leading `www.`. **Rate limit.** 15 requests per minute per client IP. The request that goes over the limit starts a 10-minute block during which every request to the Management API gets `429`. Call this endpoint sparingly, cache the profile, and never retry a `429`. `Weight` can be negative when the account is over its included volume. The call is free. + * @param xShieldDomain Your registered domain. The server matches it exactly against the domain registered in the analytics dashboard, so send it normalized: lowercase, without scheme, path, trailing slash or a leading `www.` (`https://www.Example.com/` becomes `example.com`). A missing or wrong value gets a `401` with an empty body. (required) + * @param headers Optional headers to include in the request + * @return DomainProfile + * @throws ApiException if fails to make API call + */ + public DomainProfile getDomainProfile(@javax.annotation.Nonnull String xShieldDomain, Map headers) throws ApiException { + ApiResponse localVarResponse = getDomainProfileWithHttpInfo(xShieldDomain, headers); + return localVarResponse.getData(); + } + + /** + * Get the domain profile + * Returns the registered domain, the remaining included identifications of the account and the masked keys. **Credentials.** Send the Secret Key as a Bearer token and the registered domain in `X-Shield-Domain`. The domain is matched exactly: send it lowercase, without scheme, path, trailing slash or a leading `www.`. **Rate limit.** 15 requests per minute per client IP. The request that goes over the limit starts a 10-minute block during which every request to the Management API gets `429`. Call this endpoint sparingly, cache the profile, and never retry a `429`. `Weight` can be negative when the account is over its included volume. The call is free. + * @param xShieldDomain Your registered domain. The server matches it exactly against the domain registered in the analytics dashboard, so send it normalized: lowercase, without scheme, path, trailing slash or a leading `www.` (`https://www.Example.com/` becomes `example.com`). A missing or wrong value gets a `401` with an empty body. (required) + * @return ApiResponse<DomainProfile> + * @throws ApiException if fails to make API call + */ + public ApiResponse getDomainProfileWithHttpInfo(@javax.annotation.Nonnull String xShieldDomain) throws ApiException { + return getDomainProfileWithHttpInfo(xShieldDomain, null); + } + + /** + * Get the domain profile + * Returns the registered domain, the remaining included identifications of the account and the masked keys. **Credentials.** Send the Secret Key as a Bearer token and the registered domain in `X-Shield-Domain`. The domain is matched exactly: send it lowercase, without scheme, path, trailing slash or a leading `www.`. **Rate limit.** 15 requests per minute per client IP. The request that goes over the limit starts a 10-minute block during which every request to the Management API gets `429`. Call this endpoint sparingly, cache the profile, and never retry a `429`. `Weight` can be negative when the account is over its included volume. The call is free. + * @param xShieldDomain Your registered domain. The server matches it exactly against the domain registered in the analytics dashboard, so send it normalized: lowercase, without scheme, path, trailing slash or a leading `www.` (`https://www.Example.com/` becomes `example.com`). A missing or wrong value gets a `401` with an empty body. (required) + * @param headers Optional headers to include in the request + * @return ApiResponse<DomainProfile> + * @throws ApiException if fails to make API call + */ + public ApiResponse getDomainProfileWithHttpInfo(@javax.annotation.Nonnull String xShieldDomain, Map headers) throws ApiException { + HttpRequest.Builder localVarRequestBuilder = getDomainProfileRequestBuilder(xShieldDomain, headers); + try { + HttpResponse localVarResponse = memberVarHttpClient.send( + localVarRequestBuilder.build(), + HttpResponse.BodyHandlers.ofInputStream()); + if (memberVarResponseInterceptor != null) { + memberVarResponseInterceptor.accept(localVarResponse); + } + InputStream localVarResponseBody = null; + try { + if (localVarResponse.statusCode()/ 100 != 2) { + throw getApiException("getDomainProfile", localVarResponse); + } + localVarResponseBody = ApiClient.getResponseBody(localVarResponse); + if (localVarResponseBody == null) { + return new ApiResponse( + localVarResponse.statusCode(), + localVarResponse.headers().map(), + null + ); + } + + + + String responseBody = new String(localVarResponseBody.readAllBytes()); + DomainProfile responseValue = responseBody.isBlank()? null: memberVarObjectMapper.readValue(responseBody, new TypeReference() {}); + + + return new ApiResponse( + localVarResponse.statusCode(), + localVarResponse.headers().map(), + responseValue + ); + } finally { + if (localVarResponseBody != null) { + localVarResponseBody.close(); + } + } + } catch (IOException e) { + throw new ApiException(e); + } + catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new ApiException(e); + } + } + + private HttpRequest.Builder getDomainProfileRequestBuilder(@javax.annotation.Nonnull String xShieldDomain, Map headers) throws ApiException { + // verify the required parameter 'xShieldDomain' is set + if (xShieldDomain == null) { + throw new ApiException(400, "Missing the required parameter 'xShieldDomain' when calling getDomainProfile"); + } + + HttpRequest.Builder localVarRequestBuilder = HttpRequest.newBuilder(); + + String localVarPath = "/v1/profile"; + + localVarRequestBuilder.uri(URI.create(memberVarBaseUri + localVarPath)); + + if (xShieldDomain != null) { + localVarRequestBuilder.header("X-Shield-Domain", xShieldDomain.toString()); + } + localVarRequestBuilder.header("Accept", "application/json, text/plain, text/html"); + + localVarRequestBuilder.method("GET", HttpRequest.BodyPublishers.noBody()); + if (memberVarReadTimeout != null) { + localVarRequestBuilder.timeout(memberVarReadTimeout); + } + // Add custom headers if provided + localVarRequestBuilder = HttpRequestBuilderExtensions.withAdditionalHeaders(localVarRequestBuilder, headers); + if (memberVarInterceptor != null) { + memberVarInterceptor.accept(localVarRequestBuilder); + } + return localVarRequestBuilder; + } + + /** + * Search history by identifier (deprecated) + * **Deprecated.** This endpoint stops working after Sat, 01 Jan 2027 00:00:00 GMT. Use `searchHistory` on the History API instead: `https://account.shieldlabs.ai/api/v1/history`. Every answer of this route except `429` and `503` carries `Deprecation: true`, a `Sunset` header and a `Link` header with `rel=\"successor-version\"` pointing there. The plain-text `404` for a path that matches no route and the edge proxy errors do not carry them. Differences from the History API: the answer is a bare array of PascalCase objects; only rows whose request host equals `X-Shield-Domain` are returned (no subdomain traffic); `limit` defaults to 100 and there is no `offset`. It uses the Management API credentials and rate limit (15 requests per minute per client IP, then a 10-minute block). The call is free. + * @param xShieldDomain Your registered domain. The server matches it exactly against the domain registered in the analytics dashboard, so send it normalized: lowercase, without scheme, path, trailing slash or a leading `www.` (`https://www.Example.com/` becomes `example.com`). A missing or wrong value gets a `401` with an empty body. (required) + * @param type Identifier to search by. Other values get a `404` with a bare JSON string such as `\"auto is not supported\"`. (required) + * @param value Value of the identifier. UUID types accept a UUID of any version; `ip` must be an IP address (an IPv6 address passes validation but then fails with `400` and a `null` body); `user_hid` is free text. (required) + * @param limit Maximum number of identifications, from 1 to 100. Any other value becomes 100. There is no `offset`. (optional, default to 100) + * @return List<LegacySnapshot> + * @throws ApiException if fails to make API call + * @deprecated + */ + @Deprecated + public List searchHistoryDeprecated(@javax.annotation.Nonnull String xShieldDomain, @javax.annotation.Nonnull String type, @javax.annotation.Nonnull String value, @javax.annotation.Nullable Integer limit) throws ApiException { + return searchHistoryDeprecated(xShieldDomain, type, value, limit, null); + } + + /** + * Search history by identifier (deprecated) + * **Deprecated.** This endpoint stops working after Sat, 01 Jan 2027 00:00:00 GMT. Use `searchHistory` on the History API instead: `https://account.shieldlabs.ai/api/v1/history`. Every answer of this route except `429` and `503` carries `Deprecation: true`, a `Sunset` header and a `Link` header with `rel=\"successor-version\"` pointing there. The plain-text `404` for a path that matches no route and the edge proxy errors do not carry them. Differences from the History API: the answer is a bare array of PascalCase objects; only rows whose request host equals `X-Shield-Domain` are returned (no subdomain traffic); `limit` defaults to 100 and there is no `offset`. It uses the Management API credentials and rate limit (15 requests per minute per client IP, then a 10-minute block). The call is free. + * @param xShieldDomain Your registered domain. The server matches it exactly against the domain registered in the analytics dashboard, so send it normalized: lowercase, without scheme, path, trailing slash or a leading `www.` (`https://www.Example.com/` becomes `example.com`). A missing or wrong value gets a `401` with an empty body. (required) + * @param type Identifier to search by. Other values get a `404` with a bare JSON string such as `\"auto is not supported\"`. (required) + * @param value Value of the identifier. UUID types accept a UUID of any version; `ip` must be an IP address (an IPv6 address passes validation but then fails with `400` and a `null` body); `user_hid` is free text. (required) + * @param limit Maximum number of identifications, from 1 to 100. Any other value becomes 100. There is no `offset`. (optional, default to 100) + * @param headers Optional headers to include in the request + * @return List<LegacySnapshot> + * @throws ApiException if fails to make API call + * @deprecated + */ + @Deprecated + public List searchHistoryDeprecated(@javax.annotation.Nonnull String xShieldDomain, @javax.annotation.Nonnull String type, @javax.annotation.Nonnull String value, @javax.annotation.Nullable Integer limit, Map headers) throws ApiException { + ApiResponse> localVarResponse = searchHistoryDeprecatedWithHttpInfo(xShieldDomain, type, value, limit, headers); + return localVarResponse.getData(); + } + + /** + * Search history by identifier (deprecated) + * **Deprecated.** This endpoint stops working after Sat, 01 Jan 2027 00:00:00 GMT. Use `searchHistory` on the History API instead: `https://account.shieldlabs.ai/api/v1/history`. Every answer of this route except `429` and `503` carries `Deprecation: true`, a `Sunset` header and a `Link` header with `rel=\"successor-version\"` pointing there. The plain-text `404` for a path that matches no route and the edge proxy errors do not carry them. Differences from the History API: the answer is a bare array of PascalCase objects; only rows whose request host equals `X-Shield-Domain` are returned (no subdomain traffic); `limit` defaults to 100 and there is no `offset`. It uses the Management API credentials and rate limit (15 requests per minute per client IP, then a 10-minute block). The call is free. + * @param xShieldDomain Your registered domain. The server matches it exactly against the domain registered in the analytics dashboard, so send it normalized: lowercase, without scheme, path, trailing slash or a leading `www.` (`https://www.Example.com/` becomes `example.com`). A missing or wrong value gets a `401` with an empty body. (required) + * @param type Identifier to search by. Other values get a `404` with a bare JSON string such as `\"auto is not supported\"`. (required) + * @param value Value of the identifier. UUID types accept a UUID of any version; `ip` must be an IP address (an IPv6 address passes validation but then fails with `400` and a `null` body); `user_hid` is free text. (required) + * @param limit Maximum number of identifications, from 1 to 100. Any other value becomes 100. There is no `offset`. (optional, default to 100) + * @return ApiResponse<List<LegacySnapshot>> + * @throws ApiException if fails to make API call + * @deprecated + */ + @Deprecated + public ApiResponse> searchHistoryDeprecatedWithHttpInfo(@javax.annotation.Nonnull String xShieldDomain, @javax.annotation.Nonnull String type, @javax.annotation.Nonnull String value, @javax.annotation.Nullable Integer limit) throws ApiException { + return searchHistoryDeprecatedWithHttpInfo(xShieldDomain, type, value, limit, null); + } + + /** + * Search history by identifier (deprecated) + * **Deprecated.** This endpoint stops working after Sat, 01 Jan 2027 00:00:00 GMT. Use `searchHistory` on the History API instead: `https://account.shieldlabs.ai/api/v1/history`. Every answer of this route except `429` and `503` carries `Deprecation: true`, a `Sunset` header and a `Link` header with `rel=\"successor-version\"` pointing there. The plain-text `404` for a path that matches no route and the edge proxy errors do not carry them. Differences from the History API: the answer is a bare array of PascalCase objects; only rows whose request host equals `X-Shield-Domain` are returned (no subdomain traffic); `limit` defaults to 100 and there is no `offset`. It uses the Management API credentials and rate limit (15 requests per minute per client IP, then a 10-minute block). The call is free. + * @param xShieldDomain Your registered domain. The server matches it exactly against the domain registered in the analytics dashboard, so send it normalized: lowercase, without scheme, path, trailing slash or a leading `www.` (`https://www.Example.com/` becomes `example.com`). A missing or wrong value gets a `401` with an empty body. (required) + * @param type Identifier to search by. Other values get a `404` with a bare JSON string such as `\"auto is not supported\"`. (required) + * @param value Value of the identifier. UUID types accept a UUID of any version; `ip` must be an IP address (an IPv6 address passes validation but then fails with `400` and a `null` body); `user_hid` is free text. (required) + * @param limit Maximum number of identifications, from 1 to 100. Any other value becomes 100. There is no `offset`. (optional, default to 100) + * @param headers Optional headers to include in the request + * @return ApiResponse<List<LegacySnapshot>> + * @throws ApiException if fails to make API call + * @deprecated + */ + @Deprecated + public ApiResponse> searchHistoryDeprecatedWithHttpInfo(@javax.annotation.Nonnull String xShieldDomain, @javax.annotation.Nonnull String type, @javax.annotation.Nonnull String value, @javax.annotation.Nullable Integer limit, Map headers) throws ApiException { + HttpRequest.Builder localVarRequestBuilder = searchHistoryDeprecatedRequestBuilder(xShieldDomain, type, value, limit, headers); + try { + HttpResponse localVarResponse = memberVarHttpClient.send( + localVarRequestBuilder.build(), + HttpResponse.BodyHandlers.ofInputStream()); + if (memberVarResponseInterceptor != null) { + memberVarResponseInterceptor.accept(localVarResponse); + } + InputStream localVarResponseBody = null; + try { + if (localVarResponse.statusCode()/ 100 != 2) { + throw getApiException("searchHistoryDeprecated", localVarResponse); + } + localVarResponseBody = ApiClient.getResponseBody(localVarResponse); + if (localVarResponseBody == null) { + return new ApiResponse>( + localVarResponse.statusCode(), + localVarResponse.headers().map(), + null + ); + } + + + + String responseBody = new String(localVarResponseBody.readAllBytes()); + List responseValue = responseBody.isBlank()? null: memberVarObjectMapper.readValue(responseBody, new TypeReference>() {}); + + + return new ApiResponse>( + localVarResponse.statusCode(), + localVarResponse.headers().map(), + responseValue + ); + } finally { + if (localVarResponseBody != null) { + localVarResponseBody.close(); + } + } + } catch (IOException e) { + throw new ApiException(e); + } + catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new ApiException(e); + } + } + + private HttpRequest.Builder searchHistoryDeprecatedRequestBuilder(@javax.annotation.Nonnull String xShieldDomain, @javax.annotation.Nonnull String type, @javax.annotation.Nonnull String value, @javax.annotation.Nullable Integer limit, Map headers) throws ApiException { + // verify the required parameter 'xShieldDomain' is set + if (xShieldDomain == null) { + throw new ApiException(400, "Missing the required parameter 'xShieldDomain' when calling searchHistoryDeprecated"); + } + // verify the required parameter 'type' is set + if (type == null) { + throw new ApiException(400, "Missing the required parameter 'type' when calling searchHistoryDeprecated"); + } + // verify the required parameter 'value' is set + if (value == null) { + throw new ApiException(400, "Missing the required parameter 'value' when calling searchHistoryDeprecated"); + } + + HttpRequest.Builder localVarRequestBuilder = HttpRequest.newBuilder(); + + String localVarPath = "/v1/history/{type}/{value}" + .replace("{type}", ApiClient.urlEncode(type.toString())) + .replace("{value}", ApiClient.urlEncode(value.toString())); + + List localVarQueryParams = new ArrayList<>(); + StringJoiner localVarQueryStringJoiner = new StringJoiner("&"); + String localVarQueryParameterBaseName; + localVarQueryParameterBaseName = "limit"; + localVarQueryParams.addAll(ApiClient.parameterToPairs("limit", limit)); + + if (!localVarQueryParams.isEmpty() || localVarQueryStringJoiner.length() != 0) { + StringJoiner queryJoiner = new StringJoiner("&"); + localVarQueryParams.forEach(p -> queryJoiner.add(p.getName() + '=' + p.getValue())); + if (localVarQueryStringJoiner.length() != 0) { + queryJoiner.add(localVarQueryStringJoiner.toString()); + } + localVarRequestBuilder.uri(URI.create(memberVarBaseUri + localVarPath + '?' + queryJoiner.toString())); + } else { + localVarRequestBuilder.uri(URI.create(memberVarBaseUri + localVarPath)); + } + + if (xShieldDomain != null) { + localVarRequestBuilder.header("X-Shield-Domain", xShieldDomain.toString()); + } + localVarRequestBuilder.header("Accept", "application/json, text/plain, text/html"); + + localVarRequestBuilder.method("GET", HttpRequest.BodyPublishers.noBody()); + if (memberVarReadTimeout != null) { + localVarRequestBuilder.timeout(memberVarReadTimeout); + } + // Add custom headers if provided + localVarRequestBuilder = HttpRequestBuilderExtensions.withAdditionalHeaders(localVarRequestBuilder, headers); + if (memberVarInterceptor != null) { + memberVarInterceptor.accept(localVarRequestBuilder); + } + return localVarRequestBuilder; + } + +} diff --git a/generated/src/main/java/ai/shieldlabs/generated/model/AbstractOpenApiSchema.java b/generated/src/main/java/ai/shieldlabs/generated/model/AbstractOpenApiSchema.java new file mode 100644 index 0000000..abc5040 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/model/AbstractOpenApiSchema.java @@ -0,0 +1,144 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated.model; + +import java.util.Objects; +import java.lang.reflect.Type; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Abstract class for oneOf,anyOf schemas defined in OpenAPI spec + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public abstract class AbstractOpenApiSchema { + + // store the actual instance of the schema/object + private Object instance; + + // is nullable + private Boolean isNullable; + + // schema type (e.g. oneOf, anyOf) + private final String schemaType; + + public AbstractOpenApiSchema(String schemaType, Boolean isNullable) { + this.schemaType = schemaType; + this.isNullable = isNullable; + } + + /** + * Get the list of oneOf/anyOf composed schemas allowed to be stored in this object + * + * @return an instance of the actual schema/object + */ + public abstract Map> getSchemas(); + + /** + * Get the actual instance + * + * @return an instance of the actual schema/object + */ + @JsonValue + public Object getActualInstance() {return instance;} + + /** + * Set the actual instance + * + * @param instance the actual instance of the schema/object + */ + public void setActualInstance(Object instance) {this.instance = instance;} + + /** + * Get the instant recursively when the schemas defined in oneOf/anyof happen to be oneOf/anyOf schema as well + * + * @return an instance of the actual schema/object + */ + public Object getActualInstanceRecursively() { + return getActualInstanceRecursively(this); + } + + private Object getActualInstanceRecursively(AbstractOpenApiSchema object) { + if (object.getActualInstance() == null) { + return null; + } else if (object.getActualInstance() instanceof AbstractOpenApiSchema) { + return getActualInstanceRecursively((AbstractOpenApiSchema)object.getActualInstance()); + } else { + return object.getActualInstance(); + } + } + + /** + * Get the schema type (e.g. anyOf, oneOf) + * + * @return the schema type + */ + public String getSchemaType() { + return schemaType; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ").append(getClass()).append(" {\n"); + sb.append(" instance: ").append(toIndentedString(instance)).append("\n"); + sb.append(" isNullable: ").append(toIndentedString(isNullable)).append("\n"); + sb.append(" schemaType: ").append(toIndentedString(schemaType)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AbstractOpenApiSchema a = (AbstractOpenApiSchema) o; + return Objects.equals(this.instance, a.instance) && + Objects.equals(this.isNullable, a.isNullable) && + Objects.equals(this.schemaType, a.schemaType); + } + + @Override + public int hashCode() { + return Objects.hash(instance, isNullable, schemaType); + } + + /** + * Is nullable + * + * @return true if it's nullable + */ + public Boolean isNullable() { + if (Boolean.TRUE.equals(isNullable)) { + return Boolean.TRUE; + } else { + return Boolean.FALSE; + } + } + + + +} diff --git a/generated/src/main/java/ai/shieldlabs/generated/model/DetectionFlags.java b/generated/src/main/java/ai/shieldlabs/generated/model/DetectionFlags.java new file mode 100644 index 0000000..0e0df4e --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/model/DetectionFlags.java @@ -0,0 +1,796 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated.model; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.StringJoiner; +import java.util.Objects; +import java.util.Map; +import java.util.HashMap; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +import ai.shieldlabs.generated.ApiClient; +/** + * Stable yes/no verdicts for the identification. Always all 19 keys. Branch on these flags and on the Risk Score; signal names are for display and logging. When `search_bot` is `true`, `incognito`, `check_incomplete`, `ip_mismatch` and `javascript_disabled` are always `false`. + */ +@JsonPropertyOrder({ + DetectionFlags.JSON_PROPERTY_VPN, + DetectionFlags.JSON_PROPERTY_PRIVACY_RELAY, + DetectionFlags.JSON_PROPERTY_BROWSER_VPN_PROXY, + DetectionFlags.JSON_PROPERTY_TOR, + DetectionFlags.JSON_PROPERTY_PROXY, + DetectionFlags.JSON_PROPERTY_DATACENTER_IP, + DetectionFlags.JSON_PROPERTY_ABUSER, + DetectionFlags.JSON_PROPERTY_OS_MISMATCH, + DetectionFlags.JSON_PROPERTY_OS_NOT_DETECTED, + DetectionFlags.JSON_PROPERTY_TIMEZONE_MISMATCH, + DetectionFlags.JSON_PROPERTY_ANTI_DETECT_BROWSER, + DetectionFlags.JSON_PROPERTY_BROWSER_AUTOMATION, + DetectionFlags.JSON_PROPERTY_IP_MISMATCH, + DetectionFlags.JSON_PROPERTY_INCOGNITO, + DetectionFlags.JSON_PROPERTY_SEARCH_BOT, + DetectionFlags.JSON_PROPERTY_SUSPICIOUS_PAID_CLICK, + DetectionFlags.JSON_PROPERTY_JAVASCRIPT_DISABLED, + DetectionFlags.JSON_PROPERTY_STUN_NOT_CHECKED, + DetectionFlags.JSON_PROPERTY_CHECK_INCOMPLETE +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class DetectionFlags { + public static final String JSON_PROPERTY_VPN = "vpn"; + @javax.annotation.Nonnull + private Boolean vpn; + + public static final String JSON_PROPERTY_PRIVACY_RELAY = "privacy_relay"; + @javax.annotation.Nonnull + private Boolean privacyRelay; + + public static final String JSON_PROPERTY_BROWSER_VPN_PROXY = "browser_vpn_proxy"; + @javax.annotation.Nonnull + private Boolean browserVpnProxy; + + public static final String JSON_PROPERTY_TOR = "tor"; + @javax.annotation.Nonnull + private Boolean tor; + + public static final String JSON_PROPERTY_PROXY = "proxy"; + @javax.annotation.Nonnull + private Boolean proxy; + + public static final String JSON_PROPERTY_DATACENTER_IP = "datacenter_ip"; + @javax.annotation.Nonnull + private Boolean datacenterIp; + + public static final String JSON_PROPERTY_ABUSER = "abuser"; + @javax.annotation.Nonnull + private Boolean abuser; + + public static final String JSON_PROPERTY_OS_MISMATCH = "os_mismatch"; + @javax.annotation.Nonnull + private Boolean osMismatch; + + public static final String JSON_PROPERTY_OS_NOT_DETECTED = "os_not_detected"; + @javax.annotation.Nonnull + private Boolean osNotDetected; + + public static final String JSON_PROPERTY_TIMEZONE_MISMATCH = "timezone_mismatch"; + @javax.annotation.Nonnull + private Boolean timezoneMismatch; + + public static final String JSON_PROPERTY_ANTI_DETECT_BROWSER = "anti_detect_browser"; + @javax.annotation.Nonnull + private Boolean antiDetectBrowser; + + public static final String JSON_PROPERTY_BROWSER_AUTOMATION = "browser_automation"; + @javax.annotation.Nonnull + private Boolean browserAutomation; + + public static final String JSON_PROPERTY_IP_MISMATCH = "ip_mismatch"; + @javax.annotation.Nonnull + private Boolean ipMismatch; + + public static final String JSON_PROPERTY_INCOGNITO = "incognito"; + @javax.annotation.Nonnull + private Boolean incognito; + + public static final String JSON_PROPERTY_SEARCH_BOT = "search_bot"; + @javax.annotation.Nonnull + private Boolean searchBot; + + public static final String JSON_PROPERTY_SUSPICIOUS_PAID_CLICK = "suspicious_paid_click"; + @javax.annotation.Nonnull + private Boolean suspiciousPaidClick; + + public static final String JSON_PROPERTY_JAVASCRIPT_DISABLED = "javascript_disabled"; + @javax.annotation.Nonnull + private Boolean javascriptDisabled; + + public static final String JSON_PROPERTY_STUN_NOT_CHECKED = "stun_not_checked"; + @javax.annotation.Nonnull + private Boolean stunNotChecked; + + public static final String JSON_PROPERTY_CHECK_INCOMPLETE = "check_incomplete"; + @javax.annotation.Nonnull + private Boolean checkIncomplete; + + public DetectionFlags() { + } + + public DetectionFlags vpn(@javax.annotation.Nonnull Boolean vpn) { + this.vpn = vpn; + return this; + } + + /** + * A VPN was detected (scored `vpn` signal). + * @return vpn + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_VPN, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getVpn() { + return vpn; + } + + + @JsonProperty(value = JSON_PROPERTY_VPN, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setVpn(@javax.annotation.Nonnull Boolean vpn) { + this.vpn = vpn; + } + + + public DetectionFlags privacyRelay(@javax.annotation.Nonnull Boolean privacyRelay) { + this.privacyRelay = privacyRelay; + return this; + } + + /** + * A privacy relay such as iCloud Private Relay was detected. + * @return privacyRelay + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_PRIVACY_RELAY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getPrivacyRelay() { + return privacyRelay; + } + + + @JsonProperty(value = JSON_PROPERTY_PRIVACY_RELAY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setPrivacyRelay(@javax.annotation.Nonnull Boolean privacyRelay) { + this.privacyRelay = privacyRelay; + } + + + public DetectionFlags browserVpnProxy(@javax.annotation.Nonnull Boolean browserVpnProxy) { + this.browserVpnProxy = browserVpnProxy; + return this; + } + + /** + * A VPN or proxy built into the browser or one of its extensions. `true` exactly when `connection_type` is `browser_vpn_proxy`. + * @return browserVpnProxy + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_BROWSER_VPN_PROXY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getBrowserVpnProxy() { + return browserVpnProxy; + } + + + @JsonProperty(value = JSON_PROPERTY_BROWSER_VPN_PROXY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setBrowserVpnProxy(@javax.annotation.Nonnull Boolean browserVpnProxy) { + this.browserVpnProxy = browserVpnProxy; + } + + + public DetectionFlags tor(@javax.annotation.Nonnull Boolean tor) { + this.tor = tor; + return this; + } + + /** + * The request came through the Tor network. + * @return tor + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_TOR, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getTor() { + return tor; + } + + + @JsonProperty(value = JSON_PROPERTY_TOR, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setTor(@javax.annotation.Nonnull Boolean tor) { + this.tor = tor; + } + + + public DetectionFlags proxy(@javax.annotation.Nonnull Boolean proxy) { + this.proxy = proxy; + return this; + } + + /** + * A proxy was detected. + * @return proxy + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_PROXY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getProxy() { + return proxy; + } + + + @JsonProperty(value = JSON_PROPERTY_PROXY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setProxy(@javax.annotation.Nonnull Boolean proxy) { + this.proxy = proxy; + } + + + public DetectionFlags datacenterIp(@javax.annotation.Nonnull Boolean datacenterIp) { + this.datacenterIp = datacenterIp; + return this; + } + + /** + * The public IP belongs to a datacenter or hosting range. + * @return datacenterIp + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_DATACENTER_IP, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getDatacenterIp() { + return datacenterIp; + } + + + @JsonProperty(value = JSON_PROPERTY_DATACENTER_IP, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDatacenterIp(@javax.annotation.Nonnull Boolean datacenterIp) { + this.datacenterIp = datacenterIp; + } + + + public DetectionFlags abuser(@javax.annotation.Nonnull Boolean abuser) { + this.abuser = abuser; + return this; + } + + /** + * The public IP has a record of abuse in IP intelligence. + * @return abuser + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_ABUSER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getAbuser() { + return abuser; + } + + + @JsonProperty(value = JSON_PROPERTY_ABUSER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setAbuser(@javax.annotation.Nonnull Boolean abuser) { + this.abuser = abuser; + } + + + public DetectionFlags osMismatch(@javax.annotation.Nonnull Boolean osMismatch) { + this.osMismatch = osMismatch; + return this; + } + + /** + * The operating system seen on the network differs from the one the browser reports. + * @return osMismatch + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_OS_MISMATCH, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getOsMismatch() { + return osMismatch; + } + + + @JsonProperty(value = JSON_PROPERTY_OS_MISMATCH, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setOsMismatch(@javax.annotation.Nonnull Boolean osMismatch) { + this.osMismatch = osMismatch; + } + + + public DetectionFlags osNotDetected(@javax.annotation.Nonnull Boolean osNotDetected) { + this.osNotDetected = osNotDetected; + return this; + } + + /** + * The operating system could not be determined from the User-Agent or the network. + * @return osNotDetected + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_OS_NOT_DETECTED, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getOsNotDetected() { + return osNotDetected; + } + + + @JsonProperty(value = JSON_PROPERTY_OS_NOT_DETECTED, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setOsNotDetected(@javax.annotation.Nonnull Boolean osNotDetected) { + this.osNotDetected = osNotDetected; + } + + + public DetectionFlags timezoneMismatch(@javax.annotation.Nonnull Boolean timezoneMismatch) { + this.timezoneMismatch = timezoneMismatch; + return this; + } + + /** + * The browser timezone differs from the timezone of the IP location. + * @return timezoneMismatch + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_TIMEZONE_MISMATCH, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getTimezoneMismatch() { + return timezoneMismatch; + } + + + @JsonProperty(value = JSON_PROPERTY_TIMEZONE_MISMATCH, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setTimezoneMismatch(@javax.annotation.Nonnull Boolean timezoneMismatch) { + this.timezoneMismatch = timezoneMismatch; + } + + + public DetectionFlags antiDetectBrowser(@javax.annotation.Nonnull Boolean antiDetectBrowser) { + this.antiDetectBrowser = antiDetectBrowser; + return this; + } + + /** + * An anti-detect browser was detected. + * @return antiDetectBrowser + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_ANTI_DETECT_BROWSER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getAntiDetectBrowser() { + return antiDetectBrowser; + } + + + @JsonProperty(value = JSON_PROPERTY_ANTI_DETECT_BROWSER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setAntiDetectBrowser(@javax.annotation.Nonnull Boolean antiDetectBrowser) { + this.antiDetectBrowser = antiDetectBrowser; + } + + + public DetectionFlags browserAutomation(@javax.annotation.Nonnull Boolean browserAutomation) { + this.browserAutomation = browserAutomation; + return this; + } + + /** + * Browser automation was detected, for example a WebDriver-controlled browser. + * @return browserAutomation + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_BROWSER_AUTOMATION, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getBrowserAutomation() { + return browserAutomation; + } + + + @JsonProperty(value = JSON_PROPERTY_BROWSER_AUTOMATION, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setBrowserAutomation(@javax.annotation.Nonnull Boolean browserAutomation) { + this.browserAutomation = browserAutomation; + } + + + public DetectionFlags ipMismatch(@javax.annotation.Nonnull Boolean ipMismatch) { + this.ipMismatch = ipMismatch; + return this; + } + + /** + * The public IP differs from the local IP found by the browser network check. Informational: it does not add to the score. + * @return ipMismatch + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IP_MISMATCH, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIpMismatch() { + return ipMismatch; + } + + + @JsonProperty(value = JSON_PROPERTY_IP_MISMATCH, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIpMismatch(@javax.annotation.Nonnull Boolean ipMismatch) { + this.ipMismatch = ipMismatch; + } + + + public DetectionFlags incognito(@javax.annotation.Nonnull Boolean incognito) { + this.incognito = incognito; + return this; + } + + /** + * The browser runs in a private window. + * @return incognito + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_INCOGNITO, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIncognito() { + return incognito; + } + + + @JsonProperty(value = JSON_PROPERTY_INCOGNITO, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIncognito(@javax.annotation.Nonnull Boolean incognito) { + this.incognito = incognito; + } + + + public DetectionFlags searchBot(@javax.annotation.Nonnull Boolean searchBot) { + this.searchBot = searchBot; + return this; + } + + /** + * A search-engine crawler. Its Risk Score is always 0. + * @return searchBot + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SEARCH_BOT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getSearchBot() { + return searchBot; + } + + + @JsonProperty(value = JSON_PROPERTY_SEARCH_BOT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setSearchBot(@javax.annotation.Nonnull Boolean searchBot) { + this.searchBot = searchBot; + } + + + public DetectionFlags suspiciousPaidClick(@javax.annotation.Nonnull Boolean suspiciousPaidClick) { + this.suspiciousPaidClick = suspiciousPaidClick; + return this; + } + + /** + * The visit came from a paid ad click (Google Ads, Meta, TikTok, Microsoft Ads, LinkedIn, Pinterest or X) and the Risk Score is 60 or more (the 999 marker included). + * @return suspiciousPaidClick + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SUSPICIOUS_PAID_CLICK, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getSuspiciousPaidClick() { + return suspiciousPaidClick; + } + + + @JsonProperty(value = JSON_PROPERTY_SUSPICIOUS_PAID_CLICK, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setSuspiciousPaidClick(@javax.annotation.Nonnull Boolean suspiciousPaidClick) { + this.suspiciousPaidClick = suspiciousPaidClick; + } + + + public DetectionFlags javascriptDisabled(@javax.annotation.Nonnull Boolean javascriptDisabled) { + this.javascriptDisabled = javascriptDisabled; + return this; + } + + /** + * JavaScript, or the browser APIs the checks need, were unavailable. + * @return javascriptDisabled + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_JAVASCRIPT_DISABLED, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getJavascriptDisabled() { + return javascriptDisabled; + } + + + @JsonProperty(value = JSON_PROPERTY_JAVASCRIPT_DISABLED, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setJavascriptDisabled(@javax.annotation.Nonnull Boolean javascriptDisabled) { + this.javascriptDisabled = javascriptDisabled; + } + + + public DetectionFlags stunNotChecked(@javax.annotation.Nonnull Boolean stunNotChecked) { + this.stunNotChecked = stunNotChecked; + return this; + } + + /** + * The browser network (STUN) check did not complete. Cleared again when a late network result arrives. + * @return stunNotChecked + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_STUN_NOT_CHECKED, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getStunNotChecked() { + return stunNotChecked; + } + + + @JsonProperty(value = JSON_PROPERTY_STUN_NOT_CHECKED, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setStunNotChecked(@javax.annotation.Nonnull Boolean stunNotChecked) { + this.stunNotChecked = stunNotChecked; + } + + + public DetectionFlags checkIncomplete(@javax.annotation.Nonnull Boolean checkIncomplete) { + this.checkIncomplete = checkIncomplete; + return this; + } + + /** + * Part of the browser checks timed out, so the verdict rests on partial data. Informational. + * @return checkIncomplete + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_CHECK_INCOMPLETE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getCheckIncomplete() { + return checkIncomplete; + } + + + @JsonProperty(value = JSON_PROPERTY_CHECK_INCOMPLETE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCheckIncomplete(@javax.annotation.Nonnull Boolean checkIncomplete) { + this.checkIncomplete = checkIncomplete; + } + + + /** + * Return true if this DetectionFlags object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DetectionFlags detectionFlags = (DetectionFlags) o; + return Objects.equals(this.vpn, detectionFlags.vpn) && + Objects.equals(this.privacyRelay, detectionFlags.privacyRelay) && + Objects.equals(this.browserVpnProxy, detectionFlags.browserVpnProxy) && + Objects.equals(this.tor, detectionFlags.tor) && + Objects.equals(this.proxy, detectionFlags.proxy) && + Objects.equals(this.datacenterIp, detectionFlags.datacenterIp) && + Objects.equals(this.abuser, detectionFlags.abuser) && + Objects.equals(this.osMismatch, detectionFlags.osMismatch) && + Objects.equals(this.osNotDetected, detectionFlags.osNotDetected) && + Objects.equals(this.timezoneMismatch, detectionFlags.timezoneMismatch) && + Objects.equals(this.antiDetectBrowser, detectionFlags.antiDetectBrowser) && + Objects.equals(this.browserAutomation, detectionFlags.browserAutomation) && + Objects.equals(this.ipMismatch, detectionFlags.ipMismatch) && + Objects.equals(this.incognito, detectionFlags.incognito) && + Objects.equals(this.searchBot, detectionFlags.searchBot) && + Objects.equals(this.suspiciousPaidClick, detectionFlags.suspiciousPaidClick) && + Objects.equals(this.javascriptDisabled, detectionFlags.javascriptDisabled) && + Objects.equals(this.stunNotChecked, detectionFlags.stunNotChecked) && + Objects.equals(this.checkIncomplete, detectionFlags.checkIncomplete); + } + + @Override + public int hashCode() { + return Objects.hash(vpn, privacyRelay, browserVpnProxy, tor, proxy, datacenterIp, abuser, osMismatch, osNotDetected, timezoneMismatch, antiDetectBrowser, browserAutomation, ipMismatch, incognito, searchBot, suspiciousPaidClick, javascriptDisabled, stunNotChecked, checkIncomplete); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class DetectionFlags {\n"); + sb.append(" vpn: ").append(toIndentedString(vpn)).append("\n"); + sb.append(" privacyRelay: ").append(toIndentedString(privacyRelay)).append("\n"); + sb.append(" browserVpnProxy: ").append(toIndentedString(browserVpnProxy)).append("\n"); + sb.append(" tor: ").append(toIndentedString(tor)).append("\n"); + sb.append(" proxy: ").append(toIndentedString(proxy)).append("\n"); + sb.append(" datacenterIp: ").append(toIndentedString(datacenterIp)).append("\n"); + sb.append(" abuser: ").append(toIndentedString(abuser)).append("\n"); + sb.append(" osMismatch: ").append(toIndentedString(osMismatch)).append("\n"); + sb.append(" osNotDetected: ").append(toIndentedString(osNotDetected)).append("\n"); + sb.append(" timezoneMismatch: ").append(toIndentedString(timezoneMismatch)).append("\n"); + sb.append(" antiDetectBrowser: ").append(toIndentedString(antiDetectBrowser)).append("\n"); + sb.append(" browserAutomation: ").append(toIndentedString(browserAutomation)).append("\n"); + sb.append(" ipMismatch: ").append(toIndentedString(ipMismatch)).append("\n"); + sb.append(" incognito: ").append(toIndentedString(incognito)).append("\n"); + sb.append(" searchBot: ").append(toIndentedString(searchBot)).append("\n"); + sb.append(" suspiciousPaidClick: ").append(toIndentedString(suspiciousPaidClick)).append("\n"); + sb.append(" javascriptDisabled: ").append(toIndentedString(javascriptDisabled)).append("\n"); + sb.append(" stunNotChecked: ").append(toIndentedString(stunNotChecked)).append("\n"); + sb.append(" checkIncomplete: ").append(toIndentedString(checkIncomplete)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `vpn` to the URL query string + if (getVpn() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%svpn%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getVpn())))); + } + + // add `privacy_relay` to the URL query string + if (getPrivacyRelay() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sprivacy_relay%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getPrivacyRelay())))); + } + + // add `browser_vpn_proxy` to the URL query string + if (getBrowserVpnProxy() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sbrowser_vpn_proxy%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getBrowserVpnProxy())))); + } + + // add `tor` to the URL query string + if (getTor() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%stor%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getTor())))); + } + + // add `proxy` to the URL query string + if (getProxy() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sproxy%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getProxy())))); + } + + // add `datacenter_ip` to the URL query string + if (getDatacenterIp() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sdatacenter_ip%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getDatacenterIp())))); + } + + // add `abuser` to the URL query string + if (getAbuser() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sabuser%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getAbuser())))); + } + + // add `os_mismatch` to the URL query string + if (getOsMismatch() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sos_mismatch%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getOsMismatch())))); + } + + // add `os_not_detected` to the URL query string + if (getOsNotDetected() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sos_not_detected%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getOsNotDetected())))); + } + + // add `timezone_mismatch` to the URL query string + if (getTimezoneMismatch() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%stimezone_mismatch%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getTimezoneMismatch())))); + } + + // add `anti_detect_browser` to the URL query string + if (getAntiDetectBrowser() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%santi_detect_browser%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getAntiDetectBrowser())))); + } + + // add `browser_automation` to the URL query string + if (getBrowserAutomation() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sbrowser_automation%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getBrowserAutomation())))); + } + + // add `ip_mismatch` to the URL query string + if (getIpMismatch() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sip_mismatch%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIpMismatch())))); + } + + // add `incognito` to the URL query string + if (getIncognito() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sincognito%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIncognito())))); + } + + // add `search_bot` to the URL query string + if (getSearchBot() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%ssearch_bot%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getSearchBot())))); + } + + // add `suspicious_paid_click` to the URL query string + if (getSuspiciousPaidClick() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%ssuspicious_paid_click%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getSuspiciousPaidClick())))); + } + + // add `javascript_disabled` to the URL query string + if (getJavascriptDisabled() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sjavascript_disabled%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getJavascriptDisabled())))); + } + + // add `stun_not_checked` to the URL query string + if (getStunNotChecked() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sstun_not_checked%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getStunNotChecked())))); + } + + // add `check_incomplete` to the URL query string + if (getCheckIncomplete() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%scheck_incomplete%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getCheckIncomplete())))); + } + + return joiner.toString(); + } +} + diff --git a/generated/src/main/java/ai/shieldlabs/generated/model/DomainProfile.java b/generated/src/main/java/ai/shieldlabs/generated/model/DomainProfile.java new file mode 100644 index 0000000..3f01b6e --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/model/DomainProfile.java @@ -0,0 +1,329 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated.model; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.StringJoiner; +import java.util.Objects; +import java.util.Map; +import java.util.HashMap; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.time.OffsetDateTime; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +import ai.shieldlabs.generated.ApiClient; +/** + * Profile of the registered domain. The keys are PascalCase on the wire. Ignore keys you do not know. + */ +@JsonPropertyOrder({ + DomainProfile.JSON_PROPERTY_DOMAIN, + DomainProfile.JSON_PROPERTY_WEIGHT, + DomainProfile.JSON_PROPERTY_CALLBACK, + DomainProfile.JSON_PROPERTY_PUBLIC_KEY, + DomainProfile.JSON_PROPERTY_SECRET, + DomainProfile.JSON_PROPERTY_CREATED_AT +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class DomainProfile { + public static final String JSON_PROPERTY_DOMAIN = "Domain"; + @javax.annotation.Nonnull + private String domain; + + public static final String JSON_PROPERTY_WEIGHT = "Weight"; + @javax.annotation.Nonnull + private Integer weight; + + public static final String JSON_PROPERTY_CALLBACK = "Callback"; + @javax.annotation.Nonnull + private String callback; + + public static final String JSON_PROPERTY_PUBLIC_KEY = "PublicKey"; + @javax.annotation.Nonnull + private String publicKey; + + public static final String JSON_PROPERTY_SECRET = "Secret"; + @javax.annotation.Nonnull + private String secret; + + public static final String JSON_PROPERTY_CREATED_AT = "CreatedAt"; + @javax.annotation.Nonnull + private OffsetDateTime createdAt; + + public DomainProfile() { + } + + public DomainProfile domain(@javax.annotation.Nonnull String domain) { + this.domain = domain; + return this; + } + + /** + * The registered domain, as sent in `X-Shield-Domain`. + * @return domain + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_DOMAIN, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getDomain() { + return domain; + } + + + @JsonProperty(value = JSON_PROPERTY_DOMAIN, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDomain(@javax.annotation.Nonnull String domain) { + this.domain = domain; + } + + + public DomainProfile weight(@javax.annotation.Nonnull Integer weight) { + this.weight = weight; + return this; + } + + /** + * Remaining included identifications of the account (shared by its domains). Can be negative when the account is over its included volume. + * @return weight + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_WEIGHT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Integer getWeight() { + return weight; + } + + + @JsonProperty(value = JSON_PROPERTY_WEIGHT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setWeight(@javax.annotation.Nonnull Integer weight) { + this.weight = weight; + } + + + public DomainProfile callback(@javax.annotation.Nonnull String callback) { + this.callback = callback; + return this; + } + + /** + * Legacy field kept for compatibility, normally an empty string. Webhook deliveries do not use it: configure webhook endpoints in the analytics dashboard. + * @return callback + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_CALLBACK, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getCallback() { + return callback; + } + + + @JsonProperty(value = JSON_PROPERTY_CALLBACK, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCallback(@javax.annotation.Nonnull String callback) { + this.callback = callback; + } + + + public DomainProfile publicKey(@javax.annotation.Nonnull String publicKey) { + this.publicKey = publicKey; + return this; + } + + /** + * The domain's Public Key, masked. + * @return publicKey + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_PUBLIC_KEY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getPublicKey() { + return publicKey; + } + + + @JsonProperty(value = JSON_PROPERTY_PUBLIC_KEY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setPublicKey(@javax.annotation.Nonnull String publicKey) { + this.publicKey = publicKey; + } + + + public DomainProfile secret(@javax.annotation.Nonnull String secret) { + this.secret = secret; + return this; + } + + /** + * The domain's Secret Key, masked. + * @return secret + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SECRET, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getSecret() { + return secret; + } + + + @JsonProperty(value = JSON_PROPERTY_SECRET, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setSecret(@javax.annotation.Nonnull String secret) { + this.secret = secret; + } + + + public DomainProfile createdAt(@javax.annotation.Nonnull OffsetDateTime createdAt) { + this.createdAt = createdAt; + return this; + } + + /** + * When the domain was registered, RFC 3339 in UTC with second precision. `0001-01-01T00:00:00Z` when unknown. + * @return createdAt + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_CREATED_AT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public OffsetDateTime getCreatedAt() { + return createdAt; + } + + + @JsonProperty(value = JSON_PROPERTY_CREATED_AT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCreatedAt(@javax.annotation.Nonnull OffsetDateTime createdAt) { + this.createdAt = createdAt; + } + + + /** + * Return true if this DomainProfile object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DomainProfile domainProfile = (DomainProfile) o; + return Objects.equals(this.domain, domainProfile.domain) && + Objects.equals(this.weight, domainProfile.weight) && + Objects.equals(this.callback, domainProfile.callback) && + Objects.equals(this.publicKey, domainProfile.publicKey) && + Objects.equals(this.secret, domainProfile.secret) && + Objects.equals(this.createdAt, domainProfile.createdAt); + } + + @Override + public int hashCode() { + return Objects.hash(domain, weight, callback, publicKey, secret, createdAt); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class DomainProfile {\n"); + sb.append(" domain: ").append(toIndentedString(domain)).append("\n"); + sb.append(" weight: ").append(toIndentedString(weight)).append("\n"); + sb.append(" callback: ").append(toIndentedString(callback)).append("\n"); + sb.append(" publicKey: ").append(toIndentedString(publicKey)).append("\n"); + sb.append(" secret: ").append(toIndentedString(secret)).append("\n"); + sb.append(" createdAt: ").append(toIndentedString(createdAt)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `Domain` to the URL query string + if (getDomain() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sDomain%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getDomain())))); + } + + // add `Weight` to the URL query string + if (getWeight() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sWeight%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getWeight())))); + } + + // add `Callback` to the URL query string + if (getCallback() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sCallback%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getCallback())))); + } + + // add `PublicKey` to the URL query string + if (getPublicKey() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sPublicKey%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getPublicKey())))); + } + + // add `Secret` to the URL query string + if (getSecret() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sSecret%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getSecret())))); + } + + // add `CreatedAt` to the URL query string + if (getCreatedAt() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sCreatedAt%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getCreatedAt())))); + } + + return joiner.toString(); + } +} + diff --git a/generated/src/main/java/ai/shieldlabs/generated/model/ErrorBody.java b/generated/src/main/java/ai/shieldlabs/generated/model/ErrorBody.java new file mode 100644 index 0000000..209a9d7 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/model/ErrorBody.java @@ -0,0 +1,148 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated.model; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.StringJoiner; +import java.util.Objects; +import java.util.Map; +import java.util.HashMap; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +import ai.shieldlabs.generated.ApiClient; +/** + * Error object sent by the History API and by the Management API rate and load limits. + */ +@JsonPropertyOrder({ + ErrorBody.JSON_PROPERTY_ERROR +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class ErrorBody { + public static final String JSON_PROPERTY_ERROR = "error"; + @javax.annotation.Nonnull + private String error; + + public ErrorBody() { + } + + public ErrorBody error(@javax.annotation.Nonnull String error) { + this.error = error; + return this; + } + + /** + * Human-readable error message. Branch on the HTTP status, not on this text. + * @return error + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_ERROR, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getError() { + return error; + } + + + @JsonProperty(value = JSON_PROPERTY_ERROR, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setError(@javax.annotation.Nonnull String error) { + this.error = error; + } + + + /** + * Return true if this ErrorBody object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ErrorBody errorBody = (ErrorBody) o; + return Objects.equals(this.error, errorBody.error); + } + + @Override + public int hashCode() { + return Objects.hash(error); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ErrorBody {\n"); + sb.append(" error: ").append(toIndentedString(error)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `error` to the URL query string + if (getError() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%serror%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getError())))); + } + + return joiner.toString(); + } +} + diff --git a/generated/src/main/java/ai/shieldlabs/generated/model/HealthStatus.java b/generated/src/main/java/ai/shieldlabs/generated/model/HealthStatus.java new file mode 100644 index 0000000..32e4847 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/model/HealthStatus.java @@ -0,0 +1,181 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated.model; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.StringJoiner; +import java.util.Objects; +import java.util.Map; +import java.util.HashMap; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +import ai.shieldlabs.generated.ApiClient; +/** + * Liveness status. + */ +@JsonPropertyOrder({ + HealthStatus.JSON_PROPERTY_STATUS +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class HealthStatus { + /** + * Always `ok` when the service answers. + */ + public enum StatusEnum { + OK(String.valueOf("ok")); + + private String value; + + StatusEnum(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static StatusEnum fromValue(String value) { + for (StatusEnum b : StatusEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + } + + public static final String JSON_PROPERTY_STATUS = "status"; + @javax.annotation.Nonnull + private StatusEnum status; + + public HealthStatus() { + } + + public HealthStatus status(@javax.annotation.Nonnull StatusEnum status) { + this.status = status; + return this; + } + + /** + * Always `ok` when the service answers. + * @return status + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_STATUS, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public StatusEnum getStatus() { + return status; + } + + + @JsonProperty(value = JSON_PROPERTY_STATUS, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setStatus(@javax.annotation.Nonnull StatusEnum status) { + this.status = status; + } + + + /** + * Return true if this HealthStatus object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + HealthStatus healthStatus = (HealthStatus) o; + return Objects.equals(this.status, healthStatus.status); + } + + @Override + public int hashCode() { + return Objects.hash(status); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class HealthStatus {\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `status` to the URL query string + if (getStatus() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sstatus%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getStatus())))); + } + + return joiner.toString(); + } +} + diff --git a/generated/src/main/java/ai/shieldlabs/generated/model/HistoryPage.java b/generated/src/main/java/ai/shieldlabs/generated/model/HistoryPage.java new file mode 100644 index 0000000..ee9a601 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/model/HistoryPage.java @@ -0,0 +1,202 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated.model; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.StringJoiner; +import java.util.Objects; +import java.util.Map; +import java.util.HashMap; +import ai.shieldlabs.generated.model.HistoryRow; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +import ai.shieldlabs.generated.ApiClient; +/** + * One page of identifications, newest first. + */ +@JsonPropertyOrder({ + HistoryPage.JSON_PROPERTY_DATA, + HistoryPage.JSON_PROPERTY_TOTAL +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class HistoryPage { + public static final String JSON_PROPERTY_DATA = "data"; + @javax.annotation.Nonnull + private List data = new ArrayList<>(); + + public static final String JSON_PROPERTY_TOTAL = "total"; + @javax.annotation.Nonnull + private Integer total; + + public HistoryPage() { + } + + public HistoryPage data(@javax.annotation.Nonnull List data) { + this.data = data; + return this; + } + + public HistoryPage addDataItem(HistoryRow dataItem) { + if (this.data == null) { + this.data = new ArrayList<>(); + } + this.data.add(dataItem); + return this; + } + + /** + * Identifications on this page, ordered by `created_at` descending. Empty when nothing matched. + * @return data + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_DATA, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public List getData() { + return data; + } + + + @JsonProperty(value = JSON_PROPERTY_DATA, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setData(@javax.annotation.Nonnull List data) { + this.data = data; + } + + + public HistoryPage total(@javax.annotation.Nonnull Integer total) { + this.total = total; + return this; + } + + /** + * Number of identifications that match the search in total, across all pages. Page with `offset` while it is below `total`. + * minimum: 0 + * @return total + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_TOTAL, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Integer getTotal() { + return total; + } + + + @JsonProperty(value = JSON_PROPERTY_TOTAL, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setTotal(@javax.annotation.Nonnull Integer total) { + this.total = total; + } + + + /** + * Return true if this HistoryPage object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + HistoryPage historyPage = (HistoryPage) o; + return Objects.equals(this.data, historyPage.data) && + Objects.equals(this.total, historyPage.total); + } + + @Override + public int hashCode() { + return Objects.hash(data, total); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class HistoryPage {\n"); + sb.append(" data: ").append(toIndentedString(data)).append("\n"); + sb.append(" total: ").append(toIndentedString(total)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `data` to the URL query string + if (getData() != null) { + for (int i = 0; i < getData().size(); i++) { + if (getData().get(i) != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sdata%s%s=%s", prefix, suffix, + "".equals(suffix) ? "" : String.format(java.util.Locale.ROOT, "%s%d%s", containerPrefix, i, containerSuffix), + ApiClient.urlEncode(ApiClient.valueToString(getData().get(i))))); + } + } + } + + // add `total` to the URL query string + if (getTotal() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%stotal%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getTotal())))); + } + + return joiner.toString(); + } +} + diff --git a/generated/src/main/java/ai/shieldlabs/generated/model/HistoryRow.java b/generated/src/main/java/ai/shieldlabs/generated/model/HistoryRow.java new file mode 100644 index 0000000..b868911 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/model/HistoryRow.java @@ -0,0 +1,2071 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated.model; + +import java.util.Map; +import java.util.HashMap; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.StringJoiner; +import java.util.Objects; +import java.util.Map; +import java.util.HashMap; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import java.util.UUID; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +import ai.shieldlabs.generated.ApiClient; +/** + * One identification as stored, in its latest version. It describes the same identification as a webhook `data` object, with different field names: | Webhook `data` | History row | |---|---| | `risk_score` | `score` | | `signals` | `score_details` (JSON-encoded string, zero weights included) | | `detection_flags` | the `is_*` columns and `check_incomplete` (each column names its flag) | | `detection_flags.browser_vpn_proxy` | derive it: `connection_type == \"browser_vpn_proxy\"` | | `domain` | `site_domain` when present, otherwise `domain` | | `public_ip` | `ip` (`0.0.0.0` instead of `\"\"`) and `country` | | `local_ip` | `webrtc_leak_ip` and `webrtc_leak_country` when `webrtc_leak_source` is set and not `none`, otherwise `web_rtc_ip` and `web_rtc_country` | | `traffic_source` | `traffic_channel`, `referrer_domain`, `entry_url`, `click_id_type`, `utm_*` (omitted when empty) | | `observed_at` (when scoring finished) | `created_at` (when the identification was made) | The `ip_mismatch` flag has no column. Rows also carry diagnostic network fields (TCP, MTU and STUN measurements) that are not part of the stable contract: ignore fields you do not know. + */ +@JsonPropertyOrder({ + HistoryRow.JSON_PROPERTY_REQUEST_ID, + HistoryRow.JSON_PROPERTY_SESSION_ID, + HistoryRow.JSON_PROPERTY_COOKIE_ID, + HistoryRow.JSON_PROPERTY_DOMAIN, + HistoryRow.JSON_PROPERTY_SITE_DOMAIN, + HistoryRow.JSON_PROPERTY_USER_HID, + HistoryRow.JSON_PROPERTY_DEVICE_ID, + HistoryRow.JSON_PROPERTY_VISITOR_ID, + HistoryRow.JSON_PROPERTY_IP, + HistoryRow.JSON_PROPERTY_OS, + HistoryRow.JSON_PROPERTY_BROWSER, + HistoryRow.JSON_PROPERTY_DEVICE_TYPE, + HistoryRow.JSON_PROPERTY_COUNTRY, + HistoryRow.JSON_PROPERTY_CONNECTION_TYPE, + HistoryRow.JSON_PROPERTY_SCORE, + HistoryRow.JSON_PROPERTY_SCORE_DETAILS, + HistoryRow.JSON_PROPERTY_CREATED_AT, + HistoryRow.JSON_PROPERTY_VER, + HistoryRow.JSON_PROPERTY_WEB_RTC_IP, + HistoryRow.JSON_PROPERTY_WEB_RTC_COUNTRY, + HistoryRow.JSON_PROPERTY_WEB_RTC_CONNECTION_TYPE, + HistoryRow.JSON_PROPERTY_WEBRTC_LEAK_IP, + HistoryRow.JSON_PROPERTY_WEBRTC_LEAK_COUNTRY, + HistoryRow.JSON_PROPERTY_WEBRTC_LEAK_CONNECTION_TYPE, + HistoryRow.JSON_PROPERTY_WEBRTC_LEAK_SOURCE, + HistoryRow.JSON_PROPERTY_IS_VPN, + HistoryRow.JSON_PROPERTY_IS_TOR, + HistoryRow.JSON_PROPERTY_IS_PROXY, + HistoryRow.JSON_PROPERTY_IS_DATACENTER, + HistoryRow.JSON_PROPERTY_IS_ABUSER, + HistoryRow.JSON_PROPERTY_IS_PRIVACY_RELAY, + HistoryRow.JSON_PROPERTY_IS_STUN_NOT_CHECKED, + HistoryRow.JSON_PROPERTY_CHECK_INCOMPLETE, + HistoryRow.JSON_PROPERTY_IS_ANTIDETECT, + HistoryRow.JSON_PROPERTY_IS_OS_MISMATCH, + HistoryRow.JSON_PROPERTY_IS_OS_NOT_DETECTED, + HistoryRow.JSON_PROPERTY_IS_TIMEZONE_MISMATCH, + HistoryRow.JSON_PROPERTY_IS_JS_DISABLED, + HistoryRow.JSON_PROPERTY_IS_BROWSER_AUTOMATION, + HistoryRow.JSON_PROPERTY_IS_INCOGNITO, + HistoryRow.JSON_PROPERTY_IS_SEARCH_BOT, + HistoryRow.JSON_PROPERTY_IS_SUSPICIOUS_PAID_CLICK, + HistoryRow.JSON_PROPERTY_ENTRY_URL, + HistoryRow.JSON_PROPERTY_UTM_SOURCE, + HistoryRow.JSON_PROPERTY_UTM_MEDIUM, + HistoryRow.JSON_PROPERTY_UTM_CAMPAIGN, + HistoryRow.JSON_PROPERTY_UTM_CONTENT, + HistoryRow.JSON_PROPERTY_UTM_TERM, + HistoryRow.JSON_PROPERTY_TRAFFIC_CHANNEL, + HistoryRow.JSON_PROPERTY_TRAFFIC_CHANNEL_GROUP, + HistoryRow.JSON_PROPERTY_TRAFFIC_REASON, + HistoryRow.JSON_PROPERTY_REFERRER_DOMAIN, + HistoryRow.JSON_PROPERTY_CLICK_ID_TYPE +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class HistoryRow { + public static final String JSON_PROPERTY_REQUEST_ID = "request_id"; + @javax.annotation.Nonnull + private UUID requestId; + + public static final String JSON_PROPERTY_SESSION_ID = "session_id"; + @javax.annotation.Nonnull + private UUID sessionId; + + public static final String JSON_PROPERTY_COOKIE_ID = "cookie_id"; + @javax.annotation.Nonnull + private UUID cookieId; + + public static final String JSON_PROPERTY_DOMAIN = "domain"; + @javax.annotation.Nonnull + private String domain; + + public static final String JSON_PROPERTY_SITE_DOMAIN = "site_domain"; + @javax.annotation.Nullable + private String siteDomain; + + public static final String JSON_PROPERTY_USER_HID = "user_hid"; + @javax.annotation.Nonnull + private String userHid; + + public static final String JSON_PROPERTY_DEVICE_ID = "device_id"; + @javax.annotation.Nonnull + private UUID deviceId; + + public static final String JSON_PROPERTY_VISITOR_ID = "visitor_id"; + @javax.annotation.Nonnull + private UUID visitorId; + + public static final String JSON_PROPERTY_IP = "ip"; + @javax.annotation.Nonnull + private String ip; + + public static final String JSON_PROPERTY_OS = "os"; + @javax.annotation.Nonnull + private String os; + + public static final String JSON_PROPERTY_BROWSER = "browser"; + @javax.annotation.Nonnull + private String browser; + + public static final String JSON_PROPERTY_DEVICE_TYPE = "device_type"; + @javax.annotation.Nonnull + private String deviceType; + + public static final String JSON_PROPERTY_COUNTRY = "country"; + @javax.annotation.Nonnull + private String country; + + public static final String JSON_PROPERTY_CONNECTION_TYPE = "connection_type"; + @javax.annotation.Nonnull + private String connectionType; + + public static final String JSON_PROPERTY_SCORE = "score"; + @javax.annotation.Nonnull + private Integer score; + + public static final String JSON_PROPERTY_SCORE_DETAILS = "score_details"; + @javax.annotation.Nonnull + private String scoreDetails; + + public static final String JSON_PROPERTY_CREATED_AT = "created_at"; + @javax.annotation.Nonnull + private String createdAt; + + public static final String JSON_PROPERTY_VER = "ver"; + @javax.annotation.Nonnull + private Long ver; + + public static final String JSON_PROPERTY_WEB_RTC_IP = "web_rtc_ip"; + @javax.annotation.Nonnull + private String webRtcIp; + + public static final String JSON_PROPERTY_WEB_RTC_COUNTRY = "web_rtc_country"; + @javax.annotation.Nonnull + private String webRtcCountry; + + public static final String JSON_PROPERTY_WEB_RTC_CONNECTION_TYPE = "web_rtc_connection_type"; + @javax.annotation.Nonnull + private String webRtcConnectionType; + + public static final String JSON_PROPERTY_WEBRTC_LEAK_IP = "webrtc_leak_ip"; + @javax.annotation.Nonnull + private String webrtcLeakIp; + + public static final String JSON_PROPERTY_WEBRTC_LEAK_COUNTRY = "webrtc_leak_country"; + @javax.annotation.Nonnull + private String webrtcLeakCountry; + + public static final String JSON_PROPERTY_WEBRTC_LEAK_CONNECTION_TYPE = "webrtc_leak_connection_type"; + @javax.annotation.Nonnull + private String webrtcLeakConnectionType; + + public static final String JSON_PROPERTY_WEBRTC_LEAK_SOURCE = "webrtc_leak_source"; + @javax.annotation.Nonnull + private String webrtcLeakSource; + + public static final String JSON_PROPERTY_IS_VPN = "is_vpn"; + @javax.annotation.Nonnull + private Boolean isVpn; + + public static final String JSON_PROPERTY_IS_TOR = "is_tor"; + @javax.annotation.Nonnull + private Boolean isTor; + + public static final String JSON_PROPERTY_IS_PROXY = "is_proxy"; + @javax.annotation.Nonnull + private Boolean isProxy; + + public static final String JSON_PROPERTY_IS_DATACENTER = "is_datacenter"; + @javax.annotation.Nonnull + private Boolean isDatacenter; + + public static final String JSON_PROPERTY_IS_ABUSER = "is_abuser"; + @javax.annotation.Nonnull + private Boolean isAbuser; + + public static final String JSON_PROPERTY_IS_PRIVACY_RELAY = "is_privacy_relay"; + @javax.annotation.Nonnull + private Boolean isPrivacyRelay; + + public static final String JSON_PROPERTY_IS_STUN_NOT_CHECKED = "is_stun_not_checked"; + @javax.annotation.Nonnull + private Boolean isStunNotChecked; + + public static final String JSON_PROPERTY_CHECK_INCOMPLETE = "check_incomplete"; + @javax.annotation.Nonnull + private Boolean checkIncomplete; + + public static final String JSON_PROPERTY_IS_ANTIDETECT = "is_antidetect"; + @javax.annotation.Nonnull + private Boolean isAntidetect; + + public static final String JSON_PROPERTY_IS_OS_MISMATCH = "is_os_mismatch"; + @javax.annotation.Nonnull + private Boolean isOsMismatch; + + public static final String JSON_PROPERTY_IS_OS_NOT_DETECTED = "is_os_not_detected"; + @javax.annotation.Nonnull + private Boolean isOsNotDetected; + + public static final String JSON_PROPERTY_IS_TIMEZONE_MISMATCH = "is_timezone_mismatch"; + @javax.annotation.Nonnull + private Boolean isTimezoneMismatch; + + public static final String JSON_PROPERTY_IS_JS_DISABLED = "is_js_disabled"; + @javax.annotation.Nonnull + private Boolean isJsDisabled; + + public static final String JSON_PROPERTY_IS_BROWSER_AUTOMATION = "is_browser_automation"; + @javax.annotation.Nonnull + private Boolean isBrowserAutomation; + + public static final String JSON_PROPERTY_IS_INCOGNITO = "is_incognito"; + @javax.annotation.Nonnull + private Boolean isIncognito; + + public static final String JSON_PROPERTY_IS_SEARCH_BOT = "is_search_bot"; + @javax.annotation.Nonnull + private Boolean isSearchBot; + + public static final String JSON_PROPERTY_IS_SUSPICIOUS_PAID_CLICK = "is_suspicious_paid_click"; + @javax.annotation.Nullable + private Boolean isSuspiciousPaidClick; + + public static final String JSON_PROPERTY_ENTRY_URL = "entry_url"; + @javax.annotation.Nullable + private String entryUrl; + + public static final String JSON_PROPERTY_UTM_SOURCE = "utm_source"; + @javax.annotation.Nullable + private String utmSource; + + public static final String JSON_PROPERTY_UTM_MEDIUM = "utm_medium"; + @javax.annotation.Nullable + private String utmMedium; + + public static final String JSON_PROPERTY_UTM_CAMPAIGN = "utm_campaign"; + @javax.annotation.Nullable + private String utmCampaign; + + public static final String JSON_PROPERTY_UTM_CONTENT = "utm_content"; + @javax.annotation.Nullable + private String utmContent; + + public static final String JSON_PROPERTY_UTM_TERM = "utm_term"; + @javax.annotation.Nullable + private String utmTerm; + + public static final String JSON_PROPERTY_TRAFFIC_CHANNEL = "traffic_channel"; + @javax.annotation.Nullable + private String trafficChannel; + + public static final String JSON_PROPERTY_TRAFFIC_CHANNEL_GROUP = "traffic_channel_group"; + @javax.annotation.Nullable + private String trafficChannelGroup; + + public static final String JSON_PROPERTY_TRAFFIC_REASON = "traffic_reason"; + @javax.annotation.Nullable + private String trafficReason; + + public static final String JSON_PROPERTY_REFERRER_DOMAIN = "referrer_domain"; + @javax.annotation.Nullable + private String referrerDomain; + + public static final String JSON_PROPERTY_CLICK_ID_TYPE = "click_id_type"; + @javax.annotation.Nullable + private String clickIdType; + + public HistoryRow() { + } + + public HistoryRow requestId(@javax.annotation.Nonnull UUID requestId) { + this.requestId = requestId; + return this; + } + + /** + * Identifies one identification. The browser creates it as a UUID v4 and hands it to your page; it is the join key between the browser, the webhook and the History API. The nil UUID appears only on rate-limit marker rows that arrived with a malformed request ID. + * @return requestId + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_REQUEST_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public UUID getRequestId() { + return requestId; + } + + + @JsonProperty(value = JSON_PROPERTY_REQUEST_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setRequestId(@javax.annotation.Nonnull UUID requestId) { + this.requestId = requestId; + } + + + public HistoryRow sessionId(@javax.annotation.Nonnull UUID sessionId) { + this.sessionId = sessionId; + return this; + } + + /** + * One visit on one origin (UUID v4 created in the browser), shared by the open tabs of that origin. The next visit after the last tab closes gets a new session ID. The nil UUID appears on rate-limit marker rows. + * @return sessionId + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SESSION_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public UUID getSessionId() { + return sessionId; + } + + + @JsonProperty(value = JSON_PROPERTY_SESSION_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setSessionId(@javax.annotation.Nonnull UUID sessionId) { + this.sessionId = sessionId; + } + + + public HistoryRow cookieId(@javax.annotation.Nonnull UUID cookieId) { + this.cookieId = cookieId; + return this; + } + + /** + * First-party browser identifier kept by the ShieldLabs agent (UUID v4). A missing or malformed value is stored as the nil UUID. + * @return cookieId + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_COOKIE_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public UUID getCookieId() { + return cookieId; + } + + + @JsonProperty(value = JSON_PROPERTY_COOKIE_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCookieId(@javax.annotation.Nonnull UUID cookieId) { + this.cookieId = cookieId; + } + + + public HistoryRow domain(@javax.annotation.Nonnull String domain) { + this.domain = domain; + return this; + } + + /** + * Host the identification came from. Can be a subdomain of your registered domain. + * @return domain + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_DOMAIN, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getDomain() { + return domain; + } + + + @JsonProperty(value = JSON_PROPERTY_DOMAIN, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDomain(@javax.annotation.Nonnull String domain) { + this.domain = domain; + } + + + public HistoryRow siteDomain(@javax.annotation.Nullable String siteDomain) { + this.siteDomain = siteDomain; + return this; + } + + /** + * Your registered domain, present when the identification came from a subdomain. Omitted when empty. + * @return siteDomain + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_SITE_DOMAIN, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public String getSiteDomain() { + return siteDomain; + } + + + @JsonProperty(value = JSON_PROPERTY_SITE_DOMAIN, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setSiteDomain(@javax.annotation.Nullable String siteDomain) { + this.siteDomain = siteDomain; + } + + + public HistoryRow userHid(@javax.annotation.Nonnull String userHid) { + this.userHid = userHid; + return this; + } + + /** + * User HID exactly as it was passed to the agent (hashed or pseudonymous account identifier). `anonymous` for anonymous checks; `fail`, `-1` and `unknown` also mean \"no user\". Empty string when no value was stored. Leave the empty string and these values out when you count accounts. + * @return userHid + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_USER_HID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getUserHid() { + return userHid; + } + + + @JsonProperty(value = JSON_PROPERTY_USER_HID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setUserHid(@javax.annotation.Nonnull String userHid) { + this.userHid = userHid; + } + + + public HistoryRow deviceId(@javax.annotation.Nonnull UUID deviceId) { + this.deviceId = deviceId; + return this; + } + + /** + * Server-side device identifier (UUID v5). It survives cleared cookies and private windows. The nil UUID `00000000-0000-0000-0000-000000000000` means that no usable device signals were collected (for example on rate-limit marker rows): never group identifications by it. + * @return deviceId + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_DEVICE_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public UUID getDeviceId() { + return deviceId; + } + + + @JsonProperty(value = JSON_PROPERTY_DEVICE_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDeviceId(@javax.annotation.Nonnull UUID deviceId) { + this.deviceId = deviceId; + } + + + public HistoryRow visitorId(@javax.annotation.Nonnull UUID visitorId) { + this.visitorId = visitorId; + return this; + } + + /** + * Server-side visitor identifier (UUID v5). It is sticky to the device: a new cookie on a known device keeps the existing visitor ID, so clearing cookies usually does not change it. The nil UUID appears on identifications without usable device data, such as rate-limit marker rows. + * @return visitorId + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_VISITOR_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public UUID getVisitorId() { + return visitorId; + } + + + @JsonProperty(value = JSON_PROPERTY_VISITOR_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setVisitorId(@javax.annotation.Nonnull UUID visitorId) { + this.visitorId = visitorId; + } + + + public HistoryRow ip(@javax.annotation.Nonnull String ip) { + this.ip = ip; + return this; + } + + /** + * Public IPv4 address of the HTTP request; `0.0.0.0` when none (for example IPv6 visitors). + * @return ip + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IP, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getIp() { + return ip; + } + + + @JsonProperty(value = JSON_PROPERTY_IP, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIp(@javax.annotation.Nonnull String ip) { + this.ip = ip; + } + + + public HistoryRow os(@javax.annotation.Nonnull String os) { + this.os = os; + return this; + } + + /** + * Operating system name, for example `Windows`, `Mac OS X`, `Linux`, `Android`, `IOS (iPhone)`, `IOS (iPad)`, `ChromeOS` or `Unknown`. Open set: display it, do not branch on it. + * @return os + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_OS, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getOs() { + return os; + } + + + @JsonProperty(value = JSON_PROPERTY_OS, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setOs(@javax.annotation.Nonnull String os) { + this.os = os; + } + + + public HistoryRow browser(@javax.annotation.Nonnull String browser) { + this.browser = browser; + return this; + } + + /** + * Browser name, for example `Chrome`, `Safari`, `Firefox`, `Microsoft Edge`, `Opera`, `Samsung Internet`, `Brave`, `Chrome (iOS)`, `Safari (iOS)` or `Unknown`. Open set: display it, do not branch on it. + * @return browser + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_BROWSER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getBrowser() { + return browser; + } + + + @JsonProperty(value = JSON_PROPERTY_BROWSER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setBrowser(@javax.annotation.Nonnull String browser) { + this.browser = browser; + } + + + public HistoryRow deviceType(@javax.annotation.Nonnull String deviceType) { + this.deviceType = deviceType; + return this; + } + + /** + * Device class from the browser. Known values: `desktop`, `mobile`, `tablet` and `unknown` (the class could not be determined). The set is open: keep values added in later versions and treat them as `unknown`. + * @return deviceType + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_DEVICE_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getDeviceType() { + return deviceType; + } + + + @JsonProperty(value = JSON_PROPERTY_DEVICE_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDeviceType(@javax.annotation.Nonnull String deviceType) { + this.deviceType = deviceType; + } + + + public HistoryRow country(@javax.annotation.Nonnull String country) { + this.country = country; + return this; + } + + /** + * Country of `ip` as an English country name, or an empty string. + * @return country + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_COUNTRY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getCountry() { + return country; + } + + + @JsonProperty(value = JSON_PROPERTY_COUNTRY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCountry(@javax.annotation.Nonnull String country) { + this.country = country; + } + + + public HistoryRow connectionType(@javax.annotation.Nonnull String connectionType) { + this.connectionType = connectionType; + return this; + } + + /** + * How the visitor connected. Known values: - `direct`: a regular connection; - `mobile`: a mobile carrier network; - `vpn`: a VPN; - `proxy`: a proxy, datacenter or hosting network (search-engine crawlers are reported here too); - `tor`: the Tor network; - `privacy_relay`: a privacy relay such as iCloud Private Relay; - `browser_vpn_proxy`: a VPN or proxy built into the browser or one of its extensions; - `unknown`: not enough data. The value can say `vpn` while `detection_flags.vpn` is `false` (IP intelligence classified the network, but the scored VPN check did not fire). Branch on `detection_flags` for decisions. The set is open: keep values added in later versions and treat them as `unknown`. + * @return connectionType + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_CONNECTION_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getConnectionType() { + return connectionType; + } + + + @JsonProperty(value = JSON_PROPERTY_CONNECTION_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setConnectionType(@javax.annotation.Nonnull String connectionType) { + this.connectionType = connectionType; + } + + + public HistoryRow score(@javax.annotation.Nonnull Integer score) { + this.score = score; + return this; + } + + /** + * Risk Score from 0 (no risk found) to 100. Search-engine crawlers always score 0. Risk bands are computed on your side from the score; no band field exists on the wire: - trusted: 0-29 - suspicious: 30-59 - dangerous: 60-100 A value above 100 is not a score. `999` is the rate-limit marker: the visitor's IP went over the ingest rate limit, and the identification carries exactly one signal, `{\"name\":\"rate_limited\",\"weight\":999}`, usually with nil identifiers. Treat every value above 100 as rate limited. One marker is written when the IP goes over the limit; request IDs issued while it stays blocked get no row and no webhook, so they stay unverified. The score usually equals the sum of the signal weights capped at 100, but carried-forward verdicts and corrections make that unreliable: never recompute or validate it yourself. + * minimum: 0 + * @return score + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SCORE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Integer getScore() { + return score; + } + + + @JsonProperty(value = JSON_PROPERTY_SCORE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setScore(@javax.annotation.Nonnull Integer score) { + this.score = score; + } + + + public HistoryRow scoreDetails(@javax.annotation.Nonnull String scoreDetails) { + this.scoreDetails = scoreDetails; + return this; + } + + /** + * The entries behind `score` as a JSON-encoded **string** holding an array of `{\"Value\": <integer>, \"Description\": <string>}`. Parse it before use. Scored entries come first, followed by informational entries with `Value` 0, which can be long. Empty string when no details were stored. The webhook `signals` are the entries with a non-zero `Value`, in the same order, with each description turned into a signal name (for example `Is proxy` becomes `proxy`). Descriptions are free text for display: never branch on them. + * @return scoreDetails + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SCORE_DETAILS, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getScoreDetails() { + return scoreDetails; + } + + + @JsonProperty(value = JSON_PROPERTY_SCORE_DETAILS, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setScoreDetails(@javax.annotation.Nonnull String scoreDetails) { + this.scoreDetails = scoreDetails; + } + + + public HistoryRow createdAt(@javax.annotation.Nonnull String createdAt) { + this.createdAt = createdAt; + return this; + } + + /** + * Time of the identification as `YYYY-MM-DD HH:MM:SS.mmm` in UTC, without a zone designator (not RFC 3339). Older rows can lack the milliseconds. + * @return createdAt + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_CREATED_AT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getCreatedAt() { + return createdAt; + } + + + @JsonProperty(value = JSON_PROPERTY_CREATED_AT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCreatedAt(@javax.annotation.Nonnull String createdAt) { + this.createdAt = createdAt; + } + + + public HistoryRow ver(@javax.annotation.Nonnull Long ver) { + this.ver = ver; + return this; + } + + /** + * Version of the row in Unix milliseconds. It increases every time the row is refined, for example when late network data re-scores it after the webhook was sent. + * @return ver + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_VER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Long getVer() { + return ver; + } + + + @JsonProperty(value = JSON_PROPERTY_VER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setVer(@javax.annotation.Nonnull Long ver) { + this.ver = ver; + } + + + public HistoryRow webRtcIp(@javax.annotation.Nonnull String webRtcIp) { + this.webRtcIp = webRtcIp; + return this; + } + + /** + * Local IP address observed by the ShieldLabs network check; `0.0.0.0` when none. + * @return webRtcIp + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_WEB_RTC_IP, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getWebRtcIp() { + return webRtcIp; + } + + + @JsonProperty(value = JSON_PROPERTY_WEB_RTC_IP, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setWebRtcIp(@javax.annotation.Nonnull String webRtcIp) { + this.webRtcIp = webRtcIp; + } + + + public HistoryRow webRtcCountry(@javax.annotation.Nonnull String webRtcCountry) { + this.webRtcCountry = webRtcCountry; + return this; + } + + /** + * Country of `web_rtc_ip`, or an empty string. + * @return webRtcCountry + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_WEB_RTC_COUNTRY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getWebRtcCountry() { + return webRtcCountry; + } + + + @JsonProperty(value = JSON_PROPERTY_WEB_RTC_COUNTRY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setWebRtcCountry(@javax.annotation.Nonnull String webRtcCountry) { + this.webRtcCountry = webRtcCountry; + } + + + public HistoryRow webRtcConnectionType(@javax.annotation.Nonnull String webRtcConnectionType) { + this.webRtcConnectionType = webRtcConnectionType; + return this; + } + + /** + * Connection class of `web_rtc_ip`, or an empty string. + * @return webRtcConnectionType + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_WEB_RTC_CONNECTION_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getWebRtcConnectionType() { + return webRtcConnectionType; + } + + + @JsonProperty(value = JSON_PROPERTY_WEB_RTC_CONNECTION_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setWebRtcConnectionType(@javax.annotation.Nonnull String webRtcConnectionType) { + this.webRtcConnectionType = webRtcConnectionType; + } + + + public HistoryRow webrtcLeakIp(@javax.annotation.Nonnull String webrtcLeakIp) { + this.webrtcLeakIp = webrtcLeakIp; + return this; + } + + /** + * Local network address leaked by the browser; `0.0.0.0` when none. + * @return webrtcLeakIp + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_WEBRTC_LEAK_IP, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getWebrtcLeakIp() { + return webrtcLeakIp; + } + + + @JsonProperty(value = JSON_PROPERTY_WEBRTC_LEAK_IP, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setWebrtcLeakIp(@javax.annotation.Nonnull String webrtcLeakIp) { + this.webrtcLeakIp = webrtcLeakIp; + } + + + public HistoryRow webrtcLeakCountry(@javax.annotation.Nonnull String webrtcLeakCountry) { + this.webrtcLeakCountry = webrtcLeakCountry; + return this; + } + + /** + * Country of `webrtc_leak_ip`, or an empty string. + * @return webrtcLeakCountry + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_WEBRTC_LEAK_COUNTRY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getWebrtcLeakCountry() { + return webrtcLeakCountry; + } + + + @JsonProperty(value = JSON_PROPERTY_WEBRTC_LEAK_COUNTRY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setWebrtcLeakCountry(@javax.annotation.Nonnull String webrtcLeakCountry) { + this.webrtcLeakCountry = webrtcLeakCountry; + } + + + public HistoryRow webrtcLeakConnectionType(@javax.annotation.Nonnull String webrtcLeakConnectionType) { + this.webrtcLeakConnectionType = webrtcLeakConnectionType; + return this; + } + + /** + * Connection class of `webrtc_leak_ip`, or an empty string. + * @return webrtcLeakConnectionType + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_WEBRTC_LEAK_CONNECTION_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getWebrtcLeakConnectionType() { + return webrtcLeakConnectionType; + } + + + @JsonProperty(value = JSON_PROPERTY_WEBRTC_LEAK_CONNECTION_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setWebrtcLeakConnectionType(@javax.annotation.Nonnull String webrtcLeakConnectionType) { + this.webrtcLeakConnectionType = webrtcLeakConnectionType; + } + + + public HistoryRow webrtcLeakSource(@javax.annotation.Nonnull String webrtcLeakSource) { + this.webrtcLeakSource = webrtcLeakSource; + return this; + } + + /** + * Which check found the local network leak. Known values: `scanner`, `shield`, `none` and the empty string. `none` or an empty string when there is no leak; the webhook `local_ip` then uses `web_rtc_ip`. The set is open: keep values added in later versions. + * @return webrtcLeakSource + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_WEBRTC_LEAK_SOURCE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getWebrtcLeakSource() { + return webrtcLeakSource; + } + + + @JsonProperty(value = JSON_PROPERTY_WEBRTC_LEAK_SOURCE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setWebrtcLeakSource(@javax.annotation.Nonnull String webrtcLeakSource) { + this.webrtcLeakSource = webrtcLeakSource; + } + + + public HistoryRow isVpn(@javax.annotation.Nonnull Boolean isVpn) { + this.isVpn = isVpn; + return this; + } + + /** + * Same meaning as `detection_flags.vpn`. + * @return isVpn + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IS_VPN, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIsVpn() { + return isVpn; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_VPN, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIsVpn(@javax.annotation.Nonnull Boolean isVpn) { + this.isVpn = isVpn; + } + + + public HistoryRow isTor(@javax.annotation.Nonnull Boolean isTor) { + this.isTor = isTor; + return this; + } + + /** + * Same meaning as `detection_flags.tor`. + * @return isTor + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IS_TOR, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIsTor() { + return isTor; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_TOR, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIsTor(@javax.annotation.Nonnull Boolean isTor) { + this.isTor = isTor; + } + + + public HistoryRow isProxy(@javax.annotation.Nonnull Boolean isProxy) { + this.isProxy = isProxy; + return this; + } + + /** + * Same meaning as `detection_flags.proxy`. + * @return isProxy + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IS_PROXY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIsProxy() { + return isProxy; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_PROXY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIsProxy(@javax.annotation.Nonnull Boolean isProxy) { + this.isProxy = isProxy; + } + + + public HistoryRow isDatacenter(@javax.annotation.Nonnull Boolean isDatacenter) { + this.isDatacenter = isDatacenter; + return this; + } + + /** + * Same meaning as `detection_flags.datacenter_ip`. + * @return isDatacenter + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IS_DATACENTER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIsDatacenter() { + return isDatacenter; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_DATACENTER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIsDatacenter(@javax.annotation.Nonnull Boolean isDatacenter) { + this.isDatacenter = isDatacenter; + } + + + public HistoryRow isAbuser(@javax.annotation.Nonnull Boolean isAbuser) { + this.isAbuser = isAbuser; + return this; + } + + /** + * Same meaning as `detection_flags.abuser`. + * @return isAbuser + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IS_ABUSER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIsAbuser() { + return isAbuser; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_ABUSER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIsAbuser(@javax.annotation.Nonnull Boolean isAbuser) { + this.isAbuser = isAbuser; + } + + + public HistoryRow isPrivacyRelay(@javax.annotation.Nonnull Boolean isPrivacyRelay) { + this.isPrivacyRelay = isPrivacyRelay; + return this; + } + + /** + * Same meaning as `detection_flags.privacy_relay`. + * @return isPrivacyRelay + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IS_PRIVACY_RELAY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIsPrivacyRelay() { + return isPrivacyRelay; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_PRIVACY_RELAY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIsPrivacyRelay(@javax.annotation.Nonnull Boolean isPrivacyRelay) { + this.isPrivacyRelay = isPrivacyRelay; + } + + + public HistoryRow isStunNotChecked(@javax.annotation.Nonnull Boolean isStunNotChecked) { + this.isStunNotChecked = isStunNotChecked; + return this; + } + + /** + * Same meaning as `detection_flags.stun_not_checked`. + * @return isStunNotChecked + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IS_STUN_NOT_CHECKED, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIsStunNotChecked() { + return isStunNotChecked; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_STUN_NOT_CHECKED, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIsStunNotChecked(@javax.annotation.Nonnull Boolean isStunNotChecked) { + this.isStunNotChecked = isStunNotChecked; + } + + + public HistoryRow checkIncomplete(@javax.annotation.Nonnull Boolean checkIncomplete) { + this.checkIncomplete = checkIncomplete; + return this; + } + + /** + * Same meaning as `detection_flags.check_incomplete`. Always `false` for search-engine crawlers. + * @return checkIncomplete + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_CHECK_INCOMPLETE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getCheckIncomplete() { + return checkIncomplete; + } + + + @JsonProperty(value = JSON_PROPERTY_CHECK_INCOMPLETE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCheckIncomplete(@javax.annotation.Nonnull Boolean checkIncomplete) { + this.checkIncomplete = checkIncomplete; + } + + + public HistoryRow isAntidetect(@javax.annotation.Nonnull Boolean isAntidetect) { + this.isAntidetect = isAntidetect; + return this; + } + + /** + * Same meaning as `detection_flags.anti_detect_browser`. + * @return isAntidetect + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IS_ANTIDETECT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIsAntidetect() { + return isAntidetect; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_ANTIDETECT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIsAntidetect(@javax.annotation.Nonnull Boolean isAntidetect) { + this.isAntidetect = isAntidetect; + } + + + public HistoryRow isOsMismatch(@javax.annotation.Nonnull Boolean isOsMismatch) { + this.isOsMismatch = isOsMismatch; + return this; + } + + /** + * Same meaning as `detection_flags.os_mismatch`. + * @return isOsMismatch + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IS_OS_MISMATCH, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIsOsMismatch() { + return isOsMismatch; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_OS_MISMATCH, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIsOsMismatch(@javax.annotation.Nonnull Boolean isOsMismatch) { + this.isOsMismatch = isOsMismatch; + } + + + public HistoryRow isOsNotDetected(@javax.annotation.Nonnull Boolean isOsNotDetected) { + this.isOsNotDetected = isOsNotDetected; + return this; + } + + /** + * Same meaning as `detection_flags.os_not_detected`. + * @return isOsNotDetected + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IS_OS_NOT_DETECTED, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIsOsNotDetected() { + return isOsNotDetected; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_OS_NOT_DETECTED, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIsOsNotDetected(@javax.annotation.Nonnull Boolean isOsNotDetected) { + this.isOsNotDetected = isOsNotDetected; + } + + + public HistoryRow isTimezoneMismatch(@javax.annotation.Nonnull Boolean isTimezoneMismatch) { + this.isTimezoneMismatch = isTimezoneMismatch; + return this; + } + + /** + * Same meaning as `detection_flags.timezone_mismatch`. + * @return isTimezoneMismatch + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IS_TIMEZONE_MISMATCH, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIsTimezoneMismatch() { + return isTimezoneMismatch; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_TIMEZONE_MISMATCH, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIsTimezoneMismatch(@javax.annotation.Nonnull Boolean isTimezoneMismatch) { + this.isTimezoneMismatch = isTimezoneMismatch; + } + + + public HistoryRow isJsDisabled(@javax.annotation.Nonnull Boolean isJsDisabled) { + this.isJsDisabled = isJsDisabled; + return this; + } + + /** + * Same meaning as `detection_flags.javascript_disabled`. Always `false` for search-engine crawlers. + * @return isJsDisabled + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IS_JS_DISABLED, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIsJsDisabled() { + return isJsDisabled; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_JS_DISABLED, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIsJsDisabled(@javax.annotation.Nonnull Boolean isJsDisabled) { + this.isJsDisabled = isJsDisabled; + } + + + public HistoryRow isBrowserAutomation(@javax.annotation.Nonnull Boolean isBrowserAutomation) { + this.isBrowserAutomation = isBrowserAutomation; + return this; + } + + /** + * Same meaning as `detection_flags.browser_automation`. + * @return isBrowserAutomation + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IS_BROWSER_AUTOMATION, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIsBrowserAutomation() { + return isBrowserAutomation; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_BROWSER_AUTOMATION, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIsBrowserAutomation(@javax.annotation.Nonnull Boolean isBrowserAutomation) { + this.isBrowserAutomation = isBrowserAutomation; + } + + + public HistoryRow isIncognito(@javax.annotation.Nonnull Boolean isIncognito) { + this.isIncognito = isIncognito; + return this; + } + + /** + * Same meaning as `detection_flags.incognito`. Always `false` for search-engine crawlers. + * @return isIncognito + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IS_INCOGNITO, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIsIncognito() { + return isIncognito; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_INCOGNITO, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIsIncognito(@javax.annotation.Nonnull Boolean isIncognito) { + this.isIncognito = isIncognito; + } + + + public HistoryRow isSearchBot(@javax.annotation.Nonnull Boolean isSearchBot) { + this.isSearchBot = isSearchBot; + return this; + } + + /** + * Same meaning as `detection_flags.search_bot`. + * @return isSearchBot + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IS_SEARCH_BOT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Boolean getIsSearchBot() { + return isSearchBot; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_SEARCH_BOT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIsSearchBot(@javax.annotation.Nonnull Boolean isSearchBot) { + this.isSearchBot = isSearchBot; + } + + + public HistoryRow isSuspiciousPaidClick(@javax.annotation.Nullable Boolean isSuspiciousPaidClick) { + this.isSuspiciousPaidClick = isSuspiciousPaidClick; + return this; + } + + /** + * Same meaning as `detection_flags.suspicious_paid_click`. Omitted when `false`. + * @return isSuspiciousPaidClick + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_IS_SUSPICIOUS_PAID_CLICK, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public Boolean getIsSuspiciousPaidClick() { + return isSuspiciousPaidClick; + } + + + @JsonProperty(value = JSON_PROPERTY_IS_SUSPICIOUS_PAID_CLICK, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setIsSuspiciousPaidClick(@javax.annotation.Nullable Boolean isSuspiciousPaidClick) { + this.isSuspiciousPaidClick = isSuspiciousPaidClick; + } + + + public HistoryRow entryUrl(@javax.annotation.Nullable String entryUrl) { + this.entryUrl = entryUrl; + return this; + } + + /** + * Landing page URL without the `#fragment` (webhook `traffic_source.landing_url`). Omitted when empty. It keeps the query string, which can contain personal data. + * @return entryUrl + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_ENTRY_URL, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public String getEntryUrl() { + return entryUrl; + } + + + @JsonProperty(value = JSON_PROPERTY_ENTRY_URL, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setEntryUrl(@javax.annotation.Nullable String entryUrl) { + this.entryUrl = entryUrl; + } + + + public HistoryRow utmSource(@javax.annotation.Nullable String utmSource) { + this.utmSource = utmSource; + return this; + } + + /** + * `utm_source`, lowercased. Omitted when empty. + * @return utmSource + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_UTM_SOURCE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public String getUtmSource() { + return utmSource; + } + + + @JsonProperty(value = JSON_PROPERTY_UTM_SOURCE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setUtmSource(@javax.annotation.Nullable String utmSource) { + this.utmSource = utmSource; + } + + + public HistoryRow utmMedium(@javax.annotation.Nullable String utmMedium) { + this.utmMedium = utmMedium; + return this; + } + + /** + * `utm_medium`, lowercased. Omitted when empty. + * @return utmMedium + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_UTM_MEDIUM, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public String getUtmMedium() { + return utmMedium; + } + + + @JsonProperty(value = JSON_PROPERTY_UTM_MEDIUM, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setUtmMedium(@javax.annotation.Nullable String utmMedium) { + this.utmMedium = utmMedium; + } + + + public HistoryRow utmCampaign(@javax.annotation.Nullable String utmCampaign) { + this.utmCampaign = utmCampaign; + return this; + } + + /** + * `utm_campaign` as sent. Omitted when empty. + * @return utmCampaign + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_UTM_CAMPAIGN, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public String getUtmCampaign() { + return utmCampaign; + } + + + @JsonProperty(value = JSON_PROPERTY_UTM_CAMPAIGN, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setUtmCampaign(@javax.annotation.Nullable String utmCampaign) { + this.utmCampaign = utmCampaign; + } + + + public HistoryRow utmContent(@javax.annotation.Nullable String utmContent) { + this.utmContent = utmContent; + return this; + } + + /** + * `utm_content` as sent. Omitted when empty. + * @return utmContent + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_UTM_CONTENT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public String getUtmContent() { + return utmContent; + } + + + @JsonProperty(value = JSON_PROPERTY_UTM_CONTENT, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setUtmContent(@javax.annotation.Nullable String utmContent) { + this.utmContent = utmContent; + } + + + public HistoryRow utmTerm(@javax.annotation.Nullable String utmTerm) { + this.utmTerm = utmTerm; + return this; + } + + /** + * `utm_term` as sent. Omitted when empty. + * @return utmTerm + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_UTM_TERM, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public String getUtmTerm() { + return utmTerm; + } + + + @JsonProperty(value = JSON_PROPERTY_UTM_TERM, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setUtmTerm(@javax.annotation.Nullable String utmTerm) { + this.utmTerm = utmTerm; + } + + + public HistoryRow trafficChannel(@javax.annotation.Nullable String trafficChannel) { + this.trafficChannel = trafficChannel; + return this; + } + + /** + * Marketing channel (webhook `traffic_source.channel`). Omitted when empty. + * @return trafficChannel + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TRAFFIC_CHANNEL, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public String getTrafficChannel() { + return trafficChannel; + } + + + @JsonProperty(value = JSON_PROPERTY_TRAFFIC_CHANNEL, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTrafficChannel(@javax.annotation.Nullable String trafficChannel) { + this.trafficChannel = trafficChannel; + } + + + public HistoryRow trafficChannelGroup(@javax.annotation.Nullable String trafficChannelGroup) { + this.trafficChannelGroup = trafficChannelGroup; + return this; + } + + /** + * Group of the marketing channel. Omitted when empty. + * @return trafficChannelGroup + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TRAFFIC_CHANNEL_GROUP, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public String getTrafficChannelGroup() { + return trafficChannelGroup; + } + + + @JsonProperty(value = JSON_PROPERTY_TRAFFIC_CHANNEL_GROUP, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTrafficChannelGroup(@javax.annotation.Nullable String trafficChannelGroup) { + this.trafficChannelGroup = trafficChannelGroup; + } + + + public HistoryRow trafficReason(@javax.annotation.Nullable String trafficReason) { + this.trafficReason = trafficReason; + return this; + } + + /** + * Why the channel was chosen. Omitted when empty. + * @return trafficReason + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_TRAFFIC_REASON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public String getTrafficReason() { + return trafficReason; + } + + + @JsonProperty(value = JSON_PROPERTY_TRAFFIC_REASON, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTrafficReason(@javax.annotation.Nullable String trafficReason) { + this.trafficReason = trafficReason; + } + + + public HistoryRow referrerDomain(@javax.annotation.Nullable String referrerDomain) { + this.referrerDomain = referrerDomain; + return this; + } + + /** + * Registrable domain of the referrer without `www.`; the crawler name (for example `GoogleBot`) for search-engine crawlers. Omitted when empty. + * @return referrerDomain + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_REFERRER_DOMAIN, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public String getReferrerDomain() { + return referrerDomain; + } + + + @JsonProperty(value = JSON_PROPERTY_REFERRER_DOMAIN, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setReferrerDomain(@javax.annotation.Nullable String referrerDomain) { + this.referrerDomain = referrerDomain; + } + + + public HistoryRow clickIdType(@javax.annotation.Nullable String clickIdType) { + this.clickIdType = clickIdType; + return this; + } + + /** + * Ad click identifier type found in the landing URL. Omitted when empty. + * @return clickIdType + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_CLICK_ID_TYPE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public String getClickIdType() { + return clickIdType; + } + + + @JsonProperty(value = JSON_PROPERTY_CLICK_ID_TYPE, required = false) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setClickIdType(@javax.annotation.Nullable String clickIdType) { + this.clickIdType = clickIdType; + } + + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + private Map additionalProperties; + + /** + * Set the additional (undeclared) property with the specified name and value. + * If the property does not already exist, create it otherwise replace it. + * @param key the name of the property + * @param value the value of the property + * @return self reference + */ + @JsonAnySetter + public HistoryRow putAdditionalProperty(String key, Object value) { + if (this.additionalProperties == null) { + this.additionalProperties = new HashMap(); + } + this.additionalProperties.put(key, value); + return this; + } + + /** + * Return the additional (undeclared) properties. + * @return the additional (undeclared) properties + */ + @JsonAnyGetter + public Map getAdditionalProperties() { + return additionalProperties; + } + + /** + * Return the additional (undeclared) property with the specified name. + * @param key the name of the property + * @return the additional (undeclared) property with the specified name + */ + public Object getAdditionalProperty(String key) { + if (this.additionalProperties == null) { + return null; + } + return this.additionalProperties.get(key); + } + + /** + * Return true if this HistoryRow object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + HistoryRow historyRow = (HistoryRow) o; + return Objects.equals(this.requestId, historyRow.requestId) && + Objects.equals(this.sessionId, historyRow.sessionId) && + Objects.equals(this.cookieId, historyRow.cookieId) && + Objects.equals(this.domain, historyRow.domain) && + Objects.equals(this.siteDomain, historyRow.siteDomain) && + Objects.equals(this.userHid, historyRow.userHid) && + Objects.equals(this.deviceId, historyRow.deviceId) && + Objects.equals(this.visitorId, historyRow.visitorId) && + Objects.equals(this.ip, historyRow.ip) && + Objects.equals(this.os, historyRow.os) && + Objects.equals(this.browser, historyRow.browser) && + Objects.equals(this.deviceType, historyRow.deviceType) && + Objects.equals(this.country, historyRow.country) && + Objects.equals(this.connectionType, historyRow.connectionType) && + Objects.equals(this.score, historyRow.score) && + Objects.equals(this.scoreDetails, historyRow.scoreDetails) && + Objects.equals(this.createdAt, historyRow.createdAt) && + Objects.equals(this.ver, historyRow.ver) && + Objects.equals(this.webRtcIp, historyRow.webRtcIp) && + Objects.equals(this.webRtcCountry, historyRow.webRtcCountry) && + Objects.equals(this.webRtcConnectionType, historyRow.webRtcConnectionType) && + Objects.equals(this.webrtcLeakIp, historyRow.webrtcLeakIp) && + Objects.equals(this.webrtcLeakCountry, historyRow.webrtcLeakCountry) && + Objects.equals(this.webrtcLeakConnectionType, historyRow.webrtcLeakConnectionType) && + Objects.equals(this.webrtcLeakSource, historyRow.webrtcLeakSource) && + Objects.equals(this.isVpn, historyRow.isVpn) && + Objects.equals(this.isTor, historyRow.isTor) && + Objects.equals(this.isProxy, historyRow.isProxy) && + Objects.equals(this.isDatacenter, historyRow.isDatacenter) && + Objects.equals(this.isAbuser, historyRow.isAbuser) && + Objects.equals(this.isPrivacyRelay, historyRow.isPrivacyRelay) && + Objects.equals(this.isStunNotChecked, historyRow.isStunNotChecked) && + Objects.equals(this.checkIncomplete, historyRow.checkIncomplete) && + Objects.equals(this.isAntidetect, historyRow.isAntidetect) && + Objects.equals(this.isOsMismatch, historyRow.isOsMismatch) && + Objects.equals(this.isOsNotDetected, historyRow.isOsNotDetected) && + Objects.equals(this.isTimezoneMismatch, historyRow.isTimezoneMismatch) && + Objects.equals(this.isJsDisabled, historyRow.isJsDisabled) && + Objects.equals(this.isBrowserAutomation, historyRow.isBrowserAutomation) && + Objects.equals(this.isIncognito, historyRow.isIncognito) && + Objects.equals(this.isSearchBot, historyRow.isSearchBot) && + Objects.equals(this.isSuspiciousPaidClick, historyRow.isSuspiciousPaidClick) && + Objects.equals(this.entryUrl, historyRow.entryUrl) && + Objects.equals(this.utmSource, historyRow.utmSource) && + Objects.equals(this.utmMedium, historyRow.utmMedium) && + Objects.equals(this.utmCampaign, historyRow.utmCampaign) && + Objects.equals(this.utmContent, historyRow.utmContent) && + Objects.equals(this.utmTerm, historyRow.utmTerm) && + Objects.equals(this.trafficChannel, historyRow.trafficChannel) && + Objects.equals(this.trafficChannelGroup, historyRow.trafficChannelGroup) && + Objects.equals(this.trafficReason, historyRow.trafficReason) && + Objects.equals(this.referrerDomain, historyRow.referrerDomain) && + Objects.equals(this.clickIdType, historyRow.clickIdType)&& + Objects.equals(this.additionalProperties, historyRow.additionalProperties); + } + + @Override + public int hashCode() { + return Objects.hash(requestId, sessionId, cookieId, domain, siteDomain, userHid, deviceId, visitorId, ip, os, browser, deviceType, country, connectionType, score, scoreDetails, createdAt, ver, webRtcIp, webRtcCountry, webRtcConnectionType, webrtcLeakIp, webrtcLeakCountry, webrtcLeakConnectionType, webrtcLeakSource, isVpn, isTor, isProxy, isDatacenter, isAbuser, isPrivacyRelay, isStunNotChecked, checkIncomplete, isAntidetect, isOsMismatch, isOsNotDetected, isTimezoneMismatch, isJsDisabled, isBrowserAutomation, isIncognito, isSearchBot, isSuspiciousPaidClick, entryUrl, utmSource, utmMedium, utmCampaign, utmContent, utmTerm, trafficChannel, trafficChannelGroup, trafficReason, referrerDomain, clickIdType, additionalProperties); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class HistoryRow {\n"); + sb.append(" requestId: ").append(toIndentedString(requestId)).append("\n"); + sb.append(" sessionId: ").append(toIndentedString(sessionId)).append("\n"); + sb.append(" cookieId: ").append(toIndentedString(cookieId)).append("\n"); + sb.append(" domain: ").append(toIndentedString(domain)).append("\n"); + sb.append(" siteDomain: ").append(toIndentedString(siteDomain)).append("\n"); + sb.append(" userHid: ").append(toIndentedString(userHid)).append("\n"); + sb.append(" deviceId: ").append(toIndentedString(deviceId)).append("\n"); + sb.append(" visitorId: ").append(toIndentedString(visitorId)).append("\n"); + sb.append(" ip: ").append(toIndentedString(ip)).append("\n"); + sb.append(" os: ").append(toIndentedString(os)).append("\n"); + sb.append(" browser: ").append(toIndentedString(browser)).append("\n"); + sb.append(" deviceType: ").append(toIndentedString(deviceType)).append("\n"); + sb.append(" country: ").append(toIndentedString(country)).append("\n"); + sb.append(" connectionType: ").append(toIndentedString(connectionType)).append("\n"); + sb.append(" score: ").append(toIndentedString(score)).append("\n"); + sb.append(" scoreDetails: ").append(toIndentedString(scoreDetails)).append("\n"); + sb.append(" createdAt: ").append(toIndentedString(createdAt)).append("\n"); + sb.append(" ver: ").append(toIndentedString(ver)).append("\n"); + sb.append(" webRtcIp: ").append(toIndentedString(webRtcIp)).append("\n"); + sb.append(" webRtcCountry: ").append(toIndentedString(webRtcCountry)).append("\n"); + sb.append(" webRtcConnectionType: ").append(toIndentedString(webRtcConnectionType)).append("\n"); + sb.append(" webrtcLeakIp: ").append(toIndentedString(webrtcLeakIp)).append("\n"); + sb.append(" webrtcLeakCountry: ").append(toIndentedString(webrtcLeakCountry)).append("\n"); + sb.append(" webrtcLeakConnectionType: ").append(toIndentedString(webrtcLeakConnectionType)).append("\n"); + sb.append(" webrtcLeakSource: ").append(toIndentedString(webrtcLeakSource)).append("\n"); + sb.append(" isVpn: ").append(toIndentedString(isVpn)).append("\n"); + sb.append(" isTor: ").append(toIndentedString(isTor)).append("\n"); + sb.append(" isProxy: ").append(toIndentedString(isProxy)).append("\n"); + sb.append(" isDatacenter: ").append(toIndentedString(isDatacenter)).append("\n"); + sb.append(" isAbuser: ").append(toIndentedString(isAbuser)).append("\n"); + sb.append(" isPrivacyRelay: ").append(toIndentedString(isPrivacyRelay)).append("\n"); + sb.append(" isStunNotChecked: ").append(toIndentedString(isStunNotChecked)).append("\n"); + sb.append(" checkIncomplete: ").append(toIndentedString(checkIncomplete)).append("\n"); + sb.append(" isAntidetect: ").append(toIndentedString(isAntidetect)).append("\n"); + sb.append(" isOsMismatch: ").append(toIndentedString(isOsMismatch)).append("\n"); + sb.append(" isOsNotDetected: ").append(toIndentedString(isOsNotDetected)).append("\n"); + sb.append(" isTimezoneMismatch: ").append(toIndentedString(isTimezoneMismatch)).append("\n"); + sb.append(" isJsDisabled: ").append(toIndentedString(isJsDisabled)).append("\n"); + sb.append(" isBrowserAutomation: ").append(toIndentedString(isBrowserAutomation)).append("\n"); + sb.append(" isIncognito: ").append(toIndentedString(isIncognito)).append("\n"); + sb.append(" isSearchBot: ").append(toIndentedString(isSearchBot)).append("\n"); + sb.append(" isSuspiciousPaidClick: ").append(toIndentedString(isSuspiciousPaidClick)).append("\n"); + sb.append(" entryUrl: ").append(toIndentedString(entryUrl)).append("\n"); + sb.append(" utmSource: ").append(toIndentedString(utmSource)).append("\n"); + sb.append(" utmMedium: ").append(toIndentedString(utmMedium)).append("\n"); + sb.append(" utmCampaign: ").append(toIndentedString(utmCampaign)).append("\n"); + sb.append(" utmContent: ").append(toIndentedString(utmContent)).append("\n"); + sb.append(" utmTerm: ").append(toIndentedString(utmTerm)).append("\n"); + sb.append(" trafficChannel: ").append(toIndentedString(trafficChannel)).append("\n"); + sb.append(" trafficChannelGroup: ").append(toIndentedString(trafficChannelGroup)).append("\n"); + sb.append(" trafficReason: ").append(toIndentedString(trafficReason)).append("\n"); + sb.append(" referrerDomain: ").append(toIndentedString(referrerDomain)).append("\n"); + sb.append(" clickIdType: ").append(toIndentedString(clickIdType)).append("\n"); + sb.append(" additionalProperties: ").append(toIndentedString(additionalProperties)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `request_id` to the URL query string + if (getRequestId() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%srequest_id%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getRequestId())))); + } + + // add `session_id` to the URL query string + if (getSessionId() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%ssession_id%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getSessionId())))); + } + + // add `cookie_id` to the URL query string + if (getCookieId() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%scookie_id%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getCookieId())))); + } + + // add `domain` to the URL query string + if (getDomain() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sdomain%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getDomain())))); + } + + // add `site_domain` to the URL query string + if (getSiteDomain() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%ssite_domain%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getSiteDomain())))); + } + + // add `user_hid` to the URL query string + if (getUserHid() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%suser_hid%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getUserHid())))); + } + + // add `device_id` to the URL query string + if (getDeviceId() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sdevice_id%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getDeviceId())))); + } + + // add `visitor_id` to the URL query string + if (getVisitorId() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%svisitor_id%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getVisitorId())))); + } + + // add `ip` to the URL query string + if (getIp() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sip%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIp())))); + } + + // add `os` to the URL query string + if (getOs() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sos%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getOs())))); + } + + // add `browser` to the URL query string + if (getBrowser() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sbrowser%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getBrowser())))); + } + + // add `device_type` to the URL query string + if (getDeviceType() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sdevice_type%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getDeviceType())))); + } + + // add `country` to the URL query string + if (getCountry() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%scountry%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getCountry())))); + } + + // add `connection_type` to the URL query string + if (getConnectionType() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sconnection_type%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getConnectionType())))); + } + + // add `score` to the URL query string + if (getScore() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sscore%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getScore())))); + } + + // add `score_details` to the URL query string + if (getScoreDetails() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sscore_details%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getScoreDetails())))); + } + + // add `created_at` to the URL query string + if (getCreatedAt() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%screated_at%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getCreatedAt())))); + } + + // add `ver` to the URL query string + if (getVer() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sver%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getVer())))); + } + + // add `web_rtc_ip` to the URL query string + if (getWebRtcIp() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sweb_rtc_ip%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getWebRtcIp())))); + } + + // add `web_rtc_country` to the URL query string + if (getWebRtcCountry() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sweb_rtc_country%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getWebRtcCountry())))); + } + + // add `web_rtc_connection_type` to the URL query string + if (getWebRtcConnectionType() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sweb_rtc_connection_type%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getWebRtcConnectionType())))); + } + + // add `webrtc_leak_ip` to the URL query string + if (getWebrtcLeakIp() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%swebrtc_leak_ip%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getWebrtcLeakIp())))); + } + + // add `webrtc_leak_country` to the URL query string + if (getWebrtcLeakCountry() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%swebrtc_leak_country%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getWebrtcLeakCountry())))); + } + + // add `webrtc_leak_connection_type` to the URL query string + if (getWebrtcLeakConnectionType() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%swebrtc_leak_connection_type%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getWebrtcLeakConnectionType())))); + } + + // add `webrtc_leak_source` to the URL query string + if (getWebrtcLeakSource() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%swebrtc_leak_source%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getWebrtcLeakSource())))); + } + + // add `is_vpn` to the URL query string + if (getIsVpn() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_vpn%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsVpn())))); + } + + // add `is_tor` to the URL query string + if (getIsTor() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_tor%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsTor())))); + } + + // add `is_proxy` to the URL query string + if (getIsProxy() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_proxy%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsProxy())))); + } + + // add `is_datacenter` to the URL query string + if (getIsDatacenter() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_datacenter%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsDatacenter())))); + } + + // add `is_abuser` to the URL query string + if (getIsAbuser() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_abuser%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsAbuser())))); + } + + // add `is_privacy_relay` to the URL query string + if (getIsPrivacyRelay() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_privacy_relay%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsPrivacyRelay())))); + } + + // add `is_stun_not_checked` to the URL query string + if (getIsStunNotChecked() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_stun_not_checked%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsStunNotChecked())))); + } + + // add `check_incomplete` to the URL query string + if (getCheckIncomplete() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%scheck_incomplete%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getCheckIncomplete())))); + } + + // add `is_antidetect` to the URL query string + if (getIsAntidetect() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_antidetect%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsAntidetect())))); + } + + // add `is_os_mismatch` to the URL query string + if (getIsOsMismatch() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_os_mismatch%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsOsMismatch())))); + } + + // add `is_os_not_detected` to the URL query string + if (getIsOsNotDetected() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_os_not_detected%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsOsNotDetected())))); + } + + // add `is_timezone_mismatch` to the URL query string + if (getIsTimezoneMismatch() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_timezone_mismatch%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsTimezoneMismatch())))); + } + + // add `is_js_disabled` to the URL query string + if (getIsJsDisabled() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_js_disabled%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsJsDisabled())))); + } + + // add `is_browser_automation` to the URL query string + if (getIsBrowserAutomation() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_browser_automation%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsBrowserAutomation())))); + } + + // add `is_incognito` to the URL query string + if (getIsIncognito() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_incognito%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsIncognito())))); + } + + // add `is_search_bot` to the URL query string + if (getIsSearchBot() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_search_bot%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsSearchBot())))); + } + + // add `is_suspicious_paid_click` to the URL query string + if (getIsSuspiciousPaidClick() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sis_suspicious_paid_click%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIsSuspiciousPaidClick())))); + } + + // add `entry_url` to the URL query string + if (getEntryUrl() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sentry_url%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getEntryUrl())))); + } + + // add `utm_source` to the URL query string + if (getUtmSource() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sutm_source%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getUtmSource())))); + } + + // add `utm_medium` to the URL query string + if (getUtmMedium() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sutm_medium%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getUtmMedium())))); + } + + // add `utm_campaign` to the URL query string + if (getUtmCampaign() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sutm_campaign%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getUtmCampaign())))); + } + + // add `utm_content` to the URL query string + if (getUtmContent() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sutm_content%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getUtmContent())))); + } + + // add `utm_term` to the URL query string + if (getUtmTerm() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sutm_term%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getUtmTerm())))); + } + + // add `traffic_channel` to the URL query string + if (getTrafficChannel() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%straffic_channel%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getTrafficChannel())))); + } + + // add `traffic_channel_group` to the URL query string + if (getTrafficChannelGroup() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%straffic_channel_group%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getTrafficChannelGroup())))); + } + + // add `traffic_reason` to the URL query string + if (getTrafficReason() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%straffic_reason%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getTrafficReason())))); + } + + // add `referrer_domain` to the URL query string + if (getReferrerDomain() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sreferrer_domain%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getReferrerDomain())))); + } + + // add `click_id_type` to the URL query string + if (getClickIdType() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sclick_id_type%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getClickIdType())))); + } + + return joiner.toString(); + } +} + diff --git a/generated/src/main/java/ai/shieldlabs/generated/model/IdentificationScoredData.java b/generated/src/main/java/ai/shieldlabs/generated/model/IdentificationScoredData.java new file mode 100644 index 0000000..dccd976 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/model/IdentificationScoredData.java @@ -0,0 +1,782 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated.model; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.StringJoiner; +import java.util.Objects; +import java.util.Map; +import java.util.HashMap; +import ai.shieldlabs.generated.model.DetectionFlags; +import ai.shieldlabs.generated.model.IpInfo; +import ai.shieldlabs.generated.model.Signal; +import ai.shieldlabs.generated.model.TrafficSource; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +import ai.shieldlabs.generated.ApiClient; +/** + * The scored identification. Every key is always present (no key is ever omitted); only `user_hid` can be `null`. + */ +@JsonPropertyOrder({ + IdentificationScoredData.JSON_PROPERTY_REQUEST_ID, + IdentificationScoredData.JSON_PROPERTY_VISITOR_ID, + IdentificationScoredData.JSON_PROPERTY_DEVICE_ID, + IdentificationScoredData.JSON_PROPERTY_SESSION_ID, + IdentificationScoredData.JSON_PROPERTY_COOKIE_ID, + IdentificationScoredData.JSON_PROPERTY_USER_HID, + IdentificationScoredData.JSON_PROPERTY_DOMAIN, + IdentificationScoredData.JSON_PROPERTY_PUBLIC_IP, + IdentificationScoredData.JSON_PROPERTY_LOCAL_IP, + IdentificationScoredData.JSON_PROPERTY_CONNECTION_TYPE, + IdentificationScoredData.JSON_PROPERTY_OS, + IdentificationScoredData.JSON_PROPERTY_BROWSER, + IdentificationScoredData.JSON_PROPERTY_DEVICE_TYPE, + IdentificationScoredData.JSON_PROPERTY_TRAFFIC_SOURCE, + IdentificationScoredData.JSON_PROPERTY_RISK_SCORE, + IdentificationScoredData.JSON_PROPERTY_SIGNALS, + IdentificationScoredData.JSON_PROPERTY_DETECTION_FLAGS, + IdentificationScoredData.JSON_PROPERTY_OBSERVED_AT +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class IdentificationScoredData { + public static final String JSON_PROPERTY_REQUEST_ID = "request_id"; + @javax.annotation.Nonnull + private UUID requestId; + + public static final String JSON_PROPERTY_VISITOR_ID = "visitor_id"; + @javax.annotation.Nonnull + private UUID visitorId; + + public static final String JSON_PROPERTY_DEVICE_ID = "device_id"; + @javax.annotation.Nonnull + private UUID deviceId; + + public static final String JSON_PROPERTY_SESSION_ID = "session_id"; + @javax.annotation.Nonnull + private UUID sessionId; + + public static final String JSON_PROPERTY_COOKIE_ID = "cookie_id"; + @javax.annotation.Nonnull + private UUID cookieId; + + public static final String JSON_PROPERTY_USER_HID = "user_hid"; + @javax.annotation.Nullable + private String userHid; + + public static final String JSON_PROPERTY_DOMAIN = "domain"; + @javax.annotation.Nonnull + private String domain; + + public static final String JSON_PROPERTY_PUBLIC_IP = "public_ip"; + @javax.annotation.Nonnull + private IpInfo publicIp; + + public static final String JSON_PROPERTY_LOCAL_IP = "local_ip"; + @javax.annotation.Nonnull + private IpInfo localIp; + + public static final String JSON_PROPERTY_CONNECTION_TYPE = "connection_type"; + @javax.annotation.Nonnull + private String connectionType; + + public static final String JSON_PROPERTY_OS = "os"; + @javax.annotation.Nonnull + private String os; + + public static final String JSON_PROPERTY_BROWSER = "browser"; + @javax.annotation.Nonnull + private String browser; + + public static final String JSON_PROPERTY_DEVICE_TYPE = "device_type"; + @javax.annotation.Nonnull + private String deviceType; + + public static final String JSON_PROPERTY_TRAFFIC_SOURCE = "traffic_source"; + @javax.annotation.Nonnull + private TrafficSource trafficSource; + + public static final String JSON_PROPERTY_RISK_SCORE = "risk_score"; + @javax.annotation.Nonnull + private Integer riskScore; + + public static final String JSON_PROPERTY_SIGNALS = "signals"; + @javax.annotation.Nonnull + private List signals = new ArrayList<>(); + + public static final String JSON_PROPERTY_DETECTION_FLAGS = "detection_flags"; + @javax.annotation.Nonnull + private DetectionFlags detectionFlags; + + public static final String JSON_PROPERTY_OBSERVED_AT = "observed_at"; + @javax.annotation.Nonnull + private OffsetDateTime observedAt; + + public IdentificationScoredData() { + } + + public IdentificationScoredData requestId(@javax.annotation.Nonnull UUID requestId) { + this.requestId = requestId; + return this; + } + + /** + * Identifies one identification. The browser creates it as a UUID v4 and hands it to your page; it is the join key between the browser, the webhook and the History API. The nil UUID appears only on rate-limit marker rows that arrived with a malformed request ID. + * @return requestId + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_REQUEST_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public UUID getRequestId() { + return requestId; + } + + + @JsonProperty(value = JSON_PROPERTY_REQUEST_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setRequestId(@javax.annotation.Nonnull UUID requestId) { + this.requestId = requestId; + } + + + public IdentificationScoredData visitorId(@javax.annotation.Nonnull UUID visitorId) { + this.visitorId = visitorId; + return this; + } + + /** + * Server-side visitor identifier (UUID v5). It is sticky to the device: a new cookie on a known device keeps the existing visitor ID, so clearing cookies usually does not change it. The nil UUID appears on identifications without usable device data, such as rate-limit marker rows. + * @return visitorId + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_VISITOR_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public UUID getVisitorId() { + return visitorId; + } + + + @JsonProperty(value = JSON_PROPERTY_VISITOR_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setVisitorId(@javax.annotation.Nonnull UUID visitorId) { + this.visitorId = visitorId; + } + + + public IdentificationScoredData deviceId(@javax.annotation.Nonnull UUID deviceId) { + this.deviceId = deviceId; + return this; + } + + /** + * Server-side device identifier (UUID v5). It survives cleared cookies and private windows. The nil UUID `00000000-0000-0000-0000-000000000000` means that no usable device signals were collected (for example on rate-limit marker rows): never group identifications by it. + * @return deviceId + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_DEVICE_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public UUID getDeviceId() { + return deviceId; + } + + + @JsonProperty(value = JSON_PROPERTY_DEVICE_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDeviceId(@javax.annotation.Nonnull UUID deviceId) { + this.deviceId = deviceId; + } + + + public IdentificationScoredData sessionId(@javax.annotation.Nonnull UUID sessionId) { + this.sessionId = sessionId; + return this; + } + + /** + * One visit on one origin (UUID v4 created in the browser), shared by the open tabs of that origin. The next visit after the last tab closes gets a new session ID. The nil UUID appears on rate-limit marker rows. + * @return sessionId + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SESSION_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public UUID getSessionId() { + return sessionId; + } + + + @JsonProperty(value = JSON_PROPERTY_SESSION_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setSessionId(@javax.annotation.Nonnull UUID sessionId) { + this.sessionId = sessionId; + } + + + public IdentificationScoredData cookieId(@javax.annotation.Nonnull UUID cookieId) { + this.cookieId = cookieId; + return this; + } + + /** + * First-party browser identifier kept by the ShieldLabs agent (UUID v4). A missing or malformed value is stored as the nil UUID. + * @return cookieId + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_COOKIE_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public UUID getCookieId() { + return cookieId; + } + + + @JsonProperty(value = JSON_PROPERTY_COOKIE_ID, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCookieId(@javax.annotation.Nonnull UUID cookieId) { + this.cookieId = cookieId; + } + + + public IdentificationScoredData userHid(@javax.annotation.Nullable String userHid) { + this.userHid = userHid; + return this; + } + + /** + * User HID: your hashed or pseudonymous account identifier, exactly as it was passed to the ShieldLabs agent. Pass a hashed value, never a raw email address or database ID. Values that do not identify a user: - `anonymous`: an anonymous check; - `fail`: the agent sent no value; - `-1` and `unknown`: rows created by ShieldLabs itself, such as rate-limit marker rows. `null` only when the stored value is an empty string. Leave `null` and the values above out when you count the accounts of one device, visitor or IP address. + * @return userHid + */ + @javax.annotation.Nullable + @JsonProperty(value = JSON_PROPERTY_USER_HID, required = false) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getUserHid() { + return userHid; + } + + + @JsonProperty(value = JSON_PROPERTY_USER_HID, required = false) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setUserHid(@javax.annotation.Nullable String userHid) { + this.userHid = userHid; + } + + + public IdentificationScoredData domain(@javax.annotation.Nonnull String domain) { + this.domain = domain; + return this; + } + + /** + * Registered domain of your site (the request host when no registered domain matched). + * @return domain + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_DOMAIN, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getDomain() { + return domain; + } + + + @JsonProperty(value = JSON_PROPERTY_DOMAIN, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDomain(@javax.annotation.Nonnull String domain) { + this.domain = domain; + } + + + public IdentificationScoredData publicIp(@javax.annotation.Nonnull IpInfo publicIp) { + this.publicIp = publicIp; + return this; + } + + /** + * Public IPv4 address of the HTTP request and its country. `ip` is empty when the request did not arrive over IPv4. + * @return publicIp + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_PUBLIC_IP, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public IpInfo getPublicIp() { + return publicIp; + } + + + @JsonProperty(value = JSON_PROPERTY_PUBLIC_IP, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setPublicIp(@javax.annotation.Nonnull IpInfo publicIp) { + this.publicIp = publicIp; + } + + + public IdentificationScoredData localIp(@javax.annotation.Nonnull IpInfo localIp) { + this.localIp = localIp; + return this; + } + + /** + * Local IP address found by the browser network check (WebRTC): the leaked address when a local network leak was found, otherwise the address ShieldLabs observed. Both keys are empty when the check found nothing. + * @return localIp + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_LOCAL_IP, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public IpInfo getLocalIp() { + return localIp; + } + + + @JsonProperty(value = JSON_PROPERTY_LOCAL_IP, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setLocalIp(@javax.annotation.Nonnull IpInfo localIp) { + this.localIp = localIp; + } + + + public IdentificationScoredData connectionType(@javax.annotation.Nonnull String connectionType) { + this.connectionType = connectionType; + return this; + } + + /** + * How the visitor connected. Known values: - `direct`: a regular connection; - `mobile`: a mobile carrier network; - `vpn`: a VPN; - `proxy`: a proxy, datacenter or hosting network (search-engine crawlers are reported here too); - `tor`: the Tor network; - `privacy_relay`: a privacy relay such as iCloud Private Relay; - `browser_vpn_proxy`: a VPN or proxy built into the browser or one of its extensions; - `unknown`: not enough data. The value can say `vpn` while `detection_flags.vpn` is `false` (IP intelligence classified the network, but the scored VPN check did not fire). Branch on `detection_flags` for decisions. The set is open: keep values added in later versions and treat them as `unknown`. + * @return connectionType + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_CONNECTION_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getConnectionType() { + return connectionType; + } + + + @JsonProperty(value = JSON_PROPERTY_CONNECTION_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setConnectionType(@javax.annotation.Nonnull String connectionType) { + this.connectionType = connectionType; + } + + + public IdentificationScoredData os(@javax.annotation.Nonnull String os) { + this.os = os; + return this; + } + + /** + * Operating system name, for example `Windows`, `Mac OS X`, `Linux`, `Android`, `IOS (iPhone)`, `IOS (iPad)`, `ChromeOS` or `Unknown`. Open set: display it, do not branch on it. + * @return os + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_OS, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getOs() { + return os; + } + + + @JsonProperty(value = JSON_PROPERTY_OS, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setOs(@javax.annotation.Nonnull String os) { + this.os = os; + } + + + public IdentificationScoredData browser(@javax.annotation.Nonnull String browser) { + this.browser = browser; + return this; + } + + /** + * Browser name, for example `Chrome`, `Safari`, `Firefox`, `Microsoft Edge`, `Opera`, `Samsung Internet`, `Brave`, `Chrome (iOS)`, `Safari (iOS)` or `Unknown`. Open set: display it, do not branch on it. + * @return browser + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_BROWSER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getBrowser() { + return browser; + } + + + @JsonProperty(value = JSON_PROPERTY_BROWSER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setBrowser(@javax.annotation.Nonnull String browser) { + this.browser = browser; + } + + + public IdentificationScoredData deviceType(@javax.annotation.Nonnull String deviceType) { + this.deviceType = deviceType; + return this; + } + + /** + * Device class from the browser. Known values: `desktop`, `mobile`, `tablet` and `unknown` (the class could not be determined). The set is open: keep values added in later versions and treat them as `unknown`. + * @return deviceType + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_DEVICE_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getDeviceType() { + return deviceType; + } + + + @JsonProperty(value = JSON_PROPERTY_DEVICE_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDeviceType(@javax.annotation.Nonnull String deviceType) { + this.deviceType = deviceType; + } + + + public IdentificationScoredData trafficSource(@javax.annotation.Nonnull TrafficSource trafficSource) { + this.trafficSource = trafficSource; + return this; + } + + /** + * Get trafficSource + * @return trafficSource + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_TRAFFIC_SOURCE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public TrafficSource getTrafficSource() { + return trafficSource; + } + + + @JsonProperty(value = JSON_PROPERTY_TRAFFIC_SOURCE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setTrafficSource(@javax.annotation.Nonnull TrafficSource trafficSource) { + this.trafficSource = trafficSource; + } + + + public IdentificationScoredData riskScore(@javax.annotation.Nonnull Integer riskScore) { + this.riskScore = riskScore; + return this; + } + + /** + * Risk Score from 0 (no risk found) to 100. Search-engine crawlers always score 0. Risk bands are computed on your side from the score; no band field exists on the wire: - trusted: 0-29 - suspicious: 30-59 - dangerous: 60-100 A value above 100 is not a score. `999` is the rate-limit marker: the visitor's IP went over the ingest rate limit, and the identification carries exactly one signal, `{\"name\":\"rate_limited\",\"weight\":999}`, usually with nil identifiers. Treat every value above 100 as rate limited. One marker is written when the IP goes over the limit; request IDs issued while it stays blocked get no row and no webhook, so they stay unverified. The score usually equals the sum of the signal weights capped at 100, but carried-forward verdicts and corrections make that unreliable: never recompute or validate it yourself. + * minimum: 0 + * @return riskScore + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_RISK_SCORE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Integer getRiskScore() { + return riskScore; + } + + + @JsonProperty(value = JSON_PROPERTY_RISK_SCORE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setRiskScore(@javax.annotation.Nonnull Integer riskScore) { + this.riskScore = riskScore; + } + + + public IdentificationScoredData signals(@javax.annotation.Nonnull List signals) { + this.signals = signals; + return this; + } + + public IdentificationScoredData addSignalsItem(Signal signalsItem) { + if (this.signals == null) { + this.signals = new ArrayList<>(); + } + this.signals.add(signalsItem); + return this; + } + + /** + * Weighted risk signals behind `risk_score`, in scoring order. Can be empty. The rate-limit marker carries exactly one entry, `{\"name\":\"rate_limited\",\"weight\":999}`. + * @return signals + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SIGNALS, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public List getSignals() { + return signals; + } + + + @JsonProperty(value = JSON_PROPERTY_SIGNALS, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setSignals(@javax.annotation.Nonnull List signals) { + this.signals = signals; + } + + + public IdentificationScoredData detectionFlags(@javax.annotation.Nonnull DetectionFlags detectionFlags) { + this.detectionFlags = detectionFlags; + return this; + } + + /** + * Get detectionFlags + * @return detectionFlags + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_DETECTION_FLAGS, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public DetectionFlags getDetectionFlags() { + return detectionFlags; + } + + + @JsonProperty(value = JSON_PROPERTY_DETECTION_FLAGS, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDetectionFlags(@javax.annotation.Nonnull DetectionFlags detectionFlags) { + this.detectionFlags = detectionFlags; + } + + + public IdentificationScoredData observedAt(@javax.annotation.Nonnull OffsetDateTime observedAt) { + this.observedAt = observedAt; + return this; + } + + /** + * When scoring finished and the event was built (not the page view time); identical to the envelope `created_at`. RFC 3339 in UTC with up to 9 fractional digits. + * @return observedAt + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_OBSERVED_AT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public OffsetDateTime getObservedAt() { + return observedAt; + } + + + @JsonProperty(value = JSON_PROPERTY_OBSERVED_AT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setObservedAt(@javax.annotation.Nonnull OffsetDateTime observedAt) { + this.observedAt = observedAt; + } + + + /** + * Return true if this IdentificationScoredData object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + IdentificationScoredData identificationScoredData = (IdentificationScoredData) o; + return Objects.equals(this.requestId, identificationScoredData.requestId) && + Objects.equals(this.visitorId, identificationScoredData.visitorId) && + Objects.equals(this.deviceId, identificationScoredData.deviceId) && + Objects.equals(this.sessionId, identificationScoredData.sessionId) && + Objects.equals(this.cookieId, identificationScoredData.cookieId) && + Objects.equals(this.userHid, identificationScoredData.userHid) && + Objects.equals(this.domain, identificationScoredData.domain) && + Objects.equals(this.publicIp, identificationScoredData.publicIp) && + Objects.equals(this.localIp, identificationScoredData.localIp) && + Objects.equals(this.connectionType, identificationScoredData.connectionType) && + Objects.equals(this.os, identificationScoredData.os) && + Objects.equals(this.browser, identificationScoredData.browser) && + Objects.equals(this.deviceType, identificationScoredData.deviceType) && + Objects.equals(this.trafficSource, identificationScoredData.trafficSource) && + Objects.equals(this.riskScore, identificationScoredData.riskScore) && + Objects.equals(this.signals, identificationScoredData.signals) && + Objects.equals(this.detectionFlags, identificationScoredData.detectionFlags) && + Objects.equals(this.observedAt, identificationScoredData.observedAt); + } + + @Override + public int hashCode() { + return Objects.hash(requestId, visitorId, deviceId, sessionId, cookieId, userHid, domain, publicIp, localIp, connectionType, os, browser, deviceType, trafficSource, riskScore, signals, detectionFlags, observedAt); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class IdentificationScoredData {\n"); + sb.append(" requestId: ").append(toIndentedString(requestId)).append("\n"); + sb.append(" visitorId: ").append(toIndentedString(visitorId)).append("\n"); + sb.append(" deviceId: ").append(toIndentedString(deviceId)).append("\n"); + sb.append(" sessionId: ").append(toIndentedString(sessionId)).append("\n"); + sb.append(" cookieId: ").append(toIndentedString(cookieId)).append("\n"); + sb.append(" userHid: ").append(toIndentedString(userHid)).append("\n"); + sb.append(" domain: ").append(toIndentedString(domain)).append("\n"); + sb.append(" publicIp: ").append(toIndentedString(publicIp)).append("\n"); + sb.append(" localIp: ").append(toIndentedString(localIp)).append("\n"); + sb.append(" connectionType: ").append(toIndentedString(connectionType)).append("\n"); + sb.append(" os: ").append(toIndentedString(os)).append("\n"); + sb.append(" browser: ").append(toIndentedString(browser)).append("\n"); + sb.append(" deviceType: ").append(toIndentedString(deviceType)).append("\n"); + sb.append(" trafficSource: ").append(toIndentedString(trafficSource)).append("\n"); + sb.append(" riskScore: ").append(toIndentedString(riskScore)).append("\n"); + sb.append(" signals: ").append(toIndentedString(signals)).append("\n"); + sb.append(" detectionFlags: ").append(toIndentedString(detectionFlags)).append("\n"); + sb.append(" observedAt: ").append(toIndentedString(observedAt)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `request_id` to the URL query string + if (getRequestId() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%srequest_id%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getRequestId())))); + } + + // add `visitor_id` to the URL query string + if (getVisitorId() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%svisitor_id%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getVisitorId())))); + } + + // add `device_id` to the URL query string + if (getDeviceId() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sdevice_id%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getDeviceId())))); + } + + // add `session_id` to the URL query string + if (getSessionId() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%ssession_id%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getSessionId())))); + } + + // add `cookie_id` to the URL query string + if (getCookieId() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%scookie_id%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getCookieId())))); + } + + // add `user_hid` to the URL query string + if (getUserHid() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%suser_hid%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getUserHid())))); + } + + // add `domain` to the URL query string + if (getDomain() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sdomain%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getDomain())))); + } + + // add `public_ip` to the URL query string + if (getPublicIp() != null) { + joiner.add(getPublicIp().toUrlQueryString(prefix + "public_ip" + suffix)); + } + + // add `local_ip` to the URL query string + if (getLocalIp() != null) { + joiner.add(getLocalIp().toUrlQueryString(prefix + "local_ip" + suffix)); + } + + // add `connection_type` to the URL query string + if (getConnectionType() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sconnection_type%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getConnectionType())))); + } + + // add `os` to the URL query string + if (getOs() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sos%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getOs())))); + } + + // add `browser` to the URL query string + if (getBrowser() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sbrowser%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getBrowser())))); + } + + // add `device_type` to the URL query string + if (getDeviceType() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sdevice_type%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getDeviceType())))); + } + + // add `traffic_source` to the URL query string + if (getTrafficSource() != null) { + joiner.add(getTrafficSource().toUrlQueryString(prefix + "traffic_source" + suffix)); + } + + // add `risk_score` to the URL query string + if (getRiskScore() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%srisk_score%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getRiskScore())))); + } + + // add `signals` to the URL query string + if (getSignals() != null) { + for (int i = 0; i < getSignals().size(); i++) { + if (getSignals().get(i) != null) { + joiner.add(getSignals().get(i).toUrlQueryString(String.format(java.util.Locale.ROOT, "%ssignals%s%s", prefix, suffix, + "".equals(suffix) ? "" : String.format(java.util.Locale.ROOT, "%s%d%s", containerPrefix, i, containerSuffix)))); + } + } + } + + // add `detection_flags` to the URL query string + if (getDetectionFlags() != null) { + joiner.add(getDetectionFlags().toUrlQueryString(prefix + "detection_flags" + suffix)); + } + + // add `observed_at` to the URL query string + if (getObservedAt() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sobserved_at%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getObservedAt())))); + } + + return joiner.toString(); + } +} + diff --git a/generated/src/main/java/ai/shieldlabs/generated/model/IdentificationScoredEvent.java b/generated/src/main/java/ai/shieldlabs/generated/model/IdentificationScoredEvent.java new file mode 100644 index 0000000..63b94de --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/model/IdentificationScoredEvent.java @@ -0,0 +1,291 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated.model; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.StringJoiner; +import java.util.Objects; +import java.util.Map; +import java.util.HashMap; +import ai.shieldlabs.generated.model.IdentificationScoredData; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.time.OffsetDateTime; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +import ai.shieldlabs.generated.ApiClient; +/** + * Body of an `identification.scored` delivery. The signature is not part of the body: it arrives in the `X-Shield-Signature` header. + */ +@JsonPropertyOrder({ + IdentificationScoredEvent.JSON_PROPERTY_EVENT_TYPE, + IdentificationScoredEvent.JSON_PROPERTY_SCHEMA_VERSION, + IdentificationScoredEvent.JSON_PROPERTY_CREATED_AT, + IdentificationScoredEvent.JSON_PROPERTY_DATA +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class IdentificationScoredEvent { + /** + * Event type. Ignore events whose type you do not know instead of failing. + */ + public enum EventTypeEnum { + IDENTIFICATION_SCORED(String.valueOf("identification.scored")); + + private String value; + + EventTypeEnum(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static EventTypeEnum fromValue(String value) { + for (EventTypeEnum b : EventTypeEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + } + + public static final String JSON_PROPERTY_EVENT_TYPE = "event_type"; + @javax.annotation.Nonnull + private EventTypeEnum eventType; + + public static final String JSON_PROPERTY_SCHEMA_VERSION = "schema_version"; + @javax.annotation.Nonnull + private String schemaVersion; + + public static final String JSON_PROPERTY_CREATED_AT = "created_at"; + @javax.annotation.Nonnull + private OffsetDateTime createdAt; + + public static final String JSON_PROPERTY_DATA = "data"; + @javax.annotation.Nonnull + private IdentificationScoredData data; + + public IdentificationScoredEvent() { + } + + public IdentificationScoredEvent eventType(@javax.annotation.Nonnull EventTypeEnum eventType) { + this.eventType = eventType; + return this; + } + + /** + * Event type. Ignore events whose type you do not know instead of failing. + * @return eventType + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_EVENT_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public EventTypeEnum getEventType() { + return eventType; + } + + + @JsonProperty(value = JSON_PROPERTY_EVENT_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setEventType(@javax.annotation.Nonnull EventTypeEnum eventType) { + this.eventType = eventType; + } + + + public IdentificationScoredEvent schemaVersion(@javax.annotation.Nonnull String schemaVersion) { + this.schemaVersion = schemaVersion; + return this; + } + + /** + * Version of the webhook payload contract. Every event sent today carries `2026-06-01`. Accept other values, so that a future version does not break your handler. + * @return schemaVersion + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SCHEMA_VERSION, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getSchemaVersion() { + return schemaVersion; + } + + + @JsonProperty(value = JSON_PROPERTY_SCHEMA_VERSION, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setSchemaVersion(@javax.annotation.Nonnull String schemaVersion) { + this.schemaVersion = schemaVersion; + } + + + public IdentificationScoredEvent createdAt(@javax.annotation.Nonnull OffsetDateTime createdAt) { + this.createdAt = createdAt; + return this; + } + + /** + * When the event was built. Equal to `data.observed_at`. + * @return createdAt + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_CREATED_AT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public OffsetDateTime getCreatedAt() { + return createdAt; + } + + + @JsonProperty(value = JSON_PROPERTY_CREATED_AT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCreatedAt(@javax.annotation.Nonnull OffsetDateTime createdAt) { + this.createdAt = createdAt; + } + + + public IdentificationScoredEvent data(@javax.annotation.Nonnull IdentificationScoredData data) { + this.data = data; + return this; + } + + /** + * Get data + * @return data + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_DATA, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public IdentificationScoredData getData() { + return data; + } + + + @JsonProperty(value = JSON_PROPERTY_DATA, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setData(@javax.annotation.Nonnull IdentificationScoredData data) { + this.data = data; + } + + + /** + * Return true if this IdentificationScoredEvent object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + IdentificationScoredEvent identificationScoredEvent = (IdentificationScoredEvent) o; + return Objects.equals(this.eventType, identificationScoredEvent.eventType) && + Objects.equals(this.schemaVersion, identificationScoredEvent.schemaVersion) && + Objects.equals(this.createdAt, identificationScoredEvent.createdAt) && + Objects.equals(this.data, identificationScoredEvent.data); + } + + @Override + public int hashCode() { + return Objects.hash(eventType, schemaVersion, createdAt, data); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class IdentificationScoredEvent {\n"); + sb.append(" eventType: ").append(toIndentedString(eventType)).append("\n"); + sb.append(" schemaVersion: ").append(toIndentedString(schemaVersion)).append("\n"); + sb.append(" createdAt: ").append(toIndentedString(createdAt)).append("\n"); + sb.append(" data: ").append(toIndentedString(data)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `event_type` to the URL query string + if (getEventType() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sevent_type%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getEventType())))); + } + + // add `schema_version` to the URL query string + if (getSchemaVersion() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sschema_version%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getSchemaVersion())))); + } + + // add `created_at` to the URL query string + if (getCreatedAt() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%screated_at%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getCreatedAt())))); + } + + // add `data` to the URL query string + if (getData() != null) { + joiner.add(getData().toUrlQueryString(prefix + "data" + suffix)); + } + + return joiner.toString(); + } +} + diff --git a/generated/src/main/java/ai/shieldlabs/generated/model/IpInfo.java b/generated/src/main/java/ai/shieldlabs/generated/model/IpInfo.java new file mode 100644 index 0000000..177422a --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/model/IpInfo.java @@ -0,0 +1,184 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated.model; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.StringJoiner; +import java.util.Objects; +import java.util.Map; +import java.util.HashMap; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +import ai.shieldlabs.generated.ApiClient; +/** + * An IPv4 address and its country. Both keys are always present and can be empty strings. + */ +@JsonPropertyOrder({ + IpInfo.JSON_PROPERTY_IP, + IpInfo.JSON_PROPERTY_COUNTRY +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class IpInfo { + public static final String JSON_PROPERTY_IP = "ip"; + @javax.annotation.Nonnull + private String ip; + + public static final String JSON_PROPERTY_COUNTRY = "country"; + @javax.annotation.Nonnull + private String country; + + public IpInfo() { + } + + public IpInfo ip(@javax.annotation.Nonnull String ip) { + this.ip = ip; + return this; + } + + /** + * Dotted IPv4 address, or an empty string when no IPv4 address is known (for example for visitors on IPv6). + * @return ip + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_IP, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getIp() { + return ip; + } + + + @JsonProperty(value = JSON_PROPERTY_IP, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIp(@javax.annotation.Nonnull String ip) { + this.ip = ip; + } + + + public IpInfo country(@javax.annotation.Nonnull String country) { + this.country = country; + return this; + } + + /** + * English country name from IP intelligence, for example `Germany` or `United States` (not an ISO code). Empty string when the country is unknown. + * @return country + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_COUNTRY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getCountry() { + return country; + } + + + @JsonProperty(value = JSON_PROPERTY_COUNTRY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCountry(@javax.annotation.Nonnull String country) { + this.country = country; + } + + + /** + * Return true if this IpInfo object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + IpInfo ipInfo = (IpInfo) o; + return Objects.equals(this.ip, ipInfo.ip) && + Objects.equals(this.country, ipInfo.country); + } + + @Override + public int hashCode() { + return Objects.hash(ip, country); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class IpInfo {\n"); + sb.append(" ip: ").append(toIndentedString(ip)).append("\n"); + sb.append(" country: ").append(toIndentedString(country)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `ip` to the URL query string + if (getIp() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sip%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIp())))); + } + + // add `country` to the URL query string + if (getCountry() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%scountry%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getCountry())))); + } + + return joiner.toString(); + } +} + diff --git a/generated/src/main/java/ai/shieldlabs/generated/model/LegacySnapshot.java b/generated/src/main/java/ai/shieldlabs/generated/model/LegacySnapshot.java new file mode 100644 index 0000000..935c675 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/model/LegacySnapshot.java @@ -0,0 +1,828 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated.model; + +import java.util.Map; +import java.util.HashMap; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.StringJoiner; +import java.util.Objects; +import java.util.Map; +import java.util.HashMap; +import ai.shieldlabs.generated.model.ScoreDetail; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +import ai.shieldlabs.generated.ApiClient; +/** + * One identification as returned by the deprecated Management API history endpoint (PascalCase keys). Also carries diagnostic network fields that are not part of the stable contract. Use the History API row instead. + */ +@JsonPropertyOrder({ + LegacySnapshot.JSON_PROPERTY_REQUEST_I_D, + LegacySnapshot.JSON_PROPERTY_SESSION_I_D, + LegacySnapshot.JSON_PROPERTY_COOKIE_I_D, + LegacySnapshot.JSON_PROPERTY_DEVICE_I_D, + LegacySnapshot.JSON_PROPERTY_VISITOR_I_D, + LegacySnapshot.JSON_PROPERTY_I_P, + LegacySnapshot.JSON_PROPERTY_CONNECTION_TYPE, + LegacySnapshot.JSON_PROPERTY_WEB_RTC_H_I_P, + LegacySnapshot.JSON_PROPERTY_WEB_RTC_COUNTRY, + LegacySnapshot.JSON_PROPERTY_WEB_RTC_CONNECTION_TYPE, + LegacySnapshot.JSON_PROPERTY_O_S, + LegacySnapshot.JSON_PROPERTY_BROWSER, + LegacySnapshot.JSON_PROPERTY_DEVICE_TYPE, + LegacySnapshot.JSON_PROPERTY_COUNTRY, + LegacySnapshot.JSON_PROPERTY_USER_H_I_D, + LegacySnapshot.JSON_PROPERTY_SCORE, + LegacySnapshot.JSON_PROPERTY_DETAILS, + LegacySnapshot.JSON_PROPERTY_LAST_REQUEST_TIME +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class LegacySnapshot { + public static final String JSON_PROPERTY_REQUEST_I_D = "RequestID"; + @javax.annotation.Nonnull + private UUID requestID; + + public static final String JSON_PROPERTY_SESSION_I_D = "SessionID"; + @javax.annotation.Nonnull + private UUID sessionID; + + public static final String JSON_PROPERTY_COOKIE_I_D = "CookieID"; + @javax.annotation.Nonnull + private UUID cookieID; + + public static final String JSON_PROPERTY_DEVICE_I_D = "DeviceID"; + @javax.annotation.Nonnull + private UUID deviceID; + + public static final String JSON_PROPERTY_VISITOR_I_D = "VisitorID"; + @javax.annotation.Nonnull + private UUID visitorID; + + public static final String JSON_PROPERTY_I_P = "IP"; + @javax.annotation.Nonnull + private String IP; + + public static final String JSON_PROPERTY_CONNECTION_TYPE = "ConnectionType"; + @javax.annotation.Nonnull + private String connectionType; + + public static final String JSON_PROPERTY_WEB_RTC_H_I_P = "WebRtcHIP"; + @javax.annotation.Nonnull + private String webRtcHIP; + + public static final String JSON_PROPERTY_WEB_RTC_COUNTRY = "WebRtcCountry"; + @javax.annotation.Nonnull + private String webRtcCountry; + + public static final String JSON_PROPERTY_WEB_RTC_CONNECTION_TYPE = "WebRtcConnectionType"; + @javax.annotation.Nonnull + private String webRtcConnectionType; + + public static final String JSON_PROPERTY_O_S = "OS"; + @javax.annotation.Nonnull + private String OS; + + public static final String JSON_PROPERTY_BROWSER = "Browser"; + @javax.annotation.Nonnull + private String browser; + + public static final String JSON_PROPERTY_DEVICE_TYPE = "DeviceType"; + @javax.annotation.Nonnull + private String deviceType; + + public static final String JSON_PROPERTY_COUNTRY = "Country"; + @javax.annotation.Nonnull + private String country; + + public static final String JSON_PROPERTY_USER_H_I_D = "UserHID"; + @javax.annotation.Nonnull + private String userHID; + + public static final String JSON_PROPERTY_SCORE = "Score"; + @javax.annotation.Nonnull + private Integer score; + + public static final String JSON_PROPERTY_DETAILS = "Details"; + @javax.annotation.Nonnull + private List details = new ArrayList<>(); + + public static final String JSON_PROPERTY_LAST_REQUEST_TIME = "LastRequestTime"; + @javax.annotation.Nonnull + private OffsetDateTime lastRequestTime; + + public LegacySnapshot() { + } + + public LegacySnapshot requestID(@javax.annotation.Nonnull UUID requestID) { + this.requestID = requestID; + return this; + } + + /** + * Identifies one identification. The browser creates it as a UUID v4 and hands it to your page; it is the join key between the browser, the webhook and the History API. The nil UUID appears only on rate-limit marker rows that arrived with a malformed request ID. + * @return requestID + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_REQUEST_I_D, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public UUID getRequestID() { + return requestID; + } + + + @JsonProperty(value = JSON_PROPERTY_REQUEST_I_D, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setRequestID(@javax.annotation.Nonnull UUID requestID) { + this.requestID = requestID; + } + + + public LegacySnapshot sessionID(@javax.annotation.Nonnull UUID sessionID) { + this.sessionID = sessionID; + return this; + } + + /** + * One visit on one origin (UUID v4 created in the browser), shared by the open tabs of that origin. The next visit after the last tab closes gets a new session ID. The nil UUID appears on rate-limit marker rows. + * @return sessionID + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SESSION_I_D, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public UUID getSessionID() { + return sessionID; + } + + + @JsonProperty(value = JSON_PROPERTY_SESSION_I_D, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setSessionID(@javax.annotation.Nonnull UUID sessionID) { + this.sessionID = sessionID; + } + + + public LegacySnapshot cookieID(@javax.annotation.Nonnull UUID cookieID) { + this.cookieID = cookieID; + return this; + } + + /** + * First-party browser identifier kept by the ShieldLabs agent (UUID v4). A missing or malformed value is stored as the nil UUID. + * @return cookieID + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_COOKIE_I_D, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public UUID getCookieID() { + return cookieID; + } + + + @JsonProperty(value = JSON_PROPERTY_COOKIE_I_D, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCookieID(@javax.annotation.Nonnull UUID cookieID) { + this.cookieID = cookieID; + } + + + public LegacySnapshot deviceID(@javax.annotation.Nonnull UUID deviceID) { + this.deviceID = deviceID; + return this; + } + + /** + * Server-side device identifier (UUID v5). It survives cleared cookies and private windows. The nil UUID `00000000-0000-0000-0000-000000000000` means that no usable device signals were collected (for example on rate-limit marker rows): never group identifications by it. + * @return deviceID + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_DEVICE_I_D, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public UUID getDeviceID() { + return deviceID; + } + + + @JsonProperty(value = JSON_PROPERTY_DEVICE_I_D, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDeviceID(@javax.annotation.Nonnull UUID deviceID) { + this.deviceID = deviceID; + } + + + public LegacySnapshot visitorID(@javax.annotation.Nonnull UUID visitorID) { + this.visitorID = visitorID; + return this; + } + + /** + * Server-side visitor identifier (UUID v5). It is sticky to the device: a new cookie on a known device keeps the existing visitor ID, so clearing cookies usually does not change it. The nil UUID appears on identifications without usable device data, such as rate-limit marker rows. + * @return visitorID + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_VISITOR_I_D, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public UUID getVisitorID() { + return visitorID; + } + + + @JsonProperty(value = JSON_PROPERTY_VISITOR_I_D, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setVisitorID(@javax.annotation.Nonnull UUID visitorID) { + this.visitorID = visitorID; + } + + + public LegacySnapshot IP(@javax.annotation.Nonnull String IP) { + this.IP = IP; + return this; + } + + /** + * Public IPv4 address of the HTTP request. + * @return IP + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_I_P, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getIP() { + return IP; + } + + + @JsonProperty(value = JSON_PROPERTY_I_P, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setIP(@javax.annotation.Nonnull String IP) { + this.IP = IP; + } + + + public LegacySnapshot connectionType(@javax.annotation.Nonnull String connectionType) { + this.connectionType = connectionType; + return this; + } + + /** + * How the visitor connected. Known values: - `direct`: a regular connection; - `mobile`: a mobile carrier network; - `vpn`: a VPN; - `proxy`: a proxy, datacenter or hosting network (search-engine crawlers are reported here too); - `tor`: the Tor network; - `privacy_relay`: a privacy relay such as iCloud Private Relay; - `browser_vpn_proxy`: a VPN or proxy built into the browser or one of its extensions; - `unknown`: not enough data. The value can say `vpn` while `detection_flags.vpn` is `false` (IP intelligence classified the network, but the scored VPN check did not fire). Branch on `detection_flags` for decisions. The set is open: keep values added in later versions and treat them as `unknown`. + * @return connectionType + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_CONNECTION_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getConnectionType() { + return connectionType; + } + + + @JsonProperty(value = JSON_PROPERTY_CONNECTION_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setConnectionType(@javax.annotation.Nonnull String connectionType) { + this.connectionType = connectionType; + } + + + public LegacySnapshot webRtcHIP(@javax.annotation.Nonnull String webRtcHIP) { + this.webRtcHIP = webRtcHIP; + return this; + } + + /** + * Local IP address observed by the ShieldLabs network check (not hashed); `0.0.0.0` when none. + * @return webRtcHIP + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_WEB_RTC_H_I_P, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getWebRtcHIP() { + return webRtcHIP; + } + + + @JsonProperty(value = JSON_PROPERTY_WEB_RTC_H_I_P, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setWebRtcHIP(@javax.annotation.Nonnull String webRtcHIP) { + this.webRtcHIP = webRtcHIP; + } + + + public LegacySnapshot webRtcCountry(@javax.annotation.Nonnull String webRtcCountry) { + this.webRtcCountry = webRtcCountry; + return this; + } + + /** + * Country of `WebRtcHIP`, or an empty string. + * @return webRtcCountry + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_WEB_RTC_COUNTRY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getWebRtcCountry() { + return webRtcCountry; + } + + + @JsonProperty(value = JSON_PROPERTY_WEB_RTC_COUNTRY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setWebRtcCountry(@javax.annotation.Nonnull String webRtcCountry) { + this.webRtcCountry = webRtcCountry; + } + + + public LegacySnapshot webRtcConnectionType(@javax.annotation.Nonnull String webRtcConnectionType) { + this.webRtcConnectionType = webRtcConnectionType; + return this; + } + + /** + * Connection class of `WebRtcHIP`, or an empty string. + * @return webRtcConnectionType + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_WEB_RTC_CONNECTION_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getWebRtcConnectionType() { + return webRtcConnectionType; + } + + + @JsonProperty(value = JSON_PROPERTY_WEB_RTC_CONNECTION_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setWebRtcConnectionType(@javax.annotation.Nonnull String webRtcConnectionType) { + this.webRtcConnectionType = webRtcConnectionType; + } + + + public LegacySnapshot OS(@javax.annotation.Nonnull String OS) { + this.OS = OS; + return this; + } + + /** + * Operating system name, for example `Windows`, `Mac OS X`, `Linux`, `Android`, `IOS (iPhone)`, `IOS (iPad)`, `ChromeOS` or `Unknown`. Open set: display it, do not branch on it. + * @return OS + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_O_S, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getOS() { + return OS; + } + + + @JsonProperty(value = JSON_PROPERTY_O_S, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setOS(@javax.annotation.Nonnull String OS) { + this.OS = OS; + } + + + public LegacySnapshot browser(@javax.annotation.Nonnull String browser) { + this.browser = browser; + return this; + } + + /** + * Browser name, for example `Chrome`, `Safari`, `Firefox`, `Microsoft Edge`, `Opera`, `Samsung Internet`, `Brave`, `Chrome (iOS)`, `Safari (iOS)` or `Unknown`. Open set: display it, do not branch on it. + * @return browser + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_BROWSER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getBrowser() { + return browser; + } + + + @JsonProperty(value = JSON_PROPERTY_BROWSER, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setBrowser(@javax.annotation.Nonnull String browser) { + this.browser = browser; + } + + + public LegacySnapshot deviceType(@javax.annotation.Nonnull String deviceType) { + this.deviceType = deviceType; + return this; + } + + /** + * Device class from the browser. Known values: `desktop`, `mobile`, `tablet` and `unknown` (the class could not be determined). The set is open: keep values added in later versions and treat them as `unknown`. + * @return deviceType + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_DEVICE_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getDeviceType() { + return deviceType; + } + + + @JsonProperty(value = JSON_PROPERTY_DEVICE_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDeviceType(@javax.annotation.Nonnull String deviceType) { + this.deviceType = deviceType; + } + + + public LegacySnapshot country(@javax.annotation.Nonnull String country) { + this.country = country; + return this; + } + + /** + * Country of `IP` as an English country name, or an empty string. + * @return country + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_COUNTRY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getCountry() { + return country; + } + + + @JsonProperty(value = JSON_PROPERTY_COUNTRY, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCountry(@javax.annotation.Nonnull String country) { + this.country = country; + } + + + public LegacySnapshot userHID(@javax.annotation.Nonnull String userHID) { + this.userHID = userHID; + return this; + } + + /** + * User HID as passed to the agent; `anonymous` for anonymous checks. + * @return userHID + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_USER_H_I_D, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getUserHID() { + return userHID; + } + + + @JsonProperty(value = JSON_PROPERTY_USER_H_I_D, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setUserHID(@javax.annotation.Nonnull String userHID) { + this.userHID = userHID; + } + + + public LegacySnapshot score(@javax.annotation.Nonnull Integer score) { + this.score = score; + return this; + } + + /** + * Risk Score from 0 (no risk found) to 100. Search-engine crawlers always score 0. Risk bands are computed on your side from the score; no band field exists on the wire: - trusted: 0-29 - suspicious: 30-59 - dangerous: 60-100 A value above 100 is not a score. `999` is the rate-limit marker: the visitor's IP went over the ingest rate limit, and the identification carries exactly one signal, `{\"name\":\"rate_limited\",\"weight\":999}`, usually with nil identifiers. Treat every value above 100 as rate limited. One marker is written when the IP goes over the limit; request IDs issued while it stays blocked get no row and no webhook, so they stay unverified. The score usually equals the sum of the signal weights capped at 100, but carried-forward verdicts and corrections make that unreliable: never recompute or validate it yourself. + * minimum: 0 + * @return score + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SCORE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Integer getScore() { + return score; + } + + + @JsonProperty(value = JSON_PROPERTY_SCORE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setScore(@javax.annotation.Nonnull Integer score) { + this.score = score; + } + + + public LegacySnapshot details(@javax.annotation.Nonnull List details) { + this.details = details; + return this; + } + + public LegacySnapshot addDetailsItem(ScoreDetail detailsItem) { + if (this.details == null) { + this.details = new ArrayList<>(); + } + this.details.add(detailsItem); + return this; + } + + /** + * Every entry behind `Score`, informational entries with `Value` 0 included (unlike the History API, this is a parsed array, not a string). + * @return details + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_DETAILS, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public List getDetails() { + return details; + } + + + @JsonProperty(value = JSON_PROPERTY_DETAILS, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDetails(@javax.annotation.Nonnull List details) { + this.details = details; + } + + + public LegacySnapshot lastRequestTime(@javax.annotation.Nonnull OffsetDateTime lastRequestTime) { + this.lastRequestTime = lastRequestTime; + return this; + } + + /** + * Time of the identification, RFC 3339 with fractional seconds. + * @return lastRequestTime + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_LAST_REQUEST_TIME, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public OffsetDateTime getLastRequestTime() { + return lastRequestTime; + } + + + @JsonProperty(value = JSON_PROPERTY_LAST_REQUEST_TIME, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setLastRequestTime(@javax.annotation.Nonnull OffsetDateTime lastRequestTime) { + this.lastRequestTime = lastRequestTime; + } + + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + private Map additionalProperties; + + /** + * Set the additional (undeclared) property with the specified name and value. + * If the property does not already exist, create it otherwise replace it. + * @param key the name of the property + * @param value the value of the property + * @return self reference + */ + @JsonAnySetter + public LegacySnapshot putAdditionalProperty(String key, Object value) { + if (this.additionalProperties == null) { + this.additionalProperties = new HashMap(); + } + this.additionalProperties.put(key, value); + return this; + } + + /** + * Return the additional (undeclared) properties. + * @return the additional (undeclared) properties + */ + @JsonAnyGetter + public Map getAdditionalProperties() { + return additionalProperties; + } + + /** + * Return the additional (undeclared) property with the specified name. + * @param key the name of the property + * @return the additional (undeclared) property with the specified name + */ + public Object getAdditionalProperty(String key) { + if (this.additionalProperties == null) { + return null; + } + return this.additionalProperties.get(key); + } + + /** + * Return true if this LegacySnapshot object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + LegacySnapshot legacySnapshot = (LegacySnapshot) o; + return Objects.equals(this.requestID, legacySnapshot.requestID) && + Objects.equals(this.sessionID, legacySnapshot.sessionID) && + Objects.equals(this.cookieID, legacySnapshot.cookieID) && + Objects.equals(this.deviceID, legacySnapshot.deviceID) && + Objects.equals(this.visitorID, legacySnapshot.visitorID) && + Objects.equals(this.IP, legacySnapshot.IP) && + Objects.equals(this.connectionType, legacySnapshot.connectionType) && + Objects.equals(this.webRtcHIP, legacySnapshot.webRtcHIP) && + Objects.equals(this.webRtcCountry, legacySnapshot.webRtcCountry) && + Objects.equals(this.webRtcConnectionType, legacySnapshot.webRtcConnectionType) && + Objects.equals(this.OS, legacySnapshot.OS) && + Objects.equals(this.browser, legacySnapshot.browser) && + Objects.equals(this.deviceType, legacySnapshot.deviceType) && + Objects.equals(this.country, legacySnapshot.country) && + Objects.equals(this.userHID, legacySnapshot.userHID) && + Objects.equals(this.score, legacySnapshot.score) && + Objects.equals(this.details, legacySnapshot.details) && + Objects.equals(this.lastRequestTime, legacySnapshot.lastRequestTime)&& + Objects.equals(this.additionalProperties, legacySnapshot.additionalProperties); + } + + @Override + public int hashCode() { + return Objects.hash(requestID, sessionID, cookieID, deviceID, visitorID, IP, connectionType, webRtcHIP, webRtcCountry, webRtcConnectionType, OS, browser, deviceType, country, userHID, score, details, lastRequestTime, additionalProperties); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class LegacySnapshot {\n"); + sb.append(" requestID: ").append(toIndentedString(requestID)).append("\n"); + sb.append(" sessionID: ").append(toIndentedString(sessionID)).append("\n"); + sb.append(" cookieID: ").append(toIndentedString(cookieID)).append("\n"); + sb.append(" deviceID: ").append(toIndentedString(deviceID)).append("\n"); + sb.append(" visitorID: ").append(toIndentedString(visitorID)).append("\n"); + sb.append(" IP: ").append(toIndentedString(IP)).append("\n"); + sb.append(" connectionType: ").append(toIndentedString(connectionType)).append("\n"); + sb.append(" webRtcHIP: ").append(toIndentedString(webRtcHIP)).append("\n"); + sb.append(" webRtcCountry: ").append(toIndentedString(webRtcCountry)).append("\n"); + sb.append(" webRtcConnectionType: ").append(toIndentedString(webRtcConnectionType)).append("\n"); + sb.append(" OS: ").append(toIndentedString(OS)).append("\n"); + sb.append(" browser: ").append(toIndentedString(browser)).append("\n"); + sb.append(" deviceType: ").append(toIndentedString(deviceType)).append("\n"); + sb.append(" country: ").append(toIndentedString(country)).append("\n"); + sb.append(" userHID: ").append(toIndentedString(userHID)).append("\n"); + sb.append(" score: ").append(toIndentedString(score)).append("\n"); + sb.append(" details: ").append(toIndentedString(details)).append("\n"); + sb.append(" lastRequestTime: ").append(toIndentedString(lastRequestTime)).append("\n"); + sb.append(" additionalProperties: ").append(toIndentedString(additionalProperties)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `RequestID` to the URL query string + if (getRequestID() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sRequestID%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getRequestID())))); + } + + // add `SessionID` to the URL query string + if (getSessionID() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sSessionID%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getSessionID())))); + } + + // add `CookieID` to the URL query string + if (getCookieID() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sCookieID%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getCookieID())))); + } + + // add `DeviceID` to the URL query string + if (getDeviceID() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sDeviceID%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getDeviceID())))); + } + + // add `VisitorID` to the URL query string + if (getVisitorID() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sVisitorID%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getVisitorID())))); + } + + // add `IP` to the URL query string + if (getIP() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sIP%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getIP())))); + } + + // add `ConnectionType` to the URL query string + if (getConnectionType() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sConnectionType%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getConnectionType())))); + } + + // add `WebRtcHIP` to the URL query string + if (getWebRtcHIP() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sWebRtcHIP%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getWebRtcHIP())))); + } + + // add `WebRtcCountry` to the URL query string + if (getWebRtcCountry() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sWebRtcCountry%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getWebRtcCountry())))); + } + + // add `WebRtcConnectionType` to the URL query string + if (getWebRtcConnectionType() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sWebRtcConnectionType%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getWebRtcConnectionType())))); + } + + // add `OS` to the URL query string + if (getOS() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sOS%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getOS())))); + } + + // add `Browser` to the URL query string + if (getBrowser() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sBrowser%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getBrowser())))); + } + + // add `DeviceType` to the URL query string + if (getDeviceType() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sDeviceType%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getDeviceType())))); + } + + // add `Country` to the URL query string + if (getCountry() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sCountry%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getCountry())))); + } + + // add `UserHID` to the URL query string + if (getUserHID() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sUserHID%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getUserHID())))); + } + + // add `Score` to the URL query string + if (getScore() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sScore%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getScore())))); + } + + // add `Details` to the URL query string + if (getDetails() != null) { + for (int i = 0; i < getDetails().size(); i++) { + if (getDetails().get(i) != null) { + joiner.add(getDetails().get(i).toUrlQueryString(String.format(java.util.Locale.ROOT, "%sDetails%s%s", prefix, suffix, + "".equals(suffix) ? "" : String.format(java.util.Locale.ROOT, "%s%d%s", containerPrefix, i, containerSuffix)))); + } + } + } + + // add `LastRequestTime` to the URL query string + if (getLastRequestTime() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sLastRequestTime%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getLastRequestTime())))); + } + + return joiner.toString(); + } +} + diff --git a/generated/src/main/java/ai/shieldlabs/generated/model/ScoreDetail.java b/generated/src/main/java/ai/shieldlabs/generated/model/ScoreDetail.java new file mode 100644 index 0000000..893db9d --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/model/ScoreDetail.java @@ -0,0 +1,184 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated.model; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.StringJoiner; +import java.util.Objects; +import java.util.Map; +import java.util.HashMap; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +import ai.shieldlabs.generated.ApiClient; +/** + * One entry behind the score, in the PascalCase shape the server stores. `Value` is the weight (0 for informational entries); `Description` is free text for display, never branch on it. + */ +@JsonPropertyOrder({ + ScoreDetail.JSON_PROPERTY_VALUE, + ScoreDetail.JSON_PROPERTY_DESCRIPTION +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class ScoreDetail { + public static final String JSON_PROPERTY_VALUE = "Value"; + @javax.annotation.Nonnull + private Integer value; + + public static final String JSON_PROPERTY_DESCRIPTION = "Description"; + @javax.annotation.Nonnull + private String description; + + public ScoreDetail() { + } + + public ScoreDetail value(@javax.annotation.Nonnull Integer value) { + this.value = value; + return this; + } + + /** + * Weight of the entry. Can be negative; 0 for informational entries. + * @return value + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_VALUE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Integer getValue() { + return value; + } + + + @JsonProperty(value = JSON_PROPERTY_VALUE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setValue(@javax.annotation.Nonnull Integer value) { + this.value = value; + } + + + public ScoreDetail description(@javax.annotation.Nonnull String description) { + this.description = description; + return this; + } + + /** + * Human-readable description, for example `Is proxy` or `Antidetect browser (turn_block)`. + * @return description + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_DESCRIPTION, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getDescription() { + return description; + } + + + @JsonProperty(value = JSON_PROPERTY_DESCRIPTION, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDescription(@javax.annotation.Nonnull String description) { + this.description = description; + } + + + /** + * Return true if this ScoreDetail object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ScoreDetail scoreDetail = (ScoreDetail) o; + return Objects.equals(this.value, scoreDetail.value) && + Objects.equals(this.description, scoreDetail.description); + } + + @Override + public int hashCode() { + return Objects.hash(value, description); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ScoreDetail {\n"); + sb.append(" value: ").append(toIndentedString(value)).append("\n"); + sb.append(" description: ").append(toIndentedString(description)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `Value` to the URL query string + if (getValue() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sValue%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getValue())))); + } + + // add `Description` to the URL query string + if (getDescription() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sDescription%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getDescription())))); + } + + return joiner.toString(); + } +} + diff --git a/generated/src/main/java/ai/shieldlabs/generated/model/Signal.java b/generated/src/main/java/ai/shieldlabs/generated/model/Signal.java new file mode 100644 index 0000000..d99ca8c --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/model/Signal.java @@ -0,0 +1,184 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated.model; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.StringJoiner; +import java.util.Objects; +import java.util.Map; +import java.util.HashMap; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +import ai.shieldlabs.generated.ApiClient; +/** + * One weighted risk signal behind the Risk Score. Only signals with a non-zero weight are listed, in scoring order. The same name can appear twice, and weights can be negative. + */ +@JsonPropertyOrder({ + Signal.JSON_PROPERTY_NAME, + Signal.JSON_PROPERTY_WEIGHT +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class Signal { + public static final String JSON_PROPERTY_NAME = "name"; + @javax.annotation.Nonnull + private String name; + + public static final String JSON_PROPERTY_WEIGHT = "weight"; + @javax.annotation.Nonnull + private Integer weight; + + public Signal() { + } + + public Signal name(@javax.annotation.Nonnull String name) { + this.name = name; + return this; + } + + /** + * Signal name. The set is open: new names can appear at any time, so keep unknown names and use them for display and logging only. Known names: - `tor`: the request came through Tor; - `vpn`: a VPN was detected; - `privacy_relay`: a privacy relay such as iCloud Private Relay; - `proxy`: a proxy was detected; - `datacenter_ip`: the IP belongs to a datacenter or hosting range; - `abuser`: the IP has a record of abuse; - `browser_vpn_proxy`: a VPN or proxy inside the browser; - `antidetect_browser`: an anti-detect browser (the matching flag is `anti_detect_browser`); - `proxy_routed_antidetect`: the network check was routed through a proxy in a way typical for anti-detect browsers; - `port_scan_routed_via_proxy`: `proxy_routed_antidetect` carried forward from an earlier identification of the same device and IP; - `browser_automation`: browser automation, for example a WebDriver-controlled browser; - `javascript_disabled`: JavaScript or the browser APIs the checks need were unavailable; - `os_mismatch`: the operating system seen on the network differs from the one the browser reports; - `os_not_detected`: the operating system could not be determined; - `timezone_mismatch`: the browser timezone differs from the IP location timezone; - `stun_not_checked`: the network (STUN) check did not complete; - `stun_late_correction`: a late network result arrived; negative weight that cancels `stun_not_checked`; - `rate_limited`: the rate-limit marker, weight 999. A verdict carried forward from an earlier identification of the same device and IP (for example `antidetect_browser`) keeps a name derived from the original signal and can carry a partial weight. + * @return name + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_NAME, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getName() { + return name; + } + + + @JsonProperty(value = JSON_PROPERTY_NAME, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setName(@javax.annotation.Nonnull String name) { + this.name = name; + } + + + public Signal weight(@javax.annotation.Nonnull Integer weight) { + this.weight = weight; + return this; + } + + /** + * Points the signal contributed. Can be negative (`stun_late_correction` is -30) and is 999 for `rate_limited`. Weights can change between releases; never add them up yourself. + * @return weight + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_WEIGHT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public Integer getWeight() { + return weight; + } + + + @JsonProperty(value = JSON_PROPERTY_WEIGHT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setWeight(@javax.annotation.Nonnull Integer weight) { + this.weight = weight; + } + + + /** + * Return true if this Signal object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Signal signal = (Signal) o; + return Objects.equals(this.name, signal.name) && + Objects.equals(this.weight, signal.weight); + } + + @Override + public int hashCode() { + return Objects.hash(name, weight); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Signal {\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" weight: ").append(toIndentedString(weight)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `name` to the URL query string + if (getName() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sname%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getName())))); + } + + // add `weight` to the URL query string + if (getWeight() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sweight%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getWeight())))); + } + + return joiner.toString(); + } +} + diff --git a/generated/src/main/java/ai/shieldlabs/generated/model/TrafficSource.java b/generated/src/main/java/ai/shieldlabs/generated/model/TrafficSource.java new file mode 100644 index 0000000..0f44ef3 --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/model/TrafficSource.java @@ -0,0 +1,436 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated.model; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.StringJoiner; +import java.util.Objects; +import java.util.Map; +import java.util.HashMap; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +import ai.shieldlabs.generated.ApiClient; +/** + * Where the visit came from. All nine keys are always present; values can be empty strings. + */ +@JsonPropertyOrder({ + TrafficSource.JSON_PROPERTY_CHANNEL, + TrafficSource.JSON_PROPERTY_REFERRER_DOMAIN, + TrafficSource.JSON_PROPERTY_LANDING_URL, + TrafficSource.JSON_PROPERTY_CLICK_ID_TYPE, + TrafficSource.JSON_PROPERTY_UTM_SOURCE, + TrafficSource.JSON_PROPERTY_UTM_MEDIUM, + TrafficSource.JSON_PROPERTY_UTM_CAMPAIGN, + TrafficSource.JSON_PROPERTY_UTM_CONTENT, + TrafficSource.JSON_PROPERTY_UTM_TERM +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class TrafficSource { + public static final String JSON_PROPERTY_CHANNEL = "channel"; + @javax.annotation.Nonnull + private String channel; + + public static final String JSON_PROPERTY_REFERRER_DOMAIN = "referrer_domain"; + @javax.annotation.Nonnull + private String referrerDomain; + + public static final String JSON_PROPERTY_LANDING_URL = "landing_url"; + @javax.annotation.Nonnull + private String landingUrl; + + public static final String JSON_PROPERTY_CLICK_ID_TYPE = "click_id_type"; + @javax.annotation.Nonnull + private String clickIdType; + + public static final String JSON_PROPERTY_UTM_SOURCE = "utm_source"; + @javax.annotation.Nonnull + private String utmSource; + + public static final String JSON_PROPERTY_UTM_MEDIUM = "utm_medium"; + @javax.annotation.Nonnull + private String utmMedium; + + public static final String JSON_PROPERTY_UTM_CAMPAIGN = "utm_campaign"; + @javax.annotation.Nonnull + private String utmCampaign; + + public static final String JSON_PROPERTY_UTM_CONTENT = "utm_content"; + @javax.annotation.Nonnull + private String utmContent; + + public static final String JSON_PROPERTY_UTM_TERM = "utm_term"; + @javax.annotation.Nonnull + private String utmTerm; + + public TrafficSource() { + } + + public TrafficSource channel(@javax.annotation.Nonnull String channel) { + this.channel = channel; + return this; + } + + /** + * Marketing channel of the visit. Known values: `Google Ads`, `Meta`, `TikTok`, `LinkedIn`, `X`, `Pinterest`, `Microsoft Ads`, `Organic Search`, `Search bot`, `Referral`, `Direct`, `Other` and the empty string. Resolved in this order: a click ID, then UTM parameters, then the referrer (search engines give `Organic Search`, social networks give the platform name, other sites give `Referral`), otherwise `Direct`. Search-engine crawlers get `Search bot`. Empty string on identifications without attribution, such as rate-limit marker rows. The set is open: keep values added in later versions and treat them as `Other`. + * @return channel + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_CHANNEL, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getChannel() { + return channel; + } + + + @JsonProperty(value = JSON_PROPERTY_CHANNEL, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setChannel(@javax.annotation.Nonnull String channel) { + this.channel = channel; + } + + + public TrafficSource referrerDomain(@javax.annotation.Nonnull String referrerDomain) { + this.referrerDomain = referrerDomain; + return this; + } + + /** + * Registrable domain of the referrer without `www.`. For search-engine crawlers, the crawler name (for example `GoogleBot`). + * @return referrerDomain + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_REFERRER_DOMAIN, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getReferrerDomain() { + return referrerDomain; + } + + + @JsonProperty(value = JSON_PROPERTY_REFERRER_DOMAIN, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setReferrerDomain(@javax.annotation.Nonnull String referrerDomain) { + this.referrerDomain = referrerDomain; + } + + + public TrafficSource landingUrl(@javax.annotation.Nonnull String landingUrl) { + this.landingUrl = landingUrl; + return this; + } + + /** + * Landing page URL without the `#fragment`. It keeps the query string, which can contain personal data: store it with care. + * @return landingUrl + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_LANDING_URL, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getLandingUrl() { + return landingUrl; + } + + + @JsonProperty(value = JSON_PROPERTY_LANDING_URL, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setLandingUrl(@javax.annotation.Nonnull String landingUrl) { + this.landingUrl = landingUrl; + } + + + public TrafficSource clickIdType(@javax.annotation.Nonnull String clickIdType) { + this.clickIdType = clickIdType; + return this; + } + + /** + * Ad click identifier found in the landing URL. Known values: `gclid`, `gbraid`, `wbraid`, `msclkid`, `ttclid`, `fbclid` and the empty string when there is none. `fbclid` counts only together with a Meta referrer or a Meta `utm_source`. The set is open: keep values added in later versions. + * @return clickIdType + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_CLICK_ID_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getClickIdType() { + return clickIdType; + } + + + @JsonProperty(value = JSON_PROPERTY_CLICK_ID_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setClickIdType(@javax.annotation.Nonnull String clickIdType) { + this.clickIdType = clickIdType; + } + + + public TrafficSource utmSource(@javax.annotation.Nonnull String utmSource) { + this.utmSource = utmSource; + return this; + } + + /** + * `utm_source` query parameter, lowercased. + * @return utmSource + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_UTM_SOURCE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getUtmSource() { + return utmSource; + } + + + @JsonProperty(value = JSON_PROPERTY_UTM_SOURCE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setUtmSource(@javax.annotation.Nonnull String utmSource) { + this.utmSource = utmSource; + } + + + public TrafficSource utmMedium(@javax.annotation.Nonnull String utmMedium) { + this.utmMedium = utmMedium; + return this; + } + + /** + * `utm_medium` query parameter, lowercased. + * @return utmMedium + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_UTM_MEDIUM, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getUtmMedium() { + return utmMedium; + } + + + @JsonProperty(value = JSON_PROPERTY_UTM_MEDIUM, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setUtmMedium(@javax.annotation.Nonnull String utmMedium) { + this.utmMedium = utmMedium; + } + + + public TrafficSource utmCampaign(@javax.annotation.Nonnull String utmCampaign) { + this.utmCampaign = utmCampaign; + return this; + } + + /** + * `utm_campaign` query parameter as sent. + * @return utmCampaign + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_UTM_CAMPAIGN, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getUtmCampaign() { + return utmCampaign; + } + + + @JsonProperty(value = JSON_PROPERTY_UTM_CAMPAIGN, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setUtmCampaign(@javax.annotation.Nonnull String utmCampaign) { + this.utmCampaign = utmCampaign; + } + + + public TrafficSource utmContent(@javax.annotation.Nonnull String utmContent) { + this.utmContent = utmContent; + return this; + } + + /** + * `utm_content` query parameter as sent. + * @return utmContent + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_UTM_CONTENT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getUtmContent() { + return utmContent; + } + + + @JsonProperty(value = JSON_PROPERTY_UTM_CONTENT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setUtmContent(@javax.annotation.Nonnull String utmContent) { + this.utmContent = utmContent; + } + + + public TrafficSource utmTerm(@javax.annotation.Nonnull String utmTerm) { + this.utmTerm = utmTerm; + return this; + } + + /** + * `utm_term` query parameter as sent. + * @return utmTerm + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_UTM_TERM, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getUtmTerm() { + return utmTerm; + } + + + @JsonProperty(value = JSON_PROPERTY_UTM_TERM, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setUtmTerm(@javax.annotation.Nonnull String utmTerm) { + this.utmTerm = utmTerm; + } + + + /** + * Return true if this TrafficSource object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TrafficSource trafficSource = (TrafficSource) o; + return Objects.equals(this.channel, trafficSource.channel) && + Objects.equals(this.referrerDomain, trafficSource.referrerDomain) && + Objects.equals(this.landingUrl, trafficSource.landingUrl) && + Objects.equals(this.clickIdType, trafficSource.clickIdType) && + Objects.equals(this.utmSource, trafficSource.utmSource) && + Objects.equals(this.utmMedium, trafficSource.utmMedium) && + Objects.equals(this.utmCampaign, trafficSource.utmCampaign) && + Objects.equals(this.utmContent, trafficSource.utmContent) && + Objects.equals(this.utmTerm, trafficSource.utmTerm); + } + + @Override + public int hashCode() { + return Objects.hash(channel, referrerDomain, landingUrl, clickIdType, utmSource, utmMedium, utmCampaign, utmContent, utmTerm); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class TrafficSource {\n"); + sb.append(" channel: ").append(toIndentedString(channel)).append("\n"); + sb.append(" referrerDomain: ").append(toIndentedString(referrerDomain)).append("\n"); + sb.append(" landingUrl: ").append(toIndentedString(landingUrl)).append("\n"); + sb.append(" clickIdType: ").append(toIndentedString(clickIdType)).append("\n"); + sb.append(" utmSource: ").append(toIndentedString(utmSource)).append("\n"); + sb.append(" utmMedium: ").append(toIndentedString(utmMedium)).append("\n"); + sb.append(" utmCampaign: ").append(toIndentedString(utmCampaign)).append("\n"); + sb.append(" utmContent: ").append(toIndentedString(utmContent)).append("\n"); + sb.append(" utmTerm: ").append(toIndentedString(utmTerm)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `channel` to the URL query string + if (getChannel() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%schannel%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getChannel())))); + } + + // add `referrer_domain` to the URL query string + if (getReferrerDomain() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sreferrer_domain%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getReferrerDomain())))); + } + + // add `landing_url` to the URL query string + if (getLandingUrl() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%slanding_url%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getLandingUrl())))); + } + + // add `click_id_type` to the URL query string + if (getClickIdType() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sclick_id_type%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getClickIdType())))); + } + + // add `utm_source` to the URL query string + if (getUtmSource() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sutm_source%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getUtmSource())))); + } + + // add `utm_medium` to the URL query string + if (getUtmMedium() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sutm_medium%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getUtmMedium())))); + } + + // add `utm_campaign` to the URL query string + if (getUtmCampaign() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sutm_campaign%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getUtmCampaign())))); + } + + // add `utm_content` to the URL query string + if (getUtmContent() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sutm_content%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getUtmContent())))); + } + + // add `utm_term` to the URL query string + if (getUtmTerm() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sutm_term%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getUtmTerm())))); + } + + return joiner.toString(); + } +} + diff --git a/generated/src/main/java/ai/shieldlabs/generated/model/WebhookPingEvent.java b/generated/src/main/java/ai/shieldlabs/generated/model/WebhookPingEvent.java new file mode 100644 index 0000000..1c0fade --- /dev/null +++ b/generated/src/main/java/ai/shieldlabs/generated/model/WebhookPingEvent.java @@ -0,0 +1,254 @@ +/* + * ShieldLabs API + * Identification results and risk scoring for your backend. + * + * The version of the OpenAPI document: 1.0.1 + * Contact: contact@shieldlabs.ai + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package ai.shieldlabs.generated.model; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.StringJoiner; +import java.util.Objects; +import java.util.Map; +import java.util.HashMap; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.time.OffsetDateTime; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + + +import ai.shieldlabs.generated.ApiClient; +/** + * Body of a `webhook.ping` delivery, sent when you verify an endpoint. It has no `data`. The keys arrive sorted alphabetically and `created_at` has second precision. + */ +@JsonPropertyOrder({ + WebhookPingEvent.JSON_PROPERTY_EVENT_TYPE, + WebhookPingEvent.JSON_PROPERTY_SCHEMA_VERSION, + WebhookPingEvent.JSON_PROPERTY_CREATED_AT +}) +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.23.0") +public class WebhookPingEvent { + /** + * Event type. + */ + public enum EventTypeEnum { + WEBHOOK_PING(String.valueOf("webhook.ping")); + + private String value; + + EventTypeEnum(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static EventTypeEnum fromValue(String value) { + for (EventTypeEnum b : EventTypeEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + } + + public static final String JSON_PROPERTY_EVENT_TYPE = "event_type"; + @javax.annotation.Nonnull + private EventTypeEnum eventType; + + public static final String JSON_PROPERTY_SCHEMA_VERSION = "schema_version"; + @javax.annotation.Nonnull + private String schemaVersion; + + public static final String JSON_PROPERTY_CREATED_AT = "created_at"; + @javax.annotation.Nonnull + private OffsetDateTime createdAt; + + public WebhookPingEvent() { + } + + public WebhookPingEvent eventType(@javax.annotation.Nonnull EventTypeEnum eventType) { + this.eventType = eventType; + return this; + } + + /** + * Event type. + * @return eventType + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_EVENT_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public EventTypeEnum getEventType() { + return eventType; + } + + + @JsonProperty(value = JSON_PROPERTY_EVENT_TYPE, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setEventType(@javax.annotation.Nonnull EventTypeEnum eventType) { + this.eventType = eventType; + } + + + public WebhookPingEvent schemaVersion(@javax.annotation.Nonnull String schemaVersion) { + this.schemaVersion = schemaVersion; + return this; + } + + /** + * Version of the webhook payload contract. Every event sent today carries `2026-06-01`. Accept other values, so that a future version does not break your handler. + * @return schemaVersion + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_SCHEMA_VERSION, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public String getSchemaVersion() { + return schemaVersion; + } + + + @JsonProperty(value = JSON_PROPERTY_SCHEMA_VERSION, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setSchemaVersion(@javax.annotation.Nonnull String schemaVersion) { + this.schemaVersion = schemaVersion; + } + + + public WebhookPingEvent createdAt(@javax.annotation.Nonnull OffsetDateTime createdAt) { + this.createdAt = createdAt; + return this; + } + + /** + * When the ping was sent, with second precision. + * @return createdAt + */ + @javax.annotation.Nonnull + @JsonProperty(value = JSON_PROPERTY_CREATED_AT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public OffsetDateTime getCreatedAt() { + return createdAt; + } + + + @JsonProperty(value = JSON_PROPERTY_CREATED_AT, required = true) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCreatedAt(@javax.annotation.Nonnull OffsetDateTime createdAt) { + this.createdAt = createdAt; + } + + + /** + * Return true if this WebhookPingEvent object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + WebhookPingEvent webhookPingEvent = (WebhookPingEvent) o; + return Objects.equals(this.eventType, webhookPingEvent.eventType) && + Objects.equals(this.schemaVersion, webhookPingEvent.schemaVersion) && + Objects.equals(this.createdAt, webhookPingEvent.createdAt); + } + + @Override + public int hashCode() { + return Objects.hash(eventType, schemaVersion, createdAt); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class WebhookPingEvent {\n"); + sb.append(" eventType: ").append(toIndentedString(eventType)).append("\n"); + sb.append(" schemaVersion: ").append(toIndentedString(schemaVersion)).append("\n"); + sb.append(" createdAt: ").append(toIndentedString(createdAt)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + return o == null ? "null" : o.toString().replace("\n", "\n "); + } + + /** + * Convert the instance into URL query string. + * + * @return URL query string + */ + public String toUrlQueryString() { + return toUrlQueryString(null); + } + + /** + * Convert the instance into URL query string. + * + * @param prefix prefix of the query string + * @return URL query string + */ + public String toUrlQueryString(String prefix) { + String suffix = ""; + String containerSuffix = ""; + String containerPrefix = ""; + if (prefix == null) { + // style=form, explode=true, e.g. /pet?name=cat&type=manx + prefix = ""; + } else { + // deepObject style e.g. /pet?id[name]=cat&id[type]=manx + prefix = prefix + "["; + suffix = "]"; + containerSuffix = "]"; + containerPrefix = "["; + } + + StringJoiner joiner = new StringJoiner("&"); + + // add `event_type` to the URL query string + if (getEventType() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sevent_type%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getEventType())))); + } + + // add `schema_version` to the URL query string + if (getSchemaVersion() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%sschema_version%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getSchemaVersion())))); + } + + // add `created_at` to the URL query string + if (getCreatedAt() != null) { + joiner.add(String.format(java.util.Locale.ROOT, "%screated_at%s=%s", prefix, suffix, ApiClient.urlEncode(ApiClient.valueToString(getCreatedAt())))); + } + + return joiner.toString(); + } +} + diff --git a/resources/shieldlabs-api.yaml b/resources/shieldlabs-api.yaml new file mode 100644 index 0000000..2838959 --- /dev/null +++ b/resources/shieldlabs-api.yaml @@ -0,0 +1,2462 @@ +openapi: 3.1.0 +info: + title: ShieldLabs API + version: 1.0.1 + summary: Identification results and risk scoring for your backend. + description: |- + The ShieldLabs API gives your backend the result of every identification the ShieldLabs agent + runs in a browser: the Risk Score, the risk signals behind it, the detection flags and the + identifiers (request, visitor, device, session, cookie and User HID) it belongs to. + + ## How it fits + + 1. **Browser.** The ShieldLabs agent, loaded from `cdn.shieldlabs.ai`, runs an identification + and hands your page a request ID. The browser never receives a Risk Score, a visitor ID or + a device ID. + 2. **Your backend.** Your page sends the request ID along with the protected action (signup, + login, checkout). Your backend reads the verdict for it from the **History API**, or + receives it in a signed `identification.scored` **webhook**. + 3. **Decision.** Your backend acts on `risk_score`, the three risk bands, `detection_flags` + and the identifiers, for example by counting how many accounts one `device_id` has used + (skipping the `user_hid` values that do not identify a user, listed under Identifiers). + + Scoring is asynchronous. The webhook usually arrives about 300 ms after the browser check; when + follow-up network checks run, it is sent when they finish, at most about 10 seconds later. The + History row appears about 1-3 seconds after the browser call and can be refined for up to about + 10 seconds as follow-up checks finish. Start the identification when the user begins the + protected action (for example when the signup form opens), then either poll the History API by + `request_id` with a short backoff or wait for the webhook. Let one identification authorize one + protected action: reject request IDs you have already used and identifications older than your + freshness window. + + ## Hosts and credentials + + | API | Host | Paths | Credentials | + |---|---|---|---| + | History API | `https://account.shieldlabs.ai` | `/api/v1/...` | `Authorization: Bearer ` (`sec_...`, one per domain) | + | Management API | `https://api.shieldlabs.ai` | `/v1/...` | `X-Shield-Domain: ` and `Authorization: Bearer ` | + | Health | both hosts | `/health` | none | + + Every operation declares its own server, so generated clients send each call to the right + host. The History API serves its paths from the host root: the full URL is + `https://account.shieldlabs.ai/api/v1/history/{search_type}/{value}`, and a base URL that + already ends in `/api` produces `/api/api/v1/...` and a `404`. + + The two credentials are not interchangeable. Keep the Private API Key and the Secret Key on your + server; only the Public Key belongs in the browser. All keys are in the analytics dashboard at + https://app.shieldlabs.ai. + + ## Rate limits + + - **History API:** about 15 requests per second per domain, shared by every caller of that + domain. Requests over the limit get `429`; there is no ban, so retry after about a second. + - **Management API:** 15 requests per minute per client IP. The request that goes over the + limit starts a 10-minute block, during which every request gets `429`. Never retry a `429` + from this API; cache the profile instead. + - **Health:** not rate limited. + + API calls and webhook deliveries are free: only identifications made by the browser agent use + your included volume. + + ## Errors + + Error bodies are not uniform. Branch on the HTTP status first, then try to parse the body as + JSON whatever its content type. + + | API | Status | Body | + |---|---|---| + | History API | 401 | JSON text `{"error":"..."}`, sent as `text/plain` | + | History API | 429 | `{"error":"too many requests"}` | + | History API | 500 | `{"error":"..."}`. A malformed UUID or IPv4 value always ends here: validate before sending and do not retry it | + | Management API | 401 | empty | + | Management API | 400 | a bare JSON string or `null` (deprecated history endpoint) | + | Management API | 429, 503 | `{"error":"..."}` | + | Both | 404 | `404 page not found` as `text/plain` when no route matches | + | Both | 502, 504 | an HTML page from the edge proxy | + + Retry `429` (History API only), `5xx` and network errors with backoff. Do not retry `400`, + `401` or `404`, nor a History API `500` caused by a malformed value. + + ## Identifiers + + - `request_id`: one identification, created in the browser (UUID v4). It joins the browser + call, the webhook and the History row. + - `session_id`: one visit on one origin (UUID v4). + - `cookie_id`: first-party browser identifier kept by the agent (UUID v4). + - `device_id`: server-side device identifier (UUID v5). It survives cleared cookies and private + windows. The nil UUID `00000000-0000-0000-0000-000000000000` means no usable device signals. + - `visitor_id`: server-side visitor identifier (UUID v5), sticky to the device: a new cookie on + a known device keeps the visitor ID. + - `user_hid`: your hashed or pseudonymous account identifier, as passed to the agent. + `anonymous` marks anonymous checks; `fail`, `-1` and `unknown` also mean "no user". Leave + these values, `null` and the empty string out when you count accounts. Hex-encoded hashes + are the easiest values to search: see the `value` parameter of `searchHistory` for how to + encode other characters. + + Validate UUIDs with any version accepted, the nil UUID included. + + ## Risk Score, risk bands and the 999 marker + + The Risk Score (`risk_score` on webhooks, `score` in the History API) is an integer from 0 to + 100. Search-engine crawlers always score 0. The three risk bands are computed on your side; no + band field exists on the wire: + + | Band | Score | + |---|---| + | trusted | 0-29 | + | suspicious | 30-59 | + | dangerous | 60-100 | + + A value above 100 is not a score. **999** is the rate-limit marker: the visitor's IP went over + the ingest rate limit, and the identification carries exactly one signal, + `{"name":"rate_limited","weight":999}`, usually with nil identifiers. Treat every value above + 100 as rate limited. One marker is written when the IP goes over the limit; request IDs issued + while it stays blocked get no row and no webhook, so they stay unverified. + + Branch on `detection_flags` and the Risk Score. Signal names are for display and logging; + weights can be negative or change between releases, so never add them up yourself. A missing + identification means "unverified", never "clean". + + ## Countries, IP addresses and timestamps + + - `country` values are English country names from IP intelligence, such as `Germany` or + `United States`, or an empty string when unknown. + - IP fields hold IPv4 addresses. Without an IPv4 address the webhook sends `""` and the History + API sends `0.0.0.0`; such identifications cannot be searched by IP. + - Webhook timestamps (`created_at`, `observed_at`) are RFC 3339 in UTC with up to 9 fractional + digits. + - The History API `created_at` is `YYYY-MM-DD HH:MM:SS.mmm` in UTC without a zone designator; + older rows can lack the milliseconds. + - The Management API `CreatedAt` is RFC 3339 with second precision. + + ## Webhooks + + ShieldLabs sends one signed `POST` for each identification to every enabled endpoint of the + domain. A delivery has a 1-second timeout and is not retried today; a later release adds + retries that resend identical bytes. Answer 2xx within a second, process the event + asynchronously, make the handler idempotent on `data.request_id`, and use the History API for + guaranteed reads. A History row can be refined after its webhook was sent (its `ver` + increases); the webhook is not sent again. See the `identification.scored` and `webhook.ping` + entries for the signature algorithm. + + ## Compatibility + + Ignore fields you do not know, keep unknown values of string fields (such as new signal names + or channels) instead of failing, and accept webhook `schema_version` values other than + `2026-06-01`. + + Start free at https://app.shieldlabs.ai. Guides: https://docs.shieldlabs.ai. + contact: + name: ShieldLabs + url: https://docs.shieldlabs.ai + email: contact@shieldlabs.ai + license: + name: MIT + identifier: MIT +servers: + - url: https://account.shieldlabs.ai + description: History API (every operation also declares its own server) + - url: https://api.shieldlabs.ai + description: Management API (every operation also declares its own server) +tags: + - name: History API + description: 'Read identifications by one identifier on `https://account.shieldlabs.ai` with the Private API Key. The canonical way to read a verdict: by `request_id` right after a protected action, or by `device_id`, `user_hid`, `visitor_id` or `ip` for account-level checks.' + - name: Management API + description: Domain profile on `https://api.shieldlabs.ai`, authenticated with the Secret Key and the `X-Shield-Domain` header. Also serves the deprecated history endpoint until 1 January 2027. + - name: Health + description: Unauthenticated liveness checks on both API hosts. + - name: Webhooks + description: 'Signed events ShieldLabs sends to your webhook endpoints: `identification.scored` for every identification and `webhook.ping` when you verify an endpoint.' +externalDocs: + description: ShieldLabs documentation + url: https://docs.shieldlabs.ai +paths: + /api/v1/history/{search_type}/{value}: + servers: + - url: https://account.shieldlabs.ai + description: History API + get: + operationId: searchHistory + tags: + - History API + summary: Search identifications + description: |- + Returns the identifications of your domain that match one identifier, newest first, together + with the total number of matches. The Private API Key selects the domain; identifications from + its subdomains are included (`domain` holds the host, `site_domain` the registered domain). + + **Read one verdict.** After a protected action, search by `request_id` with `limit=1`. The row + appears about 1-3 seconds after the browser call and can be refined for up to about 10 seconds + as follow-up network checks finish, so start the identification when the user begins the + action (for example when the signup form opens), not when the form is submitted. An empty + `data` array means "not scored yet", never "clean". Poll with backoff (first try at once, then + wait 250 ms, 500 ms, 1 s, then steps of about 1.5 s) and treat a `429` inside that loop as + "wait longer". The official server SDKs do this for you. + + **Account-level checks.** Search by `device_id`, `user_hid`, `visitor_id` or `ip` to see how + many accounts share a device, how many devices one account uses, or what else came from one + IP address. When you count accounts, skip rows whose `user_hid` is empty or one of the values + that do not identify a user: `anonymous`, `fail`, `-1` and `unknown`. + + **Validate before sending.** The server does not validate the path: an unknown `search_type` + returns the latest identifications of the whole domain unfiltered, a malformed UUID or IPv4 + value returns `500`, and a `limit` outside 1-100 silently becomes 20. + + **Paging.** Page with `offset` while it is below `total`. Rows are ordered by `created_at` + only, so paging while new identifications arrive can repeat or skip rows: deduplicate on + `request_id`. + + **Latest state.** A row can be refined after the webhook was sent, for example when late + network data re-scores it; its `ver` then increases. The History API always returns the latest + version, which makes it the guaranteed read path. + + Reads are free: they do not use your included identifications. + security: + - historyApiKey: [] + parameters: + - $ref: '#/components/parameters/HistorySearchType' + - $ref: '#/components/parameters/HistoryValue' + - $ref: '#/components/parameters/HistoryLimit' + - $ref: '#/components/parameters/HistoryOffset' + responses: + '200': + description: Matching identifications, newest first. `data` is empty when nothing matched. + content: + application/json: + schema: + $ref: '#/components/schemas/HistoryPage' + examples: + page: + $ref: '#/components/examples/HistoryPage' + empty: + $ref: '#/components/examples/HistoryPageEmpty' + '401': + $ref: '#/components/responses/HistoryUnauthorized' + '404': + $ref: '#/components/responses/NotFound' + '429': + $ref: '#/components/responses/HistoryTooManyRequests' + '500': + $ref: '#/components/responses/HistoryServerError' + '502': + $ref: '#/components/responses/BadGateway' + '504': + $ref: '#/components/responses/GatewayTimeout' + x-codeSamples: + - lang: Shell + label: curl + source: | + curl "https://account.shieldlabs.ai/api/v1/history/request_id/a5b7c9d1-e3f5-4a7b-9c1d-3e5f7a9b1c3d?limit=1" \ + -H "Authorization: Bearer $SHIELDLABS_API_KEY" + /v1/profile: + servers: + - url: https://api.shieldlabs.ai + description: Management API + get: + operationId: getDomainProfile + tags: + - Management API + summary: Get the domain profile + description: |- + Returns the registered domain, the remaining included identifications of the account and the + masked keys. + + **Credentials.** Send the Secret Key as a Bearer token and the registered domain in + `X-Shield-Domain`. The domain is matched exactly: send it lowercase, without scheme, path, + trailing slash or a leading `www.`. + + **Rate limit.** 15 requests per minute per client IP. The request that goes over the limit + starts a 10-minute block during which every request to the Management API gets `429`. Call + this endpoint sparingly, cache the profile, and never retry a `429`. + + `Weight` can be negative when the account is over its included volume. The call is free. + security: + - managementSecretKey: [] + parameters: + - $ref: '#/components/parameters/ShieldDomain' + responses: + '200': + description: The domain profile. + content: + application/json: + schema: + $ref: '#/components/schemas/DomainProfile' + examples: + profile: + $ref: '#/components/examples/DomainProfile' + '401': + $ref: '#/components/responses/ManagementUnauthorized' + '404': + $ref: '#/components/responses/NotFound' + '429': + $ref: '#/components/responses/ManagementTooManyRequests' + '502': + $ref: '#/components/responses/BadGateway' + '503': + $ref: '#/components/responses/ManagementServerBusy' + '504': + $ref: '#/components/responses/GatewayTimeout' + x-codeSamples: + - lang: Shell + label: curl + source: | + curl "https://api.shieldlabs.ai/v1/profile" \ + -H "X-Shield-Domain: $SHIELDLABS_DOMAIN" \ + -H "Authorization: Bearer $SHIELDLABS_SECRET_KEY" + /v1/history/{type}/{value}: + servers: + - url: https://api.shieldlabs.ai + description: Management API + get: + operationId: searchHistoryDeprecated + tags: + - Management API + summary: Search history by identifier (deprecated) + deprecated: true + x-sunset: '2027-01-01' + description: |- + **Deprecated.** This endpoint stops working after Sat, 01 Jan 2027 00:00:00 GMT. Use + `searchHistory` on the History API instead: `https://account.shieldlabs.ai/api/v1/history`. + Every answer of this route except `429` and `503` carries `Deprecation: true`, a `Sunset` + header and a `Link` header with `rel="successor-version"` pointing there. The plain-text `404` + for a path that matches no route and the edge proxy errors do not carry them. + + Differences from the History API: the answer is a bare array of PascalCase objects; only rows + whose request host equals `X-Shield-Domain` are returned (no subdomain traffic); `limit` + defaults to 100 and there is no `offset`. It uses the Management API credentials and rate limit + (15 requests per minute per client IP, then a 10-minute block). The call is free. + security: + - managementSecretKey: [] + parameters: + - $ref: '#/components/parameters/ShieldDomain' + - $ref: '#/components/parameters/DeprecatedHistoryType' + - $ref: '#/components/parameters/DeprecatedHistoryValue' + - $ref: '#/components/parameters/DeprecatedHistoryLimit' + responses: + '200': + description: Matching identifications, newest first. + headers: + Deprecation: + $ref: '#/components/headers/Deprecation' + Sunset: + $ref: '#/components/headers/Sunset' + Link: + $ref: '#/components/headers/Link' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/LegacySnapshot' + examples: + list: + $ref: '#/components/examples/LegacySnapshotList' + empty: + $ref: '#/components/examples/LegacySnapshotListEmpty' + '400': + description: The value failed validation (a bare JSON string) or the query failed (the JSON literal `null`, for example for an IPv6 `ip` value). Do not retry. + headers: + Deprecation: + $ref: '#/components/headers/Deprecation' + Sunset: + $ref: '#/components/headers/Sunset' + Link: + $ref: '#/components/headers/Link' + content: + application/json: + schema: + $ref: '#/components/schemas/LegacyErrorMessage' + examples: + invalidUuid: + $ref: '#/components/examples/ManagementBadRequestUuid' + invalidIp: + $ref: '#/components/examples/ManagementBadRequestIp' + emptyValue: + $ref: '#/components/examples/ManagementBadRequestEmpty' + queryFailed: + $ref: '#/components/examples/ManagementBadRequestNull' + '401': + description: Empty body, no `Content-Type`. Missing or malformed headers, unknown or disabled domain, or a wrong Secret Key. Do not retry. + headers: + Deprecation: + $ref: '#/components/headers/Deprecation' + Sunset: + $ref: '#/components/headers/Sunset' + Link: + $ref: '#/components/headers/Link' + '404': + description: '`application/json`: the `type` is not supported (a bare JSON string); this answer carries the deprecation headers. `text/plain`: no route matches the path, for example because the value is empty or contains `/`; this answer comes from the router and carries no deprecation headers. Do not retry.' + headers: + Deprecation: + $ref: '#/components/headers/Deprecation' + Sunset: + $ref: '#/components/headers/Sunset' + Link: + $ref: '#/components/headers/Link' + content: + application/json: + schema: + $ref: '#/components/schemas/LegacyErrorMessage' + examples: + unsupportedType: + $ref: '#/components/examples/ManagementUnsupportedType' + text/plain: + schema: + $ref: '#/components/schemas/PlainText' + examples: + notFound: + $ref: '#/components/examples/NotFoundText' + '429': + $ref: '#/components/responses/ManagementTooManyRequests' + '502': + $ref: '#/components/responses/BadGateway' + '503': + $ref: '#/components/responses/ManagementServerBusy' + '504': + $ref: '#/components/responses/GatewayTimeout' + /health: + servers: + - url: https://account.shieldlabs.ai + description: History API host + - url: https://api.shieldlabs.ai + description: Management API host + get: + operationId: getHealth + tags: + - Health + summary: Check service health + description: |- + Liveness check. Returns `{"status":"ok"}` while the service answers. Available on both API + hosts: `https://account.shieldlabs.ai/health` for the History API and + `https://api.shieldlabs.ai/health` for the Management API. No authentication, not rate + limited, not billed. + security: [] + responses: + '200': + description: The service is up. + content: + application/json: + schema: + $ref: '#/components/schemas/HealthStatus' + examples: + ok: + $ref: '#/components/examples/HealthOk' + '404': + description: No route matches the path. The health check lives at the host root, so `/api/health` gets this answer. Plain text body. + content: + text/plain: + schema: + $ref: '#/components/schemas/PlainText' + examples: + notFound: + $ref: '#/components/examples/NotFoundText' + '502': + $ref: '#/components/responses/BadGateway' + '504': + $ref: '#/components/responses/GatewayTimeout' + x-codeSamples: + - lang: Shell + label: curl + source: | + curl "https://account.shieldlabs.ai/health" +webhooks: + identification.scored: + post: + operationId: identificationScored + tags: + - Webhooks + summary: Identification scored + description: |- + Sent to every enabled webhook endpoint of your domain once for each identification, when its + scoring is final: usually about 300 ms after the browser check, and at most about 10 seconds + later when follow-up network checks run. + + **Verify, then parse.** Compute HMAC-SHA256 over the raw request body and compare it with + `X-Shield-Signature` before you parse the JSON: + - key: the endpoint's signing secret as UTF-8 bytes, including the `whsec_` prefix (not hex- + or base64-decoded, not stripped); + - message: the exact bytes received; re-serializing parsed JSON changes them (for example, `&` + arrives escaped as `\u0026`); + - expected header: `sha256=` followed by the lowercase hex digest, compared in constant time. + + There is no timestamp, delivery ID or event-type header. Rotating a secret replaces it at + once, so accept both the old and the new secret until your deployment has switched. + + **Respond fast.** Answer any 2xx status within 1 second and process the event asynchronously; + do not redirect. Today each identification is delivered once per endpoint, with no retries. A + later release adds retries that resend identical bytes, so make your handler idempotent on + `data.request_id`. + + **Latest state.** The event is a snapshot taken when scoring finished. The History row can + still be refined afterwards (its `ver` increases) and no second event is sent. Use the History + API for guaranteed reads and for the latest state. + + **Test deliveries.** The Test button in the analytics dashboard sends a fixed sample with keys + sorted alphabetically, second-precision timestamps and two-letter country values. Its + `detection_flags` lack `browser_automation` and `search_bot`: parse missing flags as `false`. + + Deliveries are free and do not use your included identifications. + security: [] + parameters: + - $ref: '#/components/parameters/ShieldSignature' + requestBody: + required: true + description: The event as compact JSON. Verify the signature over these exact bytes. + content: + application/json: + schema: + $ref: '#/components/schemas/IdentificationScoredEvent' + examples: + scored: + $ref: '#/components/examples/IdentificationScored' + rateLimited: + $ref: '#/components/examples/IdentificationScoredRateLimited' + testDelivery: + $ref: '#/components/examples/IdentificationScoredTestDelivery' + responses: + 2XX: + description: Delivery accepted. The response body is ignored. + 4XX: + description: Delivery rejected, for example with `401` when the signature does not verify. Any status other than 2xx, and a timeout after 1 second, counts as a failed delivery; failed deliveries are not retried today. + webhook.ping: + post: + operationId: webhookPing + tags: + - Webhooks + summary: Endpoint verification + description: |- + Sent when you verify an endpoint in the analytics dashboard. It carries no `data`. A 2xx + answer within 5 seconds marks the endpoint as verified; anything else marks the verification + as failed. + + The body is signed exactly like `identification.scored`. Its keys are sorted alphabetically + and `created_at` has second precision. Worked example with the test secret + `whsec_00112233445566778899aabbccddeeff`: the body + + ```json + {"created_at":"2026-09-30T12:34:56Z","event_type":"webhook.ping","schema_version":"2026-06-01"} + ``` + + arrives with `X-Shield-Signature: sha256=ea2685733d254f7028fb031c4214583b0650de01e6c8c93131236024edd9fdd8`. + security: [] + parameters: + - $ref: '#/components/parameters/ShieldSignature' + requestBody: + required: true + description: The ping as compact JSON with sorted keys. + content: + application/json: + schema: + $ref: '#/components/schemas/WebhookPingEvent' + examples: + ping: + $ref: '#/components/examples/WebhookPing' + responses: + 2XX: + description: Endpoint verified. The response body is ignored. + 4XX: + description: Verification failed. Any status other than 2xx, and a timeout after 5 seconds, fails it. +components: + securitySchemes: + historyApiKey: + type: http + scheme: bearer + bearerFormat: sec_xxxxxxxx-xxxxxxxx-xxxxxxxx + description: 'Private API Key of one domain, sent as `Authorization: Bearer `. Keys look like `sec_` followed by three groups of eight lowercase letters or digits separated by `-`. Create and rotate it in the analytics dashboard. It reads the History API of that domain only; keep it on your server.' + managementSecretKey: + type: http + scheme: bearer + description: 'Secret Key of the domain, sent as `Authorization: Bearer ` together with the registered domain in the `X-Shield-Domain` header. Treat the key as opaque. Find it in the analytics dashboard; keep it on your server.' + parameters: + HistorySearchType: + name: search_type + in: path + required: true + description: |- + Identifier to search by. Only these seven values are supported: + - `request_id`: one identification (read a verdict); + - `device_id`: every identification of one device; + - `user_hid`: every identification of one account; + - `visitor_id`: every identification of one visitor; + - `ip`: every identification from one public IPv4 address; + - `session_id`: every identification of one visit; + - `cookie_id`: every identification with one browser cookie. + + The server does not reject other values: it ignores them and returns the latest identifications + of the whole domain, so restrict the value on your side. + schema: + type: string + enum: + - request_id + - device_id + - user_hid + - visitor_id + - ip + - session_id + - cookie_id + examples: + requestId: + summary: Read one verdict + value: request_id + deviceId: + summary: All identifications of one device + value: device_id + HistoryValue: + name: value + in: path + required: true + description: |- + Value of the identifier, validated on your side before sending: + - `request_id`, `device_id`, `visitor_id`, `session_id`, `cookie_id`: a UUID of any version, + the nil UUID included, matching + `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`. Send it + lowercase. + - `ip`: a dotted IPv4 address. IPv6 addresses cannot be searched. + - `user_hid`: the exact, case-sensitive User HID as one path segment, encoded the way the + server reads it: send the characters `A-Z a-z 0-9 - . _ ~ $ & + , : ; = @` unescaped and + percent-encode every other byte of the UTF-8 value as uppercase `%XX`, including + `! ' ( ) *`, spaces and `%` itself. The server compares any other encoding literally, so + `%40` instead of `@`, or lowercase hex digits, return an empty page instead of the matching + rows. Many HTTP clients and generated clients escape `$ & + , : ; = @` in path values: build + this path yourself when yours does. A User HID that contains `/` cannot be searched, and most + HTTP clients cannot send `.` or `..` because they remove them as dot segments; the pattern + rejects these values. Hex-encoded hashes need no escaping at all. + + The server does not validate the value: a malformed UUID or IPv4 address gets a `500`. + schema: + type: string + minLength: 1 + pattern: ^(?:[^/.][^/]*|\.[^/.][^/]*|\.\.[^/]+)$ + examples: + requestId: + summary: A request ID + value: a5b7c9d1-e3f5-4a7b-9c1d-3e5f7a9b1c3d + ip: + summary: A public IPv4 address + value: 203.0.113.24 + userHid: + summary: A User HID + value: 9f86d081884c7d659a2feaa0c55ad015 + HistoryLimit: + name: limit + in: query + required: false + description: Maximum number of identifications to return, from 1 to 100. The server replaces any other value (and a non-numeric one) with 20 instead of clamping it, so validate it on your side. + schema: + type: integer + minimum: 1 + maximum: 100 + default: 20 + examples: + one: + summary: Read one verdict + value: 1 + page: + summary: A full page + value: 100 + HistoryOffset: + name: offset + in: query + required: false + description: 'Number of identifications to skip, for paging. The server treats negative or non-numeric values as 0. Rows are ordered by `created_at` only, so paging while new identifications arrive can repeat or skip rows: deduplicate on `request_id`.' + schema: + type: integer + minimum: 0 + default: 0 + examples: + first: + summary: First page + value: 0 + second: + summary: Second page of 100 + value: 100 + ShieldDomain: + name: X-Shield-Domain + in: header + required: true + description: 'Your registered domain. The server matches it exactly against the domain registered in the analytics dashboard, so send it normalized: lowercase, without scheme, path, trailing slash or a leading `www.` (`https://www.Example.com/` becomes `example.com`). A missing or wrong value gets a `401` with an empty body.' + schema: + type: string + minLength: 1 + maxLength: 253 + examples: + domain: + summary: A registered domain + value: example.com + DeprecatedHistoryType: + name: type + in: path + required: true + description: Identifier to search by. Other values get a `404` with a bare JSON string such as `"auto is not supported"`. + schema: + type: string + enum: + - request_id + - device_id + - user_hid + - visitor_id + - ip + - session_id + - cookie_id + examples: + requestId: + summary: Search by request ID + value: request_id + DeprecatedHistoryValue: + name: value + in: path + required: true + description: Value of the identifier. UUID types accept a UUID of any version; `ip` must be an IP address (an IPv6 address passes validation but then fails with `400` and a `null` body); `user_hid` is free text. + schema: + type: string + minLength: 1 + examples: + requestId: + summary: A request ID + value: a5b7c9d1-e3f5-4a7b-9c1d-3e5f7a9b1c3d + DeprecatedHistoryLimit: + name: limit + in: query + required: false + description: Maximum number of identifications, from 1 to 100. Any other value becomes 100. There is no `offset`. + schema: + type: integer + minimum: 1 + maximum: 100 + default: 100 + examples: + ten: + summary: Ten rows + value: 10 + ShieldSignature: + name: X-Shield-Signature + in: header + required: true + description: |- + `sha256=` followed by the lowercase hex HMAC-SHA256 of the raw request body: + - key: your endpoint's signing secret as UTF-8 bytes, the `whsec_` prefix included (not hex- or + base64-decoded, not stripped); + - message: the exact bytes of the body as received. + + Compare it with your own digest in constant time, before parsing the JSON. The example values + are the signatures of the example bodies (in their compact form as sent) with the test secret + `whsec_00112233445566778899aabbccddeeff`. + schema: + type: string + pattern: ^sha256=[0-9a-f]{64}$ + examples: + identificationScored: + summary: Signature of the identification.scored example + value: sha256=397ff9bd26888e9e86addc2d920a8c5b2037251a3a1181f3b4810ca6c5f78062 + webhookPing: + summary: Signature of the webhook.ping example + value: sha256=ea2685733d254f7028fb031c4214583b0650de01e6c8c93131236024edd9fdd8 + schemas: + RequestId: + type: string + format: uuid + description: Identifies one identification. The browser creates it as a UUID v4 and hands it to your page; it is the join key between the browser, the webhook and the History API. The nil UUID appears only on rate-limit marker rows that arrived with a malformed request ID. + examples: + - a5b7c9d1-e3f5-4a7b-9c1d-3e5f7a9b1c3d + SessionId: + type: string + format: uuid + description: One visit on one origin (UUID v4 created in the browser), shared by the open tabs of that origin. The next visit after the last tab closes gets a new session ID. The nil UUID appears on rate-limit marker rows. + examples: + - b6c8d0e2-f4a6-4b8c-8d0e-2f4a6b8c0d2e + CookieId: + type: string + format: uuid + description: First-party browser identifier kept by the ShieldLabs agent (UUID v4). A missing or malformed value is stored as the nil UUID. + examples: + - c7d9e1f3-a5b7-4c9d-ae1f-3a5b7c9d1e3f + DeviceId: + type: string + format: uuid + description: 'Server-side device identifier (UUID v5). It survives cleared cookies and private windows. The nil UUID `00000000-0000-0000-0000-000000000000` means that no usable device signals were collected (for example on rate-limit marker rows): never group identifications by it.' + examples: + - d8e0f2a4-b6c8-4d0e-bf2a-4b6c8d0e2f4a + - 00000000-0000-0000-0000-000000000000 + VisitorId: + type: string + format: uuid + description: 'Server-side visitor identifier (UUID v5). It is sticky to the device: a new cookie on a known device keeps the existing visitor ID, so clearing cookies usually does not change it. The nil UUID appears on identifications without usable device data, such as rate-limit marker rows.' + examples: + - e9f1a3b5-c7d9-4e1f-8a3b-5c7d9e1f3a5b + Ipv4: + type: string + format: ipv4 + description: Dotted IPv4 address. `0.0.0.0` when no IPv4 address is known (for example for visitors on IPv6); such identifications cannot be searched by IP. + examples: + - 203.0.113.24 + - 0.0.0.0 + OperatingSystem: + type: string + description: 'Operating system name, for example `Windows`, `Mac OS X`, `Linux`, `Android`, `IOS (iPhone)`, `IOS (iPad)`, `ChromeOS` or `Unknown`. Open set: display it, do not branch on it.' + examples: + - Windows + - Mac OS X + - Android + Browser: + type: string + description: 'Browser name, for example `Chrome`, `Safari`, `Firefox`, `Microsoft Edge`, `Opera`, `Samsung Internet`, `Brave`, `Chrome (iOS)`, `Safari (iOS)` or `Unknown`. Open set: display it, do not branch on it.' + examples: + - Chrome + - Safari + DeviceType: + type: string + description: 'Device class from the browser. Known values: `desktop`, `mobile`, `tablet` and `unknown` (the class could not be determined). The set is open: keep values added in later versions and treat them as `unknown`.' + x-extensible-enum: + - desktop + - mobile + - tablet + - unknown + examples: + - desktop + Country: + type: string + description: English country name from IP intelligence, for example `Germany` or `United States` (not an ISO code). Empty string when the country is unknown. + examples: + - Netherlands + - United States + - '' + ConnectionType: + type: string + description: |- + How the visitor connected. Known values: + - `direct`: a regular connection; + - `mobile`: a mobile carrier network; + - `vpn`: a VPN; + - `proxy`: a proxy, datacenter or hosting network (search-engine crawlers are reported here too); + - `tor`: the Tor network; + - `privacy_relay`: a privacy relay such as iCloud Private Relay; + - `browser_vpn_proxy`: a VPN or proxy built into the browser or one of its extensions; + - `unknown`: not enough data. + + The value can say `vpn` while `detection_flags.vpn` is `false` (IP intelligence classified the + network, but the scored VPN check did not fire). Branch on `detection_flags` for decisions. + The set is open: keep values added in later versions and treat them as `unknown`. + x-extensible-enum: + - direct + - mobile + - vpn + - proxy + - tor + - privacy_relay + - browser_vpn_proxy + - unknown + examples: + - direct + RiskScore: + type: integer + minimum: 0 + description: |- + Risk Score from 0 (no risk found) to 100. Search-engine crawlers always score 0. + + Risk bands are computed on your side from the score; no band field exists on the wire: + - trusted: 0-29 + - suspicious: 30-59 + - dangerous: 60-100 + + A value above 100 is not a score. `999` is the rate-limit marker: the visitor's IP went over the + ingest rate limit, and the identification carries exactly one signal, + `{"name":"rate_limited","weight":999}`, usually with nil identifiers. Treat every value above + 100 as rate limited. One marker is written when the IP goes over the limit; request IDs issued + while it stays blocked get no row and no webhook, so they stay unverified. + + The score usually equals the sum of the signal weights capped at 100, but carried-forward + verdicts and corrections make that unreliable: never recompute or validate it yourself. + examples: + - 0 + - 35 + - 80 + - 999 + ScoreDetail: + type: object + description: One entry behind the score, in the PascalCase shape the server stores. `Value` is the weight (0 for informational entries); `Description` is free text for display, never branch on it. + required: + - Value + - Description + properties: + Value: + type: integer + description: Weight of the entry. Can be negative; 0 for informational entries. + examples: + - 10 + Description: + type: string + description: Human-readable description, for example `Is proxy` or `Antidetect browser (turn_block)`. + examples: + - Is proxy + HistoryTimestamp: + type: string + pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]{3})?$ + description: Time of the identification as `YYYY-MM-DD HH:MM:SS.mmm` in UTC, without a zone designator (not RFC 3339). Older rows can lack the milliseconds. + examples: + - '2026-09-30 12:34:56.123' + - '2026-09-30 13:05:12' + NetworkClass: + type: string + description: 'Connection class of one IP address from IP intelligence. Known values: `direct`, `mobile`, `vpn`, `proxy`, `tor`, `privacy_relay` and the empty string when unknown. The set is open: keep values added in later versions.' + x-extensible-enum: + - direct + - mobile + - vpn + - proxy + - tor + - privacy_relay + - '' + examples: + - direct + TrafficChannel: + type: string + description: 'Marketing channel of the visit. Known values: `Google Ads`, `Meta`, `TikTok`, `LinkedIn`, `X`, `Pinterest`, `Microsoft Ads`, `Organic Search`, `Search bot`, `Referral`, `Direct`, `Other` and the empty string. Resolved in this order: a click ID, then UTM parameters, then the referrer (search engines give `Organic Search`, social networks give the platform name, other sites give `Referral`), otherwise `Direct`. Search-engine crawlers get `Search bot`. Empty string on identifications without attribution, such as rate-limit marker rows. The set is open: keep values added in later versions and treat them as `Other`.' + x-extensible-enum: + - Google Ads + - Meta + - TikTok + - LinkedIn + - X + - Pinterest + - Microsoft Ads + - Organic Search + - Search bot + - Referral + - Direct + - Other + - '' + examples: + - Google Ads + - Direct + TrafficChannelGroup: + type: string + description: 'Group of the marketing channel. Known values: `Paid Search`, `Paid Social`, `Organic`, `Bot`, `Social`, `Referral`, `Direct` and `Other`. History API only; not part of the webhook. The set is open: keep values added in later versions and treat them as `Other`.' + x-extensible-enum: + - Paid Search + - Paid Social + - Organic + - Bot + - Social + - Referral + - Direct + - Other + examples: + - Paid Search + TrafficReason: + type: string + description: 'Why the channel was chosen. Known values: `gclid_present`, `msclkid_present`, `ttclid_present`, `fbclid_present`, `utm_match`, `referrer_search_engine`, `ip_crawler_detected`, `referrer_social`, `external_referrer` and `no_source_detected`. History API only; not part of the webhook. The set is open: keep values added in later versions.' + x-extensible-enum: + - gclid_present + - msclkid_present + - ttclid_present + - fbclid_present + - utm_match + - referrer_search_engine + - ip_crawler_detected + - referrer_social + - external_referrer + - no_source_detected + examples: + - gclid_present + ClickIdType: + type: string + description: 'Ad click identifier found in the landing URL. Known values: `gclid`, `gbraid`, `wbraid`, `msclkid`, `ttclid`, `fbclid` and the empty string when there is none. `fbclid` counts only together with a Meta referrer or a Meta `utm_source`. The set is open: keep values added in later versions.' + x-extensible-enum: + - gclid + - gbraid + - wbraid + - msclkid + - ttclid + - fbclid + - '' + examples: + - gclid + - '' + HistoryRow: + type: object + additionalProperties: true + description: |- + One identification as stored, in its latest version. It describes the same identification as a + webhook `data` object, with different field names: + + | Webhook `data` | History row | + |---|---| + | `risk_score` | `score` | + | `signals` | `score_details` (JSON-encoded string, zero weights included) | + | `detection_flags` | the `is_*` columns and `check_incomplete` (each column names its flag) | + | `detection_flags.browser_vpn_proxy` | derive it: `connection_type == "browser_vpn_proxy"` | + | `domain` | `site_domain` when present, otherwise `domain` | + | `public_ip` | `ip` (`0.0.0.0` instead of `""`) and `country` | + | `local_ip` | `webrtc_leak_ip` and `webrtc_leak_country` when `webrtc_leak_source` is set and not `none`, otherwise `web_rtc_ip` and `web_rtc_country` | + | `traffic_source` | `traffic_channel`, `referrer_domain`, `entry_url`, `click_id_type`, `utm_*` (omitted when empty) | + | `observed_at` (when scoring finished) | `created_at` (when the identification was made) | + + The `ip_mismatch` flag has no column. Rows also carry diagnostic network fields (TCP, MTU and + STUN measurements) that are not part of the stable contract: ignore fields you do not know. + required: + - request_id + - session_id + - cookie_id + - domain + - user_hid + - device_id + - visitor_id + - ip + - os + - browser + - device_type + - country + - connection_type + - score + - score_details + - created_at + - ver + - web_rtc_ip + - web_rtc_country + - web_rtc_connection_type + - webrtc_leak_ip + - webrtc_leak_country + - webrtc_leak_connection_type + - webrtc_leak_source + - is_vpn + - is_tor + - is_proxy + - is_datacenter + - is_abuser + - is_privacy_relay + - is_stun_not_checked + - check_incomplete + - is_antidetect + - is_os_mismatch + - is_os_not_detected + - is_timezone_mismatch + - is_js_disabled + - is_browser_automation + - is_incognito + - is_search_bot + properties: + request_id: + $ref: '#/components/schemas/RequestId' + session_id: + $ref: '#/components/schemas/SessionId' + cookie_id: + $ref: '#/components/schemas/CookieId' + domain: + type: string + description: Host the identification came from. Can be a subdomain of your registered domain. + examples: + - shop.example.com + site_domain: + type: string + description: Your registered domain, present when the identification came from a subdomain. Omitted when empty. + examples: + - example.com + user_hid: + type: string + description: User HID exactly as it was passed to the agent (hashed or pseudonymous account identifier). `anonymous` for anonymous checks; `fail`, `-1` and `unknown` also mean "no user". Empty string when no value was stored. Leave the empty string and these values out when you count accounts. + examples: + - 9f86d081884c7d659a2feaa0c55ad015 + - anonymous + device_id: + $ref: '#/components/schemas/DeviceId' + visitor_id: + $ref: '#/components/schemas/VisitorId' + ip: + $ref: '#/components/schemas/Ipv4' + description: Public IPv4 address of the HTTP request; `0.0.0.0` when none (for example IPv6 visitors). + os: + $ref: '#/components/schemas/OperatingSystem' + browser: + $ref: '#/components/schemas/Browser' + device_type: + $ref: '#/components/schemas/DeviceType' + country: + $ref: '#/components/schemas/Country' + description: Country of `ip` as an English country name, or an empty string. + connection_type: + $ref: '#/components/schemas/ConnectionType' + score: + $ref: '#/components/schemas/RiskScore' + score_details: + type: string + contentMediaType: application/json + contentSchema: + type: array + items: + $ref: '#/components/schemas/ScoreDetail' + description: |- + The entries behind `score` as a JSON-encoded **string** holding an array of + `{"Value": , "Description": }`. Parse it before use. Scored entries come + first, followed by informational entries with `Value` 0, which can be long. Empty string + when no details were stored. + + The webhook `signals` are the entries with a non-zero `Value`, in the same order, with each + description turned into a signal name (for example `Is proxy` becomes `proxy`). Descriptions + are free text for display: never branch on them. + examples: + - '[{"Value":10,"Description":"Is proxy"},{"Value":0,"Description":"Check Incomplete"}]' + - '' + created_at: + $ref: '#/components/schemas/HistoryTimestamp' + ver: + type: integer + format: int64 + description: Version of the row in Unix milliseconds. It increases every time the row is refined, for example when late network data re-scores it after the webhook was sent. + examples: + - 1790771696123 + web_rtc_ip: + $ref: '#/components/schemas/Ipv4' + description: Local IP address observed by the ShieldLabs network check; `0.0.0.0` when none. + web_rtc_country: + $ref: '#/components/schemas/Country' + description: Country of `web_rtc_ip`, or an empty string. + web_rtc_connection_type: + $ref: '#/components/schemas/NetworkClass' + description: Connection class of `web_rtc_ip`, or an empty string. + webrtc_leak_ip: + $ref: '#/components/schemas/Ipv4' + description: Local network address leaked by the browser; `0.0.0.0` when none. + webrtc_leak_country: + $ref: '#/components/schemas/Country' + description: Country of `webrtc_leak_ip`, or an empty string. + webrtc_leak_connection_type: + $ref: '#/components/schemas/NetworkClass' + description: Connection class of `webrtc_leak_ip`, or an empty string. + webrtc_leak_source: + type: string + description: 'Which check found the local network leak. Known values: `scanner`, `shield`, `none` and the empty string. `none` or an empty string when there is no leak; the webhook `local_ip` then uses `web_rtc_ip`. The set is open: keep values added in later versions.' + x-extensible-enum: + - scanner + - shield + - none + - '' + examples: + - none + is_vpn: + type: boolean + description: Same meaning as `detection_flags.vpn`. + is_tor: + type: boolean + description: Same meaning as `detection_flags.tor`. + is_proxy: + type: boolean + description: Same meaning as `detection_flags.proxy`. + is_datacenter: + type: boolean + description: Same meaning as `detection_flags.datacenter_ip`. + is_abuser: + type: boolean + description: Same meaning as `detection_flags.abuser`. + is_privacy_relay: + type: boolean + description: Same meaning as `detection_flags.privacy_relay`. + is_stun_not_checked: + type: boolean + description: Same meaning as `detection_flags.stun_not_checked`. + check_incomplete: + type: boolean + description: Same meaning as `detection_flags.check_incomplete`. Always `false` for search-engine crawlers. + is_antidetect: + type: boolean + description: Same meaning as `detection_flags.anti_detect_browser`. + is_os_mismatch: + type: boolean + description: Same meaning as `detection_flags.os_mismatch`. + is_os_not_detected: + type: boolean + description: Same meaning as `detection_flags.os_not_detected`. + is_timezone_mismatch: + type: boolean + description: Same meaning as `detection_flags.timezone_mismatch`. + is_js_disabled: + type: boolean + description: Same meaning as `detection_flags.javascript_disabled`. Always `false` for search-engine crawlers. + is_browser_automation: + type: boolean + description: Same meaning as `detection_flags.browser_automation`. + is_incognito: + type: boolean + description: Same meaning as `detection_flags.incognito`. Always `false` for search-engine crawlers. + is_search_bot: + type: boolean + description: Same meaning as `detection_flags.search_bot`. + is_suspicious_paid_click: + type: boolean + description: Same meaning as `detection_flags.suspicious_paid_click`. Omitted when `false`. + entry_url: + type: string + description: Landing page URL without the `#fragment` (webhook `traffic_source.landing_url`). Omitted when empty. It keeps the query string, which can contain personal data. + examples: + - https://shop.example.com/signup?utm_source=google&utm_medium=cpc&gclid=abc123 + utm_source: + type: string + description: '`utm_source`, lowercased. Omitted when empty.' + examples: + - google + utm_medium: + type: string + description: '`utm_medium`, lowercased. Omitted when empty.' + examples: + - cpc + utm_campaign: + type: string + description: '`utm_campaign` as sent. Omitted when empty.' + examples: + - spring_launch + utm_content: + type: string + description: '`utm_content` as sent. Omitted when empty.' + examples: + - banner_a + utm_term: + type: string + description: '`utm_term` as sent. Omitted when empty.' + examples: + - device intelligence + traffic_channel: + $ref: '#/components/schemas/TrafficChannel' + description: Marketing channel (webhook `traffic_source.channel`). Omitted when empty. + traffic_channel_group: + $ref: '#/components/schemas/TrafficChannelGroup' + description: Group of the marketing channel. Omitted when empty. + traffic_reason: + $ref: '#/components/schemas/TrafficReason' + description: Why the channel was chosen. Omitted when empty. + referrer_domain: + type: string + description: Registrable domain of the referrer without `www.`; the crawler name (for example `GoogleBot`) for search-engine crawlers. Omitted when empty. + examples: + - news.example.org + click_id_type: + $ref: '#/components/schemas/ClickIdType' + description: Ad click identifier type found in the landing URL. Omitted when empty. + HistoryPage: + type: object + description: One page of identifications, newest first. + required: + - data + - total + properties: + data: + type: array + description: Identifications on this page, ordered by `created_at` descending. Empty when nothing matched. + items: + $ref: '#/components/schemas/HistoryRow' + total: + type: integer + minimum: 0 + description: Number of identifications that match the search in total, across all pages. Page with `offset` while it is below `total`. + examples: + - 37 + ErrorBody: + type: object + description: Error object sent by the History API and by the Management API rate and load limits. + required: + - error + properties: + error: + type: string + description: Human-readable error message. Branch on the HTTP status, not on this text. + examples: + - too many requests + ErrorBodyText: + type: string + contentMediaType: application/json + contentSchema: + $ref: '#/components/schemas/ErrorBody' + description: 'JSON text followed by a newline, sent with `Content-Type: text/plain; charset=utf-8`. Parse it as JSON: it holds `{"error": "..."}`.' + examples: + - | + {"error":"invalid api key"} + PlainText: + type: string + description: Plain text body. + examples: + - 404 page not found + HtmlText: + type: string + description: HTML error page from the edge proxy. Do not parse it; branch on the status. + examples: + -

502 Bad Gateway

+ MaskedKey: + type: string + pattern: ^(\*+.{4}|.{0,4})$ + description: A key with every character except the last four replaced by `*`, keeping the original length. Keys of four characters or fewer are returned as they are. + examples: + - '****************************a3f8' + DomainProfile: + type: object + description: Profile of the registered domain. The keys are PascalCase on the wire. Ignore keys you do not know. + required: + - Domain + - Weight + - Callback + - PublicKey + - Secret + - CreatedAt + properties: + Domain: + type: string + description: The registered domain, as sent in `X-Shield-Domain`. + examples: + - example.com + Weight: + type: integer + description: Remaining included identifications of the account (shared by its domains). Can be negative when the account is over its included volume. + examples: + - 148230 + Callback: + type: string + description: 'Legacy field kept for compatibility, normally an empty string. Webhook deliveries do not use it: configure webhook endpoints in the analytics dashboard.' + examples: + - '' + PublicKey: + $ref: '#/components/schemas/MaskedKey' + description: The domain's Public Key, masked. + Secret: + $ref: '#/components/schemas/MaskedKey' + description: The domain's Secret Key, masked. + CreatedAt: + type: string + format: date-time + description: When the domain was registered, RFC 3339 in UTC with second precision. `0001-01-01T00:00:00Z` when unknown. + examples: + - '2026-01-15T09:00:00Z' + LegacySnapshot: + type: object + additionalProperties: true + description: One identification as returned by the deprecated Management API history endpoint (PascalCase keys). Also carries diagnostic network fields that are not part of the stable contract. Use the History API row instead. + required: + - RequestID + - SessionID + - CookieID + - DeviceID + - VisitorID + - IP + - ConnectionType + - WebRtcHIP + - WebRtcCountry + - WebRtcConnectionType + - OS + - Browser + - DeviceType + - Country + - UserHID + - Score + - Details + - LastRequestTime + properties: + RequestID: + $ref: '#/components/schemas/RequestId' + SessionID: + $ref: '#/components/schemas/SessionId' + CookieID: + $ref: '#/components/schemas/CookieId' + DeviceID: + $ref: '#/components/schemas/DeviceId' + VisitorID: + $ref: '#/components/schemas/VisitorId' + IP: + $ref: '#/components/schemas/Ipv4' + description: Public IPv4 address of the HTTP request. + ConnectionType: + $ref: '#/components/schemas/ConnectionType' + WebRtcHIP: + $ref: '#/components/schemas/Ipv4' + description: Local IP address observed by the ShieldLabs network check (not hashed); `0.0.0.0` when none. + WebRtcCountry: + $ref: '#/components/schemas/Country' + description: Country of `WebRtcHIP`, or an empty string. + WebRtcConnectionType: + $ref: '#/components/schemas/NetworkClass' + description: Connection class of `WebRtcHIP`, or an empty string. + OS: + $ref: '#/components/schemas/OperatingSystem' + Browser: + $ref: '#/components/schemas/Browser' + DeviceType: + $ref: '#/components/schemas/DeviceType' + Country: + $ref: '#/components/schemas/Country' + description: Country of `IP` as an English country name, or an empty string. + UserHID: + type: string + description: User HID as passed to the agent; `anonymous` for anonymous checks. + examples: + - 9f86d081884c7d659a2feaa0c55ad015 + Score: + $ref: '#/components/schemas/RiskScore' + Details: + type: array + description: Every entry behind `Score`, informational entries with `Value` 0 included (unlike the History API, this is a parsed array, not a string). + items: + $ref: '#/components/schemas/ScoreDetail' + LastRequestTime: + type: string + format: date-time + description: Time of the identification, RFC 3339 with fractional seconds. + examples: + - '2026-09-30T12:34:56.123Z' + LegacyErrorMessage: + type: + - string + - 'null' + description: A bare JSON string with the error message, or the JSON literal `null` (an unexpected database error, for example for an IPv6 value). + examples: + - fail parse uuid + - null + HealthStatus: + type: object + description: Liveness status. + required: + - status + properties: + status: + type: string + const: ok + description: Always `ok` when the service answers. + SchemaVersion: + type: string + minLength: 1 + description: Version of the webhook payload contract. Every event sent today carries `2026-06-01`. Accept other values, so that a future version does not break your handler. + examples: + - '2026-06-01' + Rfc3339Timestamp: + type: string + format: date-time + pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]{1,9})?Z$ + description: RFC 3339 timestamp in UTC with up to 9 fractional digits (trailing zeros trimmed), for example `2026-09-30T12:34:57.482913041Z`. Parse it with a parser that accepts nanoseconds. + examples: + - '2026-09-30T12:34:57.482913041Z' + - '2026-09-30T12:34:56Z' + UserHid: + type: + - string + - 'null' + description: |- + User HID: your hashed or pseudonymous account identifier, exactly as it was passed to the + ShieldLabs agent. Pass a hashed value, never a raw email address or database ID. + + Values that do not identify a user: + - `anonymous`: an anonymous check; + - `fail`: the agent sent no value; + - `-1` and `unknown`: rows created by ShieldLabs itself, such as rate-limit marker rows. + + `null` only when the stored value is an empty string. Leave `null` and the values above out + when you count the accounts of one device, visitor or IP address. + examples: + - 9f86d081884c7d659a2feaa0c55ad015 + - anonymous + - null + Ipv4OrEmpty: + type: string + pattern: ^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})?$ + description: Dotted IPv4 address, or an empty string when no IPv4 address is known (for example for visitors on IPv6). + examples: + - 203.0.113.24 + - '' + IpInfo: + type: object + description: An IPv4 address and its country. Both keys are always present and can be empty strings. + required: + - ip + - country + properties: + ip: + $ref: '#/components/schemas/Ipv4OrEmpty' + country: + $ref: '#/components/schemas/Country' + TrafficSource: + type: object + description: Where the visit came from. All nine keys are always present; values can be empty strings. + required: + - channel + - referrer_domain + - landing_url + - click_id_type + - utm_source + - utm_medium + - utm_campaign + - utm_content + - utm_term + properties: + channel: + $ref: '#/components/schemas/TrafficChannel' + referrer_domain: + type: string + description: Registrable domain of the referrer without `www.`. For search-engine crawlers, the crawler name (for example `GoogleBot`). + examples: + - google.com + landing_url: + type: string + description: 'Landing page URL without the `#fragment`. It keeps the query string, which can contain personal data: store it with care.' + examples: + - https://shop.example.com/signup?utm_source=google&utm_medium=cpc&gclid=abc123 + click_id_type: + $ref: '#/components/schemas/ClickIdType' + utm_source: + type: string + description: '`utm_source` query parameter, lowercased.' + examples: + - google + utm_medium: + type: string + description: '`utm_medium` query parameter, lowercased.' + examples: + - cpc + utm_campaign: + type: string + description: '`utm_campaign` query parameter as sent.' + examples: + - spring_launch + utm_content: + type: string + description: '`utm_content` query parameter as sent.' + examples: + - '' + utm_term: + type: string + description: '`utm_term` query parameter as sent.' + examples: + - '' + Signal: + type: object + description: One weighted risk signal behind the Risk Score. Only signals with a non-zero weight are listed, in scoring order. The same name can appear twice, and weights can be negative. + required: + - name + - weight + properties: + name: + type: string + minLength: 1 + description: |- + Signal name. The set is open: new names can appear at any time, so keep unknown names and + use them for display and logging only. Known names: + - `tor`: the request came through Tor; + - `vpn`: a VPN was detected; + - `privacy_relay`: a privacy relay such as iCloud Private Relay; + - `proxy`: a proxy was detected; + - `datacenter_ip`: the IP belongs to a datacenter or hosting range; + - `abuser`: the IP has a record of abuse; + - `browser_vpn_proxy`: a VPN or proxy inside the browser; + - `antidetect_browser`: an anti-detect browser (the matching flag is `anti_detect_browser`); + - `proxy_routed_antidetect`: the network check was routed through a proxy in a way typical + for anti-detect browsers; + - `port_scan_routed_via_proxy`: `proxy_routed_antidetect` carried forward from an earlier + identification of the same device and IP; + - `browser_automation`: browser automation, for example a WebDriver-controlled browser; + - `javascript_disabled`: JavaScript or the browser APIs the checks need were unavailable; + - `os_mismatch`: the operating system seen on the network differs from the one the browser + reports; + - `os_not_detected`: the operating system could not be determined; + - `timezone_mismatch`: the browser timezone differs from the IP location timezone; + - `stun_not_checked`: the network (STUN) check did not complete; + - `stun_late_correction`: a late network result arrived; negative weight that cancels + `stun_not_checked`; + - `rate_limited`: the rate-limit marker, weight 999. + + A verdict carried forward from an earlier identification of the same device and IP (for + example `antidetect_browser`) keeps a name derived from the original signal and can carry a + partial weight. + examples: + - proxy + - antidetect_browser + weight: + type: integer + description: Points the signal contributed. Can be negative (`stun_late_correction` is -30) and is 999 for `rate_limited`. Weights can change between releases; never add them up yourself. + examples: + - 10 + - -30 + DetectionFlags: + type: object + description: |- + Stable yes/no verdicts for the identification. Always all 19 keys. Branch on these flags and on + the Risk Score; signal names are for display and logging. + + When `search_bot` is `true`, `incognito`, `check_incomplete`, `ip_mismatch` and + `javascript_disabled` are always `false`. + required: + - vpn + - privacy_relay + - browser_vpn_proxy + - tor + - proxy + - datacenter_ip + - abuser + - os_mismatch + - os_not_detected + - timezone_mismatch + - anti_detect_browser + - browser_automation + - ip_mismatch + - incognito + - search_bot + - suspicious_paid_click + - javascript_disabled + - stun_not_checked + - check_incomplete + properties: + vpn: + type: boolean + description: A VPN was detected (scored `vpn` signal). + privacy_relay: + type: boolean + description: A privacy relay such as iCloud Private Relay was detected. + browser_vpn_proxy: + type: boolean + description: A VPN or proxy built into the browser or one of its extensions. `true` exactly when `connection_type` is `browser_vpn_proxy`. + tor: + type: boolean + description: The request came through the Tor network. + proxy: + type: boolean + description: A proxy was detected. + datacenter_ip: + type: boolean + description: The public IP belongs to a datacenter or hosting range. + abuser: + type: boolean + description: The public IP has a record of abuse in IP intelligence. + os_mismatch: + type: boolean + description: The operating system seen on the network differs from the one the browser reports. + os_not_detected: + type: boolean + description: The operating system could not be determined from the User-Agent or the network. + timezone_mismatch: + type: boolean + description: The browser timezone differs from the timezone of the IP location. + anti_detect_browser: + type: boolean + description: An anti-detect browser was detected. + browser_automation: + type: boolean + description: Browser automation was detected, for example a WebDriver-controlled browser. + ip_mismatch: + type: boolean + description: 'The public IP differs from the local IP found by the browser network check. Informational: it does not add to the score.' + incognito: + type: boolean + description: The browser runs in a private window. + search_bot: + type: boolean + description: A search-engine crawler. Its Risk Score is always 0. + suspicious_paid_click: + type: boolean + description: The visit came from a paid ad click (Google Ads, Meta, TikTok, Microsoft Ads, LinkedIn, Pinterest or X) and the Risk Score is 60 or more (the 999 marker included). + javascript_disabled: + type: boolean + description: JavaScript, or the browser APIs the checks need, were unavailable. + stun_not_checked: + type: boolean + description: The browser network (STUN) check did not complete. Cleared again when a late network result arrives. + check_incomplete: + type: boolean + description: Part of the browser checks timed out, so the verdict rests on partial data. Informational. + IdentificationScoredData: + type: object + description: The scored identification. Every key is always present (no key is ever omitted); only `user_hid` can be `null`. + required: + - request_id + - visitor_id + - device_id + - session_id + - cookie_id + - user_hid + - domain + - public_ip + - local_ip + - connection_type + - os + - browser + - device_type + - traffic_source + - risk_score + - signals + - detection_flags + - observed_at + properties: + request_id: + $ref: '#/components/schemas/RequestId' + visitor_id: + $ref: '#/components/schemas/VisitorId' + device_id: + $ref: '#/components/schemas/DeviceId' + session_id: + $ref: '#/components/schemas/SessionId' + cookie_id: + $ref: '#/components/schemas/CookieId' + user_hid: + $ref: '#/components/schemas/UserHid' + domain: + type: string + description: Registered domain of your site (the request host when no registered domain matched). + examples: + - example.com + public_ip: + $ref: '#/components/schemas/IpInfo' + description: Public IPv4 address of the HTTP request and its country. `ip` is empty when the request did not arrive over IPv4. + local_ip: + $ref: '#/components/schemas/IpInfo' + description: 'Local IP address found by the browser network check (WebRTC): the leaked address when a local network leak was found, otherwise the address ShieldLabs observed. Both keys are empty when the check found nothing.' + connection_type: + $ref: '#/components/schemas/ConnectionType' + os: + $ref: '#/components/schemas/OperatingSystem' + browser: + $ref: '#/components/schemas/Browser' + device_type: + $ref: '#/components/schemas/DeviceType' + traffic_source: + $ref: '#/components/schemas/TrafficSource' + risk_score: + $ref: '#/components/schemas/RiskScore' + signals: + type: array + description: Weighted risk signals behind `risk_score`, in scoring order. Can be empty. The rate-limit marker carries exactly one entry, `{"name":"rate_limited","weight":999}`. + items: + $ref: '#/components/schemas/Signal' + detection_flags: + $ref: '#/components/schemas/DetectionFlags' + observed_at: + $ref: '#/components/schemas/Rfc3339Timestamp' + description: When scoring finished and the event was built (not the page view time); identical to the envelope `created_at`. RFC 3339 in UTC with up to 9 fractional digits. + IdentificationScoredEvent: + type: object + description: 'Body of an `identification.scored` delivery. The signature is not part of the body: it arrives in the `X-Shield-Signature` header.' + required: + - event_type + - schema_version + - created_at + - data + properties: + event_type: + type: string + const: identification.scored + description: Event type. Ignore events whose type you do not know instead of failing. + schema_version: + $ref: '#/components/schemas/SchemaVersion' + created_at: + $ref: '#/components/schemas/Rfc3339Timestamp' + description: When the event was built. Equal to `data.observed_at`. + data: + $ref: '#/components/schemas/IdentificationScoredData' + WebhookPingEvent: + type: object + description: Body of a `webhook.ping` delivery, sent when you verify an endpoint. It has no `data`. The keys arrive sorted alphabetically and `created_at` has second precision. + required: + - event_type + - schema_version + - created_at + properties: + event_type: + type: string + const: webhook.ping + description: Event type. + schema_version: + $ref: '#/components/schemas/SchemaVersion' + created_at: + $ref: '#/components/schemas/Rfc3339Timestamp' + description: When the ping was sent, with second precision. + examples: + HistoryPage: + summary: Five identifications + description: 'One page of five identifications out of 37 matches: a dangerous paid click through a proxy with an anti-detect browser, a trusted anonymous visit, a VPN visit with a local network leak and a late network correction, a rate-limit marker (999) and a search-engine crawler.' + value: + data: + - request_id: a5b7c9d1-e3f5-4a7b-9c1d-3e5f7a9b1c3d + session_id: b6c8d0e2-f4a6-4b8c-8d0e-2f4a6b8c0d2e + cookie_id: c7d9e1f3-a5b7-4c9d-ae1f-3a5b7c9d1e3f + domain: shop.example.com + site_domain: example.com + user_hid: 9f86d081884c7d659a2feaa0c55ad015 + device_id: d8e0f2a4-b6c8-4d0e-bf2a-4b6c8d0e2f4a + visitor_id: e9f1a3b5-c7d9-4e1f-8a3b-5c7d9e1f3a5b + ip: 203.0.113.24 + os: Windows + browser: Chrome + device_type: desktop + country: Netherlands + connection_type: proxy + score: 80 + score_details: '[{"Value":10,"Description":"Is proxy"},{"Value":10,"Description":"Is datacenter"},{"Value":60,"Description":"Antidetect browser (turn_block)"},{"Value":0,"Description":"Check Incomplete"}]' + created_at: '2026-09-30 12:34:56.123' + ver: 1790771696123 + web_rtc_ip: 198.51.100.23 + web_rtc_country: Germany + web_rtc_connection_type: direct + scanner_web_rtc_ip: 0.0.0.0 + scanner_web_rtc_country: '' + scanner_web_rtc_connection_type: '' + webrtc_leak_ip: 0.0.0.0 + webrtc_leak_country: '' + webrtc_leak_connection_type: '' + webrtc_leak_source: none + tcp_mss: 1460 + mtu_value: 1500 + mtu_hint: direct + is_vpn: false + is_tor: false + is_proxy: true + is_datacenter: true + is_abuser: false + is_privacy_relay: false + is_stun_not_checked: false + check_incomplete: false + is_antidetect: true + is_os_mismatch: false + is_os_not_detected: false + is_timezone_mismatch: false + is_js_disabled: false + is_browser_automation: false + is_incognito: false + is_search_bot: false + stun_request_seen: true + is_scanner_stun_passed: false + stun_flow_status: ok + entry_url: https://shop.example.com/signup?utm_source=google&utm_medium=cpc&gclid=abc123 + utm_source: google + utm_medium: cpc + traffic_channel: Google Ads + traffic_channel_group: Paid Search + traffic_reason: gclid_present + click_id_type: gclid + is_suspicious_paid_click: true + - request_id: 7c1e2f4a-3b6d-4e8f-9a0b-1c2d3e4f5a6b + session_id: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d + cookie_id: f0e1d2c3-b4a5-4968-8776-655443322110 + domain: example.com + user_hid: anonymous + device_id: 5d9a1f3e-7b2c-5e4d-8f6a-9b0c1d2e3f4a + visitor_id: 3c4d5e6f-7a8b-5c9d-8e0f-1a2b3c4d5e6f + ip: 192.0.2.44 + os: Mac OS X + browser: Safari + device_type: desktop + country: United States + connection_type: direct + score: 10 + score_details: '[{"Value":10,"Description":"Browser timezone ≠ IP-timezone"}]' + created_at: '2026-09-30 12:40:01.007' + ver: 1790772001007 + web_rtc_ip: 192.0.2.44 + web_rtc_country: United States + web_rtc_connection_type: direct + scanner_web_rtc_ip: 0.0.0.0 + scanner_web_rtc_country: '' + scanner_web_rtc_connection_type: '' + webrtc_leak_ip: 0.0.0.0 + webrtc_leak_country: '' + webrtc_leak_connection_type: '' + webrtc_leak_source: '' + tcp_mss: 1460 + mtu_value: 1500 + mtu_hint: direct + is_vpn: false + is_tor: false + is_proxy: false + is_datacenter: false + is_abuser: false + is_privacy_relay: false + is_stun_not_checked: false + check_incomplete: false + is_antidetect: false + is_os_mismatch: false + is_os_not_detected: false + is_timezone_mismatch: true + is_js_disabled: false + is_browser_automation: false + is_incognito: true + is_search_bot: false + stun_request_seen: true + is_scanner_stun_passed: false + stun_flow_status: ok + - request_id: 9e8d7c6b-5a49-4382-9716-05f4e3d2c1b0 + session_id: b0c1d2e3-f4a5-4b6c-9d7e-8f9a0b1c2d3e + cookie_id: c3d4e5f6-a7b8-4c9d-8e0f-a1b2c3d4e5f6 + domain: example.com + user_hid: '' + device_id: e1f2a3b4-c5d6-5e7f-8a9b-0c1d2e3f4a5b + visitor_id: d2e3f4a5-b6c7-5d8e-9f0a-1b2c3d4e5f6a + ip: 198.51.100.7 + os: Android + browser: Chrome + device_type: mobile + country: France + connection_type: vpn + score: 45 + score_details: '[{"Value":15,"Description":"Is VPN"},{"Value":30,"Description":"Stun is not checked"},{"Value":-30,"Description":"Stun passed (late arrival, corrected)"},{"Value":30,"Description":"Sticky verdict: Stun is not checked (request 11111111-2222-4333-8444-555555555555)"},{"Value":0,"Description":"IP ≠ leakIP (198.51.100.7 ≠ 203.0.113.9, source=scanner)"}]' + created_at: '2026-09-30 13:05:12' + ver: 1790773512000 + web_rtc_ip: 0.0.0.0 + web_rtc_country: '' + web_rtc_connection_type: '' + scanner_web_rtc_ip: 203.0.113.9 + scanner_web_rtc_country: Spain + scanner_web_rtc_connection_type: direct + webrtc_leak_ip: 203.0.113.9 + webrtc_leak_country: Spain + webrtc_leak_connection_type: direct + webrtc_leak_source: scanner + tcp_mss: 1380 + mtu_value: 1420 + mtu_hint: vpn_likely + is_vpn: true + is_tor: false + is_proxy: false + is_datacenter: false + is_abuser: false + is_privacy_relay: false + is_stun_not_checked: true + check_incomplete: true + is_antidetect: false + is_os_mismatch: false + is_os_not_detected: false + is_timezone_mismatch: false + is_js_disabled: false + is_browser_automation: false + is_incognito: false + is_search_bot: false + stun_request_seen: false + is_scanner_stun_passed: true + stun_flow_status: reply_without_request + entry_url: https://example.com/pricing + referrer_domain: news.example.org + traffic_channel: Referral + traffic_channel_group: Referral + traffic_reason: external_referrer + - request_id: 1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d + session_id: 00000000-0000-0000-0000-000000000000 + cookie_id: 00000000-0000-0000-0000-000000000000 + domain: example.com + user_hid: '-1' + device_id: 00000000-0000-0000-0000-000000000000 + visitor_id: 00000000-0000-0000-0000-000000000000 + ip: 203.0.113.200 + os: Unknown + browser: Unknown + device_type: desktop + country: '' + connection_type: unknown + score: 999 + score_details: '[{"Value":999,"Description":"User has been banned 1H, to many requests"}]' + created_at: '2026-09-30 13:10:00.500' + ver: 1790773800500 + web_rtc_ip: 0.0.0.0 + web_rtc_country: '' + web_rtc_connection_type: '' + scanner_web_rtc_ip: 0.0.0.0 + scanner_web_rtc_country: '' + scanner_web_rtc_connection_type: '' + webrtc_leak_ip: 0.0.0.0 + webrtc_leak_country: '' + webrtc_leak_connection_type: '' + webrtc_leak_source: '' + tcp_mss: 0 + mtu_value: 0 + mtu_hint: '' + is_vpn: false + is_tor: false + is_proxy: false + is_datacenter: false + is_abuser: false + is_privacy_relay: false + is_stun_not_checked: false + check_incomplete: false + is_antidetect: false + is_os_mismatch: false + is_os_not_detected: false + is_timezone_mismatch: false + is_js_disabled: false + is_browser_automation: false + is_incognito: false + is_search_bot: false + stun_request_seen: false + is_scanner_stun_passed: false + stun_flow_status: '' + - request_id: 4f5e6d7c-8b9a-4c1d-9e2f-3a4b5c6d7e8f + session_id: 5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d + cookie_id: 6b7c8d9e-0f1a-4b2c-9d3e-4f5a6b7c8d9e + domain: example.com + user_hid: anonymous + device_id: 7c8d9e0f-1a2b-5c3d-8e4f-5a6b7c8d9e0f + visitor_id: 8d9e0f1a-2b3c-5d4e-9f5a-6b7c8d9e0f1a + ip: 198.51.100.66 + os: Linux + browser: Chrome + device_type: desktop + country: United States + connection_type: proxy + score: 0 + score_details: '' + created_at: '2026-09-30 13:20:30.250' + ver: 1790774430250 + web_rtc_ip: 203.0.113.77 + web_rtc_country: United States + web_rtc_connection_type: direct + scanner_web_rtc_ip: 0.0.0.0 + scanner_web_rtc_country: '' + scanner_web_rtc_connection_type: '' + webrtc_leak_ip: 0.0.0.0 + webrtc_leak_country: '' + webrtc_leak_connection_type: '' + webrtc_leak_source: none + tcp_mss: 1460 + mtu_value: 1500 + mtu_hint: direct + is_vpn: false + is_tor: false + is_proxy: false + is_datacenter: false + is_abuser: false + is_privacy_relay: false + is_stun_not_checked: false + check_incomplete: false + is_antidetect: false + is_os_mismatch: false + is_os_not_detected: false + is_timezone_mismatch: false + is_js_disabled: false + is_browser_automation: false + is_incognito: false + is_search_bot: true + stun_request_seen: false + is_scanner_stun_passed: false + stun_flow_status: '' + referrer_domain: GoogleBot + traffic_channel: Search bot + traffic_channel_group: Bot + traffic_reason: ip_crawler_detected + total: 37 + HistoryPageEmpty: + summary: Nothing matched + description: No identification matched. When searching by `request_id` right after a protected action, this means "not scored yet" (or an invalid request ID), never "clean". + value: + data: [] + total: 0 + HistoryUnauthorizedMissingHeader: + summary: Missing or malformed Authorization header + description: JSON text sent as `text/plain`, followed by a newline. + value: | + {"error":"missing or invalid authorization header"} + HistoryUnauthorizedInvalidKey: + summary: Unknown, deleted or disabled key + description: JSON text sent as `text/plain`, followed by a newline. + value: | + {"error":"invalid api key"} + NotFoundText: + summary: No route matched + description: Plain text body of an unrouted path. + value: 404 page not found + HistoryTooManyRequests: + summary: Soft rate limit reached + description: More than about 15 requests in the current second for this domain. Retry after about a second. + value: + error: too many requests + HistoryInvalidValue: + summary: Malformed UUID value + description: 'The raw database error for a value that is not a UUID. It repeats for the same request: validate the value instead of retrying.' + value: + error: 'code: 53, message: Cannot convert string ''abc'' to type UUID' + HistoryKeyLookupFailed: + summary: Key lookup failed + description: A transient error while checking the key, sent as JSON text. Retry with backoff. + value: | + {"error":"internal error"} + BadGatewayHtml: + summary: Bad gateway + description: HTML page from the edge proxy. + value:

502 Bad Gateway

+ GatewayTimeoutHtml: + summary: Gateway timeout + description: HTML page from the edge proxy. + value:

504 Gateway Time-out

+ DomainProfile: + summary: Profile of example.com + description: A domain with 148,230 remaining included identifications and masked keys. + value: + Domain: example.com + Weight: 148230 + Callback: '' + PublicKey: '****************************a3f8' + Secret: '****************************9c2d' + CreatedAt: '2026-01-15T09:00:00Z' + ManagementTooManyRequests: + summary: Rate limit reached or block active + description: 'Do not retry: every request gets this answer until the 10-minute block ends.' + value: + error: too many requests + ManagementServerBusy: + summary: Too many requests in flight + description: Retry with backoff. + value: + error: server is busy + LegacySnapshotList: + summary: One identification (deprecated shape) + description: The PascalCase array returned by the deprecated endpoint, for the same identification as the first History API example row. + value: + - RequestID: a5b7c9d1-e3f5-4a7b-9c1d-3e5f7a9b1c3d + SessionID: b6c8d0e2-f4a6-4b8c-8d0e-2f4a6b8c0d2e + CookieID: c7d9e1f3-a5b7-4c9d-ae1f-3a5b7c9d1e3f + DeviceID: d8e0f2a4-b6c8-4d0e-bf2a-4b6c8d0e2f4a + VisitorID: e9f1a3b5-c7d9-4e1f-8a3b-5c7d9e1f3a5b + IP: 203.0.113.24 + ConnectionType: proxy + TcpMss: 1460 + MtuValue: 1500 + MtuHint: direct + WebRtcHIP: 198.51.100.23 + WebRtcCountry: Germany + WebRtcConnectionType: direct + OS: Windows + Browser: Chrome + DeviceType: desktop + Country: Netherlands + UserHID: 9f86d081884c7d659a2feaa0c55ad015 + Score: 80 + Details: + - Value: 10 + Description: Is proxy + - Value: 10 + Description: Is datacenter + - Value: 60 + Description: Antidetect browser (turn_block) + LastRequestTime: '2026-09-30T12:34:56.123Z' + LegacySnapshotListEmpty: + summary: Nothing matched + description: An empty array. + value: [] + ManagementBadRequestUuid: + summary: Value is not a UUID + description: A bare JSON string. + value: fail parse uuid + ManagementBadRequestIp: + summary: Value is not an IP address + description: A bare JSON string. + value: invalid IP address + ManagementBadRequestEmpty: + summary: Empty value + description: A bare JSON string. + value: value cannot be empty + ManagementBadRequestNull: + summary: Database error + description: The JSON literal `null`, for example for an IPv6 `ip` value. + value: null + ManagementUnsupportedType: + summary: Unsupported identifier type + description: A bare JSON string naming the type that was sent. + value: auto is not supported + HealthOk: + summary: Service is up + description: The only successful answer. + value: + status: ok + IdentificationScored: + summary: Dangerous identification from a paid click + description: Risk Score 80 from a proxy, a datacenter IP and an anti-detect browser, on a visit from a Google Ads click. + value: + event_type: identification.scored + schema_version: '2026-06-01' + created_at: '2026-09-30T12:34:57.482913041Z' + data: + request_id: a5b7c9d1-e3f5-4a7b-9c1d-3e5f7a9b1c3d + visitor_id: e9f1a3b5-c7d9-4e1f-8a3b-5c7d9e1f3a5b + device_id: d8e0f2a4-b6c8-4d0e-bf2a-4b6c8d0e2f4a + session_id: b6c8d0e2-f4a6-4b8c-8d0e-2f4a6b8c0d2e + cookie_id: c7d9e1f3-a5b7-4c9d-ae1f-3a5b7c9d1e3f + user_hid: 9f86d081884c7d659a2feaa0c55ad015 + domain: example.com + public_ip: + ip: 203.0.113.24 + country: Netherlands + local_ip: + ip: 198.51.100.23 + country: Germany + connection_type: proxy + os: Windows + browser: Chrome + device_type: desktop + traffic_source: + channel: Google Ads + referrer_domain: google.com + landing_url: https://shop.example.com/signup?utm_source=google&utm_medium=cpc&gclid=abc123 + click_id_type: gclid + utm_source: google + utm_medium: cpc + utm_campaign: '' + utm_content: '' + utm_term: '' + risk_score: 80 + signals: + - name: proxy + weight: 10 + - name: datacenter_ip + weight: 10 + - name: antidetect_browser + weight: 60 + detection_flags: + vpn: false + privacy_relay: false + browser_vpn_proxy: false + tor: false + proxy: true + datacenter_ip: true + abuser: false + os_mismatch: false + os_not_detected: false + timezone_mismatch: false + anti_detect_browser: true + browser_automation: false + ip_mismatch: true + incognito: false + search_bot: false + suspicious_paid_click: true + javascript_disabled: false + stun_not_checked: false + check_incomplete: false + observed_at: '2026-09-30T12:34:57.482913041Z' + IdentificationScoredRateLimited: + summary: Rate-limit marker (999) + description: 'The 999 rate-limit marker: one `rate_limited` signal, nil identifiers and no attribution. It is not a Risk Score.' + value: + event_type: identification.scored + schema_version: '2026-06-01' + created_at: '2026-09-30T13:10:00.5Z' + data: + request_id: 1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d + visitor_id: 00000000-0000-0000-0000-000000000000 + device_id: 00000000-0000-0000-0000-000000000000 + session_id: 00000000-0000-0000-0000-000000000000 + cookie_id: 00000000-0000-0000-0000-000000000000 + user_hid: '-1' + domain: example.com + public_ip: + ip: 203.0.113.200 + country: '' + local_ip: + ip: '' + country: '' + connection_type: unknown + os: Unknown + browser: Unknown + device_type: desktop + traffic_source: + channel: '' + referrer_domain: '' + landing_url: '' + click_id_type: '' + utm_source: '' + utm_medium: '' + utm_campaign: '' + utm_content: '' + utm_term: '' + risk_score: 999 + signals: + - name: rate_limited + weight: 999 + detection_flags: + vpn: false + privacy_relay: false + browser_vpn_proxy: false + tor: false + proxy: false + datacenter_ip: false + abuser: false + os_mismatch: false + os_not_detected: false + timezone_mismatch: false + anti_detect_browser: false + browser_automation: false + ip_mismatch: false + incognito: false + search_bot: false + suspicious_paid_click: false + javascript_disabled: false + stun_not_checked: false + check_incomplete: false + observed_at: '2026-09-30T13:10:00.5Z' + IdentificationScoredTestDelivery: + summary: Test delivery from the analytics dashboard + description: 'The fixed sample sent by the Test button: keys sorted alphabetically, second-precision timestamps, two-letter country values and only 17 detection flags (`browser_automation` and `search_bot` are missing). It differs from the schema in exactly those two flags: parse missing flags as `false`.' + value: + created_at: '2026-09-30T12:34:56Z' + data: + browser: Chrome + connection_type: proxy + cookie_id: 2c9d1e8f-4b7a-4c3e-9d2f-1a8b7c6d5e4f + detection_flags: + abuser: true + anti_detect_browser: false + browser_vpn_proxy: false + check_incomplete: false + datacenter_ip: true + incognito: false + ip_mismatch: false + javascript_disabled: false + os_mismatch: false + os_not_detected: false + privacy_relay: false + proxy: true + stun_not_checked: false + suspicious_paid_click: false + timezone_mismatch: false + tor: false + vpn: false + device_id: 6f1e2d3c-4b5a-5968-8776-655443322110 + device_type: desktop + domain: example.com + local_ip: + country: BY + ip: 198.51.100.10 + observed_at: '2026-09-30T12:34:56Z' + os: Windows + public_ip: + country: BY + ip: 203.0.113.10 + request_id: 13f84f05-7c2a-4e9b-9f1d-2a6b8c0e4d11 + risk_score: 30 + session_id: 3a2b1c0d-9e8f-4a7b-8c6d-5e4f3a2b1c0d + signals: + - name: proxy + weight: 10 + - name: datacenter_ip + weight: 10 + - name: abuser + weight: 10 + traffic_source: + channel: Direct + click_id_type: '' + landing_url: https://example.com/ + referrer_domain: '' + utm_campaign: '' + utm_content: '' + utm_medium: '' + utm_source: '' + utm_term: '' + user_hid: null + visitor_id: 7a6b5c4d-3e2f-5a1b-9c8d-7e6f5a4b3c2d + event_type: identification.scored + schema_version: '2026-06-01' + WebhookPing: + summary: Endpoint verification + description: The ping sent when you verify an endpoint. It has no `data`. + value: + created_at: '2026-09-30T12:34:56Z' + event_type: webhook.ping + schema_version: '2026-06-01' + responses: + HistoryUnauthorized: + description: 'The `Authorization` header is missing or is not a Bearer token, or the Private API Key is unknown, deleted or belongs to a disabled domain. The body is JSON text sent with `Content-Type: text/plain; charset=utf-8`: parse it as JSON anyway. Do not retry.' + content: + text/plain: + schema: + $ref: '#/components/schemas/ErrorBodyText' + examples: + missingHeader: + $ref: '#/components/examples/HistoryUnauthorizedMissingHeader' + invalidKey: + $ref: '#/components/examples/HistoryUnauthorizedInvalidKey' + NotFound: + description: No route matches the method and path, for example because the base URL repeats part of the path or a path value is empty or contains `/`. Plain text body. Check the URL; do not retry. + content: + text/plain: + schema: + $ref: '#/components/schemas/PlainText' + examples: + notFound: + $ref: '#/components/examples/NotFoundText' + HistoryTooManyRequests: + description: 'More than about 15 requests in the current second for this domain (all callers of the domain share the limit). There is no ban: retry after about a second, with backoff.' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + examples: + tooManyRequests: + $ref: '#/components/examples/HistoryTooManyRequests' + HistoryServerError: + description: |- + Server error. + - `application/json`: the query failed. A malformed UUID or IPv4 value always ends here with the + raw database message, so validate the path before sending and do not retry such a request. + Other failures are transient. + - `text/plain` (JSON text): the key lookup failed. Transient: retry with backoff. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + examples: + invalidValue: + $ref: '#/components/examples/HistoryInvalidValue' + text/plain: + schema: + $ref: '#/components/schemas/ErrorBodyText' + examples: + keyLookupFailed: + $ref: '#/components/examples/HistoryKeyLookupFailed' + BadGateway: + description: The edge proxy could not reach the service. HTML body. Retry with backoff. + content: + text/html: + schema: + $ref: '#/components/schemas/HtmlText' + examples: + badGateway: + $ref: '#/components/examples/BadGatewayHtml' + GatewayTimeout: + description: The service did not answer the edge proxy in time. HTML body. Retry with backoff. + content: + text/html: + schema: + $ref: '#/components/schemas/HtmlText' + examples: + gatewayTimeout: + $ref: '#/components/examples/GatewayTimeoutHtml' + ManagementUnauthorized: + description: Empty body, no `Content-Type`. `X-Shield-Domain` or `Authorization` is missing or malformed, the domain is unknown or disabled, or the Secret Key is wrong. Do not retry. + ManagementTooManyRequests: + description: 'More than 15 requests in the current minute from your IP, or a 10-minute block is active. The request that exceeds the limit starts the block, and every request during it gets this answer. Do not retry: wait for the block to end and cache results to stay under the limit.' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + examples: + tooManyRequests: + $ref: '#/components/examples/ManagementTooManyRequests' + ManagementServerBusy: + description: Too many requests are in flight on the server. Retry with backoff. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + examples: + serverBusy: + $ref: '#/components/examples/ManagementServerBusy' + headers: + Deprecation: + description: Marks the endpoint as deprecated. The value is the literal `true`. + schema: + type: string + const: 'true' + examples: + deprecated: + summary: Deprecated endpoint + value: 'true' + Sunset: + description: HTTP date after which the endpoint stops working. + schema: + type: string + const: Sat, 01 Jan 2027 00:00:00 GMT + examples: + sunset: + summary: Sunset date + value: Sat, 01 Jan 2027 00:00:00 GMT + Link: + description: Points to the replacement endpoint with `rel="successor-version"`. + schema: + type: string + const: ; rel="successor-version" + examples: + successor: + summary: Successor endpoint + value: ; rel="successor-version" diff --git a/sync.sh b/sync.sh new file mode 100755 index 0000000..624350a --- /dev/null +++ b/sync.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd "$(dirname "${BASH_SOURCE[0]}")" + +schemaUrl="${1:-https://raw.githubusercontent.com/ShieldLabs-ai/shieldlabs-openapi/main/dist/shieldlabs-api.yaml}" +schemaDestination="./resources/shieldlabs-api.yaml" + +mkdir -p "$(dirname "$schemaDestination")" + +echo "Downloading $schemaUrl to $schemaDestination" +curl -fSL --retry 3 --proto-redir '=https' --connect-timeout 10 --max-time 120 \ + -o "$schemaDestination" "$schemaUrl" + +echo "OpenAPI schema download complete. Run ./generate.sh to refresh generated/."