opentrust 0.1.2 → 0.2.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/README.md +12 -3
- data/lib/opentrust/client.rb +67 -7
- data/lib/opentrust/errors.rb +1 -0
- data/lib/opentrust/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1be8ac1901adb4eba6e169948dd6172743d816f582c73beb84a6665757cec2ab
|
|
4
|
+
data.tar.gz: d0f5877799fb975d2f9d34601bf86103d4f5109ce1e031e6b6daf3f6b745d4c4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c0a3d367db5b5697fbf9de7618c6cb29d29e4ea5ddd3628f1aca17befa00812622a52e44ccbc498bbf07ca428d63467848f568e0a95098976f3436e353a9d81e
|
|
7
|
+
data.tar.gz: b416321fcf6e6c13fc299148d668dfdab3fbae2def6bc1671594f237c8012d8b5fb604210a5e12ca174eadd98f643947d998ab72dc39c8a90938104307bed34e
|
data/README.md
CHANGED
|
@@ -15,12 +15,21 @@ client = OpenTrust::Client.new(api_key: ENV["OPENTRUST_API_KEY"]) # or just set
|
|
|
15
15
|
result = client.lookup("98765 43210") # uses 1 check
|
|
16
16
|
result.reported? # => true / false
|
|
17
17
|
result.report_count # => 2
|
|
18
|
-
result.reports.each { |r| puts "#{r.reason_code}: #{r.notes}" }
|
|
18
|
+
result.reports.each { |r| puts "#{r.reason_code} (#{r.incident_at}): #{r.notes}" } # other merchants' reports only
|
|
19
|
+
result.own_report? # => true if you have shared this number yourself
|
|
19
20
|
result.notice # keep this in front of anyone who sees the result
|
|
20
21
|
result.checks_remaining
|
|
21
22
|
|
|
22
23
|
client.lookup_many(%w[9876543210 9000000001]) # up to 100, all or nothing
|
|
23
|
-
client.report(phone: "9876543210", reason_code: "cod_refusal", notes: "Refused 3 COD orders in March")
|
|
24
|
+
client.report(phone: "9876543210", reason_code: "cod_refusal", notes: "Refused 3 COD orders in March", incident_at: Date.new(2026, 3, 14),
|
|
25
|
+
confirmed_by: "bank", evidence_ref: "your-ticket-123") # optional: who confirmed it (shown to others), and a private reference
|
|
26
|
+
|
|
27
|
+
# up to 100 at once; one bad row never stops the rest
|
|
28
|
+
results = client.report_many([{ phone: "9876543210", reason_code: "chargeback", incident_at: "2026-08-14" }, { phone: "9812345678", reason_code: "fake_order" }])
|
|
29
|
+
results.reject(&:recorded?).each { |r| warn "row #{r.index}: #{r.status} #{r.error_code}" }
|
|
30
|
+
|
|
31
|
+
client.withdraw_report("9876543210") # take your own report back (raises NotFoundError if there is none)
|
|
32
|
+
client.reason_codes # => [#<struct code="chargeback", group=..., label=..., description=...>, ...]
|
|
24
33
|
client.me # => { "checks_remaining" => ..., ... }
|
|
25
34
|
```
|
|
26
35
|
|
|
@@ -37,7 +46,7 @@ rescue OpenTrust::Error => e
|
|
|
37
46
|
end
|
|
38
47
|
```
|
|
39
48
|
|
|
40
|
-
Errors: `AuthenticationError` (401), `NoChecksError` (402, write to us and we'll raise your limit), `NotApprovedError` (403), `DuplicateReportError` (409), `InvalidRequestError` (422), `RateLimitError` (429), `ServerError` (5xx), `ConnectionError` (network/timeout). All inherit from `OpenTrust::Error` and carry `status` and `code`.
|
|
49
|
+
Errors: `AuthenticationError` (401), `NoChecksError` (402, write to us and we'll raise your limit), `NotApprovedError` (403), `NotFoundError` (404, withdrawing a report you don't have), `DuplicateReportError` (409), `InvalidRequestError` (422), `RateLimitError` (429), `ServerError` (5xx), `ConnectionError` (network/timeout). All inherit from `OpenTrust::Error` and carry `status` and `code`.
|
|
41
50
|
|
|
42
51
|
Timeout defaults to 5 seconds (`timeout:`). Docs: https://opentrust.in/docs
|
|
43
52
|
|
data/lib/opentrust/client.rb
CHANGED
|
@@ -3,18 +3,42 @@ require "net/http"
|
|
|
3
3
|
require "uri"
|
|
4
4
|
|
|
5
5
|
module OpenTrust
|
|
6
|
-
Report = Struct.new(:reason_code, :reason, :notes, :reported_at, :reporter_verified, keyword_init: true)
|
|
6
|
+
Report = Struct.new(:reason_code, :reason, :notes, :incident_at, :confirmed_by, :reported_at, :reporter_verified, keyword_init: true)
|
|
7
7
|
|
|
8
8
|
# The result of checking one number. Reports are unverified observations from individual merchants,
|
|
9
9
|
# not a finding about anyone. Use them as one input among others.
|
|
10
|
-
|
|
10
|
+
#
|
|
11
|
+
# `reports` and `report_count` only hold OTHER merchants' reports. `own_report` says whether you have shared this number yourself.
|
|
12
|
+
Lookup = Struct.new(:phone_last4, :report_count, :reports, :own_report, :notice, :checks_remaining, keyword_init: true) do
|
|
11
13
|
def reported?
|
|
12
14
|
report_count.to_i.positive?
|
|
13
15
|
end
|
|
16
|
+
|
|
17
|
+
def own_report?
|
|
18
|
+
own_report == true
|
|
19
|
+
end
|
|
14
20
|
end
|
|
15
21
|
|
|
16
22
|
Receipt = Struct.new(:id, :phone_last4, keyword_init: true)
|
|
17
23
|
|
|
24
|
+
# One row of a bulk report. `status` is "recorded", "duplicate" (you already shared it; treat as done) or "invalid".
|
|
25
|
+
BatchResult = Struct.new(:index, :status, :id, :phone_last4, :error_code, :error_message, keyword_init: true) do
|
|
26
|
+
def recorded?
|
|
27
|
+
status == "recorded"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def duplicate?
|
|
31
|
+
status == "duplicate"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def invalid?
|
|
35
|
+
status == "invalid"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
Withdrawal = Struct.new(:phone_last4, :status, keyword_init: true)
|
|
40
|
+
ReasonCode = Struct.new(:code, :group, :label, :description, :use_when, :not_when, keyword_init: true)
|
|
41
|
+
|
|
18
42
|
class Client
|
|
19
43
|
DEFAULT_BASE_URL = "https://opentrust.in/api/v1".freeze
|
|
20
44
|
|
|
@@ -40,11 +64,39 @@ module OpenTrust
|
|
|
40
64
|
end
|
|
41
65
|
|
|
42
66
|
# Share an experience with a number. Optional, and doesn't change your allowance.
|
|
43
|
-
|
|
44
|
-
|
|
67
|
+
# incident_at: when it happened (a Date, a Time or an ISO 8601 string); can't be in the future.
|
|
68
|
+
# confirmed_by: "bank", "payment_gateway" or "law_enforcement", only if they told you the activity was confirmed (shown to other
|
|
69
|
+
# merchants, not verified). evidence_ref: a private reference for administrators, never shown; needs confirmed_by.
|
|
70
|
+
def report(phone:, reason_code:, notes: nil, incident_at: nil, confirmed_by: nil, evidence_ref: nil)
|
|
71
|
+
body = request(:post, "/reports", report_payload(phone: phone, reason_code: reason_code, notes: notes, incident_at: incident_at,
|
|
72
|
+
confirmed_by: confirmed_by, evidence_ref: evidence_ref))
|
|
45
73
|
Receipt.new(id: body["id"], phone_last4: body["phone_last4"])
|
|
46
74
|
end
|
|
47
75
|
|
|
76
|
+
# Share up to 100 experiences at once. Each is handled on its own, so one bad row never stops the rest: the result is a
|
|
77
|
+
# BatchResult per report, in order. reports: [{ phone:, reason_code:, notes:, incident_at: }, ...]
|
|
78
|
+
def report_many(reports)
|
|
79
|
+
list = Array(reports)
|
|
80
|
+
raise ArgumentError, "report_many takes 1 to 100 reports" unless list.size.between?(1, 100)
|
|
81
|
+
|
|
82
|
+
body = request(:post, "/reports/batch", reports: list.map { |r| report_payload(**r.transform_keys(&:to_sym)) })
|
|
83
|
+
body.fetch("results").map do |r|
|
|
84
|
+
BatchResult.new(index: r["index"], status: r["status"], id: r["id"], phone_last4: r["phone_last4"],
|
|
85
|
+
error_code: r.dig("error", "code"), error_message: r.dig("error", "message"))
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Withdraw your own report for a number. Raises NotFoundError if you have no active report for it.
|
|
90
|
+
def withdraw_report(phone)
|
|
91
|
+
body = request(:delete, "/reports", phone: phone)
|
|
92
|
+
Withdrawal.new(phone_last4: body["phone_last4"], status: body["status"])
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# The reason codes with their labels and descriptions.
|
|
96
|
+
def reason_codes
|
|
97
|
+
request(:get, "/reason_codes").fetch("reason_codes").map { |c| ReasonCode.new(code: c["code"], group: c["group"], label: c["label"], description: c["description"], use_when: c["use_when"], not_when: c["not_when"]) }
|
|
98
|
+
end
|
|
99
|
+
|
|
48
100
|
# Your remaining checks and usage, as a Hash.
|
|
49
101
|
def me
|
|
50
102
|
request(:get, "/me")
|
|
@@ -52,10 +104,17 @@ module OpenTrust
|
|
|
52
104
|
|
|
53
105
|
private
|
|
54
106
|
|
|
107
|
+
def report_payload(phone:, reason_code:, notes: nil, incident_at: nil, confirmed_by: nil, evidence_ref: nil)
|
|
108
|
+
incident_at = incident_at.iso8601 if incident_at.respond_to?(:iso8601)
|
|
109
|
+
{ phone: phone, reason_code: reason_code, notes: notes, incident_at: incident_at, confirmed_by: confirmed_by, evidence_ref: evidence_ref }.compact
|
|
110
|
+
end
|
|
111
|
+
|
|
55
112
|
def lookup_from(h)
|
|
56
113
|
Lookup.new(
|
|
57
|
-
phone_last4: h["phone_last4"], report_count: h["report_count"], notice: h["notice"], checks_remaining: h["checks_remaining"],
|
|
58
|
-
reports: Array(h["reports"]).map
|
|
114
|
+
phone_last4: h["phone_last4"], report_count: h["report_count"], own_report: h["own_report"], notice: h["notice"], checks_remaining: h["checks_remaining"],
|
|
115
|
+
reports: Array(h["reports"]).map do |r|
|
|
116
|
+
Report.new(reason_code: r["reason_code"], reason: r["reason"], notes: r["notes"], incident_at: r["incident_at"], confirmed_by: r["confirmed_by"], reported_at: r["reported_at"], reporter_verified: r["reporter_verified"])
|
|
117
|
+
end
|
|
59
118
|
)
|
|
60
119
|
end
|
|
61
120
|
|
|
@@ -72,7 +131,7 @@ module OpenTrust
|
|
|
72
131
|
return @adapter.call(verb, url, headers, body) if @adapter
|
|
73
132
|
|
|
74
133
|
uri = URI(url)
|
|
75
|
-
klass =
|
|
134
|
+
klass = { get: Net::HTTP::Get, post: Net::HTTP::Post, delete: Net::HTTP::Delete }.fetch(verb)
|
|
76
135
|
req = klass.new(uri, headers)
|
|
77
136
|
req.body = body if body
|
|
78
137
|
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https", open_timeout: @timeout, read_timeout: @timeout) { |http| http.request(req) }
|
|
@@ -88,6 +147,7 @@ module OpenTrust
|
|
|
88
147
|
when 401 then AuthenticationError
|
|
89
148
|
when 402 then NoChecksError
|
|
90
149
|
when 403 then NotApprovedError
|
|
150
|
+
when 404 then NotFoundError
|
|
91
151
|
when 409 then DuplicateReportError
|
|
92
152
|
when 422 then InvalidRequestError
|
|
93
153
|
when 429 then RateLimitError
|
data/lib/opentrust/errors.rb
CHANGED
|
@@ -14,6 +14,7 @@ module OpenTrust
|
|
|
14
14
|
class AuthenticationError < Error; end # 401: missing or invalid API key
|
|
15
15
|
class NoChecksError < Error; end # 402: allowance used up
|
|
16
16
|
class NotApprovedError < Error; end # 403: account not approved or suspended
|
|
17
|
+
class NotFoundError < Error; end # 404: no active report of yours for that number (withdrawing)
|
|
17
18
|
class DuplicateReportError < Error; end # 409: you already shared this number
|
|
18
19
|
class InvalidRequestError < Error; end # 422: bad number, reason code or note
|
|
19
20
|
class RateLimitError < Error; end # 429
|
data/lib/opentrust/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: opentrust
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ParityCube
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Check mobile numbers against experiences shared by other Indian merchants,
|
|
14
14
|
and share your own. A small, dependency-free client for https://opentrust.in.
|