metrifox-sdk 1.0.3 → 1.1.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: 61978214945170e21af55446d8aa5606a14710fa5515cdd327d11227b5f95a22
4
- data.tar.gz: cc96ae1ea46452d1d1221b936048bb9ad8931bd93317c727352272f08ad796a6
3
+ metadata.gz: 1dff9fd808bc32d6349ca7a116713b9985ed31e1bd77bf49fd52d96d72ebedb3
4
+ data.tar.gz: 03364bfa5c26be341eee0ba665bef63913e1992ad82edd0d14123fdb1e21d607
5
5
  SHA512:
6
- metadata.gz: b31ffd58d394c50d65fd22b339f939dcbfa8ae31bb716cce31c759cd1ad9ab584746f1476e1e376541e6ac27539e4abed0b3aca665f6607136a594226881f2bf
7
- data.tar.gz: b7e0c2167befb2befc63e50b4cef0b940c0a4f81890933f2100937fe458a3c3a626451d7b4fc103f1f649cc7b6cac83ff79ed74c5fee21b023a5692479256d59
6
+ metadata.gz: ffe66393b2b92925c2f3dc15cc699b7129ca06fa8baf7a06eb73fc635637d2c42a8c193a94ca17a1f2405aa7e119a6725c3de225ef779db58301ac05367cebaf
7
+ data.tar.gz: e271a28735a68ce97be07578c748fd8e01247bdbb633112fbcdd664a1a945c028adac9f549d776e7cc452fd4d68520df7292f3ee30595477d1266f58afbc070b
data/CHANGELOG.md CHANGED
@@ -3,10 +3,11 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
+ - Update usage access and recording to call the meter service (`https://api-meter.metrifox.com`).
6
7
 
7
- ## [1.0.0] - 2025-09-01
8
+ ## [1.0.3] - 2025-09-01
8
9
  - Initial release
9
10
  - Access control functionality
10
11
  - Usage tracking
11
12
  - Customer management
12
- - CSV upload support
13
+ - CSV upload support
data/README.md CHANGED
@@ -35,6 +35,7 @@ METRIFOX_SDK = MetrifoxSDK.init({ api_key: "your-api-key"})
35
35
  # Or set environment variable
36
36
  ENV["METRIFOX_API_KEY"] = "your-api-key"
37
37
  METRIFOX_SDK = MetrifoxSDK.init
38
+
38
39
  ```
39
40
 
40
41
  ### Access Control
@@ -46,7 +47,28 @@ response = METRIFOX_SDK.usages.check_access({
46
47
  customer_key: "customer_123"
47
48
  })
48
49
 
49
- puts response["can_access"] # true/false
50
+ puts response["data"]["can_access"] # true/false
51
+ ```
52
+
53
+ > Access checks are now served by the Metrifox Meter service (`https://api-meter.metrifox.com`).
54
+ Example response payload:
55
+
56
+ ```json
57
+ {
58
+ "data": {
59
+ "customer_key": "cust-mit7k5v8obzs",
60
+ "feature_key": "feature_seats",
61
+ "requested_quantity": 1,
62
+ "can_access": true,
63
+ "unlimited": false,
64
+ "balance": 4,
65
+ "used_quantity": 0,
66
+ "entitlement_active": true,
67
+ "prepaid": false,
68
+ "wallet_balance": 0,
69
+ "message": "Feature found"
70
+ }
71
+ }
50
72
  ```
51
73
 
52
74
  ### Usage Tracking
@@ -56,17 +78,27 @@ puts response["can_access"] # true/false
56
78
  response = METRIFOX_SDK.usages.record_usage({
57
79
  customer_key: "customer_123",
58
80
  event_name: "api_call",
59
- amount: 1
81
+ amount: 1,
82
+ event_id: "evt_12345", # required idempotency key
83
+ timestamp: (Time.now.to_f * 1000).to_i # recommended (milliseconds)
60
84
  })
85
+ puts response["message"] # "Event received"
86
+ puts response["data"]["quantity"] # 1
87
+ ```
88
+
89
+ The usage event endpoint now returns a simple payload with the recorded `data` and a `message` confirming the event reception.
90
+
91
+ > You can send either an `event_name` or a `feature_key` when recording usage events.
61
92
 
93
+ ```ruby
62
94
  # Advanced usage recording with additional fields
