Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.15.0"
".": "0.16.0"
}
4 changes: 2 additions & 2 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -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-fdbaf5386743020c305990b67afae97f62c69478baafc39c3efbd296cb62770c.yml
openapi_spec_hash: 14d5b04b5dfa004a9cb0b1317e928abe
config_hash: 707d65d2f456a2b5ba5b2c565b60128a
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 0.16.0 (2026-09-18)

Full Changelog: [v0.15.0...v0.16.0](https://github.com/prelude-so/python-sdk/compare/v0.15.0...v0.16.0)

### Features

* **api:** api update ([0dcc0e1](https://github.com/prelude-so/python-sdk/commit/0dcc0e103c3904f1b9d3384acf5d18a05e0f2987))

## 0.15.0 (2026-09-18)

Full Changelog: [v0.14.0...v0.15.0](https://github.com/prelude-so/python-sdk/compare/v0.14.0...v0.15.0)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "prelude-python-sdk"
version = "0.15.0"
version = "0.16.0"
description = "The official Python library for the Prelude API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion src/prelude_python_sdk/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "prelude_python_sdk"
__version__ = "0.15.0" # x-release-please-version
__version__ = "0.16.0" # x-release-please-version
18 changes: 10 additions & 8 deletions src/prelude_python_sdk/resources/watch.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,11 @@ def evaluate(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> WatchEvaluateResponse:
"""
**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
Expand Down Expand Up @@ -307,10 +308,11 @@ async def evaluate(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> WatchEvaluateResponse:
"""
**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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ class Verification(BaseModel):
- `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.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,8 @@ class HistoryRetrieveResponse(BaseModel):
- `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.
"""
Expand All @@ -241,46 +241,68 @@ class HistoryRetrieveResponse(BaseModel):
block_reasons: Optional[
List[
Literal[
"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",
]
]
] = None
"""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.
"""

carrier: Optional[PhoneVerificationCarrier] = None
Expand Down
85 changes: 55 additions & 30 deletions src/prelude_python_sdk/types/verification_create_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,10 @@ class VerificationCreateResponse(BaseModel):
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.
"""
Expand All @@ -87,15 +88,24 @@ class VerificationCreateResponse(BaseModel):
risk_factors: Optional[
List[
Literal[
"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",
]
]
Expand All @@ -105,26 +115,41 @@ class VerificationCreateResponse(BaseModel):
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.
"""

silent: Optional[Silent] = None
Expand Down
27 changes: 25 additions & 2 deletions src/prelude_python_sdk/types/watch_evaluate_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@


class RecipeRule(BaseModel):
outcome: Literal["TRIGGERED", "NOT_TRIGGERED", "NOT_EVALUATED"]
outcome: Literal["TRIGGERED", "NOT_TRIGGERED", "NOT_EVALUATED", "SKIPPED"]
"""What the rule concluded.

- `TRIGGERED` - The condition held; `weight` was added to the score.
- `NOT_TRIGGERED` - The condition did not hold.
- `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.
"""

rule_id: str
Expand All @@ -26,6 +30,16 @@ class RecipeRule(BaseModel):
of is still one you can reweight, switch off, or ask us about.
"""

type: Literal["MANAGED", "CUSTOM"]
"""
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.
"""

weight: int
"""What this rule contributes to the recipe's score when it triggers."""

Expand All @@ -51,6 +65,13 @@ class RecipeRule(BaseModel):
request. `outcome` is `NOT_EVALUATED` and the failure is ours to fix.
"""

version_id: Optional[str] = None
"""
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.
"""


class Recipe(BaseModel):
partial_evidence: bool
Expand All @@ -67,7 +88,9 @@ class Recipe(BaseModel):
"""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.
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.
"""

score: int
Expand Down
Loading
Loading