From 9425a6319edcfcf7476b5be0b448663cbf653e6e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 18 Sep 2026 17:27:55 +0000 Subject: [PATCH 1/3] feat(api): api update --- .stats.yml | 4 +- .../sdk/models/VerificationCreateResponse.kt | 248 ++++++++++----- .../VerificationPhoneHistoryListResponse.kt | 9 +- ...erificationPhoneHistoryRetrieveResponse.kt | 240 +++++++++------ .../prelude/sdk/models/WatchEvaluateParams.kt | 5 +- .../sdk/models/WatchEvaluateResponse.kt | 285 +++++++++++++++++- .../sdk/models/WatchPredictResponse.kt | 238 ++++++++++----- .../sdk/services/async/WatchServiceAsync.kt | 5 +- .../sdk/services/blocking/WatchService.kt | 5 +- .../models/VerificationCreateResponseTest.kt | 6 +- ...icationPhoneHistoryRetrieveResponseTest.kt | 6 +- .../sdk/models/WatchEvaluateResponseTest.kt | 6 + .../sdk/models/WatchPredictResponseTest.kt | 6 +- .../sdk/proguard/ProGuardCompatibilityTest.kt | 2 +- 14 files changed, 793 insertions(+), 272 deletions(-) diff --git a/.stats.yml b/.stats.yml index cce5f555..9e7e8a59 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 27 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/prelude/prelude-33b70f86404b99046db5c61d3142b149dd7dec7eefe5e62ff3b397c7274aa5dc.yml -openapi_spec_hash: fb72aba38ec55a3b6b5162c9f5b4228d +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/prelude/prelude-0594c397de9595800d24337cbb03d0d1b7a1af7c0596890f5cf860662af1fd3b.yml +openapi_spec_hash: abc172473948cdc82c6baa4462fad2d9 config_hash: 707d65d2f456a2b5ba5b2c565b60128a diff --git a/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/VerificationCreateResponse.kt b/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/VerificationCreateResponse.kt index 688add68..67e9d222 100644 --- a/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/VerificationCreateResponse.kt +++ b/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/VerificationCreateResponse.kt @@ -120,8 +120,10 @@ private constructor( * * `invalid_phone_line` - The phone number is not a valid line number (e.g. landline). * * `invalid_phone_number` - The phone number is not a valid phone number (e.g. unallocated * range). - * * `invalid_signature` - The signature of the SDK signals is invalid. - * * `repeated_attempts` - The phone number has made too many verification attempts. + * * `invalid_signature` - The SDK signature did not verify, so the request cannot be attributed + * to the device it claims to come from. + * * `repeated_attempts` - The phone number exceeded the allowed number of verification attempts + * in a short period. * * `suspicious` - The verification attempt was deemed suspicious by the anti-fraud system. * * @throws PreludeInvalidDataException if the JSON field has an unexpected type (e.g. if the @@ -138,26 +140,37 @@ private constructor( /** * The risk factors that contributed to the verification being blocked. Only present when status * is "blocked" or "shadow_blocked" and the anti-fraud system detected specific risk signals. - * * `behavioral_pattern` - The phone number past behavior during verification flows exhibits - * suspicious patterns. - * * `device_attribute` - The device exhibits characteristics associated with suspicious - * activity patterns. - * * `fraud_database` - The phone number has been flagged as suspicious in one or more of our - * fraud databases. - * * `location_discrepancy` - The phone number prefix and IP address discrepancy indicates - * potential fraud. - * * `network_fingerprint` - The network connection exhibits characteristics associated with - * suspicious activity patterns. - * * `poor_conversion_history` - The phone number has a history of poorly converting to a - * verified phone number. - * * `prefix_concentration` - The phone number is part of a range known to be associated with - * suspicious activity patterns. - * * `suspected_request_tampering` - The SDK signature is invalid and the request is considered - * to be tampered with. - * * `suspicious_ip_address` - The IP address is deemed to be associated with suspicious - * activity patterns. - * * `temporary_phone_number` - The phone number is known to be a temporary or disposable - * number. + * * `automation_signature` - The request appears to come from an automated client rather than a + * person. + * * `carrier_not_permitted` - The destination carrier is one this account does not accept + * traffic for. + * * `client_fingerprint_mismatch` - The client does not appear to be the platform it identifies + * itself as. + * * `custom_policy` - A rule configured for your account matched this request. + * * `device_emulator` - The request appears to come from an emulator rather than a physical + * device. + * * `device_not_permitted` - The device platform is one your account blocks. + * * `device_reuse` - One device is driving verifications for an unusual number of phone + * numbers. + * * `expired_signals` - The SDK signals were collected too long before the request to still + * attest to it. + * * `fraud_database` - The phone number is flagged in one or more of the fraud databases + * Prelude consults. + * * `invalid_signature` - The SDK signature did not verify, so the request cannot be attributed + * to the device it claims to come from. + * * `ip_concentration` - The request shares its origin with an unusual volume of other + * verifications. + * * `ip_reputation` - The originating IP address is not trusted. + * * `location_mismatch` - The network location and the phone number's country are inconsistent. + * * `missing_signals` - The verification expected Prelude SDK signals and none arrived. + * * `number_range_abuse` - The phone number belongs to a range currently associated with abuse. + * * `poor_conversion_history` - Traffic resembling this request rarely completes a + * verification. + * * `proxy_network` - The request did not arrive over the subscriber's own access network. + * * `repeated_attempts` - The phone number exceeded the allowed number of verification attempts + * in a short period. + * * `temporary_phone_number` - The phone number belongs to a disposable or short-lived + * numbering service. * * @throws PreludeInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -383,8 +396,10 @@ private constructor( * * `invalid_phone_line` - The phone number is not a valid line number (e.g. landline). * * `invalid_phone_number` - The phone number is not a valid phone number (e.g. unallocated * range). - * * `invalid_signature` - The signature of the SDK signals is invalid. - * * `repeated_attempts` - The phone number has made too many verification attempts. + * * `invalid_signature` - The SDK signature did not verify, so the request cannot be + * attributed to the device it claims to come from. + * * `repeated_attempts` - The phone number exceeded the allowed number of verification + * attempts in a short period. * * `suspicious` - The verification attempt was deemed suspicious by the anti-fraud system. */ fun reason(reason: Reason) = reason(JsonField.of(reason)) @@ -412,26 +427,39 @@ private constructor( * The risk factors that contributed to the verification being blocked. Only present when * status is "blocked" or "shadow_blocked" and the anti-fraud system detected specific risk * signals. - * * `behavioral_pattern` - The phone number past behavior during verification flows - * exhibits suspicious patterns. - * * `device_attribute` - The device exhibits characteristics associated with suspicious - * activity patterns. - * * `fraud_database` - The phone number has been flagged as suspicious in one or more of - * our fraud databases. - * * `location_discrepancy` - The phone number prefix and IP address discrepancy indicates - * potential fraud. - * * `network_fingerprint` - The network connection exhibits characteristics associated with - * suspicious activity patterns. - * * `poor_conversion_history` - The phone number has a history of poorly converting to a - * verified phone number. - * * `prefix_concentration` - The phone number is part of a range known to be associated - * with suspicious activity patterns. - * * `suspected_request_tampering` - The SDK signature is invalid and the request is - * considered to be tampered with. - * * `suspicious_ip_address` - The IP address is deemed to be associated with suspicious - * activity patterns. - * * `temporary_phone_number` - The phone number is known to be a temporary or disposable - * number. + * * `automation_signature` - The request appears to come from an automated client rather + * than a person. + * * `carrier_not_permitted` - The destination carrier is one this account does not accept + * traffic for. + * * `client_fingerprint_mismatch` - The client does not appear to be the platform it + * identifies itself as. + * * `custom_policy` - A rule configured for your account matched this request. + * * `device_emulator` - The request appears to come from an emulator rather than a physical + * device. + * * `device_not_permitted` - The device platform is one your account blocks. + * * `device_reuse` - One device is driving verifications for an unusual number of phone + * numbers. + * * `expired_signals` - The SDK signals were collected too long before the request to still + * attest to it. + * * `fraud_database` - The phone number is flagged in one or more of the fraud databases + * Prelude consults. + * * `invalid_signature` - The SDK signature did not verify, so the request cannot be + * attributed to the device it claims to come from. + * * `ip_concentration` - The request shares its origin with an unusual volume of other + * verifications. + * * `ip_reputation` - The originating IP address is not trusted. + * * `location_mismatch` - The network location and the phone number's country are + * inconsistent. + * * `missing_signals` - The verification expected Prelude SDK signals and none arrived. + * * `number_range_abuse` - The phone number belongs to a range currently associated with + * abuse. + * * `poor_conversion_history` - Traffic resembling this request rarely completes a + * verification. + * * `proxy_network` - The request did not arrive over the subscriber's own access network. + * * `repeated_attempts` - The phone number exceeded the allowed number of verification + * attempts in a short period. + * * `temporary_phone_number` - The phone number belongs to a disposable or short-lived + * numbering service. */ fun riskFactors(riskFactors: List) = riskFactors(JsonField.of(riskFactors)) @@ -1221,8 +1249,10 @@ private constructor( * * `invalid_phone_line` - The phone number is not a valid line number (e.g. landline). * * `invalid_phone_number` - The phone number is not a valid phone number (e.g. unallocated * range). - * * `invalid_signature` - The signature of the SDK signals is invalid. - * * `repeated_attempts` - The phone number has made too many verification attempts. + * * `invalid_signature` - The SDK signature did not verify, so the request cannot be attributed + * to the device it claims to come from. + * * `repeated_attempts` - The phone number exceeded the allowed number of verification attempts + * in a short period. * * `suspicious` - The verification attempt was deemed suspicious by the anti-fraud system. */ class Reason @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -1403,23 +1433,41 @@ private constructor( companion object { - @JvmField val BEHAVIORAL_PATTERN = of("behavioral_pattern") + @JvmField val AUTOMATION_SIGNATURE = of("automation_signature") - @JvmField val DEVICE_ATTRIBUTE = of("device_attribute") + @JvmField val CARRIER_NOT_PERMITTED = of("carrier_not_permitted") + + @JvmField val CLIENT_FINGERPRINT_MISMATCH = of("client_fingerprint_mismatch") + + @JvmField val CUSTOM_POLICY = of("custom_policy") + + @JvmField val DEVICE_EMULATOR = of("device_emulator") + + @JvmField val DEVICE_NOT_PERMITTED = of("device_not_permitted") + + @JvmField val DEVICE_REUSE = of("device_reuse") + + @JvmField val EXPIRED_SIGNALS = of("expired_signals") @JvmField val FRAUD_DATABASE = of("fraud_database") - @JvmField val LOCATION_DISCREPANCY = of("location_discrepancy") + @JvmField val INVALID_SIGNATURE = of("invalid_signature") - @JvmField val NETWORK_FINGERPRINT = of("network_fingerprint") + @JvmField val IP_CONCENTRATION = of("ip_concentration") - @JvmField val POOR_CONVERSION_HISTORY = of("poor_conversion_history") + @JvmField val IP_REPUTATION = of("ip_reputation") + + @JvmField val LOCATION_MISMATCH = of("location_mismatch") - @JvmField val PREFIX_CONCENTRATION = of("prefix_concentration") + @JvmField val MISSING_SIGNALS = of("missing_signals") - @JvmField val SUSPECTED_REQUEST_TAMPERING = of("suspected_request_tampering") + @JvmField val NUMBER_RANGE_ABUSE = of("number_range_abuse") + + @JvmField val POOR_CONVERSION_HISTORY = of("poor_conversion_history") - @JvmField val SUSPICIOUS_IP_ADDRESS = of("suspicious_ip_address") + @JvmField val PROXY_NETWORK = of("proxy_network") + + @JvmField val REPEATED_ATTEMPTS = of("repeated_attempts") @JvmField val TEMPORARY_PHONE_NUMBER = of("temporary_phone_number") @@ -1428,15 +1476,24 @@ private constructor( /** An enum containing [RiskFactor]'s known values. */ enum class Known { - BEHAVIORAL_PATTERN, - DEVICE_ATTRIBUTE, + AUTOMATION_SIGNATURE, + CARRIER_NOT_PERMITTED, + CLIENT_FINGERPRINT_MISMATCH, + CUSTOM_POLICY, + DEVICE_EMULATOR, + DEVICE_NOT_PERMITTED, + DEVICE_REUSE, + EXPIRED_SIGNALS, FRAUD_DATABASE, - LOCATION_DISCREPANCY, - NETWORK_FINGERPRINT, + INVALID_SIGNATURE, + IP_CONCENTRATION, + IP_REPUTATION, + LOCATION_MISMATCH, + MISSING_SIGNALS, + NUMBER_RANGE_ABUSE, POOR_CONVERSION_HISTORY, - PREFIX_CONCENTRATION, - SUSPECTED_REQUEST_TAMPERING, - SUSPICIOUS_IP_ADDRESS, + PROXY_NETWORK, + REPEATED_ATTEMPTS, TEMPORARY_PHONE_NUMBER, } @@ -1450,15 +1507,24 @@ private constructor( * - It was constructed with an arbitrary value using the [of] method. */ enum class Value { - BEHAVIORAL_PATTERN, - DEVICE_ATTRIBUTE, + AUTOMATION_SIGNATURE, + CARRIER_NOT_PERMITTED, + CLIENT_FINGERPRINT_MISMATCH, + CUSTOM_POLICY, + DEVICE_EMULATOR, + DEVICE_NOT_PERMITTED, + DEVICE_REUSE, + EXPIRED_SIGNALS, FRAUD_DATABASE, - LOCATION_DISCREPANCY, - NETWORK_FINGERPRINT, + INVALID_SIGNATURE, + IP_CONCENTRATION, + IP_REPUTATION, + LOCATION_MISMATCH, + MISSING_SIGNALS, + NUMBER_RANGE_ABUSE, POOR_CONVERSION_HISTORY, - PREFIX_CONCENTRATION, - SUSPECTED_REQUEST_TAMPERING, - SUSPICIOUS_IP_ADDRESS, + PROXY_NETWORK, + REPEATED_ATTEMPTS, TEMPORARY_PHONE_NUMBER, /** * An enum member indicating that [RiskFactor] was instantiated with an unknown value. @@ -1475,15 +1541,24 @@ private constructor( */ fun value(): Value = when (this) { - BEHAVIORAL_PATTERN -> Value.BEHAVIORAL_PATTERN - DEVICE_ATTRIBUTE -> Value.DEVICE_ATTRIBUTE + AUTOMATION_SIGNATURE -> Value.AUTOMATION_SIGNATURE + CARRIER_NOT_PERMITTED -> Value.CARRIER_NOT_PERMITTED + CLIENT_FINGERPRINT_MISMATCH -> Value.CLIENT_FINGERPRINT_MISMATCH + CUSTOM_POLICY -> Value.CUSTOM_POLICY + DEVICE_EMULATOR -> Value.DEVICE_EMULATOR + DEVICE_NOT_PERMITTED -> Value.DEVICE_NOT_PERMITTED + DEVICE_REUSE -> Value.DEVICE_REUSE + EXPIRED_SIGNALS -> Value.EXPIRED_SIGNALS FRAUD_DATABASE -> Value.FRAUD_DATABASE - LOCATION_DISCREPANCY -> Value.LOCATION_DISCREPANCY - NETWORK_FINGERPRINT -> Value.NETWORK_FINGERPRINT + INVALID_SIGNATURE -> Value.INVALID_SIGNATURE + IP_CONCENTRATION -> Value.IP_CONCENTRATION + IP_REPUTATION -> Value.IP_REPUTATION + LOCATION_MISMATCH -> Value.LOCATION_MISMATCH + MISSING_SIGNALS -> Value.MISSING_SIGNALS + NUMBER_RANGE_ABUSE -> Value.NUMBER_RANGE_ABUSE POOR_CONVERSION_HISTORY -> Value.POOR_CONVERSION_HISTORY - PREFIX_CONCENTRATION -> Value.PREFIX_CONCENTRATION - SUSPECTED_REQUEST_TAMPERING -> Value.SUSPECTED_REQUEST_TAMPERING - SUSPICIOUS_IP_ADDRESS -> Value.SUSPICIOUS_IP_ADDRESS + PROXY_NETWORK -> Value.PROXY_NETWORK + REPEATED_ATTEMPTS -> Value.REPEATED_ATTEMPTS TEMPORARY_PHONE_NUMBER -> Value.TEMPORARY_PHONE_NUMBER else -> Value._UNKNOWN } @@ -1499,15 +1574,24 @@ private constructor( */ fun known(): Known = when (this) { - BEHAVIORAL_PATTERN -> Known.BEHAVIORAL_PATTERN - DEVICE_ATTRIBUTE -> Known.DEVICE_ATTRIBUTE + AUTOMATION_SIGNATURE -> Known.AUTOMATION_SIGNATURE + CARRIER_NOT_PERMITTED -> Known.CARRIER_NOT_PERMITTED + CLIENT_FINGERPRINT_MISMATCH -> Known.CLIENT_FINGERPRINT_MISMATCH + CUSTOM_POLICY -> Known.CUSTOM_POLICY + DEVICE_EMULATOR -> Known.DEVICE_EMULATOR + DEVICE_NOT_PERMITTED -> Known.DEVICE_NOT_PERMITTED + DEVICE_REUSE -> Known.DEVICE_REUSE + EXPIRED_SIGNALS -> Known.EXPIRED_SIGNALS FRAUD_DATABASE -> Known.FRAUD_DATABASE - LOCATION_DISCREPANCY -> Known.LOCATION_DISCREPANCY - NETWORK_FINGERPRINT -> Known.NETWORK_FINGERPRINT + INVALID_SIGNATURE -> Known.INVALID_SIGNATURE + IP_CONCENTRATION -> Known.IP_CONCENTRATION + IP_REPUTATION -> Known.IP_REPUTATION + LOCATION_MISMATCH -> Known.LOCATION_MISMATCH + MISSING_SIGNALS -> Known.MISSING_SIGNALS + NUMBER_RANGE_ABUSE -> Known.NUMBER_RANGE_ABUSE POOR_CONVERSION_HISTORY -> Known.POOR_CONVERSION_HISTORY - PREFIX_CONCENTRATION -> Known.PREFIX_CONCENTRATION - SUSPECTED_REQUEST_TAMPERING -> Known.SUSPECTED_REQUEST_TAMPERING - SUSPICIOUS_IP_ADDRESS -> Known.SUSPICIOUS_IP_ADDRESS + PROXY_NETWORK -> Known.PROXY_NETWORK + REPEATED_ATTEMPTS -> Known.REPEATED_ATTEMPTS TEMPORARY_PHONE_NUMBER -> Known.TEMPORARY_PHONE_NUMBER else -> throw PreludeInvalidDataException("Unknown RiskFactor: $value") } diff --git a/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/VerificationPhoneHistoryListResponse.kt b/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/VerificationPhoneHistoryListResponse.kt index e6f808dc..48783efa 100644 --- a/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/VerificationPhoneHistoryListResponse.kt +++ b/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/VerificationPhoneHistoryListResponse.kt @@ -353,7 +353,8 @@ private constructor( * * `invalid_line` - The phone number is not a valid line type. * * `invalid_number` - The phone number is not a valid number. * * `rate_limited` - The verification was refused by a rate limit. - * * `expired_signals` - The SDK signals were collected too long before the request. + * * `expired_signals` - The SDK signals were collected too long before the request to still + * attest to it. * * `shadowed` - The anti-fraud system flagged the verification without blocking it. * * @throws PreludeInvalidDataException if the JSON field has an unexpected type or is @@ -671,7 +672,8 @@ private constructor( * * `invalid_line` - The phone number is not a valid line type. * * `invalid_number` - The phone number is not a valid number. * * `rate_limited` - The verification was refused by a rate limit. - * * `expired_signals` - The SDK signals were collected too long before the request. + * * `expired_signals` - The SDK signals were collected too long before the request to + * still attest to it. * * `shadowed` - The anti-fraud system flagged the verification without blocking it. */ fun status(status: Status) = status(JsonField.of(status)) @@ -1303,7 +1305,8 @@ private constructor( * * `invalid_line` - The phone number is not a valid line type. * * `invalid_number` - The phone number is not a valid number. * * `rate_limited` - The verification was refused by a rate limit. - * * `expired_signals` - The SDK signals were collected too long before the request. + * * `expired_signals` - The SDK signals were collected too long before the request to still + * attest to it. * * `shadowed` - The anti-fraud system flagged the verification without blocking it. */ class Status @JsonCreator private constructor(private val value: JsonField) : Enum { diff --git a/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/VerificationPhoneHistoryRetrieveResponse.kt b/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/VerificationPhoneHistoryRetrieveResponse.kt index e40b360d..977c8728 100644 --- a/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/VerificationPhoneHistoryRetrieveResponse.kt +++ b/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/VerificationPhoneHistoryRetrieveResponse.kt @@ -171,7 +171,8 @@ private constructor( * * `invalid_line` - The phone number is not a valid line type. * * `invalid_number` - The phone number is not a valid number. * * `rate_limited` - The verification was refused by a rate limit. - * * `expired_signals` - The SDK signals were collected too long before the request. + * * `expired_signals` - The SDK signals were collected too long before the request to still + * attest to it. * * `shadowed` - The anti-fraud system flagged the verification without blocking it. * * @throws PreludeInvalidDataException if the JSON field has an unexpected type or is @@ -188,26 +189,39 @@ private constructor( fun appVersion(): Optional = appVersion.getOptional("app_version") /** - * Why the anti-fraud system blocked the verification. Empty unless it did. - * * `behavioral_pattern` - The phone number past behavior during verification flows exhibits - * suspicious patterns. - * * `device_attribute` - The end-user device reported attributes associated with fraud or - * emulation. - * * `fraud_database` - The phone number appears in a fraud database. - * * `location_discrepancy` - The phone number region and the observed location disagree. + * Why the anti-fraud system blocked the verification. Empty unless it did. These are the same + * labels the Verify and Watch APIs serve as `risk_factors`. + * * `automation_signature` - The request appears to come from an automated client rather than a + * person. + * * `carrier_not_permitted` - The destination carrier is one this account does not accept + * traffic for. + * * `client_fingerprint_mismatch` - The client does not appear to be the platform it identifies + * itself as. + * * `custom_policy` - A rule configured for your account matched this request. + * * `device_emulator` - The request appears to come from an emulator rather than a physical + * device. + * * `device_not_permitted` - The device platform is one your account blocks. + * * `device_reuse` - One device is driving verifications for an unusual number of phone + * numbers. + * * `expired_signals` - The SDK signals were collected too long before the request to still + * attest to it. + * * `fraud_database` - The phone number is flagged in one or more of the fraud databases + * Prelude consults. + * * `invalid_signature` - The SDK signature did not verify, so the request cannot be attributed + * to the device it claims to come from. + * * `ip_concentration` - The request shares its origin with an unusual volume of other + * verifications. + * * `ip_reputation` - The originating IP address is not trusted. + * * `location_mismatch` - The network location and the phone number's country are inconsistent. * * `missing_signals` - The verification expected Prelude SDK signals and none arrived. - * * `network_fingerprint` - The network fingerprint matches known fraudulent traffic. - * * `poor_conversion_history` - The phone number rarely completes the verifications it starts. - * * `prefix_concentration` - The phone number is part of a range known to be associated with - * suspicious activity patterns. - * * `repeated_number` - The phone number was used far more often than normal traffic would - * explain. - * * `suspected_request_tampering` - The SDK signals were altered or expired between collection - * and use. - * * `suspicious_ip_address` - The originating IP address is associated with suspicious - * activity. - * * `temporary_phone_number` - The phone number is known to be a temporary or disposable - * number. + * * `number_range_abuse` - The phone number belongs to a range currently associated with abuse. + * * `poor_conversion_history` - Traffic resembling this request rarely completes a + * verification. + * * `proxy_network` - The request did not arrive over the subscriber's own access network. + * * `repeated_attempts` - The phone number exceeded the allowed number of verification attempts + * in a short period. + * * `temporary_phone_number` - The phone number belongs to a disposable or short-lived + * numbering service. * * @throws PreludeInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -657,7 +671,8 @@ private constructor( * * `invalid_line` - The phone number is not a valid line type. * * `invalid_number` - The phone number is not a valid number. * * `rate_limited` - The verification was refused by a rate limit. - * * `expired_signals` - The SDK signals were collected too long before the request. + * * `expired_signals` - The SDK signals were collected too long before the request to still + * attest to it. * * `shadowed` - The anti-fraud system flagged the verification without blocking it. */ fun status(status: Status) = status(JsonField.of(status)) @@ -683,27 +698,41 @@ private constructor( fun appVersion(appVersion: JsonField) = apply { this.appVersion = appVersion } /** - * Why the anti-fraud system blocked the verification. Empty unless it did. - * * `behavioral_pattern` - The phone number past behavior during verification flows - * exhibits suspicious patterns. - * * `device_attribute` - The end-user device reported attributes associated with fraud or - * emulation. - * * `fraud_database` - The phone number appears in a fraud database. - * * `location_discrepancy` - The phone number region and the observed location disagree. + * Why the anti-fraud system blocked the verification. Empty unless it did. These are the + * same labels the Verify and Watch APIs serve as `risk_factors`. + * * `automation_signature` - The request appears to come from an automated client rather + * than a person. + * * `carrier_not_permitted` - The destination carrier is one this account does not accept + * traffic for. + * * `client_fingerprint_mismatch` - The client does not appear to be the platform it + * identifies itself as. + * * `custom_policy` - A rule configured for your account matched this request. + * * `device_emulator` - The request appears to come from an emulator rather than a physical + * device. + * * `device_not_permitted` - The device platform is one your account blocks. + * * `device_reuse` - One device is driving verifications for an unusual number of phone + * numbers. + * * `expired_signals` - The SDK signals were collected too long before the request to still + * attest to it. + * * `fraud_database` - The phone number is flagged in one or more of the fraud databases + * Prelude consults. + * * `invalid_signature` - The SDK signature did not verify, so the request cannot be + * attributed to the device it claims to come from. + * * `ip_concentration` - The request shares its origin with an unusual volume of other + * verifications. + * * `ip_reputation` - The originating IP address is not trusted. + * * `location_mismatch` - The network location and the phone number's country are + * inconsistent. * * `missing_signals` - The verification expected Prelude SDK signals and none arrived. - * * `network_fingerprint` - The network fingerprint matches known fraudulent traffic. - * * `poor_conversion_history` - The phone number rarely completes the verifications it - * starts. - * * `prefix_concentration` - The phone number is part of a range known to be associated - * with suspicious activity patterns. - * * `repeated_number` - The phone number was used far more often than normal traffic would - * explain. - * * `suspected_request_tampering` - The SDK signals were altered or expired between - * collection and use. - * * `suspicious_ip_address` - The originating IP address is associated with suspicious - * activity. - * * `temporary_phone_number` - The phone number is known to be a temporary or disposable - * number. + * * `number_range_abuse` - The phone number belongs to a range currently associated with + * abuse. + * * `poor_conversion_history` - Traffic resembling this request rarely completes a + * verification. + * * `proxy_network` - The request did not arrive over the subscriber's own access network. + * * `repeated_attempts` - The phone number exceeded the allowed number of verification + * attempts in a short period. + * * `temporary_phone_number` - The phone number belongs to a disposable or short-lived + * numbering service. */ fun blockReasons(blockReasons: List) = blockReasons(JsonField.of(blockReasons)) @@ -1077,7 +1106,8 @@ private constructor( * * `invalid_line` - The phone number is not a valid line type. * * `invalid_number` - The phone number is not a valid number. * * `rate_limited` - The verification was refused by a rate limit. - * * `expired_signals` - The SDK signals were collected too long before the request. + * * `expired_signals` - The SDK signals were collected too long before the request to still + * attest to it. * * `shadowed` - The anti-fraud system flagged the verification without blocking it. */ class Status @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -1289,27 +1319,41 @@ private constructor( companion object { - @JvmField val BEHAVIORAL_PATTERN = of("behavioral_pattern") + @JvmField val AUTOMATION_SIGNATURE = of("automation_signature") - @JvmField val DEVICE_ATTRIBUTE = of("device_attribute") + @JvmField val CARRIER_NOT_PERMITTED = of("carrier_not_permitted") + + @JvmField val CLIENT_FINGERPRINT_MISMATCH = of("client_fingerprint_mismatch") + + @JvmField val CUSTOM_POLICY = of("custom_policy") + + @JvmField val DEVICE_EMULATOR = of("device_emulator") + + @JvmField val DEVICE_NOT_PERMITTED = of("device_not_permitted") + + @JvmField val DEVICE_REUSE = of("device_reuse") + + @JvmField val EXPIRED_SIGNALS = of("expired_signals") @JvmField val FRAUD_DATABASE = of("fraud_database") - @JvmField val LOCATION_DISCREPANCY = of("location_discrepancy") + @JvmField val INVALID_SIGNATURE = of("invalid_signature") - @JvmField val MISSING_SIGNALS = of("missing_signals") + @JvmField val IP_CONCENTRATION = of("ip_concentration") - @JvmField val NETWORK_FINGERPRINT = of("network_fingerprint") + @JvmField val IP_REPUTATION = of("ip_reputation") - @JvmField val POOR_CONVERSION_HISTORY = of("poor_conversion_history") + @JvmField val LOCATION_MISMATCH = of("location_mismatch") + + @JvmField val MISSING_SIGNALS = of("missing_signals") - @JvmField val PREFIX_CONCENTRATION = of("prefix_concentration") + @JvmField val NUMBER_RANGE_ABUSE = of("number_range_abuse") - @JvmField val REPEATED_NUMBER = of("repeated_number") + @JvmField val POOR_CONVERSION_HISTORY = of("poor_conversion_history") - @JvmField val SUSPECTED_REQUEST_TAMPERING = of("suspected_request_tampering") + @JvmField val PROXY_NETWORK = of("proxy_network") - @JvmField val SUSPICIOUS_IP_ADDRESS = of("suspicious_ip_address") + @JvmField val REPEATED_ATTEMPTS = of("repeated_attempts") @JvmField val TEMPORARY_PHONE_NUMBER = of("temporary_phone_number") @@ -1318,17 +1362,24 @@ private constructor( /** An enum containing [BlockReason]'s known values. */ enum class Known { - BEHAVIORAL_PATTERN, - DEVICE_ATTRIBUTE, + AUTOMATION_SIGNATURE, + CARRIER_NOT_PERMITTED, + CLIENT_FINGERPRINT_MISMATCH, + CUSTOM_POLICY, + DEVICE_EMULATOR, + DEVICE_NOT_PERMITTED, + DEVICE_REUSE, + EXPIRED_SIGNALS, FRAUD_DATABASE, - LOCATION_DISCREPANCY, + INVALID_SIGNATURE, + IP_CONCENTRATION, + IP_REPUTATION, + LOCATION_MISMATCH, MISSING_SIGNALS, - NETWORK_FINGERPRINT, + NUMBER_RANGE_ABUSE, POOR_CONVERSION_HISTORY, - PREFIX_CONCENTRATION, - REPEATED_NUMBER, - SUSPECTED_REQUEST_TAMPERING, - SUSPICIOUS_IP_ADDRESS, + PROXY_NETWORK, + REPEATED_ATTEMPTS, TEMPORARY_PHONE_NUMBER, } @@ -1342,17 +1393,24 @@ private constructor( * - It was constructed with an arbitrary value using the [of] method. */ enum class Value { - BEHAVIORAL_PATTERN, - DEVICE_ATTRIBUTE, + AUTOMATION_SIGNATURE, + CARRIER_NOT_PERMITTED, + CLIENT_FINGERPRINT_MISMATCH, + CUSTOM_POLICY, + DEVICE_EMULATOR, + DEVICE_NOT_PERMITTED, + DEVICE_REUSE, + EXPIRED_SIGNALS, FRAUD_DATABASE, - LOCATION_DISCREPANCY, + INVALID_SIGNATURE, + IP_CONCENTRATION, + IP_REPUTATION, + LOCATION_MISMATCH, MISSING_SIGNALS, - NETWORK_FINGERPRINT, + NUMBER_RANGE_ABUSE, POOR_CONVERSION_HISTORY, - PREFIX_CONCENTRATION, - REPEATED_NUMBER, - SUSPECTED_REQUEST_TAMPERING, - SUSPICIOUS_IP_ADDRESS, + PROXY_NETWORK, + REPEATED_ATTEMPTS, TEMPORARY_PHONE_NUMBER, /** * An enum member indicating that [BlockReason] was instantiated with an unknown value. @@ -1369,17 +1427,24 @@ private constructor( */ fun value(): Value = when (this) { - BEHAVIORAL_PATTERN -> Value.BEHAVIORAL_PATTERN - DEVICE_ATTRIBUTE -> Value.DEVICE_ATTRIBUTE + AUTOMATION_SIGNATURE -> Value.AUTOMATION_SIGNATURE + CARRIER_NOT_PERMITTED -> Value.CARRIER_NOT_PERMITTED + CLIENT_FINGERPRINT_MISMATCH -> Value.CLIENT_FINGERPRINT_MISMATCH + CUSTOM_POLICY -> Value.CUSTOM_POLICY + DEVICE_EMULATOR -> Value.DEVICE_EMULATOR + DEVICE_NOT_PERMITTED -> Value.DEVICE_NOT_PERMITTED + DEVICE_REUSE -> Value.DEVICE_REUSE + EXPIRED_SIGNALS -> Value.EXPIRED_SIGNALS FRAUD_DATABASE -> Value.FRAUD_DATABASE - LOCATION_DISCREPANCY -> Value.LOCATION_DISCREPANCY + INVALID_SIGNATURE -> Value.INVALID_SIGNATURE + IP_CONCENTRATION -> Value.IP_CONCENTRATION + IP_REPUTATION -> Value.IP_REPUTATION + LOCATION_MISMATCH -> Value.LOCATION_MISMATCH MISSING_SIGNALS -> Value.MISSING_SIGNALS - NETWORK_FINGERPRINT -> Value.NETWORK_FINGERPRINT + NUMBER_RANGE_ABUSE -> Value.NUMBER_RANGE_ABUSE POOR_CONVERSION_HISTORY -> Value.POOR_CONVERSION_HISTORY - PREFIX_CONCENTRATION -> Value.PREFIX_CONCENTRATION - REPEATED_NUMBER -> Value.REPEATED_NUMBER - SUSPECTED_REQUEST_TAMPERING -> Value.SUSPECTED_REQUEST_TAMPERING - SUSPICIOUS_IP_ADDRESS -> Value.SUSPICIOUS_IP_ADDRESS + PROXY_NETWORK -> Value.PROXY_NETWORK + REPEATED_ATTEMPTS -> Value.REPEATED_ATTEMPTS TEMPORARY_PHONE_NUMBER -> Value.TEMPORARY_PHONE_NUMBER else -> Value._UNKNOWN } @@ -1395,17 +1460,24 @@ private constructor( */ fun known(): Known = when (this) { - BEHAVIORAL_PATTERN -> Known.BEHAVIORAL_PATTERN - DEVICE_ATTRIBUTE -> Known.DEVICE_ATTRIBUTE + AUTOMATION_SIGNATURE -> Known.AUTOMATION_SIGNATURE + CARRIER_NOT_PERMITTED -> Known.CARRIER_NOT_PERMITTED + CLIENT_FINGERPRINT_MISMATCH -> Known.CLIENT_FINGERPRINT_MISMATCH + CUSTOM_POLICY -> Known.CUSTOM_POLICY + DEVICE_EMULATOR -> Known.DEVICE_EMULATOR + DEVICE_NOT_PERMITTED -> Known.DEVICE_NOT_PERMITTED + DEVICE_REUSE -> Known.DEVICE_REUSE + EXPIRED_SIGNALS -> Known.EXPIRED_SIGNALS FRAUD_DATABASE -> Known.FRAUD_DATABASE - LOCATION_DISCREPANCY -> Known.LOCATION_DISCREPANCY + INVALID_SIGNATURE -> Known.INVALID_SIGNATURE + IP_CONCENTRATION -> Known.IP_CONCENTRATION + IP_REPUTATION -> Known.IP_REPUTATION + LOCATION_MISMATCH -> Known.LOCATION_MISMATCH MISSING_SIGNALS -> Known.MISSING_SIGNALS - NETWORK_FINGERPRINT -> Known.NETWORK_FINGERPRINT + NUMBER_RANGE_ABUSE -> Known.NUMBER_RANGE_ABUSE POOR_CONVERSION_HISTORY -> Known.POOR_CONVERSION_HISTORY - PREFIX_CONCENTRATION -> Known.PREFIX_CONCENTRATION - REPEATED_NUMBER -> Known.REPEATED_NUMBER - SUSPECTED_REQUEST_TAMPERING -> Known.SUSPECTED_REQUEST_TAMPERING - SUSPICIOUS_IP_ADDRESS -> Known.SUSPICIOUS_IP_ADDRESS + PROXY_NETWORK -> Known.PROXY_NETWORK + REPEATED_ATTEMPTS -> Known.REPEATED_ATTEMPTS TEMPORARY_PHONE_NUMBER -> Known.TEMPORARY_PHONE_NUMBER else -> throw PreludeInvalidDataException("Unknown BlockReason: $value") } diff --git a/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/WatchEvaluateParams.kt b/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/WatchEvaluateParams.kt index b6cbb0ab..1e80496d 100644 --- a/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/WatchEvaluateParams.kt +++ b/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/WatchEvaluateParams.kt @@ -22,8 +22,9 @@ import so.prelude.sdk.core.toImmutable import so.prelude.sdk.errors.PreludeInvalidDataException /** - * **Beta.** The request and response shapes may still change, and flows and recipes are configured - * by Prelude on your behalf for now. Talk to us before you build against it. + * **Beta.** The request and response shapes may still change. Talk to us before you build against + * it. Flows, recipes and rules are authored through the Watch Management API, or configured by + * Prelude on your behalf. * * Score a target against the rules configured for one moment in your product — signup, checkout, * password reset. The flow selects which recipes run; each recipe scores its rules against a diff --git a/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/WatchEvaluateResponse.kt b/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/WatchEvaluateResponse.kt index b1f9e167..da6fa357 100644 --- a/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/WatchEvaluateResponse.kt +++ b/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/WatchEvaluateResponse.kt @@ -519,7 +519,9 @@ private constructor( /** * One result per rule in the recipe, in membership order. Every rule runs — a score is only - * meaningful when complete, so there is no short-circuit on the first trigger. + * meaningful when complete, so there is no short-circuit on the first trigger. The + * exception is a recipe whose verdict a preempting rule has already determined, where a + * rule that could no longer change it may report `SKIPPED` instead. * * @throws PreludeInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -704,7 +706,9 @@ private constructor( /** * One result per rule in the recipe, in membership order. Every rule runs — a score is - * only meaningful when complete, so there is no short-circuit on the first trigger. + * only meaningful when complete, so there is no short-circuit on the first trigger. The + * exception is a recipe whose verdict a preempting rule has already determined, where a + * rule that could no longer change it may report `SKIPPED` instead. */ fun rules(rules: List) = rules(JsonField.of(rules)) @@ -895,10 +899,12 @@ private constructor( private constructor( private val outcome: JsonField, private val ruleId: JsonField, + private val type: JsonField, private val weight: JsonField, private val blockedBy: JsonField, private val name: JsonField, private val unavailable: JsonField, + private val versionId: JsonField, private val additionalProperties: MutableMap, ) { @@ -910,6 +916,7 @@ private constructor( @JsonProperty("rule_id") @ExcludeMissing ruleId: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), @JsonProperty("weight") @ExcludeMissing weight: JsonField = JsonMissing.of(), @JsonProperty("blocked_by") @ExcludeMissing @@ -918,7 +925,20 @@ private constructor( @JsonProperty("unavailable") @ExcludeMissing unavailable: JsonField = JsonMissing.of(), - ) : this(outcome, ruleId, weight, blockedBy, name, unavailable, mutableMapOf()) + @JsonProperty("version_id") + @ExcludeMissing + versionId: JsonField = JsonMissing.of(), + ) : this( + outcome, + ruleId, + type, + weight, + blockedBy, + name, + unavailable, + versionId, + mutableMapOf(), + ) /** * What the rule concluded. @@ -927,6 +947,10 @@ private constructor( * * `NOT_EVALUATED` - The rule could not run, because something it reads never arrived. * This is not a quieter `NOT_TRIGGERED`: it contributed nothing either way, and it is * why `partial_evidence` is set on the recipe. + * * `SKIPPED` - The rule was not run, because another rule had already determined the + * recipe's verdict — see `determined_by`. Nothing was missing and nothing failed, so + * `partial_evidence` is not set: `determined_by` is what accounts for the recipe's + * score resting on fewer rules. * * @throws PreludeInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected @@ -945,6 +969,19 @@ private constructor( */ fun ruleId(): String = ruleId.getRequired("rule_id") + /** + * Who authored the rule, which is what says how much of the rest of this result you + * get. + * * `MANAGED` - Prelude-owned, shared with customers: `name` and `version_id` are + * omitted, and `blocked_by` reports only `missing_data`. + * * `CUSTOM` - Yours: every field is returned. + * + * @throws PreludeInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun type(): Type = type.getRequired("type") + /** * What this rule contributes to the recipe's score when it triggers. * @@ -985,6 +1022,16 @@ private constructor( */ fun unavailable(): Optional = unavailable.getOptional("unavailable") + /** + * The version of the rule that scored — the one this recipe is pinned to, or the + * version current at evaluation time when it is not pinned. Present for a rule you + * authored, and omitted for a Prelude-managed one. + * + * @throws PreludeInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun versionId(): Optional = versionId.getOptional("version_id") + /** * Returns the raw JSON value of [outcome]. * @@ -999,6 +1046,13 @@ private constructor( */ @JsonProperty("rule_id") @ExcludeMissing fun _ruleId(): JsonField = ruleId + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + /** * Returns the raw JSON value of [weight]. * @@ -1033,6 +1087,16 @@ private constructor( @ExcludeMissing fun _unavailable(): JsonField = unavailable + /** + * Returns the raw JSON value of [versionId]. + * + * Unlike [versionId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("version_id") + @ExcludeMissing + fun _versionId(): JsonField = versionId + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -1054,6 +1118,7 @@ private constructor( * ```java * .outcome() * .ruleId() + * .type() * .weight() * ``` */ @@ -1065,20 +1130,24 @@ private constructor( private var outcome: JsonField? = null private var ruleId: JsonField? = null + private var type: JsonField? = null private var weight: JsonField? = null private var blockedBy: JsonField = JsonMissing.of() private var name: JsonField = JsonMissing.of() private var unavailable: JsonField = JsonMissing.of() + private var versionId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(rule: Rule) = apply { outcome = rule.outcome ruleId = rule.ruleId + type = rule.type weight = rule.weight blockedBy = rule.blockedBy name = rule.name unavailable = rule.unavailable + versionId = rule.versionId additionalProperties = rule.additionalProperties.toMutableMap() } @@ -1089,6 +1158,10 @@ private constructor( * * `NOT_EVALUATED` - The rule could not run, because something it reads never * arrived. This is not a quieter `NOT_TRIGGERED`: it contributed nothing either * way, and it is why `partial_evidence` is set on the recipe. + * * `SKIPPED` - The rule was not run, because another rule had already determined + * the recipe's verdict — see `determined_by`. Nothing was missing and nothing + * failed, so `partial_evidence` is not set: `determined_by` is what accounts for + * the recipe's score resting on fewer rules. */ fun outcome(outcome: Outcome) = outcome(JsonField.of(outcome)) @@ -1117,6 +1190,24 @@ private constructor( */ fun ruleId(ruleId: JsonField) = apply { this.ruleId = ruleId } + /** + * Who authored the rule, which is what says how much of the rest of this result you + * get. + * * `MANAGED` - Prelude-owned, shared with customers: `name` and `version_id` are + * omitted, and `blocked_by` reports only `missing_data`. + * * `CUSTOM` - Yours: every field is returned. + */ + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + /** What this rule contributes to the recipe's score when it triggers. */ fun weight(weight: Long) = weight(JsonField.of(weight)) @@ -1181,6 +1272,22 @@ private constructor( this.unavailable = unavailable } + /** + * The version of the rule that scored — the one this recipe is pinned to, or the + * version current at evaluation time when it is not pinned. Present for a rule you + * authored, and omitted for a Prelude-managed one. + */ + fun versionId(versionId: String) = versionId(JsonField.of(versionId)) + + /** + * Sets [Builder.versionId] to an arbitrary JSON value. + * + * You should usually call [Builder.versionId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun versionId(versionId: JsonField) = apply { this.versionId = versionId } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -1212,6 +1319,7 @@ private constructor( * ```java * .outcome() * .ruleId() + * .type() * .weight() * ``` * @@ -1221,10 +1329,12 @@ private constructor( Rule( checkRequired("outcome", outcome), checkRequired("ruleId", ruleId), + checkRequired("type", type), checkRequired("weight", weight), blockedBy, name, unavailable, + versionId, additionalProperties.toMutableMap(), ) } @@ -1248,10 +1358,12 @@ private constructor( outcome().validate() ruleId() + type().validate() weight() blockedBy() name() unavailable() + versionId() validated = true } @@ -1273,10 +1385,12 @@ private constructor( internal fun validity(): Int = (outcome.asKnown().getOrNull()?.validity() ?: 0) + (if (ruleId.asKnown().isPresent) 1 else 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + (if (weight.asKnown().isPresent) 1 else 0) + (if (blockedBy.asKnown().isPresent) 1 else 0) + (if (name.asKnown().isPresent) 1 else 0) + - (if (unavailable.asKnown().isPresent) 1 else 0) + (if (unavailable.asKnown().isPresent) 1 else 0) + + (if (versionId.asKnown().isPresent) 1 else 0) /** * What the rule concluded. @@ -1285,6 +1399,10 @@ private constructor( * * `NOT_EVALUATED` - The rule could not run, because something it reads never arrived. * This is not a quieter `NOT_TRIGGERED`: it contributed nothing either way, and it is * why `partial_evidence` is set on the recipe. + * * `SKIPPED` - The rule was not run, because another rule had already determined the + * recipe's verdict — see `determined_by`. Nothing was missing and nothing failed, so + * `partial_evidence` is not set: `determined_by` is what accounts for the recipe's + * score resting on fewer rules. */ class Outcome @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -1307,6 +1425,8 @@ private constructor( @JvmField val NOT_EVALUATED = of("NOT_EVALUATED") + @JvmField val SKIPPED = of("SKIPPED") + @JvmStatic fun of(value: String) = Outcome(JsonField.of(value)) } @@ -1315,6 +1435,7 @@ private constructor( TRIGGERED, NOT_TRIGGERED, NOT_EVALUATED, + SKIPPED, } /** @@ -1330,6 +1451,7 @@ private constructor( TRIGGERED, NOT_TRIGGERED, NOT_EVALUATED, + SKIPPED, /** * An enum member indicating that [Outcome] was instantiated with an unknown * value. @@ -1349,6 +1471,7 @@ private constructor( TRIGGERED -> Value.TRIGGERED NOT_TRIGGERED -> Value.NOT_TRIGGERED NOT_EVALUATED -> Value.NOT_EVALUATED + SKIPPED -> Value.SKIPPED else -> Value._UNKNOWN } @@ -1366,6 +1489,7 @@ private constructor( TRIGGERED -> Known.TRIGGERED NOT_TRIGGERED -> Known.NOT_TRIGGERED NOT_EVALUATED -> Known.NOT_EVALUATED + SKIPPED -> Known.SKIPPED else -> throw PreludeInvalidDataException("Unknown Outcome: $value") } @@ -1433,6 +1557,153 @@ private constructor( override fun toString() = value.toString() } + /** + * Who authored the rule, which is what says how much of the rest of this result you + * get. + * * `MANAGED` - Prelude-owned, shared with customers: `name` and `version_id` are + * omitted, and `blocked_by` reports only `missing_data`. + * * `CUSTOM` - Yours: every field is returned. + */ + class Type @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known member, and you want to know that value. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val MANAGED = of("MANAGED") + + @JvmField val CUSTOM = of("CUSTOM") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + MANAGED, + CUSTOM, + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, + * if the SDK is on an older version than the API, then the API may respond with + * new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + MANAGED, + CUSTOM, + /** + * An enum member indicating that [Type] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if + * you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + MANAGED -> Value.MANAGED + CUSTOM -> Value.CUSTOM + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws PreludeInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + MANAGED -> Known.MANAGED + CUSTOM -> Known.CUSTOM + else -> throw PreludeInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws PreludeInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + PreludeInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws PreludeInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: PreludeInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Type && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + override fun equals(other: Any?): Boolean { if (this === other) { return true @@ -1441,10 +1712,12 @@ private constructor( return other is Rule && outcome == other.outcome && ruleId == other.ruleId && + type == other.type && weight == other.weight && blockedBy == other.blockedBy && name == other.name && unavailable == other.unavailable && + versionId == other.versionId && additionalProperties == other.additionalProperties } @@ -1452,10 +1725,12 @@ private constructor( Objects.hash( outcome, ruleId, + type, weight, blockedBy, name, unavailable, + versionId, additionalProperties, ) } @@ -1463,7 +1738,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "Rule{outcome=$outcome, ruleId=$ruleId, weight=$weight, blockedBy=$blockedBy, name=$name, unavailable=$unavailable, additionalProperties=$additionalProperties}" + "Rule{outcome=$outcome, ruleId=$ruleId, type=$type, weight=$weight, blockedBy=$blockedBy, name=$name, unavailable=$unavailable, versionId=$versionId, additionalProperties=$additionalProperties}" } /** diff --git a/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/WatchPredictResponse.kt b/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/WatchPredictResponse.kt index 5e4f5c55..dc35a483 100644 --- a/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/WatchPredictResponse.kt +++ b/prelude-java-core/src/main/kotlin/so/prelude/sdk/models/WatchPredictResponse.kt @@ -70,28 +70,39 @@ private constructor( /** * The risk factors that contributed to the suspicious prediction. Only present when prediction * is "suspicious" and the anti-fraud system detected specific risk signals. - * * `account_risk_profile` - The target matches a risk profile derived from the outcomes - * reported on your own account, rather than from a signal shared across accounts. - * * `behavioral_pattern` - The phone number past behavior during verification flows exhibits - * suspicious patterns. - * * `device_attribute` - The device exhibits characteristics associated with suspicious - * activity patterns. - * * `fraud_database` - The phone number has been flagged as suspicious in one or more of our - * fraud databases. - * * `location_discrepancy` - The phone number prefix and IP address discrepancy indicates - * potential fraud. - * * `network_fingerprint` - The network connection exhibits characteristics associated with - * suspicious activity patterns. - * * `poor_conversion_history` - The phone number has a history of poorly converting to a - * verified phone number. - * * `prefix_concentration` - The phone number is part of a range known to be associated with - * suspicious activity patterns. - * * `suspected_request_tampering` - The SDK signature is invalid and the request is considered - * to be tampered with. - * * `suspicious_ip_address` - The IP address is deemed to be associated with suspicious - * activity patterns. - * * `temporary_phone_number` - The phone number is known to be a temporary or disposable - * number. + * * `account_risk_profile` - The request matches a risk profile derived from the outcomes + * reported on your own account. + * * `automation_signature` - The request appears to come from an automated client rather than a + * person. + * * `carrier_not_permitted` - The destination carrier is one this account does not accept + * traffic for. + * * `client_fingerprint_mismatch` - The client does not appear to be the platform it identifies + * itself as. + * * `custom_policy` - A rule configured for your account matched this request. + * * `device_emulator` - The request appears to come from an emulator rather than a physical + * device. + * * `device_not_permitted` - The device platform is one your account blocks. + * * `device_reuse` - One device is driving verifications for an unusual number of phone + * numbers. + * * `expired_signals` - The SDK signals were collected too long before the request to still + * attest to it. + * * `fraud_database` - The phone number is flagged in one or more of the fraud databases + * Prelude consults. + * * `invalid_signature` - The SDK signature did not verify, so the request cannot be attributed + * to the device it claims to come from. + * * `ip_concentration` - The request shares its origin with an unusual volume of other + * verifications. + * * `ip_reputation` - The originating IP address is not trusted. + * * `location_mismatch` - The network location and the phone number's country are inconsistent. + * * `missing_signals` - The verification expected Prelude SDK signals and none arrived. + * * `number_range_abuse` - The phone number belongs to a range currently associated with abuse. + * * `poor_conversion_history` - Traffic resembling this request rarely completes a + * verification. + * * `proxy_network` - The request did not arrive over the subscriber's own access network. + * * `repeated_attempts` - The phone number exceeded the allowed number of verification attempts + * in a short period. + * * `temporary_phone_number` - The phone number belongs to a disposable or short-lived + * numbering service. * * @throws PreludeInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -216,28 +227,41 @@ private constructor( /** * The risk factors that contributed to the suspicious prediction. Only present when * prediction is "suspicious" and the anti-fraud system detected specific risk signals. - * * `account_risk_profile` - The target matches a risk profile derived from the outcomes - * reported on your own account, rather than from a signal shared across accounts. - * * `behavioral_pattern` - The phone number past behavior during verification flows - * exhibits suspicious patterns. - * * `device_attribute` - The device exhibits characteristics associated with suspicious - * activity patterns. - * * `fraud_database` - The phone number has been flagged as suspicious in one or more of - * our fraud databases. - * * `location_discrepancy` - The phone number prefix and IP address discrepancy indicates - * potential fraud. - * * `network_fingerprint` - The network connection exhibits characteristics associated with - * suspicious activity patterns. - * * `poor_conversion_history` - The phone number has a history of poorly converting to a - * verified phone number. - * * `prefix_concentration` - The phone number is part of a range known to be associated - * with suspicious activity patterns. - * * `suspected_request_tampering` - The SDK signature is invalid and the request is - * considered to be tampered with. - * * `suspicious_ip_address` - The IP address is deemed to be associated with suspicious - * activity patterns. - * * `temporary_phone_number` - The phone number is known to be a temporary or disposable - * number. + * * `account_risk_profile` - The request matches a risk profile derived from the outcomes + * reported on your own account. + * * `automation_signature` - The request appears to come from an automated client rather + * than a person. + * * `carrier_not_permitted` - The destination carrier is one this account does not accept + * traffic for. + * * `client_fingerprint_mismatch` - The client does not appear to be the platform it + * identifies itself as. + * * `custom_policy` - A rule configured for your account matched this request. + * * `device_emulator` - The request appears to come from an emulator rather than a physical + * device. + * * `device_not_permitted` - The device platform is one your account blocks. + * * `device_reuse` - One device is driving verifications for an unusual number of phone + * numbers. + * * `expired_signals` - The SDK signals were collected too long before the request to still + * attest to it. + * * `fraud_database` - The phone number is flagged in one or more of the fraud databases + * Prelude consults. + * * `invalid_signature` - The SDK signature did not verify, so the request cannot be + * attributed to the device it claims to come from. + * * `ip_concentration` - The request shares its origin with an unusual volume of other + * verifications. + * * `ip_reputation` - The originating IP address is not trusted. + * * `location_mismatch` - The network location and the phone number's country are + * inconsistent. + * * `missing_signals` - The verification expected Prelude SDK signals and none arrived. + * * `number_range_abuse` - The phone number belongs to a range currently associated with + * abuse. + * * `poor_conversion_history` - Traffic resembling this request rarely completes a + * verification. + * * `proxy_network` - The request did not arrive over the subscriber's own access network. + * * `repeated_attempts` - The phone number exceeded the allowed number of verification + * attempts in a short period. + * * `temporary_phone_number` - The phone number belongs to a disposable or short-lived + * numbering service. */ fun riskFactors(riskFactors: List) = riskFactors(JsonField.of(riskFactors)) @@ -502,23 +526,41 @@ private constructor( @JvmField val ACCOUNT_RISK_PROFILE = of("account_risk_profile") - @JvmField val BEHAVIORAL_PATTERN = of("behavioral_pattern") + @JvmField val AUTOMATION_SIGNATURE = of("automation_signature") - @JvmField val DEVICE_ATTRIBUTE = of("device_attribute") + @JvmField val CARRIER_NOT_PERMITTED = of("carrier_not_permitted") + + @JvmField val CLIENT_FINGERPRINT_MISMATCH = of("client_fingerprint_mismatch") + + @JvmField val CUSTOM_POLICY = of("custom_policy") + + @JvmField val DEVICE_EMULATOR = of("device_emulator") + + @JvmField val DEVICE_NOT_PERMITTED = of("device_not_permitted") + + @JvmField val DEVICE_REUSE = of("device_reuse") + + @JvmField val EXPIRED_SIGNALS = of("expired_signals") @JvmField val FRAUD_DATABASE = of("fraud_database") - @JvmField val LOCATION_DISCREPANCY = of("location_discrepancy") + @JvmField val INVALID_SIGNATURE = of("invalid_signature") - @JvmField val NETWORK_FINGERPRINT = of("network_fingerprint") + @JvmField val IP_CONCENTRATION = of("ip_concentration") - @JvmField val POOR_CONVERSION_HISTORY = of("poor_conversion_history") + @JvmField val IP_REPUTATION = of("ip_reputation") + + @JvmField val LOCATION_MISMATCH = of("location_mismatch") + + @JvmField val MISSING_SIGNALS = of("missing_signals") - @JvmField val PREFIX_CONCENTRATION = of("prefix_concentration") + @JvmField val NUMBER_RANGE_ABUSE = of("number_range_abuse") + + @JvmField val POOR_CONVERSION_HISTORY = of("poor_conversion_history") - @JvmField val SUSPECTED_REQUEST_TAMPERING = of("suspected_request_tampering") + @JvmField val PROXY_NETWORK = of("proxy_network") - @JvmField val SUSPICIOUS_IP_ADDRESS = of("suspicious_ip_address") + @JvmField val REPEATED_ATTEMPTS = of("repeated_attempts") @JvmField val TEMPORARY_PHONE_NUMBER = of("temporary_phone_number") @@ -528,15 +570,24 @@ private constructor( /** An enum containing [RiskFactor]'s known values. */ enum class Known { ACCOUNT_RISK_PROFILE, - BEHAVIORAL_PATTERN, - DEVICE_ATTRIBUTE, + AUTOMATION_SIGNATURE, + CARRIER_NOT_PERMITTED, + CLIENT_FINGERPRINT_MISMATCH, + CUSTOM_POLICY, + DEVICE_EMULATOR, + DEVICE_NOT_PERMITTED, + DEVICE_REUSE, + EXPIRED_SIGNALS, FRAUD_DATABASE, - LOCATION_DISCREPANCY, - NETWORK_FINGERPRINT, + INVALID_SIGNATURE, + IP_CONCENTRATION, + IP_REPUTATION, + LOCATION_MISMATCH, + MISSING_SIGNALS, + NUMBER_RANGE_ABUSE, POOR_CONVERSION_HISTORY, - PREFIX_CONCENTRATION, - SUSPECTED_REQUEST_TAMPERING, - SUSPICIOUS_IP_ADDRESS, + PROXY_NETWORK, + REPEATED_ATTEMPTS, TEMPORARY_PHONE_NUMBER, } @@ -551,15 +602,24 @@ private constructor( */ enum class Value { ACCOUNT_RISK_PROFILE, - BEHAVIORAL_PATTERN, - DEVICE_ATTRIBUTE, + AUTOMATION_SIGNATURE, + CARRIER_NOT_PERMITTED, + CLIENT_FINGERPRINT_MISMATCH, + CUSTOM_POLICY, + DEVICE_EMULATOR, + DEVICE_NOT_PERMITTED, + DEVICE_REUSE, + EXPIRED_SIGNALS, FRAUD_DATABASE, - LOCATION_DISCREPANCY, - NETWORK_FINGERPRINT, + INVALID_SIGNATURE, + IP_CONCENTRATION, + IP_REPUTATION, + LOCATION_MISMATCH, + MISSING_SIGNALS, + NUMBER_RANGE_ABUSE, POOR_CONVERSION_HISTORY, - PREFIX_CONCENTRATION, - SUSPECTED_REQUEST_TAMPERING, - SUSPICIOUS_IP_ADDRESS, + PROXY_NETWORK, + REPEATED_ATTEMPTS, TEMPORARY_PHONE_NUMBER, /** * An enum member indicating that [RiskFactor] was instantiated with an unknown value. @@ -577,15 +637,24 @@ private constructor( fun value(): Value = when (this) { ACCOUNT_RISK_PROFILE -> Value.ACCOUNT_RISK_PROFILE - BEHAVIORAL_PATTERN -> Value.BEHAVIORAL_PATTERN - DEVICE_ATTRIBUTE -> Value.DEVICE_ATTRIBUTE + AUTOMATION_SIGNATURE -> Value.AUTOMATION_SIGNATURE + CARRIER_NOT_PERMITTED -> Value.CARRIER_NOT_PERMITTED + CLIENT_FINGERPRINT_MISMATCH -> Value.CLIENT_FINGERPRINT_MISMATCH + CUSTOM_POLICY -> Value.CUSTOM_POLICY + DEVICE_EMULATOR -> Value.DEVICE_EMULATOR + DEVICE_NOT_PERMITTED -> Value.DEVICE_NOT_PERMITTED + DEVICE_REUSE -> Value.DEVICE_REUSE + EXPIRED_SIGNALS -> Value.EXPIRED_SIGNALS FRAUD_DATABASE -> Value.FRAUD_DATABASE - LOCATION_DISCREPANCY -> Value.LOCATION_DISCREPANCY - NETWORK_FINGERPRINT -> Value.NETWORK_FINGERPRINT + INVALID_SIGNATURE -> Value.INVALID_SIGNATURE + IP_CONCENTRATION -> Value.IP_CONCENTRATION + IP_REPUTATION -> Value.IP_REPUTATION + LOCATION_MISMATCH -> Value.LOCATION_MISMATCH + MISSING_SIGNALS -> Value.MISSING_SIGNALS + NUMBER_RANGE_ABUSE -> Value.NUMBER_RANGE_ABUSE POOR_CONVERSION_HISTORY -> Value.POOR_CONVERSION_HISTORY - PREFIX_CONCENTRATION -> Value.PREFIX_CONCENTRATION - SUSPECTED_REQUEST_TAMPERING -> Value.SUSPECTED_REQUEST_TAMPERING - SUSPICIOUS_IP_ADDRESS -> Value.SUSPICIOUS_IP_ADDRESS + PROXY_NETWORK -> Value.PROXY_NETWORK + REPEATED_ATTEMPTS -> Value.REPEATED_ATTEMPTS TEMPORARY_PHONE_NUMBER -> Value.TEMPORARY_PHONE_NUMBER else -> Value._UNKNOWN } @@ -602,15 +671,24 @@ private constructor( fun known(): Known = when (this) { ACCOUNT_RISK_PROFILE -> Known.ACCOUNT_RISK_PROFILE - BEHAVIORAL_PATTERN -> Known.BEHAVIORAL_PATTERN - DEVICE_ATTRIBUTE -> Known.DEVICE_ATTRIBUTE + AUTOMATION_SIGNATURE -> Known.AUTOMATION_SIGNATURE + CARRIER_NOT_PERMITTED -> Known.CARRIER_NOT_PERMITTED + CLIENT_FINGERPRINT_MISMATCH -> Known.CLIENT_FINGERPRINT_MISMATCH + CUSTOM_POLICY -> Known.CUSTOM_POLICY + DEVICE_EMULATOR -> Known.DEVICE_EMULATOR + DEVICE_NOT_PERMITTED -> Known.DEVICE_NOT_PERMITTED + DEVICE_REUSE -> Known.DEVICE_REUSE + EXPIRED_SIGNALS -> Known.EXPIRED_SIGNALS FRAUD_DATABASE -> Known.FRAUD_DATABASE - LOCATION_DISCREPANCY -> Known.LOCATION_DISCREPANCY - NETWORK_FINGERPRINT -> Known.NETWORK_FINGERPRINT + INVALID_SIGNATURE -> Known.INVALID_SIGNATURE + IP_CONCENTRATION -> Known.IP_CONCENTRATION + IP_REPUTATION -> Known.IP_REPUTATION + LOCATION_MISMATCH -> Known.LOCATION_MISMATCH + MISSING_SIGNALS -> Known.MISSING_SIGNALS + NUMBER_RANGE_ABUSE -> Known.NUMBER_RANGE_ABUSE POOR_CONVERSION_HISTORY -> Known.POOR_CONVERSION_HISTORY - PREFIX_CONCENTRATION -> Known.PREFIX_CONCENTRATION - SUSPECTED_REQUEST_TAMPERING -> Known.SUSPECTED_REQUEST_TAMPERING - SUSPICIOUS_IP_ADDRESS -> Known.SUSPICIOUS_IP_ADDRESS + PROXY_NETWORK -> Known.PROXY_NETWORK + REPEATED_ATTEMPTS -> Known.REPEATED_ATTEMPTS TEMPORARY_PHONE_NUMBER -> Known.TEMPORARY_PHONE_NUMBER else -> throw PreludeInvalidDataException("Unknown RiskFactor: $value") } diff --git a/prelude-java-core/src/main/kotlin/so/prelude/sdk/services/async/WatchServiceAsync.kt b/prelude-java-core/src/main/kotlin/so/prelude/sdk/services/async/WatchServiceAsync.kt index 4cc71753..76c375c1 100644 --- a/prelude-java-core/src/main/kotlin/so/prelude/sdk/services/async/WatchServiceAsync.kt +++ b/prelude-java-core/src/main/kotlin/so/prelude/sdk/services/async/WatchServiceAsync.kt @@ -32,8 +32,9 @@ interface WatchServiceAsync { fun withOptions(modifier: Consumer): WatchServiceAsync /** - * **Beta.** The request and response shapes may still change, and flows and recipes are - * configured by Prelude on your behalf for now. Talk to us before you build against it. + * **Beta.** The request and response shapes may still change. Talk to us before you build + * against it. Flows, recipes and rules are authored through the Watch Management API, or + * configured by Prelude on your behalf. * * Score a target against the rules configured for one moment in your product — signup, * checkout, password reset. The flow selects which recipes run; each recipe scores its rules diff --git a/prelude-java-core/src/main/kotlin/so/prelude/sdk/services/blocking/WatchService.kt b/prelude-java-core/src/main/kotlin/so/prelude/sdk/services/blocking/WatchService.kt index c0cdd836..21d58a77 100644 --- a/prelude-java-core/src/main/kotlin/so/prelude/sdk/services/blocking/WatchService.kt +++ b/prelude-java-core/src/main/kotlin/so/prelude/sdk/services/blocking/WatchService.kt @@ -32,8 +32,9 @@ interface WatchService { fun withOptions(modifier: Consumer): WatchService /** - * **Beta.** The request and response shapes may still change, and flows and recipes are - * configured by Prelude on your behalf for now. Talk to us before you build against it. + * **Beta.** The request and response shapes may still change. Talk to us before you build + * against it. Flows, recipes and rules are authored through the Watch Management API, or + * configured by Prelude on your behalf. * * Score a target against the rules configured for one moment in your product — signup, * checkout, password reset. The flow selects which recipes run; each recipe scores its rules diff --git a/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/VerificationCreateResponseTest.kt b/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/VerificationCreateResponseTest.kt index e42a6898..c535d99d 100644 --- a/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/VerificationCreateResponseTest.kt +++ b/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/VerificationCreateResponseTest.kt @@ -25,7 +25,7 @@ internal class VerificationCreateResponseTest { ) .reason(VerificationCreateResponse.Reason.INVALID_PHONE_NUMBER) .requestId("request_id") - .addRiskFactor(VerificationCreateResponse.RiskFactor.SUSPICIOUS_IP_ADDRESS) + .addRiskFactor(VerificationCreateResponse.RiskFactor.PROXY_NETWORK) .addRiskFactor(VerificationCreateResponse.RiskFactor.FRAUD_DATABASE) .silent( VerificationCreateResponse.Silent.builder().requestUrl("request_url").build() @@ -50,7 +50,7 @@ internal class VerificationCreateResponseTest { assertThat(verificationCreateResponse.requestId()).contains("request_id") assertThat(verificationCreateResponse.riskFactors().getOrNull()) .containsExactly( - VerificationCreateResponse.RiskFactor.SUSPICIOUS_IP_ADDRESS, + VerificationCreateResponse.RiskFactor.PROXY_NETWORK, VerificationCreateResponse.RiskFactor.FRAUD_DATABASE, ) assertThat(verificationCreateResponse.silent()) @@ -73,7 +73,7 @@ internal class VerificationCreateResponseTest { ) .reason(VerificationCreateResponse.Reason.INVALID_PHONE_NUMBER) .requestId("request_id") - .addRiskFactor(VerificationCreateResponse.RiskFactor.SUSPICIOUS_IP_ADDRESS) + .addRiskFactor(VerificationCreateResponse.RiskFactor.PROXY_NETWORK) .addRiskFactor(VerificationCreateResponse.RiskFactor.FRAUD_DATABASE) .silent( VerificationCreateResponse.Silent.builder().requestUrl("request_url").build() diff --git a/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/VerificationPhoneHistoryRetrieveResponseTest.kt b/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/VerificationPhoneHistoryRetrieveResponseTest.kt index 3e51d763..707c86fd 100644 --- a/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/VerificationPhoneHistoryRetrieveResponseTest.kt +++ b/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/VerificationPhoneHistoryRetrieveResponseTest.kt @@ -22,7 +22,7 @@ internal class VerificationPhoneHistoryRetrieveResponseTest { .status(VerificationPhoneHistoryRetrieveResponse.Status.CONVERTED) .appVersion("app_version") .addBlockReason( - VerificationPhoneHistoryRetrieveResponse.BlockReason.BEHAVIORAL_PATTERN + VerificationPhoneHistoryRetrieveResponse.BlockReason.AUTOMATION_SIGNATURE ) .carrier(PhoneVerificationCarrier.builder().mccmnc("208-01").name("Orange").build()) .correlationId("correlation_id") @@ -225,7 +225,7 @@ internal class VerificationPhoneHistoryRetrieveResponseTest { assertThat(verificationPhoneHistoryRetrieveResponse.appVersion()).contains("app_version") assertThat(verificationPhoneHistoryRetrieveResponse.blockReasons().getOrNull()) .containsExactly( - VerificationPhoneHistoryRetrieveResponse.BlockReason.BEHAVIORAL_PATTERN + VerificationPhoneHistoryRetrieveResponse.BlockReason.AUTOMATION_SIGNATURE ) assertThat(verificationPhoneHistoryRetrieveResponse.carrier()) .contains(PhoneVerificationCarrier.builder().mccmnc("208-01").name("Orange").build()) @@ -429,7 +429,7 @@ internal class VerificationPhoneHistoryRetrieveResponseTest { .status(VerificationPhoneHistoryRetrieveResponse.Status.CONVERTED) .appVersion("app_version") .addBlockReason( - VerificationPhoneHistoryRetrieveResponse.BlockReason.BEHAVIORAL_PATTERN + VerificationPhoneHistoryRetrieveResponse.BlockReason.AUTOMATION_SIGNATURE ) .carrier(PhoneVerificationCarrier.builder().mccmnc("208-01").name("Orange").build()) .correlationId("correlation_id") diff --git a/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/WatchEvaluateResponseTest.kt b/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/WatchEvaluateResponseTest.kt index d04670ff..8f34bd84 100644 --- a/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/WatchEvaluateResponseTest.kt +++ b/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/WatchEvaluateResponseTest.kt @@ -23,10 +23,12 @@ internal class WatchEvaluateResponseTest { WatchEvaluateResponse.Recipe.Rule.builder() .outcome(WatchEvaluateResponse.Recipe.Rule.Outcome.TRIGGERED) .ruleId("rul_01jc0t6fwwfgfsq1md24mhyztj") + .type(WatchEvaluateResponse.Recipe.Rule.Type.MANAGED) .weight(10L) .blockedBy("missing_data") .name("high_value_cart_new_account") .unavailable(true) + .versionId("3sL4kqtJlcpXroDTDmJ.o.Jj7bB5dGH6") .build() ) .score(20L) @@ -49,10 +51,12 @@ internal class WatchEvaluateResponseTest { WatchEvaluateResponse.Recipe.Rule.builder() .outcome(WatchEvaluateResponse.Recipe.Rule.Outcome.TRIGGERED) .ruleId("rul_01jc0t6fwwfgfsq1md24mhyztj") + .type(WatchEvaluateResponse.Recipe.Rule.Type.MANAGED) .weight(10L) .blockedBy("missing_data") .name("high_value_cart_new_account") .unavailable(true) + .versionId("3sL4kqtJlcpXroDTDmJ.o.Jj7bB5dGH6") .build() ) .score(20L) @@ -79,10 +83,12 @@ internal class WatchEvaluateResponseTest { WatchEvaluateResponse.Recipe.Rule.builder() .outcome(WatchEvaluateResponse.Recipe.Rule.Outcome.TRIGGERED) .ruleId("rul_01jc0t6fwwfgfsq1md24mhyztj") + .type(WatchEvaluateResponse.Recipe.Rule.Type.MANAGED) .weight(10L) .blockedBy("missing_data") .name("high_value_cart_new_account") .unavailable(true) + .versionId("3sL4kqtJlcpXroDTDmJ.o.Jj7bB5dGH6") .build() ) .score(20L) diff --git a/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/WatchPredictResponseTest.kt b/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/WatchPredictResponseTest.kt index a3ec651d..7226f572 100644 --- a/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/WatchPredictResponseTest.kt +++ b/prelude-java-core/src/test/kotlin/so/prelude/sdk/models/WatchPredictResponseTest.kt @@ -17,7 +17,7 @@ internal class WatchPredictResponseTest { .id("prd_01jc0t6fwwfgfsq1md24mhyztj") .prediction(WatchPredictResponse.Prediction.LEGITIMATE) .requestId("3d19215e-2991-4a05-a41a-527314e6ff6a") - .addRiskFactor(WatchPredictResponse.RiskFactor.SUSPICIOUS_IP_ADDRESS) + .addRiskFactor(WatchPredictResponse.RiskFactor.PROXY_NETWORK) .addRiskFactor(WatchPredictResponse.RiskFactor.FRAUD_DATABASE) .build() @@ -28,7 +28,7 @@ internal class WatchPredictResponseTest { .isEqualTo("3d19215e-2991-4a05-a41a-527314e6ff6a") assertThat(watchPredictResponse.riskFactors().getOrNull()) .containsExactly( - WatchPredictResponse.RiskFactor.SUSPICIOUS_IP_ADDRESS, + WatchPredictResponse.RiskFactor.PROXY_NETWORK, WatchPredictResponse.RiskFactor.FRAUD_DATABASE, ) } @@ -41,7 +41,7 @@ internal class WatchPredictResponseTest { .id("prd_01jc0t6fwwfgfsq1md24mhyztj") .prediction(WatchPredictResponse.Prediction.LEGITIMATE) .requestId("3d19215e-2991-4a05-a41a-527314e6ff6a") - .addRiskFactor(WatchPredictResponse.RiskFactor.SUSPICIOUS_IP_ADDRESS) + .addRiskFactor(WatchPredictResponse.RiskFactor.PROXY_NETWORK) .addRiskFactor(WatchPredictResponse.RiskFactor.FRAUD_DATABASE) .build() diff --git a/prelude-java-proguard-test/src/test/kotlin/so/prelude/sdk/proguard/ProGuardCompatibilityTest.kt b/prelude-java-proguard-test/src/test/kotlin/so/prelude/sdk/proguard/ProGuardCompatibilityTest.kt index 9df77a52..f6bcd8c9 100644 --- a/prelude-java-proguard-test/src/test/kotlin/so/prelude/sdk/proguard/ProGuardCompatibilityTest.kt +++ b/prelude-java-proguard-test/src/test/kotlin/so/prelude/sdk/proguard/ProGuardCompatibilityTest.kt @@ -72,7 +72,7 @@ internal class ProGuardCompatibilityTest { ) .reason(VerificationCreateResponse.Reason.INVALID_PHONE_NUMBER) .requestId("request_id") - .addRiskFactor(VerificationCreateResponse.RiskFactor.SUSPICIOUS_IP_ADDRESS) + .addRiskFactor(VerificationCreateResponse.RiskFactor.PROXY_NETWORK) .addRiskFactor(VerificationCreateResponse.RiskFactor.FRAUD_DATABASE) .silent( VerificationCreateResponse.Silent.builder().requestUrl("request_url").build() From 6d8a6e26fb857e50ff40dd4a4ce07a21934a1c1b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 18 Sep 2026 18:25:09 +0000 Subject: [PATCH 2/3] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 9e7e8a59..73ca5fad 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 27 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/prelude/prelude-0594c397de9595800d24337cbb03d0d1b7a1af7c0596890f5cf860662af1fd3b.yml -openapi_spec_hash: abc172473948cdc82c6baa4462fad2d9 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/prelude/prelude-fdbaf5386743020c305990b67afae97f62c69478baafc39c3efbd296cb62770c.yml +openapi_spec_hash: 14d5b04b5dfa004a9cb0b1317e928abe config_hash: 707d65d2f456a2b5ba5b2c565b60128a From 880b4db85314a40efe1563da97f129841275c8e5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 18 Sep 2026 18:25:31 +0000 Subject: [PATCH 3/3] release: 0.16.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ README.md | 10 +++++----- build.gradle.kts | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8f3e0a49..b4e9013b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.15.0" + ".": "0.16.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8317f99e..235aa304 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.16.0 (2026-09-18) + +Full Changelog: [v0.15.0...v0.16.0](https://github.com/prelude-so/java-sdk/compare/v0.15.0...v0.16.0) + +### Features + +* **api:** api update ([9425a63](https://github.com/prelude-so/java-sdk/commit/9425a6319edcfcf7476b5be0b448663cbf653e6e)) + ## 0.15.0 (2026-09-18) Full Changelog: [v0.14.0...v0.15.0](https://github.com/prelude-so/java-sdk/compare/v0.14.0...v0.15.0) diff --git a/README.md b/README.md index b560586c..7250b50b 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/so.prelude.sdk/prelude-java)](https://central.sonatype.com/artifact/so.prelude.sdk/prelude-java/0.15.0) -[![javadoc](https://javadoc.io/badge2/so.prelude.sdk/prelude-java/javadoc.svg)](https://javadoc.io/doc/so.prelude.sdk/prelude-java/0.15.0) +[![Maven Central](https://img.shields.io/maven-central/v/so.prelude.sdk/prelude-java)](https://central.sonatype.com/artifact/so.prelude.sdk/prelude-java/0.16.0) +[![javadoc](https://javadoc.io/badge2/so.prelude.sdk/prelude-java/javadoc.svg)](https://javadoc.io/doc/so.prelude.sdk/prelude-java/0.16.0) @@ -13,7 +13,7 @@ It is generated with [Stainless](https://www.stainless.com/). -The REST API documentation can be found on [docs.prelude.so](https://docs.prelude.so). Javadocs are available on [javadoc.io](https://javadoc.io/doc/so.prelude.sdk/prelude-java/0.15.0). +The REST API documentation can be found on [docs.prelude.so](https://docs.prelude.so). Javadocs are available on [javadoc.io](https://javadoc.io/doc/so.prelude.sdk/prelude-java/0.16.0). @@ -24,7 +24,7 @@ The REST API documentation can be found on [docs.prelude.so](https://docs.prelud ### Gradle ```kotlin -implementation("so.prelude.sdk:prelude-java:0.15.0") +implementation("so.prelude.sdk:prelude-java:0.16.0") ``` ### Maven @@ -33,7 +33,7 @@ implementation("so.prelude.sdk:prelude-java:0.15.0") so.prelude.sdk prelude-java - 0.15.0 + 0.16.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index f2d0c2e9..195f7533 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ repositories { allprojects { group = "so.prelude.sdk" - version = "0.15.0" // x-release-please-version + version = "0.16.0" // x-release-please-version } subprojects {