creem 0.0.1
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/.github/workflows/ci.yml +50 -0
- data/.github/workflows/release.yml +49 -0
- data/.gitignore +6 -0
- data/.rspec +3 -0
- data/.rubocop.yml +126 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +17 -0
- data/CLAUDE.md +38 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +85 -0
- data/LICENSE +21 -0
- data/Makefile +108 -0
- data/README.md +193 -0
- data/Rakefile +9 -0
- data/creem.gemspec +49 -0
- data/docs/api_reference.md +335 -0
- data/docs/architecture.md +145 -0
- data/docs/development.md +137 -0
- data/docs/error_handling.md +85 -0
- data/docs/getting_started.md +116 -0
- data/docs/webhooks.md +179 -0
- data/lib/creem/client.rb +119 -0
- data/lib/creem/configuration.rb +18 -0
- data/lib/creem/errors.rb +24 -0
- data/lib/creem/resources/base.rb +23 -0
- data/lib/creem/resources/checkouts.rb +22 -0
- data/lib/creem/resources/customers.rb +24 -0
- data/lib/creem/resources/discounts.rb +13 -0
- data/lib/creem/resources/licenses.rb +25 -0
- data/lib/creem/resources/products.rb +17 -0
- data/lib/creem/resources/subscriptions.rb +31 -0
- data/lib/creem/resources/transactions.rb +13 -0
- data/lib/creem/version.rb +5 -0
- data/lib/creem/webhook.rb +33 -0
- data/lib/creem.rb +33 -0
- metadata +157 -0
data/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Creem Ruby SDK
|
|
2
|
+
|
|
3
|
+
Ruby SDK for the [Creem](https://creem.io) payment platform API — a Merchant of Record for SaaS and digital businesses.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add to your Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem "creem"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or install directly:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
gem install creem
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
require "creem"
|
|
23
|
+
|
|
24
|
+
# Global configuration
|
|
25
|
+
Creem.configure do |config|
|
|
26
|
+
config.api_key = "creem_YOUR_API_KEY"
|
|
27
|
+
config.test_mode = true # Use sandbox environment
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
client = Creem::Client.new
|
|
31
|
+
|
|
32
|
+
# Or pass options directly
|
|
33
|
+
client = Creem::Client.new(api_key: "creem_YOUR_API_KEY", test_mode: true)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
### Products
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
# List products
|
|
42
|
+
products = client.products.list(page_number: 1, page_size: 10)
|
|
43
|
+
|
|
44
|
+
# Get a product
|
|
45
|
+
product = client.products.retrieve("prod_123")
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Checkouts
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
# Create a checkout session
|
|
52
|
+
checkout = client.checkouts.create(
|
|
53
|
+
product_id: "prod_123",
|
|
54
|
+
success_url: "https://yoursite.com/success"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
puts checkout["checkout_url"] # Redirect customer here
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Subscriptions
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
# List subscriptions
|
|
64
|
+
subs = client.subscriptions.list
|
|
65
|
+
|
|
66
|
+
# Get a subscription
|
|
67
|
+
sub = client.subscriptions.retrieve("sub_123")
|
|
68
|
+
|
|
69
|
+
# Update a subscription
|
|
70
|
+
client.subscriptions.update("sub_123",
|
|
71
|
+
items: [{ product_id: "prod_456", units: 3 }],
|
|
72
|
+
update_behavior: "proration-charge"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Cancel a subscription
|
|
76
|
+
client.subscriptions.cancel("sub_123", mode: "immediate")
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Customers
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
# List customers
|
|
83
|
+
customers = client.customers.list
|
|
84
|
+
|
|
85
|
+
# Get by ID or email
|
|
86
|
+
customer = client.customers.retrieve(customer_id: "cust_123")
|
|
87
|
+
customer = client.customers.retrieve(email: "user@example.com")
|
|
88
|
+
|
|
89
|
+
# Generate billing portal link
|
|
90
|
+
portal = client.customers.billing_portal("cust_123")
|
|
91
|
+
puts portal["customer_portal_link"]
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Licenses
|
|
95
|
+
|
|
96
|
+
```ruby
|
|
97
|
+
# Activate a license
|
|
98
|
+
license = client.licenses.activate(key: "ABC-123", instance_name: "My Device")
|
|
99
|
+
|
|
100
|
+
# Validate a license
|
|
101
|
+
license = client.licenses.validate(key: "ABC-123", instance_id: "inst_456")
|
|
102
|
+
|
|
103
|
+
# Deactivate a license
|
|
104
|
+
client.licenses.deactivate(key: "ABC-123", instance_id: "inst_456")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Transactions
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
transactions = client.transactions.list(page_number: 1, page_size: 10)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Discounts
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
discounts = client.discounts.list(page_number: 1, page_size: 10)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Webhook Verification
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
# Verify webhook signature
|
|
123
|
+
payload = request.body.read
|
|
124
|
+
signature = request.headers["creem-signature"]
|
|
125
|
+
secret = "whsec_your_webhook_secret"
|
|
126
|
+
|
|
127
|
+
# Returns parsed event or raises Creem::WebhookSignatureError
|
|
128
|
+
event = Creem::Webhook.construct_event(
|
|
129
|
+
payload: payload,
|
|
130
|
+
secret: secret,
|
|
131
|
+
signature: signature
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
case event["event"]
|
|
135
|
+
when "checkout.completed"
|
|
136
|
+
# Handle checkout completion
|
|
137
|
+
when "subscription.active"
|
|
138
|
+
# Handle new subscription
|
|
139
|
+
end
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Error Handling
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
begin
|
|
146
|
+
client.products.retrieve("prod_invalid")
|
|
147
|
+
rescue Creem::AuthenticationError => e
|
|
148
|
+
puts "Invalid API key: #{e.message}"
|
|
149
|
+
rescue Creem::NotFoundError => e
|
|
150
|
+
puts "Resource not found: #{e.message}"
|
|
151
|
+
rescue Creem::BadRequestError => e
|
|
152
|
+
puts "Bad request: #{e.message}"
|
|
153
|
+
rescue Creem::RateLimitError => e
|
|
154
|
+
puts "Rate limited: #{e.message}"
|
|
155
|
+
rescue Creem::ServerError => e
|
|
156
|
+
puts "Server error: #{e.message}"
|
|
157
|
+
rescue Creem::ApiError => e
|
|
158
|
+
puts "API error (#{e.status}): #{e.message}"
|
|
159
|
+
end
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Test Mode
|
|
163
|
+
|
|
164
|
+
Toggle between production and sandbox environments:
|
|
165
|
+
|
|
166
|
+
```ruby
|
|
167
|
+
# Via configuration
|
|
168
|
+
Creem.configure do |config|
|
|
169
|
+
config.test_mode = ENV["RAILS_ENV"] != "production"
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Or per-client
|
|
173
|
+
client = Creem::Client.new(api_key: "key", test_mode: true)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
| | Production | Test Mode |
|
|
177
|
+
|---|---|---|
|
|
178
|
+
| Base URL | `https://api.creem.io/v1` | `https://test-api.creem.io/v1` |
|
|
179
|
+
| Payments | Real charges | Simulated |
|
|
180
|
+
|
|
181
|
+
## Development
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
make install # Install dependencies
|
|
185
|
+
make test # Run tests
|
|
186
|
+
make lint # Run linters
|
|
187
|
+
make format # Auto-fix formatting
|
|
188
|
+
make console # Interactive console
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
data/Rakefile
ADDED
data/creem.gemspec
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/creem/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "creem"
|
|
7
|
+
spec.version = Creem::VERSION
|
|
8
|
+
spec.authors = ["Creem Contributors"]
|
|
9
|
+
spec.email = ["richard.sun@ai-firstly.com"]
|
|
10
|
+
spec.summary = "Ruby SDK for the Creem payment platform API"
|
|
11
|
+
spec.description = "Official Ruby SDK for Creem - a Merchant of Record platform for SaaS and digital businesses. " \
|
|
12
|
+
"Manage products, checkouts, subscriptions, customers, transactions, licenses, and discounts."
|
|
13
|
+
spec.homepage = "https://github.com/ai-firstly/creem-ruby"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
spec.required_ruby_version = [">= 3.3.0", "< 5.0"]
|
|
16
|
+
|
|
17
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
18
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
19
|
+
spec.metadata["source_code_uri"] = "https://github.com/ai-firstly/creem-ruby"
|
|
20
|
+
spec.metadata["changelog_uri"] = "https://github.com/ai-firstly/creem-ruby/blob/main/CHANGELOG.md"
|
|
21
|
+
spec.metadata["documentation_uri"] = "https://rubydoc.info/gems/creem"
|
|
22
|
+
spec.metadata["bug_tracker_uri"] = "https://github.com/ai-firstly/creem-ruby/issues"
|
|
23
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
|
24
|
+
|
|
25
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
26
|
+
if File.exist?(".git")
|
|
27
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
28
|
+
f.match(%r{\A(?:test|spec|features)/})
|
|
29
|
+
end
|
|
30
|
+
else
|
|
31
|
+
Dir.glob("**/*").reject do |f|
|
|
32
|
+
File.directory?(f) ||
|
|
33
|
+
f.match(%r{\A(?:test|spec|features)/}) ||
|
|
34
|
+
f.match(/\A\./) ||
|
|
35
|
+
f.match(/\.gem$/)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
spec.bindir = "exe"
|
|
40
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
41
|
+
spec.require_paths = ["lib"]
|
|
42
|
+
|
|
43
|
+
spec.add_dependency "net-http", ">= 0"
|
|
44
|
+
|
|
45
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
46
|
+
spec.add_development_dependency "rspec", "~> 3.12"
|
|
47
|
+
spec.add_development_dependency "rubocop", "~> 1.50"
|
|
48
|
+
spec.add_development_dependency "webmock", "~> 3.18"
|
|
49
|
+
end
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
# API 参考
|
|
2
|
+
|
|
3
|
+
Creem Ruby SDK 提供以下资源模块,均通过 `Creem::Client` 实例访问。所有方法返回解析后的 `Hash`(JSON 响应体)。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Products(产品)
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
client.products
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### `list(page_number: 1, page_size: 10)`
|
|
14
|
+
|
|
15
|
+
获取产品列表。
|
|
16
|
+
|
|
17
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
18
|
+
|------|------|--------|------|
|
|
19
|
+
| `page_number` | Integer | 1 | 页码 |
|
|
20
|
+
| `page_size` | Integer | 10 | 每页数量 |
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
products = client.products.list(page_number: 1, page_size: 20)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**API 端点**:`GET /products/search`
|
|
27
|
+
|
|
28
|
+
### `retrieve(product_id)`
|
|
29
|
+
|
|
30
|
+
获取单个产品。
|
|
31
|
+
|
|
32
|
+
| 参数 | 类型 | 说明 |
|
|
33
|
+
|------|------|------|
|
|
34
|
+
| `product_id` | String | 产品 ID |
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
product = client.products.retrieve("prod_123")
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**API 端点**:`GET /products?product_id=...`
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Checkouts(结账)
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
client.checkouts
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### `create(product_id:, success_url: nil, request_id: nil, units: nil, discount_code: nil, customer: nil, custom_fields: nil, metadata: nil)`
|
|
51
|
+
|
|
52
|
+
创建结账会话。
|
|
53
|
+
|
|
54
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
55
|
+
|------|------|------|------|
|
|
56
|
+
| `product_id` | String | ✅ | 产品 ID |
|
|
57
|
+
| `success_url` | String | - | 支付成功后的回调 URL |
|
|
58
|
+
| `request_id` | String | - | 幂等请求 ID |
|
|
59
|
+
| `units` | Integer | - | 购买数量 |
|
|
60
|
+
| `discount_code` | String | - | 折扣码 |
|
|
61
|
+
| `customer` | Hash | - | 客户信息 |
|
|
62
|
+
| `custom_fields` | Hash | - | 自定义字段 |
|
|
63
|
+
| `metadata` | Hash | - | 元数据 |
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
checkout = client.checkouts.create(
|
|
67
|
+
product_id: "prod_123",
|
|
68
|
+
success_url: "https://yoursite.com/success",
|
|
69
|
+
units: 2,
|
|
70
|
+
metadata: { order_ref: "ORD-001" }
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
puts checkout["checkout_url"] # 重定向客户到此 URL
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**API 端点**:`POST /checkouts`
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Subscriptions(订阅)
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
client.subscriptions
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `list(page_number: 1, page_size: 10)`
|
|
87
|
+
|
|
88
|
+
获取订阅列表。
|
|
89
|
+
|
|
90
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
91
|
+
|------|------|--------|------|
|
|
92
|
+
| `page_number` | Integer | 1 | 页码 |
|
|
93
|
+
| `page_size` | Integer | 10 | 每页数量 |
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
subs = client.subscriptions.list(page_number: 1, page_size: 20)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**API 端点**:`GET /subscriptions/search`
|
|
100
|
+
|
|
101
|
+
### `retrieve(subscription_id)`
|
|
102
|
+
|
|
103
|
+
获取单个订阅。
|
|
104
|
+
|
|
105
|
+
| 参数 | 类型 | 说明 |
|
|
106
|
+
|------|------|------|
|
|
107
|
+
| `subscription_id` | String | 订阅 ID |
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
sub = client.subscriptions.retrieve("sub_123")
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**API 端点**:`GET /subscriptions?subscription_id=...`
|
|
114
|
+
|
|
115
|
+
### `update(id, items: nil, update_behavior: nil)`
|
|
116
|
+
|
|
117
|
+
更新订阅。
|
|
118
|
+
|
|
119
|
+
| 参数 | 类型 | 说明 |
|
|
120
|
+
|------|------|------|
|
|
121
|
+
| `id` | String | 订阅 ID(路径参数)|
|
|
122
|
+
| `items` | Array\<Hash\> | 订阅项,如 `[{ product_id: "prod_456", units: 3 }]` |
|
|
123
|
+
| `update_behavior` | String | 更新行为,如 `"proration-charge"` |
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
client.subscriptions.update("sub_123",
|
|
127
|
+
items: [{ product_id: "prod_456", units: 3 }],
|
|
128
|
+
update_behavior: "proration-charge"
|
|
129
|
+
)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**API 端点**:`POST /subscriptions/:id`
|
|
133
|
+
|
|
134
|
+
### `cancel(id, mode: nil, on_execute: nil)`
|
|
135
|
+
|
|
136
|
+
取消订阅。
|
|
137
|
+
|
|
138
|
+
| 参数 | 类型 | 说明 |
|
|
139
|
+
|------|------|------|
|
|
140
|
+
| `id` | String | 订阅 ID(路径参数)|
|
|
141
|
+
| `mode` | String | 取消模式,如 `"immediate"`, `"at_period_end"` |
|
|
142
|
+
| `on_execute` | String | 执行时的回调行为 |
|
|
143
|
+
|
|
144
|
+
> **注意**:`on_execute` 在请求体中以 camelCase(`onExecute`)发送,这是 Creem API 要求的格式。
|
|
145
|
+
|
|
146
|
+
```ruby
|
|
147
|
+
client.subscriptions.cancel("sub_123", mode: "immediate")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**API 端点**:`POST /subscriptions/:id/cancel`
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Customers(客户)
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
client.customers
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### `list(page_number: 1, page_size: 50)`
|
|
161
|
+
|
|
162
|
+
获取客户列表。
|
|
163
|
+
|
|
164
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
165
|
+
|------|------|--------|------|
|
|
166
|
+
| `page_number` | Integer | 1 | 页码 |
|
|
167
|
+
| `page_size` | Integer | 50 | 每页数量 |
|
|
168
|
+
|
|
169
|
+
```ruby
|
|
170
|
+
customers = client.customers.list(page_number: 1, page_size: 20)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**API 端点**:`GET /customers/list`
|
|
174
|
+
|
|
175
|
+
### `retrieve(customer_id: nil, email: nil)`
|
|
176
|
+
|
|
177
|
+
通过 ID 或邮箱获取客户。至少传入一个参数。
|
|
178
|
+
|
|
179
|
+
| 参数 | 类型 | 说明 |
|
|
180
|
+
|------|------|------|
|
|
181
|
+
| `customer_id` | String | 客户 ID |
|
|
182
|
+
| `email` | String | 客户邮箱 |
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
# 按 ID 查询
|
|
186
|
+
customer = client.customers.retrieve(customer_id: "cust_123")
|
|
187
|
+
|
|
188
|
+
# 按邮箱查询
|
|
189
|
+
customer = client.customers.retrieve(email: "user@example.com")
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**API 端点**:`GET /customers`
|
|
193
|
+
|
|
194
|
+
### `billing_portal(customer_id)`
|
|
195
|
+
|
|
196
|
+
生成客户的账单门户链接。
|
|
197
|
+
|
|
198
|
+
| 参数 | 类型 | 说明 |
|
|
199
|
+
|------|------|------|
|
|
200
|
+
| `customer_id` | String | 客户 ID |
|
|
201
|
+
|
|
202
|
+
```ruby
|
|
203
|
+
portal = client.customers.billing_portal("cust_123")
|
|
204
|
+
puts portal["customer_portal_link"]
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**API 端点**:`POST /customers/billing-portal`
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Transactions(交易)
|
|
212
|
+
|
|
213
|
+
```ruby
|
|
214
|
+
client.transactions
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### `list(page_number: 1, page_size: 10)`
|
|
218
|
+
|
|
219
|
+
获取交易列表。
|
|
220
|
+
|
|
221
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
222
|
+
|------|------|--------|------|
|
|
223
|
+
| `page_number` | Integer | 1 | 页码 |
|
|
224
|
+
| `page_size` | Integer | 10 | 每页数量 |
|
|
225
|
+
|
|
226
|
+
```ruby
|
|
227
|
+
transactions = client.transactions.list(page_number: 1, page_size: 20)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**API 端点**:`GET /transactions/search`
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Licenses(许可证)
|
|
235
|
+
|
|
236
|
+
```ruby
|
|
237
|
+
client.licenses
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### `list(page_number: 1, page_size: 10)`
|
|
241
|
+
|
|
242
|
+
获取许可证列表。
|
|
243
|
+
|
|
244
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
245
|
+
|------|------|--------|------|
|
|
246
|
+
| `page_number` | Integer | 1 | 页码 |
|
|
247
|
+
| `page_size` | Integer | 10 | 每页数量 |
|
|
248
|
+
|
|
249
|
+
```ruby
|
|
250
|
+
licenses = client.licenses.list
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**API 端点**:`GET /licenses/search`
|
|
254
|
+
|
|
255
|
+
### `activate(key:, instance_name:)`
|
|
256
|
+
|
|
257
|
+
激活许可证。
|
|
258
|
+
|
|
259
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
260
|
+
|------|------|------|------|
|
|
261
|
+
| `key` | String | ✅ | 许可证密钥 |
|
|
262
|
+
| `instance_name` | String | ✅ | 实例名称 |
|
|
263
|
+
|
|
264
|
+
```ruby
|
|
265
|
+
result = client.licenses.activate(key: "ABC-123", instance_name: "My Device")
|
|
266
|
+
puts result["instance_id"] # 保存此 ID 用于后续验证/停用
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**API 端点**:`POST /licenses/activate`
|
|
270
|
+
|
|
271
|
+
### `validate(key:, instance_id:)`
|
|
272
|
+
|
|
273
|
+
验证许可证是否有效。
|
|
274
|
+
|
|
275
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
276
|
+
|------|------|------|------|
|
|
277
|
+
| `key` | String | ✅ | 许可证密钥 |
|
|
278
|
+
| `instance_id` | String | ✅ | 实例 ID |
|
|
279
|
+
|
|
280
|
+
```ruby
|
|
281
|
+
result = client.licenses.validate(key: "ABC-123", instance_id: "inst_456")
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**API 端点**:`POST /licenses/validate`
|
|
285
|
+
|
|
286
|
+
### `deactivate(key:, instance_id:)`
|
|
287
|
+
|
|
288
|
+
停用许可证。
|
|
289
|
+
|
|
290
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
291
|
+
|------|------|------|------|
|
|
292
|
+
| `key` | String | ✅ | 许可证密钥 |
|
|
293
|
+
| `instance_id` | String | ✅ | 实例 ID |
|
|
294
|
+
|
|
295
|
+
```ruby
|
|
296
|
+
client.licenses.deactivate(key: "ABC-123", instance_id: "inst_456")
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**API 端点**:`POST /licenses/deactivate`
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Discounts(折扣)
|
|
304
|
+
|
|
305
|
+
```ruby
|
|
306
|
+
client.discounts
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### `list(page_number: 1, page_size: 10)`
|
|
310
|
+
|
|
311
|
+
获取折扣列表。
|
|
312
|
+
|
|
313
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
314
|
+
|------|------|--------|------|
|
|
315
|
+
| `page_number` | Integer | 1 | 页码 |
|
|
316
|
+
| `page_size` | Integer | 10 | 每页数量 |
|
|
317
|
+
|
|
318
|
+
```ruby
|
|
319
|
+
discounts = client.discounts.list(page_number: 1, page_size: 20)
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**API 端点**:`GET /discounts/search`
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## 分页
|
|
327
|
+
|
|
328
|
+
所有 `list` 方法都支持分页,通过 `page_number` 和 `page_size` 参数控制:
|
|
329
|
+
|
|
330
|
+
```ruby
|
|
331
|
+
# 获取第 2 页,每页 25 条
|
|
332
|
+
products = client.products.list(page_number: 2, page_size: 25)
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
响应中通常包含分页元数据,可用于构建翻页逻辑。
|