noresponse 4.0.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/no_response/accounts.rb +1 -1
- data/lib/no_response/assessments.rb +4 -4
- data/lib/no_response/integrations.rb +1 -1
- data/lib/no_response/issued_credential.rb +1 -1
- data/lib/no_response/keyusage.rb +2 -2
- data/lib/no_response/late_results.rb +1 -1
- data/lib/no_response/models/operations/createassessment_request.rb +1 -1
- data/lib/no_response/models/operations/deleteaccount_request.rb +1 -1
- data/lib/no_response/models/operations/deleteintegration_request.rb +1 -1
- data/lib/no_response/models/operations/deletewebhookendpoint_request.rb +1 -1
- data/lib/no_response/models/operations/getaccount_request.rb +1 -1
- data/lib/no_response/models/operations/listaccountassessments_request.rb +1 -1
- data/lib/no_response/models/operations/listwebhookdeliveries_request.rb +1 -1
- data/lib/no_response/models/operations/recordassessmentoutcome_request.rb +1 -1
- data/lib/no_response/models/operations/recordkeyusage_request.rb +1 -1
- data/lib/no_response/models/operations/replaywebhookdelivery_request.rb +2 -2
- data/lib/no_response/models/operations/rotateintegrationsecret_request.rb +1 -1
- data/lib/no_response/models/operations/rotatewebhooksigningkey_request.rb +1 -1
- data/lib/no_response/models/operations/sendwebhooktestevent_request.rb +1 -1
- data/lib/no_response/models/shared/account.rb +3 -3
- data/lib/no_response/models/shared/accountdecisionsbyflow.rb +7 -7
- data/lib/no_response/models/shared/accountdecisionsbyflow.rbi +2 -2
- data/lib/no_response/models/shared/accountdeletion.rb +1 -1
- data/lib/no_response/models/shared/assessment.rb +2 -2
- data/lib/no_response/models/shared/assessmentdeletion.rb +1 -1
- data/lib/no_response/models/shared/assessmentdetail.rb +4 -4
- data/lib/no_response/models/shared/assessmentdetailauthcontext.rb +1 -1
- data/lib/no_response/models/shared/assessmentlist.rb +3 -3
- data/lib/no_response/models/shared/assessmentoutcome.rb +3 -3
- data/lib/no_response/models/shared/assessmentoutcomerequest.rb +2 -2
- data/lib/no_response/models/shared/assessmentquery.rb +2 -2
- data/lib/no_response/models/shared/assessmentrequest.rb +5 -5
- data/lib/no_response/models/shared/assessmentrequestclientcontext.rb +4 -4
- data/lib/no_response/models/shared/assessmentrequestidentifiers.rb +1 -1
- data/lib/no_response/models/shared/assessmentrequestissuedcredential.rb +1 -1
- data/lib/no_response/models/shared/assessmentrequestpolicycontext.rb +1 -1
- data/lib/no_response/models/shared/authcontext.rb +1 -1
- data/lib/no_response/models/shared/flow.rb +2 -2
- data/lib/no_response/models/shared/integration.rb +1 -1
- data/lib/no_response/models/shared/integrationlist.rb +1 -1
- data/lib/no_response/models/shared/integrationrequest.rb +1 -1
- data/lib/no_response/models/shared/ipsummary.rb +8 -8
- data/lib/no_response/models/shared/ipsummary.rbi +2 -2
- data/lib/no_response/models/shared/keyrotationrequest.rb +1 -1
- data/lib/no_response/models/shared/keyusagebatchrequest.rb +1 -1
- data/lib/no_response/models/shared/outcome.rb +1 -1
- data/lib/no_response/models/shared/permissiondeniederrorcode.rb +1 -1
- data/lib/no_response/models/shared/reasoncode.rb +1 -1
- data/lib/no_response/models/shared/risk.rb +3 -3
- data/lib/no_response/models/shared/risksummary.rb +1 -1
- data/lib/no_response/models/shared/signal.rb +1 -1
- data/lib/no_response/models/shared/webhookdeliverylist.rb +2 -2
- data/lib/no_response/models/shared/webhookendpoint.rb +1 -1
- data/lib/no_response/models/shared/webhookendpointcreated.rb +1 -1
- data/lib/no_response/models/shared/webhookendpointlist.rb +1 -1
- data/lib/no_response/models/shared/webhookendpointrequest.rb +1 -1
- data/lib/no_response/sdkconfiguration.rb +2 -2
- data/lib/no_response/webhookendpoints.rb +2 -2
- data/lib/no_response/webhooks.rb +8 -8
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a5cc779fba02d556d64cfc5380616093dcef3728b81aaff1c695bc21b5fc7304
|
|
4
|
+
data.tar.gz: c0a927bcd4495917a0e7ada33c1846952b9050962b54f201991bcd2eb76cdd03
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f49f16f788ae91a0c7519fe3afa6ec25c28565cee60a9825341b4dc1f81f3887d0ec896828c8674c3df14b321eb29a1dfd5cdf26f67b9ed7fbea4569b4bb0503
|
|
7
|
+
data.tar.gz: 770c20e277eb10ad7dee955495ae925147c0142743582a1ad638a47efafd3f7c6e7c0684d5710b13f71fb4c455290cd83dc19f2a2736fecec7367af1c1e9ae1f
|
data/lib/no_response/accounts.rb
CHANGED
|
@@ -636,7 +636,7 @@ module NoResponse
|
|
|
636
636
|
http_headers: nil
|
|
637
637
|
)
|
|
638
638
|
# list_assessments - Page through one account's unexpired assessments.
|
|
639
|
-
# The account's history: the same page as POST /v1/assessments/query for this account_id, newest first, each at its latest assessment_version. Requires the history scope. Read-only and safe to retry. An account with no assessments answers 200 with empty items. The cursor is opaque and bound to your
|
|
639
|
+
# The account's history: the same page as POST /v1/assessments/query for this account_id, newest first, each at its latest assessment_version. Requires the history scope. Read-only and safe to retry. An account with no assessments answers 200 with empty items. The cursor is opaque and bound to your workspace and the account; a tampered or expired cursor answers 400 invalid_cursor. response_mode=detailed needs the detailed scope. The account_id travels in the URL; use POST /v1/assessments/query to keep it out of access logs.
|
|
640
640
|
request = Models::Operations::ListAccountAssessmentsRequest.new(
|
|
641
641
|
account_id: account_id,
|
|
642
642
|
limit: limit,
|
|
@@ -16,7 +16,7 @@ module NoResponse
|
|
|
16
16
|
class Assessments
|
|
17
17
|
extend T::Sig
|
|
18
18
|
|
|
19
|
-
#
|
|
19
|
+
# Assessments of account creation, login and purchase.
|
|
20
20
|
|
|
21
21
|
sig { params(sdk_config: SDKConfiguration).void }
|
|
22
22
|
def initialize(sdk_config)
|
|
@@ -50,7 +50,7 @@ module NoResponse
|
|
|
50
50
|
}
|
|
51
51
|
def create(body:, idempotency_key: nil, retries: nil, timeout_ms: nil, http_headers: nil)
|
|
52
52
|
# create - Assess identifiers for a signup or gateway decision.
|
|
53
|
-
# Assesses one
|
|
53
|
+
# Assesses one account creation, login or purchase (flow) and answers with the account's one current risk: account.risk.decision is the decision for this flow (allow, step_up, review or block, where block means your block threshold was reached), and detail holds this assessment's own facts. depth sets how long the answer waits for sources: quick waits only for the fast ones (500 ms), full for the whole budget (3000 ms at most); it defaults to full for account_creation and purchase and quick for login. 200 carries complete or partial, 202 carries pending with Location and Retry-After. While the account's first assessment is pending, account is absent: apply your own fallback for that, 429, 503 or a timeout. NoResponse blocks nothing itself; you decide. Requires the assess scope. Idempotency-Key is optional in the SDK and is bound to the body for 24 hours: the same key with the same body replays the latest assessment with Idempotent-Replayed: true and starts no new work; the same key with a different body answers 409 idempotency_key_reused. response_mode defaults to standard; detailed needs the detailed scope.
|
|
54
54
|
request = Models::Operations::CreateAssessmentRequest.new(
|
|
55
55
|
body: body,
|
|
56
56
|
idempotency_key: idempotency_key
|
|
@@ -348,7 +348,7 @@ module NoResponse
|
|
|
348
348
|
}
|
|
349
349
|
def get(assessment_id:, response_mode: nil, retries: nil, timeout_ms: nil, http_headers: nil)
|
|
350
350
|
# get - Poll the authoritative assessment of one assessment.
|
|
351
|
-
# Returns the highest assessment_version, with the account's current risk. Requires the assess or history scope. While status is pending, or partial with a source still running, the response carries Retry-After; poll no faster than it says. Another
|
|
351
|
+
# Returns the highest assessment_version, with the account's current risk. Requires the assess or history scope. While status is pending, or partial with a source still running, the response carries Retry-After; poll no faster than it says. Another workspace's assessment, an unknown or expired assessment and a malformed assessment_id all answer 404 not_found. response_mode=detailed needs the detailed scope.
|
|
352
352
|
request = Models::Operations::GetAssessmentRequest.new(
|
|
353
353
|
assessment_id: assessment_id,
|
|
354
354
|
response_mode: response_mode
|
|
@@ -1232,7 +1232,7 @@ module NoResponse
|
|
|
1232
1232
|
}
|
|
1233
1233
|
def query(request:, retries: nil, timeout_ms: nil, http_headers: nil)
|
|
1234
1234
|
# query - Page through one account's unexpired assessments.
|
|
1235
|
-
# History is a POST with account_id in the body so an account identifier stays out of URLs and access logs. Requires the history scope. Read-only and safe to retry. Newest first, each at its latest assessment_version. An account with no assessments answers 200 with empty items. The cursor is opaque and bound to your
|
|
1235
|
+
# History is a POST with account_id in the body so an account identifier stays out of URLs and access logs. Requires the history scope. Read-only and safe to retry. Newest first, each at its latest assessment_version. An account with no assessments answers 200 with empty items. The cursor is opaque and bound to your workspace and the account; a tampered or expired cursor answers 400 invalid_cursor. response_mode=detailed needs the detailed scope.
|
|
1236
1236
|
url, params = @sdk_configuration.get_server_details
|
|
1237
1237
|
base_url = Utils.template_url(url, params)
|
|
1238
1238
|
url = "#{base_url}/v1/assessments/query"
|
|
@@ -324,7 +324,7 @@ module NoResponse
|
|
|
324
324
|
.returns(Models::Operations::ListIntegrationsResponse)
|
|
325
325
|
}
|
|
326
326
|
def list(retries: nil, timeout_ms: nil, http_headers: nil)
|
|
327
|
-
# list - List the
|
|
327
|
+
# list - List the workspace's integrations.
|
|
328
328
|
# Every integration, oldest first. Listings carry no secrets. Requires the integrations scope.
|
|
329
329
|
url, params = @sdk_configuration.get_server_details
|
|
330
330
|
base_url = Utils.template_url(url, params)
|
data/lib/no_response/keyusage.rb
CHANGED
|
@@ -46,8 +46,8 @@ module NoResponse
|
|
|
46
46
|
.returns(Models::Operations::RecordKeyUsageResponse)
|
|
47
47
|
}
|
|
48
48
|
def record(body:, idempotency_key: nil, retries: nil, timeout_ms: nil, http_headers: nil)
|
|
49
|
-
# record - Report requests made with API keys your
|
|
50
|
-
# Records requests made with API keys your
|
|
49
|
+
# record - Report requests made with API keys your platform issued.
|
|
50
|
+
# Records requests made with API keys your platform issued to your accounts, one event per request: the key's SHA-256 (the issued_credential.sha256 the account's assessment carried), the client IP, the time and optionally the user agent, model and token counts. Most callers use the SDK's usage buffer, which batches events and sends them in the background. Sampling is allowed: sample_rate weights an event's request and token counts. Requires the assess scope. Idempotency-Key is optional in the SDK and handled as on POST /v1/assessments: a retry with the same key and body answers the same record with Idempotent-Replayed: true and counts nothing again; a different body answers 409. A batch holds 1 to 500 events and at most 256 KiB. No raw event is kept: usage is aggregated per key, and IPs, user agents and models are kept only as keyed digests, with the IP's country, for 24 hours. When one key is used from 20 or more IP addresses, or 3 or more countries, within 24 hours, every account whose assessment carried that key gets the shared_api_key reason for 30 days.
|
|
51
51
|
request = Models::Operations::RecordKeyUsageRequest.new(
|
|
52
52
|
body: body,
|
|
53
53
|
idempotency_key: idempotency_key
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
# Late-result handlers. Hand-written beside the generated client.
|
|
5
5
|
#
|
|
6
|
-
# An assessment can be revised after the
|
|
6
|
+
# An assessment can be revised after the account creation was allowed: a slow source
|
|
7
7
|
# settles and the account's decision rises. NoResponse sends the new version as a
|
|
8
8
|
# signed assessment.updated webhook. LateResults.handle verifies that delivery
|
|
9
9
|
# with Webhooks.construct_event, picks an action from your policy, and acts
|
|
@@ -10,7 +10,7 @@ module NoResponse
|
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
12
|
field :body, Models::Shared::AssessmentRequest, {'request': {'media_type': "application/json"}}
|
|
13
|
-
# Opaque client key, 16 to 128 characters of [A-Za-z0-9._:-] (a UUID or ULID fits). Scoped to the
|
|
13
|
+
# Opaque client key, 16 to 128 characters of [A-Za-z0-9._:-] (a UUID or ULID fits). Scoped to the workspace principal and bound to the canonical body for 24 hours. Optional: the SDK generates a UUID when you omit it and sends the same key on every retry of the call.
|
|
14
14
|
field(
|
|
15
15
|
:idempotency_key,
|
|
16
16
|
Crystalline::Nilable.new(::String),
|
|
@@ -9,7 +9,7 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# The account_id the
|
|
12
|
+
# The account_id the workspace sends with its assessments, as one path segment (percent-encode '|' and ':' if the client requires it). A value that does not match the account_id shape answers 400 invalid_request.
|
|
13
13
|
field :account_id, ::String, {'path_param': {'field_name': "account_id", 'style': "simple", 'explode': false}}
|
|
14
14
|
|
|
15
15
|
sig { params(account_id: ::String).void }
|
|
@@ -9,7 +9,7 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# Path segment, matched case-sensitively. A value that does not match the integration_id shape, or another
|
|
12
|
+
# Path segment, matched case-sensitively. A value that does not match the integration_id shape, or another workspace's id, answers 404.
|
|
13
13
|
field(
|
|
14
14
|
:integration_id,
|
|
15
15
|
::String,
|
|
@@ -9,7 +9,7 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# The endpoint's whe_ id. An id that is unknown, malformed or another
|
|
12
|
+
# The endpoint's whe_ id. An id that is unknown, malformed or another workspace's answers 404.
|
|
13
13
|
field :endpoint_id, ::String, {'path_param': {'field_name': "endpoint_id", 'style': "simple", 'explode': false}}
|
|
14
14
|
|
|
15
15
|
sig { params(endpoint_id: ::String).void }
|
|
@@ -9,7 +9,7 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# The account_id the
|
|
12
|
+
# The account_id the workspace sends with its assessments, as one path segment (percent-encode '|' and ':' if the client requires it). A value that does not match the account_id shape answers 400 invalid_request.
|
|
13
13
|
field :account_id, ::String, {'path_param': {'field_name': "account_id", 'style': "simple", 'explode': false}}
|
|
14
14
|
|
|
15
15
|
sig { params(account_id: ::String).void }
|
|
@@ -9,7 +9,7 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# The account_id the
|
|
12
|
+
# The account_id the workspace sends with its assessments, as one path segment (percent-encode '|' and ':' if the client requires it). A value that does not match the account_id shape answers 400 invalid_request.
|
|
13
13
|
field :account_id, ::String, {'path_param': {'field_name': "account_id", 'style': "simple", 'explode': false}}
|
|
14
14
|
# next_cursor from the previous page, unchanged.
|
|
15
15
|
field(
|
|
@@ -9,7 +9,7 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# The endpoint's whe_ id. An id that is unknown, malformed or another
|
|
12
|
+
# The endpoint's whe_ id. An id that is unknown, malformed or another workspace's answers 404.
|
|
13
13
|
field :endpoint_id, ::String, {'path_param': {'field_name': "endpoint_id", 'style': "simple", 'explode': false}}
|
|
14
14
|
# next_cursor from the previous page, unchanged.
|
|
15
15
|
field(
|
|
@@ -17,7 +17,7 @@ module NoResponse
|
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
field :body, Models::Shared::AssessmentOutcomeRequest, {'request': {'media_type': "application/json"}}
|
|
20
|
-
# Opaque client key, 16 to 128 characters of [A-Za-z0-9._:-] (a UUID or ULID fits). Scoped to the
|
|
20
|
+
# Opaque client key, 16 to 128 characters of [A-Za-z0-9._:-] (a UUID or ULID fits). Scoped to the workspace principal and bound to the canonical body for 24 hours. Optional: the SDK generates a UUID when you omit it and sends the same key on every retry of the call.
|
|
21
21
|
field(
|
|
22
22
|
:idempotency_key,
|
|
23
23
|
Crystalline::Nilable.new(::String),
|
|
@@ -10,7 +10,7 @@ module NoResponse
|
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
12
|
field :body, Models::Shared::KeyUsageBatchRequest, {'request': {'media_type': "application/json"}}
|
|
13
|
-
# Opaque client key, 16 to 128 characters of [A-Za-z0-9._:-] (a UUID or ULID fits). Scoped to the
|
|
13
|
+
# Opaque client key, 16 to 128 characters of [A-Za-z0-9._:-] (a UUID or ULID fits). Scoped to the workspace principal and bound to the canonical body for 24 hours. Optional: the SDK generates a UUID when you omit it and sends the same key on every retry of the call.
|
|
14
14
|
field(
|
|
15
15
|
:idempotency_key,
|
|
16
16
|
Crystalline::Nilable.new(::String),
|
|
@@ -9,9 +9,9 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# The endpoint's whe_ id. An id that is unknown, malformed or another
|
|
12
|
+
# The endpoint's whe_ id. An id that is unknown, malformed or another workspace's answers 404.
|
|
13
13
|
field :endpoint_id, ::String, {'path_param': {'field_name': "endpoint_id", 'style': "simple", 'explode': false}}
|
|
14
|
-
# The evt_ id of a delivery the endpoint's log holds, as GET /v1/webhooks/{endpoint_id}/deliveries lists it. An id that is malformed, not sent to this endpoint, past the log's retention or another
|
|
14
|
+
# The evt_ id of a delivery the endpoint's log holds, as GET /v1/webhooks/{endpoint_id}/deliveries lists it. An id that is malformed, not sent to this endpoint, past the log's retention or another workspace's answers 404.
|
|
15
15
|
field :event_id, ::String, {'path_param': {'field_name': "event_id", 'style': "simple", 'explode': false}}
|
|
16
16
|
|
|
17
17
|
field :body, Models::Shared::WebhookReplayRequest, {'request': {'media_type': "application/json"}}
|
|
@@ -9,7 +9,7 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# Path segment, matched case-sensitively. A value that does not match the integration_id shape, or another
|
|
12
|
+
# Path segment, matched case-sensitively. A value that does not match the integration_id shape, or another workspace's id, answers 404.
|
|
13
13
|
field(
|
|
14
14
|
:integration_id,
|
|
15
15
|
::String,
|
|
@@ -9,7 +9,7 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# The endpoint's whe_ id. An id that is unknown, malformed or another
|
|
12
|
+
# The endpoint's whe_ id. An id that is unknown, malformed or another workspace's answers 404.
|
|
13
13
|
field :endpoint_id, ::String, {'path_param': {'field_name': "endpoint_id", 'style': "simple", 'explode': false}}
|
|
14
14
|
|
|
15
15
|
field :body, Models::Shared::WebhookKeyRotationRequest, {'request': {'media_type': "application/json"}}
|
|
@@ -9,7 +9,7 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# The endpoint's whe_ id. An id that is unknown, malformed or another
|
|
12
|
+
# The endpoint's whe_ id. An id that is unknown, malformed or another workspace's answers 404.
|
|
13
13
|
field :endpoint_id, ::String, {'path_param': {'field_name': "endpoint_id", 'style': "simple", 'explode': false}}
|
|
14
14
|
|
|
15
15
|
field :body, Models::Shared::WebhookTestRequest, {'request': {'media_type': "application/json"}}
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# Body of the 200 answer to GET /v1/accounts/{account_id}: the one current risk of one of the calling
|
|
7
|
+
# Body of the 200 answer to GET /v1/accounts/{account_id}: the one current risk of one of the calling workspace's accounts. It is the risk of the account's latest assessment that has a decision (status complete or partial), by created_at and then assessment_id, scored exactly as GET /v1/assessments/{assessment_id} scores that assessment, plus the account's own reason shared_api_key when a key issued to the account was used from many IP addresses or countries (POST /v1/key_usage/batches). Its assessments are the account's history (GET /v1/accounts/{account_id}/assessments).
|
|
8
8
|
class Account
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# The account_id the
|
|
12
|
+
# The account_id the workspace sends with its assessments.
|
|
13
13
|
field :id, ::String, {'format_json': {'letter_case': ::NoResponse::Utils.field_name("id"), required: true}}
|
|
14
14
|
|
|
15
15
|
field(
|
|
@@ -17,7 +17,7 @@ module NoResponse
|
|
|
17
17
|
Models::Shared::AccountRisk,
|
|
18
18
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("risk"), required: true}}
|
|
19
19
|
)
|
|
20
|
-
# The decision for each flow: the account's score under that flow's thresholds. A flow the workspace has not set uses its
|
|
20
|
+
# The decision for each flow: the account's score under that flow's thresholds. A flow the workspace has not set uses its account_creation thresholds, so the flows differ only where it set them.
|
|
21
21
|
field(
|
|
22
22
|
:decisions_by_flow,
|
|
23
23
|
Models::Shared::AccountDecisionsByFlow,
|
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# The decision for each flow: the account's score under that flow's thresholds. A flow the workspace has not set uses its
|
|
7
|
+
# The decision for each flow: the account's score under that flow's thresholds. A flow the workspace has not set uses its account_creation thresholds, so the flows differ only where it set them.
|
|
8
8
|
class AccountDecisionsByFlow
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
12
|
# block when the score reached your block threshold (risk.block of the assessment), otherwise the assessment's recommendation. Your application applies it.
|
|
13
13
|
field(
|
|
14
|
-
:
|
|
14
|
+
:account_creation,
|
|
15
15
|
Models::Shared::AccountDecision,
|
|
16
16
|
{
|
|
17
17
|
'format_json': {
|
|
18
|
-
'letter_case': ::NoResponse::Utils.field_name("
|
|
18
|
+
'letter_case': ::NoResponse::Utils.field_name("account_creation"),
|
|
19
19
|
required: true,
|
|
20
20
|
'decoder': ::NoResponse::Utils.open_enum_from_string(Models::Shared::AccountDecision, false)
|
|
21
21
|
}
|
|
@@ -48,14 +48,14 @@ module NoResponse
|
|
|
48
48
|
|
|
49
49
|
sig {
|
|
50
50
|
params(
|
|
51
|
-
|
|
51
|
+
account_creation: Models::Shared::AccountDecision,
|
|
52
52
|
login: Models::Shared::AccountDecision,
|
|
53
53
|
purchase: Models::Shared::AccountDecision
|
|
54
54
|
)
|
|
55
55
|
.void
|
|
56
56
|
}
|
|
57
|
-
def initialize(
|
|
58
|
-
@
|
|
57
|
+
def initialize(account_creation:, login:, purchase:)
|
|
58
|
+
@account_creation = account_creation
|
|
59
59
|
@login = login
|
|
60
60
|
@purchase = purchase
|
|
61
61
|
end
|
|
@@ -63,7 +63,7 @@ module NoResponse
|
|
|
63
63
|
sig { params(other: T.untyped).returns(T::Boolean) }
|
|
64
64
|
def ==(other)
|
|
65
65
|
return false unless other.is_a?(self.class)
|
|
66
|
-
return false unless @
|
|
66
|
+
return false unless @account_creation == other.account_creation
|
|
67
67
|
return false unless @login == other.login
|
|
68
68
|
return false unless @purchase == other.purchase
|
|
69
69
|
true
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# Body of the 200 answer to DELETE /v1/accounts/{account_id}: the calling
|
|
7
|
+
# Body of the 200 answer to DELETE /v1/accounts/{account_id}: the calling workspace's account was erased in the environment of the calling key. Every assessment of the account went, with its revisions, evidence, outcomes and the identity-graph marks its outcomes set, and an assessment that was still running when the call arrived is stopped. Afterwards GET /v1/accounts/{account_id} and GET /v1/assessments/{assessment_id} of each erased assessment answer 404, and the history page is empty. The call is idempotent: a repeat, or an account with nothing to erase, answers 200 with assessments_deleted 0. The account_id can be assessed again later, as a new account.
|
|
8
8
|
class AccountDeletion
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
@@ -23,7 +23,7 @@ module NoResponse
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
)
|
|
26
|
-
# The
|
|
26
|
+
# The event an assessment is made for: account_creation (a user creates an account), login (a user returns to an existing account) or purchase (a payment or a credit grant). The account's risk is reported with the decision for this flow.
|
|
27
27
|
field(
|
|
28
28
|
:flow,
|
|
29
29
|
Models::Shared::Flow,
|
|
@@ -59,7 +59,7 @@ module NoResponse
|
|
|
59
59
|
::String,
|
|
60
60
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("schema_version"), required: true}}
|
|
61
61
|
)
|
|
62
|
-
# Body of the 200 answer to GET /v1/accounts/{account_id}: the one current risk of one of the calling
|
|
62
|
+
# Body of the 200 answer to GET /v1/accounts/{account_id}: the one current risk of one of the calling workspace's accounts. It is the risk of the account's latest assessment that has a decision (status complete or partial), by created_at and then assessment_id, scored exactly as GET /v1/assessments/{assessment_id} scores that assessment, plus the account's own reason shared_api_key when a key issued to the account was used from many IP addresses or countries (POST /v1/key_usage/batches). Its assessments are the account's history (GET /v1/accounts/{account_id}/assessments).
|
|
63
63
|
field(
|
|
64
64
|
:account,
|
|
65
65
|
Crystalline::Nilable.new(Models::Shared::Account),
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# Body of the 200 answer to DELETE /v1/assessments/{assessment_id}: one of the calling
|
|
7
|
+
# Body of the 200 answer to DELETE /v1/assessments/{assessment_id}: one of the calling workspace's assessments was deleted, with its versions, evidence, outcomes and the identity-graph marks its outcomes set. Afterwards GET /v1/assessments/{assessment_id} answers 404 and the assessment leaves the account's history. The account is scored again from what remains: account.current_assessment_id names the assessment GET /v1/accounts/{account_id} now serves its risk from, and is absent when the account has no assessment with a decision left. Deleting an assessment that is already gone answers 404.
|
|
8
8
|
class AssessmentDeletion
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
@@ -9,13 +9,13 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# Opaque, server-assigned assessment id: 'asm_' and a 26-character Crockford base32 ULID. Unique within the
|
|
12
|
+
# Opaque, server-assigned assessment id: 'asm_' and a 26-character Crockford base32 ULID. Unique within the workspace; another workspace's assessment id answers 404.
|
|
13
13
|
field(
|
|
14
14
|
:assessment_id,
|
|
15
15
|
::String,
|
|
16
16
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("assessment_id"), required: true}}
|
|
17
17
|
)
|
|
18
|
-
# Your own opaque identifier for the account being checked, scoped to your
|
|
18
|
+
# Your own opaque identifier for the account being checked, scoped to your workspace. Use an id you mint, with no direct identifier (email, phone, name or national id) in it. '|' is accepted so an Auth0 user id such as 'auth0|64abc' passes unchanged; '@', '+', '$' and whitespace are refused by the pattern, as is an exact-shape JWT; a hex digest such as a SHA-256 is allowed, because hashing an internal id is a common pseudonymous scheme. A value such as '07700900123' or 'jane.doe.gmail.com' cannot be told apart from an opaque id. It travels in bodies, and in a URL only as the path segment of GET /v1/accounts/{account_id} and its /assessments. An assessment requested by a provider hook at pre_registration, which has no account yet, carries the server-issued account_id pre: followed by its assessment_id.
|
|
19
19
|
field(
|
|
20
20
|
:account_id,
|
|
21
21
|
::String,
|
|
@@ -51,7 +51,7 @@ module NoResponse
|
|
|
51
51
|
Crystalline::Array.new(Models::Shared::IncompleteSource),
|
|
52
52
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("incomplete_sources"), required: true}}
|
|
53
53
|
)
|
|
54
|
-
# Version of the hand-authored heuristic weights that produced the recommendation, for example 'risk-2026-10.7'. A
|
|
54
|
+
# Version of the hand-authored heuristic weights that produced the recommendation, for example 'risk-2026-10.7'. A workspace threshold override adds a +t<N> suffix, e.g. 'risk-2026-10.7+t3'.
|
|
55
55
|
field(
|
|
56
56
|
:policy_version,
|
|
57
57
|
::String,
|
|
@@ -134,7 +134,7 @@ module NoResponse
|
|
|
134
134
|
Crystalline::Nilable.new(::String),
|
|
135
135
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("assessment_url")}}
|
|
136
136
|
)
|
|
137
|
-
# The identity fields of the auth context the assessment was made with, echoed for the
|
|
137
|
+
# The identity fields of the auth context the assessment was made with, echoed for the workspace's own correlation: the request's auth_context, or the one a hosted provider hook (POST /hooks/{integration_id}) built, with transport provider_hook and its hook_point. Present exactly when the request carried an auth_context, and the same on every revision of the assessment. Values are as the request or the hook sent them; tokens, timestamps, roles and scopes are not echoed, and the echo does not change the score.
|
|
138
138
|
field(
|
|
139
139
|
:auth_context,
|
|
140
140
|
Crystalline::Nilable.new(Models::Shared::AssessmentDetailAuthContext),
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# The identity fields of the auth context the assessment was made with, echoed for the
|
|
7
|
+
# The identity fields of the auth context the assessment was made with, echoed for the workspace's own correlation: the request's auth_context, or the one a hosted provider hook (POST /hooks/{integration_id}) built, with transport provider_hook and its hook_point. Present exactly when the request carried an auth_context, and the same on every revision of the assessment. Values are as the request or the hook sent them; tokens, timestamps, roles and scopes are not echoed, and the echo does not change the score.
|
|
8
8
|
class AssessmentDetailAuthContext
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# Body of the 200 answer to POST /v1/assessments/query: one page of the calling
|
|
7
|
+
# Body of the 200 answer to POST /v1/assessments/query: one page of the calling workspace's unexpired assessments for one account, newest first, each at its latest assessment_version, as its detail; the account's current risk is GET /v1/accounts/{account_id}. Every item's account_id equals the page's. An assessment past its expires_at is not listed. next_cursor is present only when another page exists.
|
|
8
8
|
class AssessmentList
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# Your own opaque identifier for the account being checked, scoped to your
|
|
12
|
+
# Your own opaque identifier for the account being checked, scoped to your workspace. Use an id you mint, with no direct identifier (email, phone, name or national id) in it. '|' is accepted so an Auth0 user id such as 'auth0|64abc' passes unchanged; '@', '+', '$' and whitespace are refused by the pattern, as is an exact-shape JWT; a hex digest such as a SHA-256 is allowed, because hashing an internal id is a common pseudonymous scheme. A value such as '07700900123' or 'jane.doe.gmail.com' cannot be told apart from an opaque id. It travels in bodies, and in a URL only as the path segment of GET /v1/accounts/{account_id} and its /assessments. An assessment requested by a provider hook at pre_registration, which has no account yet, carries the server-issued account_id pre: followed by its assessment_id.
|
|
13
13
|
field(
|
|
14
14
|
:account_id,
|
|
15
15
|
::String,
|
|
@@ -27,7 +27,7 @@ module NoResponse
|
|
|
27
27
|
::String,
|
|
28
28
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("schema_version"), required: true}}
|
|
29
29
|
)
|
|
30
|
-
# Opaque cursor for the next page, bound to your
|
|
30
|
+
# Opaque cursor for the next page, bound to your workspace and the account_id it was issued for. Pass it back unchanged in the next query; a tampered, foreign or expired cursor answers 400 invalid_cursor.
|
|
31
31
|
field(
|
|
32
32
|
:next_cursor,
|
|
33
33
|
Crystalline::Nilable.new(::String),
|
|
@@ -9,15 +9,15 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# Opaque, server-assigned id of one recorded outcome: 'out_' and a 26-character Crockford base32 ULID. Unique within the
|
|
12
|
+
# Opaque, server-assigned id of one recorded outcome: 'out_' and a 26-character Crockford base32 ULID. Unique within the workspace.
|
|
13
13
|
field :id, ::String, {'format_json': {'letter_case': ::NoResponse::Utils.field_name("id"), required: true}}
|
|
14
|
-
# Opaque, server-assigned assessment id: 'asm_' and a 26-character Crockford base32 ULID. Unique within the
|
|
14
|
+
# Opaque, server-assigned assessment id: 'asm_' and a 26-character Crockford base32 ULID. Unique within the workspace; another workspace's assessment id answers 404.
|
|
15
15
|
field(
|
|
16
16
|
:assessment_id,
|
|
17
17
|
::String,
|
|
18
18
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("assessment_id"), required: true}}
|
|
19
19
|
)
|
|
20
|
-
# What the provider later learned about the assessed account. confirmed_abuse, account_takeover and chargeback report abuse; false_positive and legitimate withdraw an earlier abuse report of this
|
|
20
|
+
# What the provider later learned about the assessed account. confirmed_abuse, account_takeover and chargeback report abuse; false_positive and legitimate withdraw an earlier abuse report of this workspace for the assessment; unknown is recorded only. Outcomes are append-only and the latest one recorded for an assessment wins.
|
|
21
21
|
field(
|
|
22
22
|
:outcome,
|
|
23
23
|
Models::Shared::Outcome,
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# POST /v1/assessments/{assessment_id}/outcomes body: what the provider later learned about the account it assessed. The assessment is named by the path and the
|
|
7
|
+
# POST /v1/assessments/{assessment_id}/outcomes body: what the provider later learned about the account it assessed. The assessment is named by the path and the workspace by the API key, so neither is a body member. Idempotency-Key is required and binds the body as it does on POST /v1/assessments.
|
|
8
8
|
class AssessmentOutcomeRequest
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# What the provider later learned about the assessed account. confirmed_abuse, account_takeover and chargeback report abuse; false_positive and legitimate withdraw an earlier abuse report of this
|
|
12
|
+
# What the provider later learned about the assessed account. confirmed_abuse, account_takeover and chargeback report abuse; false_positive and legitimate withdraw an earlier abuse report of this workspace for the assessment; unknown is recorded only. Outcomes are append-only and the latest one recorded for an assessment wins.
|
|
13
13
|
field(
|
|
14
14
|
:outcome,
|
|
15
15
|
Models::Shared::Outcome,
|
|
@@ -9,13 +9,13 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# Your own opaque identifier for the account being checked, scoped to your
|
|
12
|
+
# Your own opaque identifier for the account being checked, scoped to your workspace. Use an id you mint, with no direct identifier (email, phone, name or national id) in it. '|' is accepted so an Auth0 user id such as 'auth0|64abc' passes unchanged; '@', '+', '$' and whitespace are refused by the pattern, as is an exact-shape JWT; a hex digest such as a SHA-256 is allowed, because hashing an internal id is a common pseudonymous scheme. A value such as '07700900123' or 'jane.doe.gmail.com' cannot be told apart from an opaque id. It travels in bodies, and in a URL only as the path segment of GET /v1/accounts/{account_id} and its /assessments. An assessment requested by a provider hook at pre_registration, which has no account yet, carries the server-issued account_id pre: followed by its assessment_id.
|
|
13
13
|
field(
|
|
14
14
|
:account_id,
|
|
15
15
|
::String,
|
|
16
16
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("account_id"), required: true}}
|
|
17
17
|
)
|
|
18
|
-
# next_cursor from the previous page, unchanged. Opaque, MAC'd and bound to the
|
|
18
|
+
# next_cursor from the previous page, unchanged. Opaque, MAC'd and bound to the workspace and account_id.
|
|
19
19
|
field(
|
|
20
20
|
:cursor,
|
|
21
21
|
Crystalline::Nilable.new(::String),
|
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# POST /v1/assessments body. At least one of email, username or phone is required; name and ip only refine an assessment. No field carries a password, hash, token or breach value, and unknown members are refused. The email local part is kept as received and only the domain is lower-cased; the username is compared case-insensitively; the phone is strict E.164 and is assessed asynchronously. The whole body is capped at 32768 bytes. client_context holds bounded hints from the
|
|
7
|
+
# POST /v1/assessments body. At least one of email, username or phone is required; name and ip only refine an assessment. No field carries a password, hash, token or breach value, and unknown members are refused. The email local part is kept as received and only the domain is lower-cased; the username is compared case-insensitively; the phone is strict E.164 and is assessed asynchronously. The whole body is capped at 32768 bytes. client_context holds bounded hints from the client of the user; auth_context holds normalised claims from a session your backend has verified. Raw tokens are refused.
|
|
8
8
|
class AssessmentRequest
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# Your own opaque identifier for the account being checked, scoped to your
|
|
12
|
+
# Your own opaque identifier for the account being checked, scoped to your workspace. Use an id you mint, with no direct identifier (email, phone, name or national id) in it. '|' is accepted so an Auth0 user id such as 'auth0|64abc' passes unchanged; '@', '+', '$' and whitespace are refused by the pattern, as is an exact-shape JWT; a hex digest such as a SHA-256 is allowed, because hashing an internal id is a common pseudonymous scheme. A value such as '07700900123' or 'jane.doe.gmail.com' cannot be told apart from an opaque id. It travels in bodies, and in a URL only as the path segment of GET /v1/accounts/{account_id} and its /assessments. An assessment requested by a provider hook at pre_registration, which has no account yet, carries the server-issued account_id pre: followed by its assessment_id.
|
|
13
13
|
field(
|
|
14
14
|
:account_id,
|
|
15
15
|
::String,
|
|
16
16
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("account_id"), required: true}}
|
|
17
17
|
)
|
|
18
|
-
# The
|
|
18
|
+
# The event an assessment is made for: account_creation (a user creates an account), login (a user returns to an existing account) or purchase (a payment or a credit grant). The account's risk is reported with the decision for this flow.
|
|
19
19
|
field(
|
|
20
20
|
:flow,
|
|
21
21
|
Models::Shared::Flow,
|
|
@@ -73,7 +73,7 @@ module NoResponse
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
)
|
|
76
|
-
# Optional context observed by
|
|
76
|
+
# Optional context observed by the client of the user. The server parses these hints into coarse features, leaves raw user_agent and opaque ids out of every answer, and weighs a mismatch with the other evidence.
|
|
77
77
|
field(
|
|
78
78
|
:client_context,
|
|
79
79
|
Crystalline::Nilable.new(Models::Shared::AssessmentRequestClientContext),
|
|
@@ -85,7 +85,7 @@ module NoResponse
|
|
|
85
85
|
Crystalline::Nilable.new(Models::Shared::AuthContext),
|
|
86
86
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("auth_context")}}
|
|
87
87
|
)
|
|
88
|
-
# Optional. When
|
|
88
|
+
# Optional. When your platform issues an API key to the new account, send SHA-256 of that key, so later usage of the key, or a leaked copy, ties back to this assessment. Each SDK has a helper that computes it. Send only the hash: customer keys are high-entropy, so the hash reveals nothing about them. The assessment stores it, and no response, webhook or log carries it.
|
|
89
89
|
field(
|
|
90
90
|
:issued_credential,
|
|
91
91
|
Crystalline::Nilable.new(Models::Shared::AssessmentRequestIssuedCredential),
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# Optional context observed by
|
|
7
|
+
# Optional context observed by the client of the user. The server parses these hints into coarse features, leaves raw user_agent and opaque ids out of every answer, and weighs a mismatch with the other evidence.
|
|
8
8
|
class AssessmentRequestClientContext
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
@@ -38,19 +38,19 @@ module NoResponse
|
|
|
38
38
|
Crystalline::Nilable.new(::String),
|
|
39
39
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("app_version")}}
|
|
40
40
|
)
|
|
41
|
-
# The raw User-Agent header of the
|
|
41
|
+
# The raw User-Agent header of the request that the user sent, at most 512 characters. It is parsed into coarse features and left out of every answer.
|
|
42
42
|
field(
|
|
43
43
|
:user_agent,
|
|
44
44
|
Crystalline::Nilable.new(::String),
|
|
45
45
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("user_agent")}}
|
|
46
46
|
)
|
|
47
|
-
#
|
|
47
|
+
# Workspace-scoped opaque identifier your application mints and rotates when the account or device changes. Send an id of your own, not a hardware fingerprint.
|
|
48
48
|
field(
|
|
49
49
|
:device_id,
|
|
50
50
|
Crystalline::Nilable.new(::String),
|
|
51
51
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("device_id")}}
|
|
52
52
|
)
|
|
53
|
-
# Opaque signup session identifier. It is used for
|
|
53
|
+
# Opaque signup session identifier. It is used for workspace-scoped velocity and replay checks only.
|
|
54
54
|
field(
|
|
55
55
|
:session_id,
|
|
56
56
|
Crystalline::Nilable.new(::String),
|
|
@@ -33,7 +33,7 @@ module NoResponse
|
|
|
33
33
|
Crystalline::Nilable.new(::String),
|
|
34
34
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("name")}}
|
|
35
35
|
)
|
|
36
|
-
# The
|
|
36
|
+
# The account_creation's client IP address: an IPv4 dotted quad without leading zeros, or an IPv6 address in its RFC 5952 text form (lower case, no leading zeros, the longest zero run compressed). Send an IPv4 client as a dotted quad, not IPv4-mapped. No zone, port or prefix. The server refuses a non-canonical IPv6 spelling, and every private, loopback, link-local, multicast, documentation or otherwise reserved address (the IANA special-purpose registries), with 400: only a public address says anything about a signup.
|
|
37
37
|
field(
|
|
38
38
|
:ip,
|
|
39
39
|
Crystalline::Nilable.new(::String),
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# Optional. When
|
|
7
|
+
# Optional. When your platform issues an API key to the new account, send SHA-256 of that key, so later usage of the key, or a leaked copy, ties back to this assessment. Each SDK has a helper that computes it. Send only the hash: customer keys are high-entropy, so the hash reveals nothing about them. The assessment stores it, and no response, webhook or log carries it.
|
|
8
8
|
class AssessmentRequestIssuedCredential
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
@@ -9,7 +9,7 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# ISO 3166-1 alpha-2 region of the
|
|
12
|
+
# ISO 3166-1 alpha-2 region of the user, as the provider determines it.
|
|
13
13
|
field(
|
|
14
14
|
:region,
|
|
15
15
|
Crystalline::Nilable.new(::String),
|
|
@@ -57,7 +57,7 @@ module NoResponse
|
|
|
57
57
|
Crystalline::Nilable.new(::String),
|
|
58
58
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("organization_id")}}
|
|
59
59
|
)
|
|
60
|
-
# The provider
|
|
60
|
+
# The provider workspace identifier, when distinct from organization_id.
|
|
61
61
|
field(
|
|
62
62
|
:tenant_id,
|
|
63
63
|
Crystalline::Nilable.new(::String),
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# Flow - The
|
|
7
|
+
# Flow - The event an assessment is made for: account_creation (a user creates an account), login (a user returns to an existing account) or purchase (a payment or a credit grant). The account's risk is reported with the decision for this flow.
|
|
8
8
|
class Flow
|
|
9
9
|
include ::Crystalline::Enum
|
|
10
10
|
enums do
|
|
11
|
-
|
|
11
|
+
ACCOUNT_CREATION = new("account_creation")
|
|
12
12
|
LOGIN = new("login")
|
|
13
13
|
PURCHASE = new("purchase")
|
|
14
14
|
end
|
|
@@ -9,7 +9,7 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# Opaque, server-assigned integration id: int_ and a 26-character Crockford base32 ULID. Another
|
|
12
|
+
# Opaque, server-assigned integration id: int_ and a 26-character Crockford base32 ULID. Another workspace's integration id answers 404.
|
|
13
13
|
field(
|
|
14
14
|
:integration_id,
|
|
15
15
|
::String,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# GET /v1/integrations: every integration of the
|
|
7
|
+
# GET /v1/integrations: every integration of the workspace, oldest first, at most 10. No secret is ever listed.
|
|
8
8
|
class IntegrationList
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# POST /v1/integrations body. Registers a hosted endpoint for one authentication provider. The
|
|
7
|
+
# POST /v1/integrations body. Registers a hosted endpoint for one authentication provider. The workspace is the API key that signs the request, so the body has no workspace field and refuses one like any other unknown member. A WorkOS integration needs signing_secret, the Actions secret shown in the WorkOS dashboard, which NoResponse uses to verify each Action request and to sign its answer. An Auth0 integration sends no signing_secret: NoResponse generates the shared secret and returns it once.
|
|
8
8
|
class IntegrationRequest
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# Facts about the submitted IP from the offline database and this
|
|
7
|
+
# Facts about the submitted IP from the offline database and this workspace's own recent assessments. Every member is optional; absent makes no claim.
|
|
8
8
|
class IpSummary
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
@@ -26,25 +26,25 @@ module NoResponse
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
)
|
|
29
|
-
# Assessments in this
|
|
29
|
+
# Assessments in this workspace with the same IP in the last 24 hours, this one included. A count only.
|
|
30
30
|
field(
|
|
31
|
-
:
|
|
31
|
+
:seen_in_workspace,
|
|
32
32
|
Crystalline::Nilable.new(::Integer),
|
|
33
|
-
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("
|
|
33
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("seen_in_workspace")}}
|
|
34
34
|
)
|
|
35
35
|
|
|
36
36
|
sig {
|
|
37
37
|
params(
|
|
38
38
|
country: T.nilable(::String),
|
|
39
39
|
type: T.nilable(Models::Shared::IpSummaryType),
|
|
40
|
-
|
|
40
|
+
seen_in_workspace: T.nilable(::Integer)
|
|
41
41
|
)
|
|
42
42
|
.void
|
|
43
43
|
}
|
|
44
|
-
def initialize(country: nil, type: nil,
|
|
44
|
+
def initialize(country: nil, type: nil, seen_in_workspace: nil)
|
|
45
45
|
@country = country
|
|
46
46
|
@type = type
|
|
47
|
-
@
|
|
47
|
+
@seen_in_workspace = seen_in_workspace
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
sig { params(other: T.untyped).returns(T::Boolean) }
|
|
@@ -52,7 +52,7 @@ module NoResponse
|
|
|
52
52
|
return false unless other.is_a?(self.class)
|
|
53
53
|
return false unless @country == other.country
|
|
54
54
|
return false unless @type == other.type
|
|
55
|
-
return false unless @
|
|
55
|
+
return false unless @seen_in_workspace == other.seen_in_workspace
|
|
56
56
|
true
|
|
57
57
|
end
|
|
58
58
|
end
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# POST /v1/keys/rotate body. The
|
|
7
|
+
# POST /v1/keys/rotate body. The workspace and the key being rotated are the API key that signs the request, so neither is a body member. An empty object takes the default overlap.
|
|
8
8
|
class KeyRotationRequest
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# POST /v1/key_usage/batches body: facts about requests made with API keys your
|
|
7
|
+
# POST /v1/key_usage/batches body: facts about requests made with API keys your platform issued to your accounts, one event per request. Each event names the key by the SHA-256 that the assessment's issued_credential.sha256 carried, not the key itself. The SDKs buffer events and send them in the background. A batch holds 1 to 500 events and at most 256 KiB. Idempotency-Key is required and binds the body as on POST /v1/assessments, so a retried batch is counted once.
|
|
8
8
|
class KeyUsageBatchRequest
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# Outcome - What the provider later learned about the assessed account. confirmed_abuse, account_takeover and chargeback report abuse; false_positive and legitimate withdraw an earlier abuse report of this
|
|
7
|
+
# Outcome - What the provider later learned about the assessed account. confirmed_abuse, account_takeover and chargeback report abuse; false_positive and legitimate withdraw an earlier abuse report of this workspace for the assessment; unknown is recorded only. Outcomes are append-only and the latest one recorded for an assessment wins.
|
|
8
8
|
class Outcome
|
|
9
9
|
include ::Crystalline::Enum
|
|
10
10
|
enums do
|
|
@@ -19,7 +19,7 @@ module NoResponse
|
|
|
19
19
|
PROXY_IP = new("proxy_ip")
|
|
20
20
|
SEEN_BEFORE = new("seen_before")
|
|
21
21
|
SHARED_IP = new("shared_ip")
|
|
22
|
-
|
|
22
|
+
MANY_RECENT_ACCOUNTS = new("many_recent_accounts")
|
|
23
23
|
ESTABLISHED_ACCOUNTS = new("established_accounts")
|
|
24
24
|
AGED_IDENTITY = new("aged_identity")
|
|
25
25
|
BREACH_NAME_MATCH = new("breach_name_match")
|
|
@@ -50,7 +50,7 @@ module NoResponse
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
)
|
|
53
|
-
# Version of the hand-authored heuristic weights that produced the recommendation, for example 'risk-2026-10.7'. A
|
|
53
|
+
# Version of the hand-authored heuristic weights that produced the recommendation, for example 'risk-2026-10.7'. A workspace threshold override adds a +t<N> suffix, e.g. 'risk-2026-10.7+t3'.
|
|
54
54
|
field(
|
|
55
55
|
:policy_version,
|
|
56
56
|
::String,
|
|
@@ -68,13 +68,13 @@ module NoResponse
|
|
|
68
68
|
Models::Shared::RiskCoverage,
|
|
69
69
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("coverage"), required: true}}
|
|
70
70
|
)
|
|
71
|
-
# true when the
|
|
71
|
+
# true when the workspace's block threshold is set and score reached it. A provider hook can deny the account creation on it; the provider decides and enforces. It does not change recommendation. It is false while blocking is off, the default, and a body from before the flag existed omits it: read absent as false.
|
|
72
72
|
field(
|
|
73
73
|
:block,
|
|
74
74
|
Crystalline::Nilable.new(Crystalline::Boolean.new),
|
|
75
75
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("block")}}
|
|
76
76
|
)
|
|
77
|
-
# The block threshold this answer used: block is true exactly when score is at least this value. Absent while blocking is off. NoResponse sets it per
|
|
77
|
+
# The block threshold this answer used: block is true exactly when score is at least this value. Absent while blocking is off. NoResponse sets it per workspace on request, at or above the review threshold.
|
|
78
78
|
field(
|
|
79
79
|
:block_threshold,
|
|
80
80
|
Crystalline::Nilable.new(::Integer),
|
|
@@ -26,7 +26,7 @@ module NoResponse
|
|
|
26
26
|
Crystalline::Nilable.new(Models::Shared::RiskSummaryUsername),
|
|
27
27
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("username")}}
|
|
28
28
|
)
|
|
29
|
-
# Facts about the submitted IP from the offline database and this
|
|
29
|
+
# Facts about the submitted IP from the offline database and this workspace's own recent assessments. Every member is optional; absent makes no claim.
|
|
30
30
|
field(
|
|
31
31
|
:ip,
|
|
32
32
|
Crystalline::Nilable.new(Models::Shared::IpSummary),
|
|
@@ -35,7 +35,7 @@ module NoResponse
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
)
|
|
38
|
-
# Opaque,
|
|
38
|
+
# Opaque, workspace-scoped projection of the source that produced a signal. It stays stable for your workspace while the projection key is unchanged and reveals no upstream provider, feed, breach table or source record.
|
|
39
39
|
field(
|
|
40
40
|
:source_id,
|
|
41
41
|
::String,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# The 200 answer of GET /v1/webhooks/{endpoint_id}/deliveries: one page of the endpoint's delivery attempts, newest first. Each item is one POST to the endpoint. Attempts are kept for 30 days, or the
|
|
7
|
+
# The 200 answer of GET /v1/webhooks/{endpoint_id}/deliveries: one page of the endpoint's delivery attempts, newest first. Each item is one POST to the endpoint. Attempts are kept for 30 days, or the workspace's retention_days when that is shorter, and are deleted with the assessment they carried. next_cursor is present only when another page exists.
|
|
8
8
|
class WebhookDeliveryList
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
@@ -21,7 +21,7 @@ module NoResponse
|
|
|
21
21
|
Crystalline::Array.new(Models::Shared::WebhookDeliveryAttempt),
|
|
22
22
|
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("items"), required: true}}
|
|
23
23
|
)
|
|
24
|
-
# Opaque cursor for the next page, MAC'd by the server and bound to the
|
|
24
|
+
# Opaque cursor for the next page, MAC'd by the server and bound to the workspace and endpoint it was issued for. Pass it back unchanged as cursor; a tampered, foreign or expired cursor answers 400 invalid_cursor.
|
|
25
25
|
field(
|
|
26
26
|
:next_cursor,
|
|
27
27
|
Crystalline::Nilable.new(::String),
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# One of the
|
|
7
|
+
# One of the workspace's registered webhook endpoints. Signing secrets are not part of it: a secret is shown once, when it is issued (POST /v1/webhooks and POST /v1/webhooks/{endpoint_id}/rotate).
|
|
8
8
|
class WebhookEndpoint
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
@@ -9,7 +9,7 @@ module NoResponse
|
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
11
11
|
|
|
12
|
-
# One of the
|
|
12
|
+
# One of the workspace's registered webhook endpoints. Signing secrets are not part of it: a secret is shown once, when it is issued (POST /v1/webhooks and POST /v1/webhooks/{endpoint_id}/rotate).
|
|
13
13
|
field(
|
|
14
14
|
:endpoint,
|
|
15
15
|
Models::Shared::WebhookEndpoint,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# GET /v1/webhooks answer: every endpoint of the calling
|
|
7
|
+
# GET /v1/webhooks answer: every endpoint of the calling workspace, in every state, ordered by endpoint_id. A workspace holds at most 5, so there is no page.
|
|
8
8
|
class WebhookEndpointList
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module NoResponse
|
|
5
5
|
module Models
|
|
6
6
|
module Shared
|
|
7
|
-
# POST /v1/webhooks body. The
|
|
7
|
+
# POST /v1/webhooks body. The workspace is the API key that signs the request, so it is not a body member. The URL must be https on port 443 or 8443 with a DNS name, not an IP literal, and every address the name resolves to must be public.
|
|
8
8
|
class WebhookEndpointRequest
|
|
9
9
|
extend T::Sig
|
|
10
10
|
include Crystalline::MetadataFields
|
|
@@ -95,9 +95,9 @@ module NoResponse
|
|
|
95
95
|
|
|
96
96
|
@language = "ruby"
|
|
97
97
|
@openapi_doc_version = "1"
|
|
98
|
-
@sdk_version = "
|
|
98
|
+
@sdk_version = "5.0.0"
|
|
99
99
|
@gen_version = "internal"
|
|
100
|
-
@user_agent = "noresponse-sdk/ruby
|
|
100
|
+
@user_agent = "noresponse-sdk/ruby 5.0.0 internal 1 noresponse"
|
|
101
101
|
end
|
|
102
102
|
|
|
103
103
|
sig { returns([String, T::Hash[Symbol, String]]) }
|
|
@@ -47,7 +47,7 @@ module NoResponse
|
|
|
47
47
|
.returns(Models::Operations::ListWebhookEndpointsResponse)
|
|
48
48
|
}
|
|
49
49
|
def list(retries: nil, timeout_ms: nil, http_headers: nil)
|
|
50
|
-
# list - List the
|
|
50
|
+
# list - List the workspace's webhook endpoints.
|
|
51
51
|
# Lists your webhook endpoints in every state, ordered by endpoint_id, with the ids of their signing keys and without secrets. Requires the webhooks scope.
|
|
52
52
|
url, params = @sdk_configuration.get_server_details
|
|
53
53
|
base_url = Utils.template_url(url, params)
|
|
@@ -1455,7 +1455,7 @@ module NoResponse
|
|
|
1455
1455
|
}
|
|
1456
1456
|
def list_deliveries(endpoint_id:, limit: nil, cursor: nil, retries: nil, timeout_ms: nil, http_headers: nil)
|
|
1457
1457
|
# list_deliveries - List an endpoint's delivery attempts.
|
|
1458
|
-
# Every POST the endpoint received, newest first: the event id and type, which attempt it was, whether it was a replay, delivered or failed, the response code, why it failed and how long it took. Attempts are kept for 30 days, or your retention_days when that is shorter, and are deleted with the assessment they carried. Requires the webhooks scope. Read-only and safe to retry. The cursor is opaque and bound to your
|
|
1458
|
+
# Every POST the endpoint received, newest first: the event id and type, which attempt it was, whether it was a replay, delivered or failed, the response code, why it failed and how long it took. Attempts are kept for 30 days, or your retention_days when that is shorter, and are deleted with the assessment they carried. Requires the webhooks scope. Read-only and safe to retry. The cursor is opaque and bound to your workspace and the endpoint; a tampered or expired cursor answers 400 invalid_cursor.
|
|
1459
1459
|
request = Models::Operations::ListWebhookDeliveriesRequest.new(
|
|
1460
1460
|
endpoint_id: endpoint_id,
|
|
1461
1461
|
limit: limit,
|
data/lib/no_response/webhooks.rb
CHANGED
|
@@ -53,7 +53,7 @@ module NoResponse
|
|
|
53
53
|
|
|
54
54
|
# The workspace was deleted. Sent once per environment ("live" or "test")
|
|
55
55
|
# before its endpoints are torn down: the last event this endpoint receives.
|
|
56
|
-
|
|
56
|
+
WorkspaceDeleted = Struct.new(:workspace_id, :environment, :deleted_at, keyword_init: true)
|
|
57
57
|
|
|
58
58
|
# Another endpoint of this environment was disabled after failing
|
|
59
59
|
# continuously for 72 hours, since failing_since. It receives nothing more
|
|
@@ -72,7 +72,7 @@ module NoResponse
|
|
|
72
72
|
# assessments.get returns it) or an AssessmentExpired for type
|
|
73
73
|
# "assessment.updated", an EndpointVerification for
|
|
74
74
|
# "endpoint.verification", an AccountDeleted for "account.deleted", a
|
|
75
|
-
#
|
|
75
|
+
# WorkspaceDeleted for "workspace.deleted", an EndpointDisabled for
|
|
76
76
|
# "webhook_endpoint.disabled" and an AccountRiskChanged for
|
|
77
77
|
# "account.risk_changed". Deliveries are at least once and unordered:
|
|
78
78
|
# deduplicate on id and keep the highest detail.assessment_version.
|
|
@@ -183,8 +183,8 @@ module NoResponse
|
|
|
183
183
|
end
|
|
184
184
|
when 'account.deleted'
|
|
185
185
|
account_deleted(data)
|
|
186
|
-
when '
|
|
187
|
-
|
|
186
|
+
when 'workspace.deleted'
|
|
187
|
+
workspace_deleted(data)
|
|
188
188
|
when 'webhook_endpoint.disabled'
|
|
189
189
|
endpoint_disabled(data)
|
|
190
190
|
when 'account.risk_changed'
|
|
@@ -216,15 +216,15 @@ module NoResponse
|
|
|
216
216
|
deleted_at: data['deleted_at'])
|
|
217
217
|
end
|
|
218
218
|
|
|
219
|
-
def
|
|
219
|
+
def workspace_deleted(data)
|
|
220
220
|
unless data['workspace_id'].is_a?(String) && WORKSPACE_ID.match?(data['workspace_id']) &&
|
|
221
221
|
%w[live test].include?(data['environment']) &&
|
|
222
222
|
data['deleted_at'].is_a?(String) && valid_datetime?(data['deleted_at'])
|
|
223
|
-
raise VerificationError.new(:invalid_payload, '
|
|
223
|
+
raise VerificationError.new(:invalid_payload, 'Workspace deleted event is malformed')
|
|
224
224
|
end
|
|
225
225
|
|
|
226
|
-
|
|
227
|
-
|
|
226
|
+
WorkspaceDeleted.new(workspace_id: data['workspace_id'], environment: data['environment'],
|
|
227
|
+
deleted_at: data['deleted_at'])
|
|
228
228
|
end
|
|
229
229
|
|
|
230
230
|
def endpoint_disabled(data)
|