metrifox-sdk 1.2.0 → 1.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3cdf295c1adaab10f96e19c3075c40731a28bb799a1a696ff956abfaf2f0a724
4
- data.tar.gz: 5c964c16f80530bd851132092261a09939473c60e53fe9d65ef309a9d354b9e7
3
+ metadata.gz: 5b50b292611bbf15e93297b499fe95c413bb78742469c7f8fe3c72b828c0c562
4
+ data.tar.gz: f2927b301e5b5e2f52f3bf900bddb92438ad5e3372c4cddf32e101bf9596ce9e
5
5
  SHA512:
6
- metadata.gz: 7f391b66aae02c8854acd698a3f4031d0bf8996715367c28187346217b8a6be06fffce582cb42ace51de436e85bf3def974e0100c8364adeaddb5586522ec537
7
- data.tar.gz: b8b03fe8d55a00d308b2affb7fc1fe6e8fe8a32a7d50b15cee248e406123690ad579e202331352a83b85bdfb75cff4f90c0b798bf59e924d3d625d2e058f8a15
6
+ metadata.gz: a17ff50508a89fee40d85b970b6fd51418fb1aff4695c58e9f1c240ebbf2c14f98bc9e12140e2c07999e9b7f4dd51a696f4003fab8a11082484b3d9e7a4089b2
7
+ data.tar.gz: 26309f0d2ef619f1149f294e487b6dcdca6f10a81f31af5890a13c8035c75bdd9c3a55aac2fb2cd506a583565dbbc764e3c6d0fd3f457ebf41604b09b57795ef
data/CHANGELOG.md CHANGED
@@ -3,6 +3,16 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
+
7
+ ## [1.3.0]
8
+ - Add `wallets` module with `list`, `list_credit_allocations`, and `get_credit_allocation` methods.
9
+ - Add `customers.archive` and `customers.unarchive`.
10
+ - Add `checkout.card_collection_url(subscription_id:, order_id:)` for generating card-collection URLs.
11
+ - Add `usages.list_events` for listing recorded usage events with optional filters and pagination.
12
+ - Add `usages.quantity_price(customer_key:, feature_key:, quantity:)` for computing the price of a usage quantity.
13
+ - Allow overriding the meter service base URL via `meter_service_base_url` config or `METRIFOX_METER_SERVICE_BASE_URL` env var.
14
+
15
+ ## [1.2.x]
6
16
  - Update usage access and recording to call the meter service (`https://api-meter.metrifox.com`).
7
17
 
8
18
  ## [1.0.3] - 2025-09-01
data/README.md CHANGED
@@ -36,6 +36,15 @@ METRIFOX_SDK = MetrifoxSDK.init({ api_key: "your-api-key"})
36
36
  ENV["METRIFOX_API_KEY"] = "your-api-key"
37
37
  METRIFOX_SDK = MetrifoxSDK.init
38
38
 
39
+ # Override base URLs (e.g. for staging or self-hosted environments)
40
+ METRIFOX_SDK = MetrifoxSDK.init({
41
+ api_key: "your-api-key",
42
+ base_url: "https://api.staging.metrifox.com/api/v1/",
43
+ meter_service_base_url: "https://api-meter.staging.metrifox.com/"
44
+ })
45
+
46
+ # The meter service URL can also be set via env var
47
+ ENV["METRIFOX_METER_SERVICE_BASE_URL"] = "https://api-meter.staging.metrifox.com/"
39
48
  ```
40
49
 
41
50
  ### Access Control
@@ -189,6 +198,41 @@ response = METRIFOX_SDK.customers.list({
189
198
  # Delete customer
190
199
  response = METRIFOX_SDK.customers.delete_customer({ customer_key: "customer_123" })
191
200
 
201
+ # Archive customer
202
+ response = METRIFOX_SDK.customers.archive("customer_123")
203
+
204
+ # Unarchive customer
205
+ response = METRIFOX_SDK.customers.unarchive("customer_123")
206
+
207
+ ```
208
+
209
+ ### Bulk Create Customers
210
+
211
+ Create multiple customers in a single API call:
212
+
213
+ ```ruby
214
+ result = METRIFOX_SDK.customers.bulk_create({
215
+ customers: [
216
+ {
217
+ customer_key: "customer_001",
218
+ customer_type: "BUSINESS",
219
+ primary_email: "contact@acme.com",
220
+ legal_name: "Acme Corp",
221
+ display_name: "Acme"
222
+ },
223
+ {
224
+ customer_key: "customer_002",
225
+ customer_type: "INDIVIDUAL",
226
+ primary_email: "jane@example.com",
227
+ first_name: "Jane",
228
+ last_name: "Doe"
229
+ }
230
+ ]
231
+ })
232
+
233
+ puts result["data"]["total"]
234
+ puts result["data"]["successful_count"]
235
+ puts result["data"]["failed_count"]
192
236
  ```
