metrifox-sdk 1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f814153e75795c0d87de3d15f3164f73fc6a561be992a209900880d2b8461406
4
+ data.tar.gz: 5329b40387f7555df0895e7889f0e5f63b52b854571d34816627d159340bccd5
5
+ SHA512:
6
+ metadata.gz: 0efde0b9967198c7f0631b7bd35343f00fa94c56d8cfde2696eb7b6f4405ca6995adb82776f5ea516a6f5e40d132ff1023690e4c0526560ad429879a1dfc605a
7
+ data.tar.gz: 7c14771a87ad8032448a53d38b20e3ed94fb423c4b674897c9263408cc4693fcfd7033931c1ac66e53c0c962dda0f92f29841aa8b9a35065a1512fd496aa11b1
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [1.0.0] - 2025-09-01
8
+ - Initial release
9
+ - Access control functionality
10
+ - Usage tracking
11
+ - Customer management
12
+ - CSV upload support
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Your Name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,171 @@
1
+ # MetrifoxSDK Ruby Gem
2
+
3
+ A Ruby SDK for interacting with the Metrifox platform API.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'metrifox_sdk'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ $ bundle install
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```bash
22
+ $ gem install metrifox_sdk
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ### Configuration
28
+
29
+ ```ruby
30
+ require 'metrifox_sdk'
31
+
32
+ # Initialize with configuration
33
+ MetrifoxSDK.init({
34
+ api_key: "your-api-key",
35
+ base_url: "https://metrifox-api.staging.useyala.com/api/v1/",
36
+ web_app_base_url: "https://frontend-v3.staging.useyala.com"
37
+ })
38
+
39
+ # Or set environment variable
40
+ ENV["METRIFOX_API_KEY"] = "your-api-key"
41
+ MetrifoxSDK.init
42
+ ```
43
+
44
+ ### Access Control
45
+
46
+ ```ruby
47
+ # Check feature access
48
+ response = MetrifoxSDK.usages.check_access({
49
+ feature_key: "premium_feature",
50
+ customer_key: "customer_123"
51
+ })
52
+
53
+ puts response["can_access"] # true/false
54
+ ```
55
+
56
+ ### Usage Tracking
57
+
58
+ ```ruby
59
+ # Record usage event
60
+ response = MetrifoxSDK.usages.record_usage({
61
+ customer_key: "customer_123",
62
+ event_name: "api_call",
63
+ amount: 1
64
+ })
65
+ ```
66
+
67
+ ### Customer Management
68
+
69
+ ```ruby
70
+ # Create customer
71
+ customer_data = {
72
+ customer_key: "customer_123",
73
+ customer_type: "BUSINESS",
74
+ primary_email: "customer@example.com",
75
+ legal_name: "Acme Corp",
76
+ display_name: "ACME"
77
+ }
78
+
79
+ response = MetrifoxSDK.customers.create(customer_data)
80
+
81
+ # Update customer
82
+ update_data = {
83
+ display_name: "ACME Corporation",
84
+ website_url: "https://acme.com"
85
+ }
86
+
87
+ response = MetrifoxSDK.customers.update("customer_123", update_data)
88
+
89
+ # Get customer
90
+ response = MetrifoxSDK.customers.get_customer({ customer_key: "customer_123" })
91
+
92
+ # Get customer details
93
+ response = MetrifoxSDK.customers.get_details({ customer_key: "customer_123" })
94
+
95
+ # Delete customer
96
+ response = MetrifoxSDK.delete_customer({ customer_key: "customer_123" })
97
+ ```
98
+
99
+ ### CSV Upload
100
+
101
+ ```ruby
102
+ # Upload customers via CSV
103
+ response = MetrifoxSDK.customers.upload_csv("/path/to/customers.csv")
104
+
105
+ puts response["data"]["total_customers"]
106
+ puts response["data"]["successful_upload_count"]
107
+ ```
108
+
109
+ ### Using Client Instance
110
+
111
+ ```ruby
112
+ client = MetrifoxSDK::Client.new({
113
+ api_key: "your-api-key"
114
+ })
115
+
116
+ response = client.usages.check_access({
117
+ feature_key: "premium_feature",
118
+ customer_key: "customer_123"
119
+ })
120
+ ```
121
+
122
+ ## Type Safety with Structs
123
+
124
+ The SDK provides structured types for better type safety:
125
+
126
+ ```ruby
127
+ # Using structured request objects
128
+ access_request = MetrifoxSDK::Types::AccessCheckRequest.new(
129
+ feature_key: "premium_feature",
130
+ customer_key: "customer_123"
131
+ )
132
+
133
+ response = MetrifoxSDK.usages.check_access(access_request)
134
+
135
+ # Customer creation with structured data
136
+ customer_request = MetrifoxSDK::Types::CustomerCreateRequest.new(
137
+ customer_key: "customer_123",
138
+ customer_type: MetrifoxSDK::Types::CustomerType::BUSINESS,
139
+ primary_email: "customer@example.com",
140
+ legal_name: "Acme Corp"
141
+ )
142
+
143
+ response = MetrifoxSDK.customers.create(customer_request)
144
+ ```
145
+
146
+ ## Error Handling
147
+
148
+ ```ruby
149
+ begin
150
+ response = MetrifoxSDK.usages.check_access({
151
+ feature_key: "premium_feature",
152
+ customer_key: "customer_123"
153
+ })
154
+ rescue MetrifoxSDK::APIError => e
155
+ puts "API Error: #{e.message}"
156
+ rescue MetrifoxSDK::ConfigurationError => e
157
+ puts "Configuration Error: #{e.message}"
158
+ end
159
+ ```
160
+
161
+ ## Development
162
+
163
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
164
+
165
+ ## Contributing
166
+
167
+ Bug reports and pull requests are welcome on GitHub at https://github.com/yourusername/metrifox_ruby_sdk.
168
+
169
+ ## License
170
+
171
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,16 @@
1
+ require_relative "metrifox_sdk/version"
2
+ require_relative "metrifox_sdk/client"
3
+ require_relative "metrifox_sdk/types"
4
+ require_relative "metrifox_sdk/util_methods"
5
+ require_relative "metrifox_sdk/base_api"
6
+ require_relative "metrifox_sdk/base_module"
7
+ require_relative "metrifox_sdk/customers/module"
8
+ require_relative "metrifox_sdk/usages/module"
9
+
10
+ module MetrifoxSDK
11
+ class << self
12
+ def init(config = {})
13
+ Client.new(config)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,76 @@
1
+ require "net/http"
2
+ require "uri"
3
+ require "json"
4
+ require "mime/types"
5
+
6
+ module MetrifoxSDK
7
+ class BaseApi
8
+ private
9
+
10
+ def make_request(uri, method, api_key, body = nil)
11
+ headers = {
12
+ "x-api-key" => api_key,
13
+ "Content-Type" => "application/json"
14
+ }
15
+
16
+ body_json = body ? JSON.generate(body) : nil
17
+ make_raw_request(uri, method, headers, body_json)
18
+ end
19
+
20
+ def make_raw_request(uri, method, headers, body = nil)
21
+ http = Net::HTTP.new(uri.host, uri.port)
22
+ http.use_ssl = uri.scheme == "https"
23
+
24
+ request = case method
25
+ when "GET"
26
+ Net::HTTP::Get.new(uri)
27
+ when "POST"
28
+ Net::HTTP::Post.new(uri)
29
+ when "PATCH"
30
+ Net::HTTP::Patch.new(uri)
31
+ when "DELETE"
32
+ Net::HTTP::Delete.new(uri)
33
+ else
34
+ raise ArgumentError, "Unsupported HTTP method: #{method}"
35
+ end
36
+
37
+ headers.each { |key, value| request[key] = value }
38
+ request.body = body if body
39
+
40
+ http.request(request)
41
+ end
42
+
43
+ def parse_response(response, error_message)
44
+ unless response.is_a?(Net::HTTPSuccess)
45
+ raise APIError, "#{error_message}: #{response.code} #{response.message}"
46
+ end
47
+
48
+ JSON.parse(response.body)
49
+ rescue JSON::ParserError => e
50
+ raise APIError, "Invalid JSON response: #{e.message}"
51
+ end
52
+
53
+ def build_multipart_body(file_path, boundary)
54
+ unless File.exist?(file_path)
55
+ raise ArgumentError, "File not found: #{file_path}"
56
+ end
57
+
58
+ file_content = File.read(file_path)
59
+ filename = File.basename(file_path)
60
+ mime_type = MIME::Types.type_for(filename).first&.content_type || "text/csv"
61
+
62
+ body = []
63
+ body << "--#{boundary}"
64
+ body << 'Content-Disposition: form-data; name="csv"; filename="' + filename + '"'
65
+ body << "Content-Type: #{mime_type}"
66
+ body << ""
67
+ body << file_content
68
+ body << "--#{boundary}--"
69
+ body << ""
70
+
71
+ body.join("\r\n")
72
+ end
73
+ end
74
+
75
+ class APIError < StandardError; end
76
+ end
@@ -0,0 +1,27 @@
1
+ module MetrifoxSDK
2
+ class BaseModule
3
+ attr_reader :client
4
+
5
+ def initialize(client)
6
+ @client = client
7
+ end
8
+
9
+ protected
10
+
11
+ def api_key
12
+ @client.api_key
13
+ end
14
+
15
+ def base_url
16
+ @client.base_url
17
+ end
18
+
19
+ def validate_api_key!
20
+ if api_key.nil? || api_key.empty?
21
+ raise ConfigurationError, "API key required. Set it via config or METRIFOX_API_KEY environment variable."
22
+ end
23
+ end
24
+ end
25
+
26
+ class ConfigurationError < StandardError; end
27
+ end
@@ -0,0 +1,31 @@
1
+ require_relative './util_methods'
2
+
3
+ module MetrifoxSDK
4
+ class Client
5
+ include MetrifoxSDK::UtilMethods
6
+
7
+ attr_reader :config, :api_key, :base_url, :web_app_base_url
8
+
9
+ def initialize(config = {})
10
+ @config = config
11
+ @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"
14
+ end
15
+
16
+ def customers
17
+ @customers ||= Customers::Module.new(self)
18
+ end
19
+
20
+ def usages
21
+ @usages ||= Usages::Module.new(self)
22
+ end
23
+
24
+ private
25
+
26
+ def get_api_key_from_environment
27
+ MetrifoxSDK::UtilMethods.load_dotenv
28
+ ENV["METRIFOX_API_KEY"] || ""
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,82 @@
1
+ require "net/http"
2
+ require "uri"
3
+ require "json"
4
+ require "mime/types"
5
+ require_relative "../base_api"
6
+
7
+ module MetrifoxSDK::Customers
8
+ class API < MetrifoxSDK::BaseApi
9
+ def customer_create_request(base_url, api_key, request_payload)
10
+ uri = URI.join(base_url, "customers/new")
11
+ body = serialize_customer_request(request_payload)
12
+ response = make_request(uri, "POST", api_key, body)
13
+ parse_response(response, "Failed to Create Customer")
14
+ end
15
+
16
+ def customer_update_request(base_url, api_key, customer_key, request_payload)
17
+ uri = URI.join(base_url, "customers/#{customer_key}")
18
+ body = serialize_customer_request(request_payload)
19
+ response = make_request(uri, "PATCH", api_key, body)
20
+ parse_response(response, "Failed to UPDATE Customer")
21
+ end
22
+
23
+ def customer_delete_request(base_url, api_key, request_payload)
24
+ customer_key = get_value(request_payload, :customer_key)
25
+ uri = URI.join(base_url, "customers/#{customer_key}")
26
+ response = make_request(uri, "DELETE", api_key)
27
+ parse_response(response, "Failed to DELETE Customer")
28
+ end
29
+
30
+ def customer_get_request(base_url, api_key, request_payload)
31
+ customer_key = get_value(request_payload, :customer_key)
32
+ uri = URI.join(base_url, "customers/#{customer_key}")
33
+ response = make_request(uri, "GET", api_key)
34
+ parse_response(response, "Failed to Fetch Customer")
35
+ end
36
+
37
+ def customer_details_get_request(base_url, api_key, request_payload)
38
+ customer_key = get_value(request_payload, :customer_key)
39
+ uri = URI.join(base_url, "customers/#{customer_key}/details")
40
+ response = make_request(uri, "GET", api_key)
41
+ parse_response(response, "Failed to Fetch Customer Details")
42
+ end
43
+
44
+ def upload_customers_csv(base_url, api_key, file_path)
45
+ uri = URI.join(base_url, "customers/csv-upload")
46
+
47
+ boundary = "----WebKitFormBoundary#{Random.hex(16)}"
48
+ body = build_multipart_body(file_path, boundary)
49
+
50
+ headers = {
51
+ "x-api-key" => api_key,
52
+ "Content-Type" => "multipart/form-data; boundary=#{boundary}"
53
+ }
54
+
55
+ response = make_raw_request(uri, "POST", headers, body)
56
+ parse_response(response, "Failed to upload CSV")
57
+ end
58
+
59
+ private
60
+
61
+ def serialize_customer_request(request)
62
+ if request.respond_to?(:to_h)
63
+ request.to_h.compact
64
+ elsif request.is_a?(Hash)
65
+ request.compact
66
+ else
67
+ raise ArgumentError, "Invalid request format"
68
+ end
69
+ end
70
+
71
+ # Helper method to get value from either hash or struct
72
+ def get_value(object, key)
73
+ if object.respond_to?(key)
74
+ object.public_send(key)
75
+ elsif object.respond_to?(:[])
76
+ object[key] || object[key.to_s]
77
+ else
78
+ nil
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,44 @@
1
+ require_relative "api"
2
+ require_relative "../base_module"
3
+
4
+ module MetrifoxSDK
5
+ module Customers
6
+ class Module < BaseModule
7
+ def create(request_payload)
8
+ validate_api_key!
9
+ api.customer_create_request(base_url, api_key, request_payload)
10
+ end
11
+
12
+ def update(customer_key, request_payload)
13
+ validate_api_key!
14
+ api.customer_update_request(base_url, api_key, customer_key, request_payload)
15
+ end
16
+
17
+ def get_customer(request_payload)
18
+ validate_api_key!
19
+ api.customer_get_request(base_url, api_key, request_payload)
20
+ end
21
+
22
+ def get_details(request_payload)
23
+ validate_api_key!
24
+ api.customer_details_get_request(base_url, api_key, request_payload)
25
+ end
26
+
27
+ def delete_customer(request_payload)
28
+ validate_api_key!
29
+ api.customer_delete_request(base_url, api_key, request_payload)
30
+ end
31
+
32
+ def upload_csv(file_path)
33
+ validate_api_key!
34
+ api.upload_customers_csv(base_url, api_key, file_path)
35
+ end
36
+
37
+ private
38
+
39
+ def api
40
+ @api ||= API.new
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,111 @@
1
+ module MetrifoxSDK
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
+ UsageEventRequest = Struct.new(:customer_key, :event_name, :amount, keyword_init: true) do
48
+ def initialize(customer_key:, event_name:, amount: 1)
49
+ super
50
+ end
51
+ end
52
+
53
+ UsageEventResponse = Struct.new(:message, :event_name, :customer_key, keyword_init: true)
54
+
55
+ CustomerCreateRequest = Struct.new(
56
+ # Core fields
57
+ :customer_key, :customer_type, :primary_email, :primary_phone,
58
+ # Business fields
59
+ :legal_name, :display_name, :legal_number, :tax_identification_number,
60
+ :logo_url, :website_url, :account_manager,
61
+ # Individual fields
62
+ :first_name, :middle_name, :last_name, :date_of_birth, :billing_email,
63
+ # Preferences
64
+ :timezone, :language, :currency, :tax_status,
65
+ # Address fields
66
+ :address_line1, :address_line2, :city, :state, :country, :zip_code,
67
+ # Shipping address fields
68
+ :shipping_address_line1, :shipping_address_line2, :shipping_city,
69
+ :shipping_state, :shipping_country, :shipping_zip_code,
70
+ # Complex fields
71
+ :billing_configuration, :tax_identifications, :contact_people,
72
+ :payment_terms, :metadata, keyword_init: true
73
+ )
74
+
75
+ CustomerUpdateRequest = Struct.new(
76
+ # Core fields
77
+ :customer_key, :customer_type, :primary_email, :primary_phone, :billing_email,
78
+ # Business fields
79
+ :legal_name, :display_name, :legal_number, :tax_identification_number,
80
+ :logo_url, :website_url, :account_manager,
81
+ # Individual fields
82
+ :first_name, :middle_name, :last_name, :date_of_birth,
83
+ # Preferences
84
+ :timezone, :language, :currency, :tax_status,
85
+ # Address fields
86
+ :address_line1, :address_line2, :city, :state, :country, :zip_code,
87
+ # Shipping address fields
88
+ :shipping_address_line1, :shipping_address_line2, :shipping_city,
89
+ :shipping_state, :shipping_country, :shipping_zip_code,
90
+ # Complex fields
91
+ :billing_configuration, :tax_identifications, :contact_people,
92
+ :payment_terms, :metadata, :phone_numbers, :email_addresses, keyword_init: true
93
+ )
94
+
95
+ CustomerDeleteRequest = Struct.new(:customer_key, keyword_init: true)
96
+ CustomerGetRequest = Struct.new(:customer_key, keyword_init: true)
97
+
98
+ CustomerCSVSyncResponse = Struct.new(
99
+ :status_code, :message, :data, :errors, :meta, keyword_init: true
100
+ ) do
101
+ CSVSyncData = Struct.new(
102
+ :total_customers, :successful_upload_count, :failed_upload_count,
103
+ :customers_added, :customers_failed, keyword_init: true
104
+ )
105
+ end
106
+
107
+ APIResponse = Struct.new(:status_code, :message, :data, :errors, :meta, keyword_init: true)
108
+
109
+ EmbedConfig = Struct.new(:container, :product_key, keyword_init: true)
110
+ end
111
+ end
@@ -0,0 +1,70 @@
1
+ require "net/http"
2
+ require "uri"
3
+ require "json"
4
+ require "mime/types"
5
+ require_relative "../base_api"
6
+
7
+ module MetrifoxSDK::Usages
8
+ class API < MetrifoxSDK::BaseApi
9
+ def fetch_access(base_url, api_key, request_payload)
10
+ uri = URI.join(base_url, "usage/access")
11
+
12
+ # Handle both hash and struct access patterns
13
+ feature_key = get_value(request_payload, :feature_key)
14
+ customer_key = get_value(request_payload, :customer_key)
15
+
16
+ uri.query = URI.encode_www_form({
17
+ feature_key: feature_key,
18
+ customer_key: customer_key
19
+ })
20
+
21
+ response = make_request(uri, "GET", api_key)
22
+ parse_response(response, "Failed to check access")
23
+ end
24
+
25
+ def fetch_usage(base_url, api_key, request_payload)
26
+ uri = URI.join(base_url, "usage/events")
27
+
28
+ # Handle both hash and struct access patterns
29
+ customer_key = get_value(request_payload, :customer_key)
30
+ event_name = get_value(request_payload, :event_name)
31
+ amount = get_value(request_payload, :amount) || 1
32
+
33
+ body = {
34
+ customer_key: customer_key,
35
+ event_name: event_name,
36
+ amount: amount
37
+ }
38
+
39
+ response = make_request(uri, "POST", api_key, body)
40
+ parse_response(response, "Failed to record usage")
41
+ end
42
+
43
+ def fetch_tenant_id(base_url, api_key)
44
+ uri = URI.join(base_url, "auth/get-tenant-id")
45
+ response = make_request(uri, "GET", api_key)
46
+ data = parse_response(response, "Failed to get tenant id")
47
+ data.dig("data", "tenant_id")
48
+ end
49
+
50
+ def fetch_checkout_key(base_url, api_key)
51
+ uri = URI.join(base_url, "auth/checkout-username")
52
+ response = make_request(uri, "GET", api_key)
53
+ data = parse_response(response, "Failed to get tenant checkout settings")
54
+ data.dig("data", "checkout_username")
55
+ end
56
+
57
+ private
58
+
59
+ # Helper method to get value from either hash or struct
60
+ def get_value(object, key)
61
+ if object.respond_to?(key)
62
+ object.public_send(key)
63
+ elsif object.respond_to?(:[])
64
+ object[key] || object[key.to_s]
65
+ else
66
+ nil
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,34 @@
1
+ require_relative "api"
2
+ require_relative "../base_module"
3
+
4
+ module MetrifoxSDK
5
+ module Usages
6
+ class Module < BaseModule
7
+ def check_access(request_payload)
8
+ validate_api_key!
9
+ api.fetch_access(base_url, api_key, request_payload)
10
+ end
11
+
12
+ def record_usage(request_payload)
13
+ validate_api_key!
14
+ api.fetch_usage(base_url, api_key, request_payload)
15
+ end
16
+
17
+ def get_tenant_id
18
+ validate_api_key!
19
+ api.fetch_tenant_id(base_url, api_key)
20
+ end
21
+
22
+ def get_checkout_key
23
+ validate_api_key!
24
+ api.fetch_checkout_key(base_url, api_key)
25
+ end
26
+
27
+ private
28
+
29
+ def api
30
+ @api ||= API.new
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,29 @@
1
+ module MetrifoxSDK
2
+ module UtilMethods
3
+ def self.load_dotenv
4
+ return if @dotenv_loaded
5
+
6
+ env_files = ['.env.local', '.env']
7
+ env_files.each do |file|
8
+ next unless File.exist?(file)
9
+
10
+ File.readlines(file).each do |line|
11
+ line = line.strip
12
+ next if line.empty? || line.start_with?('#')
13
+
14
+ key, value = line.split('=', 2)
15
+ next unless key && value
16
+
17
+ # Remove quotes if present
18
+ value = value.gsub(/\A['"]|['"]\z/, '')
19
+
20
+ # Only set if not already set (allows override)
21
+ ENV[key] ||= value
22
+ end
23
+ break # Use first found file
24
+ end
25
+
26
+ @dotenv_loaded = true
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module MetrifoxSDK
2
+ VERSION = '1.0.1'
3
+ end
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: metrifox-sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Metrifox
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-09-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
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: mime-types
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
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: net-http
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.3'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: uri
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.12'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: dotenv
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.8'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: webmock
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.0'
111
+ description: A Ruby SDK for interacting with the Metrifox platform API
112
+ email:
113
+ - abiodun@metrifox.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - CHANGELOG.md
119
+ - LICENSE
120
+ - README.md
121
+ - lib/metrifox-sdk.rb
122
+ - lib/metrifox_sdk/base_api.rb
123
+ - lib/metrifox_sdk/base_module.rb
124
+ - lib/metrifox_sdk/client.rb
125
+ - lib/metrifox_sdk/customers/api.rb
126
+ - lib/metrifox_sdk/customers/module.rb
127
+ - lib/metrifox_sdk/types.rb
128
+ - lib/metrifox_sdk/usages/api.rb
129
+ - lib/metrifox_sdk/usages/module.rb
130
+ - lib/metrifox_sdk/util_methods.rb
131
+ - lib/metrifox_sdk/version.rb
132
+ homepage: https://github.com/metrifox/metrifox-ruby
133
+ licenses:
134
+ - MIT
135
+ metadata:
136
+ homepage_uri: https://github.com/metrifox/metrifox-ruby
137
+ source_code_uri: https://github.com/metrifox/metrifox-ruby
138
+ changelog_uri: https://github.com/metrifox/metrifox-ruby/tree/main/CHANGELOG.md
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: 2.7.0
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ requirements: []
154
+ rubygems_version: 3.5.22
155
+ signing_key:
156
+ specification_version: 4
157
+ summary: Ruby SDK for Metrifox API
158
+ test_files: []