truetrial 1.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 +7 -0
- data/README.md +233 -0
- data/lib/truetrial/client.rb +53 -0
- data/lib/truetrial/errors.rb +55 -0
- data/lib/truetrial/http_client.rb +119 -0
- data/lib/truetrial/resources/cancellations.rb +29 -0
- data/lib/truetrial/resources/digital_delivery.rb +21 -0
- data/lib/truetrial/resources/orders.rb +44 -0
- data/lib/truetrial/resources/shipments.rb +29 -0
- data/lib/truetrial/resources/system.rb +19 -0
- data/lib/truetrial/resources/temporal.rb +56 -0
- data/lib/truetrial/resources/webhooks.rb +35 -0
- data/lib/truetrial/types/cancellation.rb +29 -0
- data/lib/truetrial/types/order.rb +34 -0
- data/lib/truetrial/types/shipment.rb +33 -0
- data/lib/truetrial/types/temporal_element.rb +36 -0
- data/lib/truetrial/types/webhook_subscription.rb +29 -0
- data/lib/truetrial/version.rb +5 -0
- data/lib/truetrial/webhook.rb +82 -0
- data/lib/truetrial.rb +24 -0
- metadata +108 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 83e4d15852c9adc42118fa0641acc217e2c36991cf933bcb51545488a7328ef7
|
|
4
|
+
data.tar.gz: 9581b060426ad8f2e39a581bba1869015b6b38f27574d27376447e437f85f3e9
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 366fb7f35dd26fb7269d621e90b119407219bb4eeaf5f91f4d69d30e56bed72a25146ac707afa6ffb157feb157c92d520eacfd3654c787cc9d4b06899c532c59
|
|
7
|
+
data.tar.gz: 76f50dcc1ea4195da33a4f21da58845b6ef389a741a00b0ec420b7a3e688d84db9bf264a54c0ad36a4eea01a847b22f0e5c39c321e14d468d0195134f0419edc
|
data/README.md
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# TrueTrial Ruby SDK
|
|
2
|
+
|
|
3
|
+
Official Ruby client for the [TrueTrial](https://truetrial.com) API -- compliance-first trial, warranty, and subscription management.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Ruby >= 3.1
|
|
8
|
+
- Faraday ~> 2.0
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
Add to your Gemfile:
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
gem "truetrial", "~> 1.0"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Then run:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
bundle install
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or install directly:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
gem install truetrial
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
require "truetrial"
|
|
34
|
+
|
|
35
|
+
client = TrueTrial::Client.new(api_key: "tt_live_your_key_here")
|
|
36
|
+
|
|
37
|
+
# List orders
|
|
38
|
+
orders = client.orders.list(status: "trial_active", page: 1)
|
|
39
|
+
|
|
40
|
+
# Create an order
|
|
41
|
+
order = client.orders.create(
|
|
42
|
+
external_order_id: "ORD-12345",
|
|
43
|
+
product_type: "physical",
|
|
44
|
+
total_cents: 4999,
|
|
45
|
+
currency: "USD"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Get order details
|
|
49
|
+
order = client.orders.get("01HXYZ...")
|
|
50
|
+
|
|
51
|
+
# Check order status
|
|
52
|
+
status = client.orders.status("01HXYZ...")
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Configuration
|
|
56
|
+
|
|
57
|
+
```ruby
|
|
58
|
+
client = TrueTrial::Client.new(
|
|
59
|
+
api_key: "tt_live_your_key_here",
|
|
60
|
+
base_url: "https://truetrial.test/api/v1" # default
|
|
61
|
+
)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## API Reference
|
|
65
|
+
|
|
66
|
+
### Orders
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
client.orders.list(status: "delivered", page: 2)
|
|
70
|
+
client.orders.create(external_order_id: "ORD-123", product_type: "physical", total_cents: 2999)
|
|
71
|
+
client.orders.get("01HXYZ")
|
|
72
|
+
client.orders.status("01HXYZ")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Shipments
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
client.shipments.create("01ORDER_ID", carrier: "ups", tracking_number: "1Z999AA10123456784")
|
|
79
|
+
client.shipments.list("01ORDER_ID")
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Digital Delivery
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
client.digital_delivery.confirm("01ORDER_ID", delivered_at: "2026-01-15T10:00:00Z")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Temporal Elements (Trials, Warranties, etc.)
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
client.temporal.get("01ORDER_ID")
|
|
92
|
+
client.temporal.extend("01ORDER_ID", duration: 7, unit: "days", reason: "Customer request")
|
|
93
|
+
client.temporal.adjust("01ORDER_ID", begins_at: "2026-01-20T00:00:00Z")
|
|
94
|
+
client.temporal.claim("01ORDER_ID", reason: "Product defect", description: "Screen cracked on arrival")
|
|
95
|
+
client.temporal.resolve_claim("01ORDER_ID", status: "claim_approved", notes: "Replacement shipped")
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Cancellations
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
client.cancellations.create("01ORDER_ID", reason: "Changed mind")
|
|
102
|
+
client.cancellations.get("01ORDER_ID")
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Webhooks
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
client.webhooks.list
|
|
109
|
+
client.webhooks.create(url: "https://example.com/webhooks", events: ["order.delivered", "trial.started"])
|
|
110
|
+
client.webhooks.delete("01WEBHOOK_ID")
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### System
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
client.system.carrier_health
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Error Handling
|
|
120
|
+
|
|
121
|
+
All API errors inherit from `TrueTrial::Error`:
|
|
122
|
+
|
|
123
|
+
```ruby
|
|
124
|
+
begin
|
|
125
|
+
client.orders.get("nonexistent")
|
|
126
|
+
rescue TrueTrial::AuthenticationError => e
|
|
127
|
+
# 401 - Invalid or missing API key
|
|
128
|
+
puts e.message
|
|
129
|
+
rescue TrueTrial::NotFoundError => e
|
|
130
|
+
# 404 - Resource not found
|
|
131
|
+
puts e.message
|
|
132
|
+
rescue TrueTrial::ValidationError => e
|
|
133
|
+
# 422 - Validation failed
|
|
134
|
+
puts e.errors # => { "email" => ["is required"] }
|
|
135
|
+
rescue TrueTrial::RateLimitError => e
|
|
136
|
+
# 429 - Too many requests
|
|
137
|
+
puts "Retry after #{e.retry_after} seconds"
|
|
138
|
+
rescue TrueTrial::ServerError => e
|
|
139
|
+
# 500+ - Server error
|
|
140
|
+
puts e.status_code
|
|
141
|
+
rescue TrueTrial::Error => e
|
|
142
|
+
# Catch-all for unexpected errors
|
|
143
|
+
puts e.message
|
|
144
|
+
end
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Webhook Verification
|
|
148
|
+
|
|
149
|
+
TrueTrial signs webhook payloads with HMAC SHA-256. Verify incoming webhooks to ensure authenticity:
|
|
150
|
+
|
|
151
|
+
```ruby
|
|
152
|
+
# In your webhook controller / endpoint
|
|
153
|
+
payload = request.body.read
|
|
154
|
+
signature = request.headers["X-TrueTrial-Signature"]
|
|
155
|
+
timestamp = request.headers["X-TrueTrial-Timestamp"]
|
|
156
|
+
event_name = request.headers["X-TrueTrial-Event"]
|
|
157
|
+
secret = "whsec_your_webhook_secret"
|
|
158
|
+
|
|
159
|
+
# Simple verification (returns boolean)
|
|
160
|
+
if TrueTrial::Webhook.verify?(payload, signature, secret)
|
|
161
|
+
event = JSON.parse(payload)
|
|
162
|
+
# process event...
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Verify with timestamp tolerance (recommended for production)
|
|
166
|
+
if TrueTrial::Webhook.verify?(payload, signature, secret, tolerance: 300, timestamp: timestamp)
|
|
167
|
+
event = JSON.parse(payload)
|
|
168
|
+
# process event...
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Or use construct_event to verify and parse in one step (raises on failure)
|
|
172
|
+
begin
|
|
173
|
+
event = TrueTrial::Webhook.construct_event(payload, signature, secret, tolerance: 300, timestamp: timestamp)
|
|
174
|
+
|
|
175
|
+
case event_name
|
|
176
|
+
when "order.delivered"
|
|
177
|
+
handle_delivery(event["data"])
|
|
178
|
+
when "trial.started"
|
|
179
|
+
handle_trial_start(event["data"])
|
|
180
|
+
when "trial.expiring"
|
|
181
|
+
handle_trial_expiring(event["data"])
|
|
182
|
+
end
|
|
183
|
+
rescue TrueTrial::Error => e
|
|
184
|
+
# Invalid signature
|
|
185
|
+
render json: { error: e.message }, status: 400
|
|
186
|
+
end
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Enums
|
|
190
|
+
|
|
191
|
+
The following string values are used across the API:
|
|
192
|
+
|
|
193
|
+
**OrderStatus:** `received`, `shipped`, `in_transit`, `delivered`, `trial_active`, `converted`, `returned`, `expired`, `cancelled`
|
|
194
|
+
|
|
195
|
+
**TemporalType:** `trial`, `evaluation`, `subscription`, `warranty`, `guarantee`
|
|
196
|
+
|
|
197
|
+
**TemporalStatus:** `pending`, `active`, `expiring`, `expired`, `converted`, `cancelled`, `suspended`, `renewed`, `claimed`, `claim_approved`, `claim_denied`
|
|
198
|
+
|
|
199
|
+
**ShipmentStatus:** `pending`, `in_transit`, `out_for_delivery`, `delivered`, `failed`, `returned_to_sender`
|
|
200
|
+
|
|
201
|
+
**ProductType:** `physical`, `digital`
|
|
202
|
+
|
|
203
|
+
**Carrier:** `ups`, `fedex`, `usps`, `dhl`, `shippo`, `aftership`
|
|
204
|
+
|
|
205
|
+
**DurationUnit:** `days`, `weeks`, `months`, `years`
|
|
206
|
+
|
|
207
|
+
**DeliverySource:** `webhook`, `poll`, `manual`, `fallback_carrier`
|
|
208
|
+
|
|
209
|
+
**WebhookEvent:** `order.created`, `order.delivered`, `trial.started`, `trial.expiring`, `trial.expired`, `trial.converted`, `cancellation.initiated`, `risk_score.changed`, `subscription.renewed`, `warranty.claimed`, `temporal.extended`, `temporal.adjusted`, `warranty.claim_resolved`, `payment.succeeded`, `payment.failed`, `dispute.created`, `dispute.won`, `dispute.lost`
|
|
210
|
+
|
|
211
|
+
## Type Objects
|
|
212
|
+
|
|
213
|
+
The SDK provides type classes for deserializing API responses:
|
|
214
|
+
|
|
215
|
+
```ruby
|
|
216
|
+
data = client.orders.get("01HXYZ")
|
|
217
|
+
order = TrueTrial::Types::Order.from_hash(data)
|
|
218
|
+
puts order.id
|
|
219
|
+
puts order.status
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Available types: `Order`, `Shipment`, `TemporalElement`, `Cancellation`, `WebhookSubscription`
|
|
223
|
+
|
|
224
|
+
## Development
|
|
225
|
+
|
|
226
|
+
```sh
|
|
227
|
+
bundle install
|
|
228
|
+
bundle exec rspec
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
MIT
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TrueTrial
|
|
4
|
+
# Main entry point for interacting with the TrueTrial API.
|
|
5
|
+
#
|
|
6
|
+
# @example
|
|
7
|
+
# client = TrueTrial::Client.new(api_key: "tt_live_abc123")
|
|
8
|
+
# client.orders.list
|
|
9
|
+
class Client
|
|
10
|
+
DEFAULT_BASE_URL = "https://truetrial.test/api/v1"
|
|
11
|
+
|
|
12
|
+
# @param api_key [String] your TrueTrial API key
|
|
13
|
+
# @param base_url [String] API base URL (defaults to production)
|
|
14
|
+
def initialize(api_key:, base_url: DEFAULT_BASE_URL)
|
|
15
|
+
@http_client = HttpClient.new(api_key: api_key, base_url: base_url)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @return [TrueTrial::Resources::Orders]
|
|
19
|
+
def orders
|
|
20
|
+
@orders ||= Resources::Orders.new(@http_client)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @return [TrueTrial::Resources::Shipments]
|
|
24
|
+
def shipments
|
|
25
|
+
@shipments ||= Resources::Shipments.new(@http_client)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @return [TrueTrial::Resources::DigitalDelivery]
|
|
29
|
+
def digital_delivery
|
|
30
|
+
@digital_delivery ||= Resources::DigitalDelivery.new(@http_client)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @return [TrueTrial::Resources::Temporal]
|
|
34
|
+
def temporal
|
|
35
|
+
@temporal ||= Resources::Temporal.new(@http_client)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @return [TrueTrial::Resources::Cancellations]
|
|
39
|
+
def cancellations
|
|
40
|
+
@cancellations ||= Resources::Cancellations.new(@http_client)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @return [TrueTrial::Resources::Webhooks]
|
|
44
|
+
def webhooks
|
|
45
|
+
@webhooks ||= Resources::Webhooks.new(@http_client)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [TrueTrial::Resources::System]
|
|
49
|
+
def system
|
|
50
|
+
@system ||= Resources::System.new(@http_client)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TrueTrial
|
|
4
|
+
# Base error class for all TrueTrial API errors.
|
|
5
|
+
class Error < StandardError
|
|
6
|
+
attr_reader :status_code, :response_body
|
|
7
|
+
|
|
8
|
+
def initialize(message = nil, status_code: nil, response_body: nil)
|
|
9
|
+
@status_code = status_code
|
|
10
|
+
@response_body = response_body
|
|
11
|
+
super(message)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Raised when the API key is missing or invalid (HTTP 401).
|
|
16
|
+
class AuthenticationError < Error
|
|
17
|
+
def initialize(message = "Invalid or missing API key", response_body: nil)
|
|
18
|
+
super(message, status_code: 401, response_body: response_body)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Raised when request validation fails (HTTP 422).
|
|
23
|
+
class ValidationError < Error
|
|
24
|
+
attr_reader :errors
|
|
25
|
+
|
|
26
|
+
def initialize(message = "Validation failed", errors: {}, response_body: nil)
|
|
27
|
+
@errors = errors
|
|
28
|
+
super(message, status_code: 422, response_body: response_body)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Raised when the requested resource is not found (HTTP 404).
|
|
33
|
+
class NotFoundError < Error
|
|
34
|
+
def initialize(message = "Resource not found", response_body: nil)
|
|
35
|
+
super(message, status_code: 404, response_body: response_body)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Raised when the rate limit is exceeded (HTTP 429).
|
|
40
|
+
class RateLimitError < Error
|
|
41
|
+
attr_reader :retry_after
|
|
42
|
+
|
|
43
|
+
def initialize(message = "Rate limit exceeded", retry_after: nil, response_body: nil)
|
|
44
|
+
@retry_after = retry_after
|
|
45
|
+
super(message, status_code: 429, response_body: response_body)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Raised when the server returns a 5xx error.
|
|
50
|
+
class ServerError < Error
|
|
51
|
+
def initialize(message = "Internal server error", status_code: 500, response_body: nil)
|
|
52
|
+
super(message, status_code: status_code, response_body: response_body)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "faraday"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
module TrueTrial
|
|
7
|
+
# Low-level HTTP client wrapping Faraday for TrueTrial API communication.
|
|
8
|
+
class HttpClient
|
|
9
|
+
def initialize(api_key:, base_url:)
|
|
10
|
+
@connection = Faraday.new(url: base_url) do |conn|
|
|
11
|
+
conn.headers["X-Api-Key"] = api_key
|
|
12
|
+
conn.headers["Content-Type"] = "application/json"
|
|
13
|
+
conn.headers["Accept"] = "application/json"
|
|
14
|
+
conn.headers["User-Agent"] = "truetrial-ruby/#{TrueTrial::VERSION}"
|
|
15
|
+
conn.adapter Faraday.default_adapter
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Performs a GET request.
|
|
20
|
+
#
|
|
21
|
+
# @param path [String] the API endpoint path
|
|
22
|
+
# @param params [Hash] optional query parameters
|
|
23
|
+
# @return [Hash] parsed JSON response
|
|
24
|
+
def get(path, params: {})
|
|
25
|
+
response = @connection.get(path) do |req|
|
|
26
|
+
req.params = params unless params.empty?
|
|
27
|
+
end
|
|
28
|
+
handle_response(response)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Performs a POST request.
|
|
32
|
+
#
|
|
33
|
+
# @param path [String] the API endpoint path
|
|
34
|
+
# @param body [Hash] the request body
|
|
35
|
+
# @return [Hash] parsed JSON response
|
|
36
|
+
def post(path, body: {})
|
|
37
|
+
response = @connection.post(path) do |req|
|
|
38
|
+
req.body = JSON.generate(body)
|
|
39
|
+
end
|
|
40
|
+
handle_response(response)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Performs a DELETE request.
|
|
44
|
+
#
|
|
45
|
+
# @param path [String] the API endpoint path
|
|
46
|
+
# @return [Hash] parsed JSON response
|
|
47
|
+
def delete(path)
|
|
48
|
+
response = @connection.delete(path)
|
|
49
|
+
handle_response(response)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
# Maps HTTP status codes to appropriate error classes.
|
|
55
|
+
#
|
|
56
|
+
# @param response [Faraday::Response]
|
|
57
|
+
# @return [Hash] parsed response body on success
|
|
58
|
+
# @raise [TrueTrial::Error] on error responses
|
|
59
|
+
def handle_response(response)
|
|
60
|
+
body = parse_body(response.body)
|
|
61
|
+
|
|
62
|
+
case response.status
|
|
63
|
+
when 200..299
|
|
64
|
+
body
|
|
65
|
+
when 401
|
|
66
|
+
raise AuthenticationError.new(
|
|
67
|
+
error_message(body, "Invalid or missing API key"),
|
|
68
|
+
response_body: body
|
|
69
|
+
)
|
|
70
|
+
when 404
|
|
71
|
+
raise NotFoundError.new(
|
|
72
|
+
error_message(body, "Resource not found"),
|
|
73
|
+
response_body: body
|
|
74
|
+
)
|
|
75
|
+
when 422
|
|
76
|
+
raise ValidationError.new(
|
|
77
|
+
error_message(body, "Validation failed"),
|
|
78
|
+
errors: body.is_a?(Hash) ? body.fetch("errors", {}) : {},
|
|
79
|
+
response_body: body
|
|
80
|
+
)
|
|
81
|
+
when 429
|
|
82
|
+
retry_after = response.headers["Retry-After"]&.to_i
|
|
83
|
+
raise RateLimitError.new(
|
|
84
|
+
error_message(body, "Rate limit exceeded"),
|
|
85
|
+
retry_after: retry_after,
|
|
86
|
+
response_body: body
|
|
87
|
+
)
|
|
88
|
+
when 500..599
|
|
89
|
+
raise ServerError.new(
|
|
90
|
+
error_message(body, "Internal server error"),
|
|
91
|
+
status_code: response.status,
|
|
92
|
+
response_body: body
|
|
93
|
+
)
|
|
94
|
+
else
|
|
95
|
+
raise Error.new(
|
|
96
|
+
error_message(body, "Unexpected response"),
|
|
97
|
+
status_code: response.status,
|
|
98
|
+
response_body: body
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Safely parses JSON, returning the raw string on failure.
|
|
104
|
+
def parse_body(raw)
|
|
105
|
+
return nil if raw.nil? || raw.empty?
|
|
106
|
+
|
|
107
|
+
JSON.parse(raw)
|
|
108
|
+
rescue JSON::ParserError
|
|
109
|
+
raw
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Extracts an error message from the response body hash.
|
|
113
|
+
def error_message(body, default)
|
|
114
|
+
return default unless body.is_a?(Hash)
|
|
115
|
+
|
|
116
|
+
body["message"] || body["error"] || default
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TrueTrial
|
|
4
|
+
module Resources
|
|
5
|
+
# Provides access to cancellation-related API endpoints.
|
|
6
|
+
class Cancellations
|
|
7
|
+
def initialize(http_client)
|
|
8
|
+
@http = http_client
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Creates a cancellation for an order.
|
|
12
|
+
#
|
|
13
|
+
# @param order_id [String] the order ULID
|
|
14
|
+
# @param data [Hash] cancellation attributes (reason, etc.)
|
|
15
|
+
# @return [Hash] the created cancellation
|
|
16
|
+
def create(order_id, data)
|
|
17
|
+
@http.post("/orders/#{order_id}/cancellations", body: data)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Retrieves the cancellation for an order.
|
|
21
|
+
#
|
|
22
|
+
# @param order_id [String] the order ULID
|
|
23
|
+
# @return [Hash] the cancellation
|
|
24
|
+
def get(order_id)
|
|
25
|
+
@http.get("/orders/#{order_id}/cancellations")
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TrueTrial
|
|
4
|
+
module Resources
|
|
5
|
+
# Provides access to digital delivery confirmation endpoints.
|
|
6
|
+
class DigitalDelivery
|
|
7
|
+
def initialize(http_client)
|
|
8
|
+
@http = http_client
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Confirms digital delivery for an order.
|
|
12
|
+
#
|
|
13
|
+
# @param order_id [String] the order ULID
|
|
14
|
+
# @param data [Hash] digital delivery confirmation attributes
|
|
15
|
+
# @return [Hash] the delivery confirmation result
|
|
16
|
+
def confirm(order_id, data)
|
|
17
|
+
@http.post("/orders/#{order_id}/digital-delivery", body: data)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TrueTrial
|
|
4
|
+
module Resources
|
|
5
|
+
# Provides access to order-related API endpoints.
|
|
6
|
+
class Orders
|
|
7
|
+
def initialize(http_client)
|
|
8
|
+
@http = http_client
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Lists orders with optional filters.
|
|
12
|
+
#
|
|
13
|
+
# @param filters [Hash] optional query filters (status, page, per_page, etc.)
|
|
14
|
+
# @return [Hash] paginated list of orders
|
|
15
|
+
def list(filters = {})
|
|
16
|
+
@http.get("/orders", params: filters)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Creates a new order.
|
|
20
|
+
#
|
|
21
|
+
# @param data [Hash] order attributes
|
|
22
|
+
# @return [Hash] the created order
|
|
23
|
+
def create(data)
|
|
24
|
+
@http.post("/orders", body: data)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Retrieves a single order by ID.
|
|
28
|
+
#
|
|
29
|
+
# @param id [String] the order ULID
|
|
30
|
+
# @return [Hash] the order
|
|
31
|
+
def get(id)
|
|
32
|
+
@http.get("/orders/#{id}")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Retrieves the current status of an order.
|
|
36
|
+
#
|
|
37
|
+
# @param id [String] the order ULID
|
|
38
|
+
# @return [Hash] the order status
|
|
39
|
+
def status(id)
|
|
40
|
+
@http.get("/orders/#{id}/status")
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TrueTrial
|
|
4
|
+
module Resources
|
|
5
|
+
# Provides access to shipment-related API endpoints.
|
|
6
|
+
class Shipments
|
|
7
|
+
def initialize(http_client)
|
|
8
|
+
@http = http_client
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Creates a shipment for an order.
|
|
12
|
+
#
|
|
13
|
+
# @param order_id [String] the order ULID
|
|
14
|
+
# @param data [Hash] shipment attributes (carrier, tracking_number, etc.)
|
|
15
|
+
# @return [Hash] the created shipment
|
|
16
|
+
def create(order_id, data)
|
|
17
|
+
@http.post("/orders/#{order_id}/shipments", body: data)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Lists all shipments for an order.
|
|
21
|
+
#
|
|
22
|
+
# @param order_id [String] the order ULID
|
|
23
|
+
# @return [Hash] list of shipments
|
|
24
|
+
def list(order_id)
|
|
25
|
+
@http.get("/orders/#{order_id}/shipments")
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TrueTrial
|
|
4
|
+
module Resources
|
|
5
|
+
# Provides access to system-level API endpoints.
|
|
6
|
+
class System
|
|
7
|
+
def initialize(http_client)
|
|
8
|
+
@http = http_client
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Retrieves carrier health status.
|
|
12
|
+
#
|
|
13
|
+
# @return [Hash] carrier health information
|
|
14
|
+
def carrier_health
|
|
15
|
+
@http.get("/carrier-health")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TrueTrial
|
|
4
|
+
module Resources
|
|
5
|
+
# Provides access to temporal element API endpoints (trials, warranties, etc.).
|
|
6
|
+
class Temporal
|
|
7
|
+
def initialize(http_client)
|
|
8
|
+
@http = http_client
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Retrieves the temporal element for an order.
|
|
12
|
+
#
|
|
13
|
+
# @param order_id [String] the order ULID
|
|
14
|
+
# @return [Hash] the temporal element
|
|
15
|
+
def get(order_id)
|
|
16
|
+
@http.get("/orders/#{order_id}/temporal")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Extends a temporal element duration.
|
|
20
|
+
#
|
|
21
|
+
# @param order_id [String] the order ULID
|
|
22
|
+
# @param data [Hash] extension attributes (duration, unit, reason)
|
|
23
|
+
# @return [Hash] the updated temporal element
|
|
24
|
+
def extend(order_id, data)
|
|
25
|
+
@http.post("/orders/#{order_id}/temporal/extend", body: data)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Adjusts a temporal element (modify start/end dates).
|
|
29
|
+
#
|
|
30
|
+
# @param order_id [String] the order ULID
|
|
31
|
+
# @param data [Hash] adjustment attributes
|
|
32
|
+
# @return [Hash] the updated temporal element
|
|
33
|
+
def adjust(order_id, data)
|
|
34
|
+
@http.post("/orders/#{order_id}/temporal/adjust", body: data)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Initiates a warranty or guarantee claim.
|
|
38
|
+
#
|
|
39
|
+
# @param order_id [String] the order ULID
|
|
40
|
+
# @param data [Hash] claim attributes (reason, description)
|
|
41
|
+
# @return [Hash] the created claim
|
|
42
|
+
def claim(order_id, data)
|
|
43
|
+
@http.post("/orders/#{order_id}/temporal/claim", body: data)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Resolves a warranty or guarantee claim.
|
|
47
|
+
#
|
|
48
|
+
# @param order_id [String] the order ULID
|
|
49
|
+
# @param data [Hash] resolution attributes (status, notes)
|
|
50
|
+
# @return [Hash] the resolved claim
|
|
51
|
+
def resolve_claim(order_id, data)
|
|
52
|
+
@http.post("/orders/#{order_id}/temporal/resolve-claim", body: data)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TrueTrial
|
|
4
|
+
module Resources
|
|
5
|
+
# Provides access to webhook subscription management endpoints.
|
|
6
|
+
class Webhooks
|
|
7
|
+
def initialize(http_client)
|
|
8
|
+
@http = http_client
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Lists all webhook subscriptions.
|
|
12
|
+
#
|
|
13
|
+
# @return [Hash] list of webhook subscriptions
|
|
14
|
+
def list
|
|
15
|
+
@http.get("/webhooks")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Creates a new webhook subscription.
|
|
19
|
+
#
|
|
20
|
+
# @param data [Hash] webhook attributes (url, events, secret)
|
|
21
|
+
# @return [Hash] the created webhook subscription
|
|
22
|
+
def create(data)
|
|
23
|
+
@http.post("/webhooks", body: data)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Deletes a webhook subscription.
|
|
27
|
+
#
|
|
28
|
+
# @param id [String] the webhook subscription ULID
|
|
29
|
+
# @return [Hash] deletion confirmation
|
|
30
|
+
def delete(id)
|
|
31
|
+
@http.delete("/webhooks/#{id}")
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TrueTrial
|
|
4
|
+
module Types
|
|
5
|
+
# Represents a cancellation returned from the TrueTrial API.
|
|
6
|
+
class Cancellation
|
|
7
|
+
attr_reader :id, :order_id, :reason, :cancelled_by, :notes,
|
|
8
|
+
:created_at, :updated_at
|
|
9
|
+
|
|
10
|
+
def initialize(attributes = {})
|
|
11
|
+
@id = attributes["id"]
|
|
12
|
+
@order_id = attributes["order_id"]
|
|
13
|
+
@reason = attributes["reason"]
|
|
14
|
+
@cancelled_by = attributes["cancelled_by"]
|
|
15
|
+
@notes = attributes["notes"]
|
|
16
|
+
@created_at = attributes["created_at"]
|
|
17
|
+
@updated_at = attributes["updated_at"]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Builds a Cancellation from an API response hash.
|
|
21
|
+
#
|
|
22
|
+
# @param hash [Hash] raw API response data
|
|
23
|
+
# @return [Cancellation]
|
|
24
|
+
def self.from_hash(hash)
|
|
25
|
+
new(hash)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TrueTrial
|
|
4
|
+
module Types
|
|
5
|
+
# Represents an order returned from the TrueTrial API.
|
|
6
|
+
class Order
|
|
7
|
+
attr_reader :id, :tenant_id, :consumer_id, :external_order_id, :status,
|
|
8
|
+
:product_type, :total_cents, :currency, :metadata,
|
|
9
|
+
:created_at, :updated_at
|
|
10
|
+
|
|
11
|
+
def initialize(attributes = {})
|
|
12
|
+
@id = attributes["id"]
|
|
13
|
+
@tenant_id = attributes["tenant_id"]
|
|
14
|
+
@consumer_id = attributes["consumer_id"]
|
|
15
|
+
@external_order_id = attributes["external_order_id"]
|
|
16
|
+
@status = attributes["status"]
|
|
17
|
+
@product_type = attributes["product_type"]
|
|
18
|
+
@total_cents = attributes["total_cents"]
|
|
19
|
+
@currency = attributes["currency"]
|
|
20
|
+
@metadata = attributes["metadata"]
|
|
21
|
+
@created_at = attributes["created_at"]
|
|
22
|
+
@updated_at = attributes["updated_at"]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Builds an Order from an API response hash.
|
|
26
|
+
#
|
|
27
|
+
# @param hash [Hash] raw API response data
|
|
28
|
+
# @return [Order]
|
|
29
|
+
def self.from_hash(hash)
|
|
30
|
+
new(hash)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TrueTrial
|
|
4
|
+
module Types
|
|
5
|
+
# Represents a shipment returned from the TrueTrial API.
|
|
6
|
+
class Shipment
|
|
7
|
+
attr_reader :id, :order_id, :carrier, :tracking_number, :status,
|
|
8
|
+
:shipped_at, :delivered_at, :delivery_source,
|
|
9
|
+
:created_at, :updated_at
|
|
10
|
+
|
|
11
|
+
def initialize(attributes = {})
|
|
12
|
+
@id = attributes["id"]
|
|
13
|
+
@order_id = attributes["order_id"]
|
|
14
|
+
@carrier = attributes["carrier"]
|
|
15
|
+
@tracking_number = attributes["tracking_number"]
|
|
16
|
+
@status = attributes["status"]
|
|
17
|
+
@shipped_at = attributes["shipped_at"]
|
|
18
|
+
@delivered_at = attributes["delivered_at"]
|
|
19
|
+
@delivery_source = attributes["delivery_source"]
|
|
20
|
+
@created_at = attributes["created_at"]
|
|
21
|
+
@updated_at = attributes["updated_at"]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Builds a Shipment from an API response hash.
|
|
25
|
+
#
|
|
26
|
+
# @param hash [Hash] raw API response data
|
|
27
|
+
# @return [Shipment]
|
|
28
|
+
def self.from_hash(hash)
|
|
29
|
+
new(hash)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TrueTrial
|
|
4
|
+
module Types
|
|
5
|
+
# Represents a temporal element (trial, warranty, subscription, etc.)
|
|
6
|
+
# returned from the TrueTrial API.
|
|
7
|
+
class TemporalElement
|
|
8
|
+
attr_reader :id, :order_id, :type, :status, :duration, :duration_unit,
|
|
9
|
+
:begins_at, :expires_at, :converted_at, :cancelled_at,
|
|
10
|
+
:created_at, :updated_at
|
|
11
|
+
|
|
12
|
+
def initialize(attributes = {})
|
|
13
|
+
@id = attributes["id"]
|
|
14
|
+
@order_id = attributes["order_id"]
|
|
15
|
+
@type = attributes["type"]
|
|
16
|
+
@status = attributes["status"]
|
|
17
|
+
@duration = attributes["duration"]
|
|
18
|
+
@duration_unit = attributes["duration_unit"]
|
|
19
|
+
@begins_at = attributes["begins_at"]
|
|
20
|
+
@expires_at = attributes["expires_at"]
|
|
21
|
+
@converted_at = attributes["converted_at"]
|
|
22
|
+
@cancelled_at = attributes["cancelled_at"]
|
|
23
|
+
@created_at = attributes["created_at"]
|
|
24
|
+
@updated_at = attributes["updated_at"]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Builds a TemporalElement from an API response hash.
|
|
28
|
+
#
|
|
29
|
+
# @param hash [Hash] raw API response data
|
|
30
|
+
# @return [TemporalElement]
|
|
31
|
+
def self.from_hash(hash)
|
|
32
|
+
new(hash)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TrueTrial
|
|
4
|
+
module Types
|
|
5
|
+
# Represents a webhook subscription returned from the TrueTrial API.
|
|
6
|
+
class WebhookSubscription
|
|
7
|
+
attr_reader :id, :url, :events, :secret, :active,
|
|
8
|
+
:created_at, :updated_at
|
|
9
|
+
|
|
10
|
+
def initialize(attributes = {})
|
|
11
|
+
@id = attributes["id"]
|
|
12
|
+
@url = attributes["url"]
|
|
13
|
+
@events = attributes["events"]
|
|
14
|
+
@secret = attributes["secret"]
|
|
15
|
+
@active = attributes["active"]
|
|
16
|
+
@created_at = attributes["created_at"]
|
|
17
|
+
@updated_at = attributes["updated_at"]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Builds a WebhookSubscription from an API response hash.
|
|
21
|
+
#
|
|
22
|
+
# @param hash [Hash] raw API response data
|
|
23
|
+
# @return [WebhookSubscription]
|
|
24
|
+
def self.from_hash(hash)
|
|
25
|
+
new(hash)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "openssl"
|
|
4
|
+
require "json"
|
|
5
|
+
require "time"
|
|
6
|
+
|
|
7
|
+
module TrueTrial
|
|
8
|
+
# Utilities for verifying and parsing incoming TrueTrial webhooks.
|
|
9
|
+
#
|
|
10
|
+
# Webhook payloads are signed with HMAC SHA-256. The signature is delivered
|
|
11
|
+
# in the X-TrueTrial-Signature header and is computed from the raw JSON body
|
|
12
|
+
# using the webhook secret.
|
|
13
|
+
module Webhook
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
# Verifies that a webhook payload matches its signature.
|
|
17
|
+
#
|
|
18
|
+
# @param payload [String] the raw JSON request body
|
|
19
|
+
# @param signature [String] the value of the X-TrueTrial-Signature header
|
|
20
|
+
# @param secret [String] the webhook signing secret
|
|
21
|
+
# @param tolerance [Integer, nil] maximum age of the event in seconds (optional)
|
|
22
|
+
# @param timestamp [String, nil] the value of the X-TrueTrial-Timestamp header (required when tolerance is set)
|
|
23
|
+
# @return [Boolean] true if the signature is valid
|
|
24
|
+
def verify?(payload, signature, secret, tolerance: nil, timestamp: nil)
|
|
25
|
+
expected = compute_signature(payload, secret)
|
|
26
|
+
valid = secure_compare(expected, signature)
|
|
27
|
+
|
|
28
|
+
if valid && tolerance && timestamp
|
|
29
|
+
event_time = Time.parse(timestamp)
|
|
30
|
+
valid = (Time.now - event_time).abs <= tolerance
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
valid
|
|
34
|
+
rescue ArgumentError, TypeError
|
|
35
|
+
false
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Verifies and parses a webhook payload into a hash.
|
|
39
|
+
#
|
|
40
|
+
# @param payload [String] the raw JSON request body
|
|
41
|
+
# @param signature [String] the value of the X-TrueTrial-Signature header
|
|
42
|
+
# @param secret [String] the webhook signing secret
|
|
43
|
+
# @param tolerance [Integer, nil] maximum age of the event in seconds (optional)
|
|
44
|
+
# @param timestamp [String, nil] the value of the X-TrueTrial-Timestamp header (required when tolerance is set)
|
|
45
|
+
# @return [Hash] the parsed event data
|
|
46
|
+
# @raise [TrueTrial::Error] if the signature is invalid
|
|
47
|
+
def construct_event(payload, signature, secret, tolerance: nil, timestamp: nil)
|
|
48
|
+
unless verify?(payload, signature, secret, tolerance: tolerance, timestamp: timestamp)
|
|
49
|
+
raise Error.new("Invalid webhook signature")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
JSON.parse(payload)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Computes the HMAC SHA-256 hex digest for a payload.
|
|
56
|
+
#
|
|
57
|
+
# @param payload [String] the raw payload
|
|
58
|
+
# @param secret [String] the signing secret
|
|
59
|
+
# @return [String] hex-encoded HMAC signature
|
|
60
|
+
def compute_signature(payload, secret)
|
|
61
|
+
OpenSSL::HMAC.hexdigest("SHA256", secret, payload)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Performs a constant-time string comparison to prevent timing attacks.
|
|
65
|
+
#
|
|
66
|
+
# @param a [String]
|
|
67
|
+
# @param b [String]
|
|
68
|
+
# @return [Boolean]
|
|
69
|
+
def secure_compare(a, b)
|
|
70
|
+
return false unless a.bytesize == b.bytesize
|
|
71
|
+
|
|
72
|
+
OpenSSL.fixed_length_secure_compare(a, b)
|
|
73
|
+
rescue NoMethodError
|
|
74
|
+
# Fallback for older OpenSSL versions
|
|
75
|
+
l = a.unpack("C*")
|
|
76
|
+
r = b.unpack("C*")
|
|
77
|
+
result = 0
|
|
78
|
+
l.zip(r) { |x, y| result |= x ^ y }
|
|
79
|
+
result.zero?
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
data/lib/truetrial.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "truetrial/version"
|
|
4
|
+
require_relative "truetrial/errors"
|
|
5
|
+
require_relative "truetrial/http_client"
|
|
6
|
+
require_relative "truetrial/client"
|
|
7
|
+
require_relative "truetrial/webhook"
|
|
8
|
+
|
|
9
|
+
require_relative "truetrial/types/order"
|
|
10
|
+
require_relative "truetrial/types/shipment"
|
|
11
|
+
require_relative "truetrial/types/temporal_element"
|
|
12
|
+
require_relative "truetrial/types/cancellation"
|
|
13
|
+
require_relative "truetrial/types/webhook_subscription"
|
|
14
|
+
|
|
15
|
+
require_relative "truetrial/resources/orders"
|
|
16
|
+
require_relative "truetrial/resources/shipments"
|
|
17
|
+
require_relative "truetrial/resources/digital_delivery"
|
|
18
|
+
require_relative "truetrial/resources/temporal"
|
|
19
|
+
require_relative "truetrial/resources/cancellations"
|
|
20
|
+
require_relative "truetrial/resources/webhooks"
|
|
21
|
+
require_relative "truetrial/resources/system"
|
|
22
|
+
|
|
23
|
+
module TrueTrial
|
|
24
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: truetrial
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- TrueTrial
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-05-07 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: faraday
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '2.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rspec
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '3.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '3.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: webmock
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '3.0'
|
|
55
|
+
description: Official Ruby client for the TrueTrial compliance-first trial and warranty
|
|
56
|
+
management platform.
|
|
57
|
+
email:
|
|
58
|
+
- support@truetrial.com
|
|
59
|
+
executables: []
|
|
60
|
+
extensions: []
|
|
61
|
+
extra_rdoc_files: []
|
|
62
|
+
files:
|
|
63
|
+
- README.md
|
|
64
|
+
- lib/truetrial.rb
|
|
65
|
+
- lib/truetrial/client.rb
|
|
66
|
+
- lib/truetrial/errors.rb
|
|
67
|
+
- lib/truetrial/http_client.rb
|
|
68
|
+
- lib/truetrial/resources/cancellations.rb
|
|
69
|
+
- lib/truetrial/resources/digital_delivery.rb
|
|
70
|
+
- lib/truetrial/resources/orders.rb
|
|
71
|
+
- lib/truetrial/resources/shipments.rb
|
|
72
|
+
- lib/truetrial/resources/system.rb
|
|
73
|
+
- lib/truetrial/resources/temporal.rb
|
|
74
|
+
- lib/truetrial/resources/webhooks.rb
|
|
75
|
+
- lib/truetrial/types/cancellation.rb
|
|
76
|
+
- lib/truetrial/types/order.rb
|
|
77
|
+
- lib/truetrial/types/shipment.rb
|
|
78
|
+
- lib/truetrial/types/temporal_element.rb
|
|
79
|
+
- lib/truetrial/types/webhook_subscription.rb
|
|
80
|
+
- lib/truetrial/version.rb
|
|
81
|
+
- lib/truetrial/webhook.rb
|
|
82
|
+
homepage: https://github.com/truetrial/truetrial-ruby-sdk
|
|
83
|
+
licenses:
|
|
84
|
+
- MIT
|
|
85
|
+
metadata:
|
|
86
|
+
homepage_uri: https://github.com/truetrial/truetrial-ruby-sdk
|
|
87
|
+
source_code_uri: https://github.com/truetrial/truetrial-ruby-sdk
|
|
88
|
+
changelog_uri: https://github.com/truetrial/truetrial-ruby-sdk/blob/main/CHANGELOG.md
|
|
89
|
+
post_install_message:
|
|
90
|
+
rdoc_options: []
|
|
91
|
+
require_paths:
|
|
92
|
+
- lib
|
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
94
|
+
requirements:
|
|
95
|
+
- - ">="
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
version: '3.1'
|
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0'
|
|
103
|
+
requirements: []
|
|
104
|
+
rubygems_version: 3.4.19
|
|
105
|
+
signing_key:
|
|
106
|
+
specification_version: 4
|
|
107
|
+
summary: Ruby SDK for the TrueTrial API
|
|
108
|
+
test_files: []
|