193
237
 
194
238
  ### CSV Upload
@@ -232,6 +276,76 @@ checkout_config = MetrifoxSDK::Types::CheckoutConfig.new(
232
276
  checkout_url = METRIFOX_SDK.checkout.url(checkout_config)
233
277
  ```
234
278
 
279
+ ### Card Collection URL
280
+
281
+ Generate a hosted URL for collecting a payment method against an existing subscription or order:
282
+
283
+ ```ruby
284
+ # For a subscription
285
+ url = METRIFOX_SDK.checkout.card_collection_url(subscription_id: "sub_uuid_123")
286
+
287
+ # For an order
288
+ url = METRIFOX_SDK.checkout.card_collection_url(order_id: "order_uuid_456")
289
+ ```
290
+
291
+ ### Usage Events
292
+
293
+ ```ruby
294
+ # List usage events with optional filters and pagination
295
+ response = METRIFOX_SDK.usages.list_events(
296
+ customer_key: "customer_123", # optional
297
+ feature_key: "feature_seats", # optional
298
+ page: 1, # optional
299
+ per_page: 25 # optional
300
+ )
301
+
302
+ response["data"].each do |event|
303
+ puts "#{event['feature_key']}: #{event['quantity']} at #{event['timestamp']}"
304
+ end
305
+ ```
306
+
307
+ ### Compute Quantity Price
308
+
309
+ Compute the price for a given quantity of a feature for a customer, based on their plan. Useful for previewing upgrade costs or showing the cost of additional usage before a customer commits.
310
+
311
+ ```ruby
312
+ response = METRIFOX_SDK.usages.quantity_price(
313
+ customer_key: "customer_123",
314
+ feature_key: "feature_interview_booking",
315
+ quantity: 500
316
+ )
317
+
318
+ puts "#{response['data']['price']} #{response['data']['unit']}"
319
+
320
+ # For tiered pricing, inspect the per-tier breakdown
321
+ response["data"]["applied_tiers"].each do |tier|
322
+ puts " Tier #{tier['first_unit']}-#{tier['last_unit']}: #{tier['units_consumed']} units -> #{tier['tier_price']}"
323
+ end
324
+ ```
325
+
326
+ > Only available to tenants whose plan includes the finance API feature.
327
+
328
+ ### Wallets
329
+
330
+ ```ruby
331
+ # List wallets for a customer
332
+ response = METRIFOX_SDK.wallets.list("customer_123")
333
+ response["data"].each do |wallet|
334
+ puts "#{wallet['name']}: #{wallet['balance']} #{wallet['credit_unit_plural']}"
335
+ end
336
+
337
+ # List credit allocations for a wallet (optionally filtered by status)
338
+ response = METRIFOX_SDK.wallets.list_credit_allocations("wallet_uuid_123")
339
+ response = METRIFOX_SDK.wallets.list_credit_allocations("wallet_uuid_123", status: "active")
340
+
341
+ # Get a single credit allocation with its transactions
342
+ response = METRIFOX_SDK.wallets.get_credit_allocation("alloc_uuid_123")
343
+ puts response["data"]["amount"]
344
+ response["data"]["transactions"].each do |txn|
345
+ puts " #{txn['amount']} at #{txn['created_at']}"
346
+ end
347
+ ```
348
+
235
349
  ### Subscriptions
236
350
 
237
351
  ```ruby
@@ -252,6 +366,26 @@ response = METRIFOX_SDK.subscriptions.get_entitlements_usage("subscription_uuid"
252
366
  puts response["data"]
253
367
  ```
254
368
 
369
+ ### Bulk Assign Plan
370
+
371
+ Assign a plan to multiple customers at once:
372
+
373
+ ```ruby
374
+ result = METRIFOX_SDK.subscriptions.bulk_assign_plan(
375
+ customer_keys: ["customer_001", "customer_002"],
376
+ plan_key: "pro-plan",
377
+ billing_interval: "monthly", # optional
378
+ currency_code: "USD", # optional
379
+ items: [ # optional: credit/feature quantities
380
+ { credit_key: "api_credits", quantity: 500 }
381
+ ],
382
+ skip_invoice: false # optional
383
+ )
384
+
385
+ puts result["data"]["succeeded"] # Array of successful assignments
386
+ puts result["data"]["failed"] # Array of failures with error details
387
+ ```
388
+
255
389
  ### Using Client Instance
256
390
 
257
391
  ```ruby
data/lib/metrifox-sdk.rb CHANGED
@@ -11,6 +11,8 @@ require_relative "metrifox_sdk/checkout/api"
11
11
  require_relative "metrifox_sdk/checkout/module"
12
12
  require_relative "metrifox_sdk/subscriptions/api"
13
13
  require_relative "metrifox_sdk/subscriptions/module"
14
+ require_relative "metrifox_sdk/wallets/api"
15
+ require_relative "metrifox_sdk/wallets/module"
14
16
 
15
17
  module MetrifoxSDK
16
18
  class << self
@@ -19,5 +19,13 @@ module MetrifoxSDK::Checkout
19
19
  data = parse_response(response, "Failed to generate checkout URL")
20
20
  data.dig("data", "checkout_url")
21
21
  end
22
+
23
+ def generate_card_collection_url(base_url, api_key, query_params)
24
+ uri = URI.join(base_url, "checkout/generate-card-collection-url")
25
+ uri.query = URI.encode_www_form(query_params)
26
+ response = make_request(uri, "GET", api_key)
27
+ data = parse_response(response, "Failed to generate card collection URL")
28
+ data.dig("data", "checkout_url")
29
+ end
22
30
  end
23
31
  end
@@ -26,6 +26,23 @@ module MetrifoxSDK
26
26
  checkout_url
27
27
  end
28
28
 
29
+ def card_collection_url(subscription_id: nil, order_id: nil)
30
+ validate_api_key!
31
+
32
+ if (subscription_id.nil? || subscription_id.to_s.empty?) && (order_id.nil? || order_id.to_s.empty?)
33
+ raise ArgumentError, "Either subscription_id or order_id is required"
34
+ end
35
+
36
+ query_params = {}
37
+ query_params[:subscription_id] = subscription_id if subscription_id && !subscription_id.to_s.empty?
38
+ query_params[:order_id] = order_id if order_id && !order_id.to_s.empty?
39
+
40
+ checkout_url = api.generate_card_collection_url(base_url, api_key, query_params)
41
+ raise StandardError, "Card collection URL could not be generated" if checkout_url.nil? || checkout_url.empty?
42
+
43
+ checkout_url
44
+ end
45
+
29
46
  private
30
47
 
31
48
  def get_checkout_key
@@ -15,7 +15,7 @@ module MetrifoxSDK
15
15
  @api_key = config[:api_key] || get_api_key_from_environment
16
16
  @base_url = config[:base_url] || DEFAULT_BASE_URL
17
17
  @web_app_base_url = config[:web_app_base_url] || DEFAULT_WEB_APP_BASE_URL
18
- @meter_service_base_url = METER_SERVICE_BASE_URL
18
+ @meter_service_base_url = config[:meter_service_base_url] || ENV["METRIFOX_METER_SERVICE_BASE_URL"] || METER_SERVICE_BASE_URL
19
19
  end
20
20
 
21
21
  def customers
@@ -34,6 +34,10 @@ module MetrifoxSDK
34
34
  @subscriptions ||= Subscriptions::Module.new(self)
35
35
  end
36
36
 
37
+ def wallets
38
+ @wallets ||= Wallets::Module.new(self)
39
+ end
40
+
37
41
  private
38
42
 
39
43
  def get_api_key_from_environment
@@ -47,6 +47,18 @@ module MetrifoxSDK::Customers
47
47
  parse_response(response, "Failed to Check Active Subscription")
48
48
  end
49
49
 
50
+ def customer_archive_request(base_url, api_key, customer_key)
51
+ uri = URI.join(base_url, "customers/#{customer_key}/archive")
52
+ response = make_request(uri, "POST", api_key)
53
+ parse_response(response, "Failed to Archive Customer")
54
+ end
55
+
56
+ def customer_unarchive_request(base_url, api_key, customer_key)
57
+ uri = URI.join(base_url, "customers/#{customer_key}/unarchive")
58
+ response = make_request(uri, "POST", api_key)
59
+ parse_response(response, "Failed to Unarchive Customer")
60
+ end
61
+
50
62
  def customer_list_request(base_url, api_key, request_payload = {})
51
63
  uri = URI.join(base_url, "customers")
52
64
 
@@ -75,6 +87,13 @@ module MetrifoxSDK::Customers
75
87
  parse_response(response, "Failed to upload CSV")
76
88
  end
77
89
 
90
+ def bulk_create_request(base_url, api_key, request_payload)
91
+ uri = URI.join(base_url, "customers/bulk-create")
92
+ body = serialize_customer_request(request_payload)
93
+ response = make_request(uri, "POST", api_key, body)
94
+ parse_response(response, "Failed to Bulk Create Customers")
95
+ end
96
+
78
97
  private
79
98
 
80
99
  def serialize_customer_request(request)
@@ -44,6 +44,16 @@ module MetrifoxSDK
44
44
  delete_customer(request_payload)
45
45
  end
46
46
 
47
+ def archive(customer_key)
48
+ validate_api_key!
49
+ api.customer_archive_request(base_url, api_key, customer_key)
50
+ end
51
+
52
+ def unarchive(customer_key)
53
+ validate_api_key!
54
+ api.customer_unarchive_request(base_url, api_key, customer_key)
55
+ end
56
+
47
57
  def list(request_payload = {})
48
58
  validate_api_key!
49
59
  api.customer_list_request(base_url, api_key, request_payload)
@@ -54,6 +64,11 @@ module MetrifoxSDK
54
64
  api.upload_customers_csv(base_url, api_key, file_path)
55
65
  end
56
66
 
67
+ def bulk_create(request_payload)
68
+ validate_api_key!
69
+ api.bulk_create_request(base_url, api_key, request_payload)
70
+ end
71
+
57
72
  private
58
73
 
59
74
  def api
@@ -22,5 +22,18 @@ module MetrifoxSDK::Subscriptions
22
22
  response = make_request(uri, "GET", api_key)
23
23
  parse_response(response, "Failed to Fetch Entitlements Usage")
24
24
  end
25
+
26
+ def bulk_assign_plan_request(base_url, api_key, request_payload)
27
+ uri = URI.join(base_url, "subscriptions/bulk-assign-plan")
28
+ body = if request_payload.respond_to?(:to_h)
29
+ request_payload.to_h.compact
30
+ elsif request_payload.is_a?(Hash)
31
+ request_payload.compact
32
+ else
33
+ raise ArgumentError, "Invalid request format"
34
+ end
35
+ response = make_request(uri, "POST", api_key, body)
36
+ parse_response(response, "Failed to Bulk Assign Plan")
37
+ end
25
38
  end
26
39
  end
@@ -19,6 +19,19 @@ module MetrifoxSDK
19
19
  api.entitlements_usage_request(base_url, api_key, subscription_id)
20
20
  end
21
21
 
22
+ def bulk_assign_plan(customer_keys:, plan_key:, billing_interval: nil, currency_code: nil, items: nil, skip_invoice: nil)
23
+ validate_api_key!
24
+ request_payload = {
25
+ customer_keys: customer_keys,
26
+ plan_key: plan_key,
27
+ billing_interval: billing_interval,
28
+ currency_code: currency_code,
29
+ items: items,
30
+ skip_invoice: skip_invoice
31
+ }.compact
32
+ api.bulk_assign_plan_request(base_url, api_key, request_payload)
33
+ end
34
+
22
35
  private
23
36
 
24
37
  def api
@@ -52,6 +52,20 @@ module MetrifoxSDK::Usages
52
52
  parse_response(response, "Failed to record usage")
53
53
  end
54
54
 
55
+ def list_events(base_url, api_key, query_params = {})
56
+ uri = URI.join(base_url, "usage/events")
57
+ uri.query = URI.encode_www_form(query_params) unless query_params.empty?
58
+ response = make_request(uri, "GET", api_key)
59
+ parse_response(response, "Failed to list usage events")
60
+ end
61
+
62
+ def quantity_price(base_url, api_key, customer_key:, feature_key:, quantity:)
63
+ uri = URI.join(base_url, "usage/quantity-price")
64
+ uri.query = URI.encode_www_form(customer_key: customer_key, feature_key: feature_key, quantity: quantity)
65
+ response = make_request(uri, "GET", api_key)
66
+ parse_response(response, "Failed to compute quantity price")
67
+ end
68
+
55
69
  def fetch_tenant_id(base_url, api_key)
56
70
  uri = URI.join(base_url, "auth/get-tenant-id")
57
71
  response = make_request(uri, "GET", api_key)
@@ -14,6 +14,21 @@ module MetrifoxSDK
14
14
  api.record_usage(meter_service_base_url, api_key, request_payload)
15
15
  end
16
16
 
17
+ def list_events(customer_key: nil, feature_key: nil, page: nil, per_page: nil)
18
+ validate_api_key!
19
+ query_params = {}
20
+ query_params[:customer_key] = customer_key if customer_key
21
+ query_params[:feature_key] = feature_key if feature_key
22
+ query_params[:page] = page if page
23
+ query_params[:per_page] = per_page if per_page
24
+ api.list_events(meter_service_base_url, api_key, query_params)
25
+ end
26
+
27
+ def quantity_price(customer_key:, feature_key:, quantity:)
28
+ validate_api_key!
29
+ api.quantity_price(base_url, api_key, customer_key: customer_key, feature_key: feature_key, quantity: quantity)
30
+ end
31
+
17
32
  def get_tenant_id
18
33
  validate_api_key!
19
34
  api.fetch_tenant_id(base_url, api_key)
@@ -1,3 +1,3 @@
1
1
  module MetrifoxSDK
2
- VERSION = '1.2.0'
2
+ VERSION = '1.3.0'
3
3
  end
@@ -0,0 +1,28 @@
1
+ require "net/http"
2
+ require "uri"
3
+ require "json"
4
+ require_relative "../base_api"
5
+
6
+ module MetrifoxSDK::Wallets
7
+ class API < MetrifoxSDK::BaseApi
8
+ def list_wallets(base_url, api_key, customer_key)
9
+ uri = URI.join(base_url, "credit_systems/v2/wallets")
10
+ uri.query = URI.encode_www_form(customer_key: customer_key)
11
+ response = make_request(uri, "GET", api_key)
12
+ parse_response(response, "Failed to list wallets")
13
+ end
14
+
15
+ def list_credit_allocations(base_url, api_key, wallet_id, status: nil)
16
+ uri = URI.join(base_url, "credit_systems/v2/wallets/#{wallet_id}/credit-allocations")
17
+ uri.query = URI.encode_www_form(status: status) if status && !status.to_s.empty?
18
+ response = make_request(uri, "GET", api_key)
19
+ parse_response(response, "Failed to list credit allocations")
20
+ end
21
+
22
+ def get_credit_allocation(base_url, api_key, allocation_id)
23
+ uri = URI.join(base_url, "credit_systems/v2/credit-allocations/#{allocation_id}")
24
+ response = make_request(uri, "GET", api_key)
25
+ parse_response(response, "Failed to get credit allocation")
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ require_relative "api"
2
+ require_relative "../base_module"
3
+
4
+ module MetrifoxSDK
5
+ module Wallets
6
+ class Module < BaseModule
7
+ def list(customer_key)
8
+ validate_api_key!
9
+ api.list_wallets(base_url, api_key, customer_key)
10
+ end
11
+
12
+ def list_credit_allocations(wallet_id, status: nil)
13
+ validate_api_key!
14
+ api.list_credit_allocations(base_url, api_key, wallet_id, status: status)
15
+ end
16
+
17
+ def get_credit_allocation(allocation_id)
18
+ validate_api_key!
19
+ api.get_credit_allocation(base_url, api_key, allocation_id)
20
+ end
21
+
22
+ private
23
+
24
+ def api
25
+ @api ||= API.new
26
+ end
27
+ end
28
+ end
29
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metrifox-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Metrifox
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-02-16 00:00:00.000000000 Z
11
+ date: 2026-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -133,6 +133,8 @@ files:
133
133
  - lib/metrifox_sdk/usages/module.rb
134
134
  - lib/metrifox_sdk/util_methods.rb
135
135
  - lib/metrifox_sdk/version.rb
136
+ - lib/metrifox_sdk/wallets/api.rb
137
+ - lib/metrifox_sdk/wallets/module.rb
136
138
  homepage: https://github.com/metrifox/metrifox-ruby
137
139
  licenses:
138
140
  - MIT