63
95
  response = METRIFOX_SDK.usages.record_usage({
64
96
  customer_key: "customer_123",
65
- event_name: "api_call",
97
+ event_name: "api_call", # Or use feature_key
66
98
  amount: 1,
99
+ event_id: "event_uuid_123", # required idempotency key
67
100
  credit_used: 5,
68
- event_id: "event_uuid_123",
69
- timestamp: 1640995200,
101
+ timestamp: (Time.now.to_f * 1000).to_i,
70
102
  metadata: {
71
103
  source: "web_app",
72
104
  feature: "premium_search"
@@ -76,17 +108,30 @@ response = METRIFOX_SDK.usages.record_usage({
76
108
  # Using structured request object
77
109
  usage_request = MetrifoxSDK::Types::UsageEventRequest.new(
78
110
  customer_key: "customer_123",
79
- event_name: "api_call",
111
+ feature_key: "feat_my_feat_234", # OR use event_name
80
112
  amount: 1,
81
113
  credit_used: 5,
82
114
  event_id: "event_uuid_123",
83
- timestamp: Time.now.to_i,
115
+ timestamp: (Time.now.to_f * 1000).to_i,
84
116
  metadata: { source: "mobile_app" }
85
117
  )
86
118
 
87
119
  response = METRIFOX_SDK.usages.record_usage(usage_request)
88
120
  ```
89
121
 
122
+ Sample response body:
123
+
124
+ ```json
125
+ {
126
+ "data": {
127
+ "customer_key": "cust-mit7k5v8obzs",
128
+ "quantity": 1,
129
+ "feature_key": "feature_job_posts"
130
+ },
131
+ "message": "Event received"
132
+ }
133
+ ```
134
+
90
135
  ### Customer Management
91
136
 
92
137
  ```ruby
@@ -199,35 +244,29 @@ response = METRIFOX_SDK.usages.check_access({
199
244
 
200
245
  ## Type Safety with Structs
201
246
 
202
- The SDK provides structured types for better type safety:
247
+ The SDK exposes lightweight structs for the usage and checkout helpers when you want a bit more structure:
203
248
 
204
249
  ```ruby
205
- # Using structured request objects
206
- access_request = MetrifoxSDK::Types::AccessCheckRequest.new(
207
- feature_key: "premium_feature",
208
- customer_key: "customer_123"
209
- )
210
-
211
- response = METRIFOX_SDK.usages.check_access(access_request)
212
-
213
- # Customer creation with structured data (customer_key is REQUIRED)
214
- customer_request = MetrifoxSDK::Types::CustomerCreateRequest.new(
215
- customer_key: "customer_123", # Required
216
- customer_type: MetrifoxSDK::Types::CustomerType::BUSINESS,
217
- primary_email: "customer@example.com",
218
- legal_name: "Acme Corp"
250
+ # Usage events (event_id required for idempotency)
251
+ usage_request = MetrifoxSDK::Types::UsageEventRequest.new(
252
+ customer_key: "customer_123",
253
+ feature_key: "feature_seats",
254
+ amount: 1,
255
+ event_id: "event_uuid_123",
256
+ timestamp: (Time.now.to_f * 1000).to_i,
257
+ metadata: { source: "mobile_app" }
219
258
  )
220
259
 
221
- response = METRIFOX_SDK.customers.create(customer_request)
260
+ response = METRIFOX_SDK.usages.record_usage(usage_request)
222
261
 
223
- # Customer update with structured data (customer_key is immutable)
224
- customer_update = MetrifoxSDK::Types::CustomerUpdateRequest.new(
225
- display_name: "Acme Corporation",
226
- website_url: "https://acme.com"
227
- # Note: customer_key is NOT a field in CustomerUpdateRequest
262
+ # Checkout configuration
263
+ checkout_config = MetrifoxSDK::Types::CheckoutConfig.new(
264
+ offering_key: "premium_plan",
265
+ billing_interval: "monthly",
266
+ customer_key: "customer_123"
228
267
  )
229
268
 
230
- response = METRIFOX_SDK.customers.update("customer_123", customer_update)
269
+ checkout_url = METRIFOX_SDK.checkout.url(checkout_config)
231
270
  ```
232
271
 
233
272
  ## Error Handling
@@ -4,13 +4,18 @@ module MetrifoxSDK
4
4
  class Client
5
5
  include MetrifoxSDK::UtilMethods
6
6
 
7
- attr_reader :config, :api_key, :base_url, :web_app_base_url
7
+ DEFAULT_BASE_URL = "https://api.metrifox.com/api/v1/".freeze
8
+ DEFAULT_WEB_APP_BASE_URL = "https://app.metrifox.com".freeze
9
+ METER_SERVICE_BASE_URL = "https://api-meter.metrifox.com/".freeze
10
+
11
+ attr_reader :config, :api_key, :base_url, :web_app_base_url, :meter_service_base_url
8
12
 
9
13
  def initialize(config = {})
10
14
  @config = config
11
15
  @api_key = config[:api_key] || get_api_key_from_environment
12
- @base_url = config[:base_url] || "https://api.metrifox.com/api/v1/"
13
- @web_app_base_url = config[:web_app_base_url] || "https://app.metrifox.com"
16
+ @base_url = config[:base_url] || DEFAULT_BASE_URL
17
+ @web_app_base_url = config[:web_app_base_url] || DEFAULT_WEB_APP_BASE_URL
18
+ @meter_service_base_url = METER_SERVICE_BASE_URL
14
19
  end
15
20
 
16
21
  def customers
@@ -1,115 +1,14 @@
1
1
  module MetrifoxSDK
2
2
  module Types
3
- # Enums
4
- module TaxStatus
5
- TAXABLE = "TAXABLE"
6
- TAX_EXEMPT = "TAX_EXEMPT"
7
- REVERSE_CHARGE = "REVERSE_CHARGE"
8
- end
9
-
10
- module CustomerType
11
- BUSINESS = "BUSINESS"
12
- INDIVIDUAL = "INDIVIDUAL"
13
- end
14
-
15
- # Value objects / Structs
16
- EmailAddress = Struct.new(:email, :is_primary, keyword_init: true)
17
- PhoneNumber = Struct.new(:phone_number, :country_code, :is_primary, keyword_init: true)
18
-
19
- Address = Struct.new(
20
- :country, :address_line_one, :address_line_two, :city,
21
- :state, :zip_code, :phone_number, keyword_init: true
22
- )
23
-
24
- BillingConfig = Struct.new(
25
- :preferred_payment_gateway, :preferred_payment_method, :billing_email,
26
- :billing_address, :payment_reminder_days, keyword_init: true
27
- )
28
-
29
- TaxIdentification = Struct.new(:type, :number, :country, keyword_init: true)
30
-
31
- ContactPerson = Struct.new(
32
- :first_name, :last_name, :email_address, :designation,
33
- :department, :is_primary, :phone_number, keyword_init: true
34
- )
35
-
36
- PaymentTerm = Struct.new(:type, :value, keyword_init: true)
37
-
38
- # Request/Response objects
39
- AccessCheckRequest = Struct.new(:feature_key, :customer_key, keyword_init: true)
40
-
41
- AccessResponse = Struct.new(
42
- :message, :can_access, :customer_id, :feature_key, :required_quantity,
43
- :used_quantity, :included_usage, :next_reset_at, :quota, :unlimited,
44
- :carryover_quantity, :balance, keyword_init: true
45
- )
46
-
47
3
  UsageEventRequest = Struct.new(
48
- :customer_key, :event_name, :amount, :credit_used, :event_id, :timestamp, :metadata,
4
+ :customer_key, :event_name, :feature_key, :amount, :credit_used, :event_id, :timestamp, :metadata,
49
5
  keyword_init: true
50
6
  ) do
51
- def initialize(customer_key:, event_name:, amount: 1, credit_used: nil, event_id: nil, timestamp: nil, metadata: {})
7
+ def initialize(customer_key:, event_name: nil, feature_key: nil, amount: 1, credit_used: nil, event_id: nil, timestamp: nil, metadata: {})
52
8
  super
53
9
  end
54
10
  end
55
11
 
56
- UsageEventResponse = Struct.new(:message, :event_name, :customer_key, keyword_init: true)
57
-
58
- CustomerCreateRequest = Struct.new(
59
- # Core fields (customer_key is REQUIRED)
60
- :customer_key, :customer_type, :primary_email, :primary_phone,
61
- # Business fields
62
- :legal_name, :display_name, :legal_number, :tax_identification_number,
63
- :logo_url, :website_url, :account_manager,
64
- # Individual fields
65
- :first_name, :middle_name, :last_name, :date_of_birth, :billing_email,
66
- # Preferences
67
- :timezone, :language, :currency, :tax_status,
68
- # Address fields
69
- :address_line1, :address_line2, :city, :state, :country, :zip_code,
70
- # Shipping address fields
71
- :shipping_address_line1, :shipping_address_line2, :shipping_city,
72
- :shipping_state, :shipping_country, :shipping_zip_code,
73
- # Complex fields
74
- :billing_configuration, :tax_identifications, :contact_people,
75
- :payment_terms, :metadata, keyword_init: true
76
- )
77
-
78
- CustomerUpdateRequest = Struct.new(
79
- # Core fields (customer_key is NOT included - it's immutable and passed as a parameter)
80
- :customer_type, :primary_email, :primary_phone, :billing_email,
81
- # Business fields
82
- :legal_name, :display_name, :legal_number, :tax_identification_number,
83
- :logo_url, :website_url, :account_manager,
84
- # Individual fields
85
- :first_name, :middle_name, :last_name, :date_of_birth,
86
- # Preferences
87
- :timezone, :language, :currency, :tax_status,
88
- # Address fields
89
- :address_line1, :address_line2, :city, :state, :country, :zip_code,
90
- # Shipping address fields
91
- :shipping_address_line1, :shipping_address_line2, :shipping_city,
92
- :shipping_state, :shipping_country, :shipping_zip_code,
93
- # Complex fields
94
- :billing_configuration, :tax_identifications, :contact_people,
95
- :payment_terms, :metadata, :phone_numbers, :email_addresses, keyword_init: true
96
- )
97
-
98
- CustomerDeleteRequest = Struct.new(:customer_key, keyword_init: true)
99
- CustomerGetRequest = Struct.new(:customer_key, keyword_init: true)
100
-
101
- CustomerCSVSyncResponse = Struct.new(
102
- :status_code, :message, :data, :errors, :meta, keyword_init: true
103
- ) do
104
- CSVSyncData = Struct.new(
105
- :total_customers, :successful_upload_count, :failed_upload_count,
106
- :customers_added, :customers_failed, keyword_init: true
107
- )
108
- end
109
-
110
- APIResponse = Struct.new(:status_code, :message, :data, :errors, :meta, keyword_init: true)
111
-
112
- EmbedConfig = Struct.new(:container, :product_key, keyword_init: true)
113
12
  CheckoutConfig = Struct.new(:offering_key, :billing_interval, :customer_key, keyword_init: true)
114
13
  end
115
- end
14
+ end
@@ -22,7 +22,7 @@ module MetrifoxSDK::Usages
22
22
  parse_response(response, "Failed to check access")
23
23
  end
24
24
 
25
- def fetch_usage(base_url, api_key, request_payload)
25
+ def record_usage(base_url, api_key, request_payload)
26
26
  uri = URI.join(base_url, "usage/events")
27
27
 
28
28
  # Handle both hash and struct access patterns
@@ -33,18 +33,20 @@ module MetrifoxSDK::Usages
33
33
  event_id = get_value(request_payload, :event_id)
34
34
  timestamp = get_value(request_payload, :timestamp)
35
35
  metadata = get_value(request_payload, :metadata) || {}
36
+ feature_key = get_value(request_payload, :feature_key)
36
37
 
37
38
  body = {
38
- customer_key: customer_key,
39
- event_name: event_name,
40
- amount: amount
39
+ customer_key:,
40
+ amount:,
41
+ event_id:
41
42
  }
42
43
 
43
44
  # Add optional fields if present
44
45
  body[:credit_used] = credit_used if credit_used
45
- body[:event_id] = event_id if event_id && !event_id.empty?
46
46
  body[:timestamp] = timestamp if timestamp
47
47
  body[:metadata] = metadata if metadata
48
+ body[:feature_key] = feature_key if feature_key
49
+ body[:event_name] = event_name if event_name
48
50
 
49
51
  response = make_request(uri, "POST", api_key, body)
50
52
  parse_response(response, "Failed to record usage")
@@ -77,4 +79,4 @@ module MetrifoxSDK::Usages
77
79
  end
78
80
  end
79
81
  end
80
- end
82
+ end
@@ -6,12 +6,12 @@ module MetrifoxSDK
6
6
  class Module < BaseModule
7
7
  def check_access(request_payload)
8
8
  validate_api_key!
9
- api.fetch_access(base_url, api_key, request_payload)
9
+ api.fetch_access(meter_service_base_url, api_key, request_payload)
10
10
  end
11
11
 
12
12
  def record_usage(request_payload)
13
13
  validate_api_key!
14
- api.fetch_usage(base_url, api_key, request_payload)
14
+ api.record_usage(meter_service_base_url, api_key, request_payload)
15
15
  end
16
16
 
17
17
  def get_tenant_id
@@ -26,9 +26,13 @@ module MetrifoxSDK
26
26
 
27
27
  private
28
28
 
29
+ def meter_service_base_url
30
+ client.respond_to?(:meter_service_base_url) ? client.meter_service_base_url : base_url
31
+ end
32
+
29
33
  def api
30
34
  @api ||= API.new
31
35
  end
32
36
  end
33
37
  end
34
- end
38
+ end
@@ -1,3 +1,3 @@
1
1
  module MetrifoxSDK
2
- VERSION = '1.0.3'
2
+ VERSION = '1.1.0'
3
3
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metrifox-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Metrifox
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-11-26 00:00:00.000000000 Z
10
+ date: 2025-12-12 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: json