billingio 1.0.0 → 2.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +226 -1
  3. data/billingio.gemspec +4 -3
  4. data/lib/billingio/client.rb +55 -0
  5. data/lib/billingio/http_client.rb +10 -0
  6. data/lib/billingio/models/accounting_report.rb +46 -0
  7. data/lib/billingio/models/adjustment.rb +46 -0
  8. data/lib/billingio/models/customer.rb +46 -0
  9. data/lib/billingio/models/entitlement.rb +46 -0
  10. data/lib/billingio/models/entitlement_check.rb +39 -0
  11. data/lib/billingio/models/payment_link.rb +47 -0
  12. data/lib/billingio/models/payment_method.rb +51 -0
  13. data/lib/billingio/models/payout_intent.rb +51 -0
  14. data/lib/billingio/models/revenue_event.rb +49 -0
  15. data/lib/billingio/models/settlement.rb +51 -0
  16. data/lib/billingio/models/subscription.rb +50 -0
  17. data/lib/billingio/models/subscription_plan.rb +51 -0
  18. data/lib/billingio/models/subscription_renewal.rb +49 -0
  19. data/lib/billingio/resources/adjustments.rb +52 -0
  20. data/lib/billingio/resources/customers.rb +75 -0
  21. data/lib/billingio/resources/entitlements.rb +95 -0
  22. data/lib/billingio/resources/payment_links.rb +47 -0
  23. data/lib/billingio/resources/payment_methods.rb +91 -0
  24. data/lib/billingio/resources/payout_intents.rb +78 -0
  25. data/lib/billingio/resources/revenue_events.rb +47 -0
  26. data/lib/billingio/resources/settlements.rb +30 -0
  27. data/lib/billingio/resources/subscription_plans.rb +71 -0
  28. data/lib/billingio/resources/subscription_renewals.rb +42 -0
  29. data/lib/billingio/resources/subscriptions.rb +67 -0
  30. data/lib/billingio/version.rb +1 -1
  31. data/lib/billingio.rb +24 -0
  32. metadata +30 -6
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BillingIO
4
+ # Represents a payout intent (withdrawal request).
5
+ #
6
+ # @attr_reader payout_id [String] unique identifier (prefixed +po_+)
7
+ # @attr_reader amount_usd [Float] payout amount in USD
8
+ # @attr_reader chain [String] blockchain network
9
+ # @attr_reader token [String] stablecoin token
10
+ # @attr_reader destination [String] destination wallet address
11
+ # @attr_reader tx_hash [String, nil] on-chain transaction hash
12
+ # @attr_reader status [String] payout status
13
+ # @attr_reader metadata [Hash, nil] arbitrary key-value pairs
14
+ # @attr_reader executed_at [String, nil] ISO-8601 execution timestamp
15
+ # @attr_reader created_at [String] ISO-8601 creation timestamp
16
+ # @attr_reader updated_at [String] ISO-8601 last-update timestamp
17
+ class PayoutIntent
18
+ ATTRS = %i[
19
+ payout_id amount_usd chain token destination
20
+ tx_hash status metadata
21
+ executed_at created_at updated_at
22
+ ].freeze
23
+
24
+ attr_reader(*ATTRS)
25
+
26
+ # @param attrs [Hash{String,Symbol => Object}]
27
+ def initialize(attrs = {})
28
+ ATTRS.each do |attr|
29
+ value = attrs[attr.to_s] || attrs[attr]
30
+ instance_variable_set(:"@#{attr}", value)
31
+ end
32
+ end
33
+
34
+ # @param hash [Hash]
35
+ # @return [BillingIO::PayoutIntent]
36
+ def self.from_hash(hash)
37
+ new(hash)
38
+ end
39
+
40
+ # @return [Hash{String => Object}]
41
+ def to_h
42
+ ATTRS.each_with_object({}) do |attr, h|
43
+ h[attr.to_s] = instance_variable_get(:"@#{attr}")
44
+ end
45
+ end
46
+
47
+ def inspect
48
+ "#<BillingIO::PayoutIntent payout_id=#{@payout_id.inspect} amount_usd=#{@amount_usd.inspect} status=#{@status.inspect}>"
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BillingIO
4
+ # Represents a revenue event for reporting.
5
+ #
6
+ # @attr_reader revenue_event_id [String] unique identifier (prefixed +rev_+)
7
+ # @attr_reader type [String] event type (e.g. "payment", "refund")
8
+ # @attr_reader amount_usd [Float] revenue amount in USD
9
+ # @attr_reader customer_id [String, nil] related customer
10
+ # @attr_reader checkout_id [String, nil] related checkout
11
+ # @attr_reader subscription_id [String, nil] related subscription
12
+ # @attr_reader metadata [Hash, nil] arbitrary key-value pairs
13
+ # @attr_reader occurred_at [String] ISO-8601 event timestamp
14
+ # @attr_reader created_at [String] ISO-8601 creation timestamp
15
+ class RevenueEvent
16
+ ATTRS = %i[
17
+ revenue_event_id type amount_usd
18
+ customer_id checkout_id subscription_id
19
+ metadata occurred_at created_at
20
+ ].freeze
21
+
22
+ attr_reader(*ATTRS)
23
+
24
+ # @param attrs [Hash{String,Symbol => Object}]
25
+ def initialize(attrs = {})
26
+ ATTRS.each do |attr|
27
+ value = attrs[attr.to_s] || attrs[attr]
28
+ instance_variable_set(:"@#{attr}", value)
29
+ end
30
+ end
31
+
32
+ # @param hash [Hash]
33
+ # @return [BillingIO::RevenueEvent]
34
+ def self.from_hash(hash)
35
+ new(hash)
36
+ end
37
+
38
+ # @return [Hash{String => Object}]
39
+ def to_h
40
+ ATTRS.each_with_object({}) do |attr, h|
41
+ h[attr.to_s] = instance_variable_get(:"@#{attr}")
42
+ end
43
+ end
44
+
45
+ def inspect
46
+ "#<BillingIO::RevenueEvent revenue_event_id=#{@revenue_event_id.inspect} type=#{@type.inspect} amount_usd=#{@amount_usd.inspect}>"
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BillingIO
4
+ # Represents a payout settlement record.
5
+ #
6
+ # @attr_reader settlement_id [String] unique identifier (prefixed +stl_+)
7
+ # @attr_reader payout_id [String] parent payout intent
8
+ # @attr_reader amount_usd [Float] settled amount in USD
9
+ # @attr_reader fee_usd [Float] fee amount in USD
10
+ # @attr_reader net_usd [Float] net amount in USD
11
+ # @attr_reader chain [String] blockchain network
12
+ # @attr_reader token [String] stablecoin token
13
+ # @attr_reader tx_hash [String, nil] on-chain transaction hash
14
+ # @attr_reader status [String] settlement status
15
+ # @attr_reader settled_at [String, nil] ISO-8601 settlement timestamp
16
+ # @attr_reader created_at [String] ISO-8601 creation timestamp
17
+ class Settlement
18
+ ATTRS = %i[
19
+ settlement_id payout_id amount_usd fee_usd net_usd
20
+ chain token tx_hash status
21
+ settled_at created_at
22
+ ].freeze
23
+
24
+ attr_reader(*ATTRS)
25
+
26
+ # @param attrs [Hash{String,Symbol => Object}]
27
+ def initialize(attrs = {})
28
+ ATTRS.each do |attr|
29
+ value = attrs[attr.to_s] || attrs[attr]
30
+ instance_variable_set(:"@#{attr}", value)
31
+ end
32
+ end
33
+
34
+ # @param hash [Hash]
35
+ # @return [BillingIO::Settlement]
36
+ def self.from_hash(hash)
37
+ new(hash)
38
+ end
39
+
40
+ # @return [Hash{String => Object}]
41
+ def to_h
42
+ ATTRS.each_with_object({}) do |attr, h|
43
+ h[attr.to_s] = instance_variable_get(:"@#{attr}")
44
+ end
45
+ end
46
+
47
+ def inspect
48
+ "#<BillingIO::Settlement settlement_id=#{@settlement_id.inspect} amount_usd=#{@amount_usd.inspect} status=#{@status.inspect}>"
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BillingIO
4
+ # Represents an active subscription.
5
+ #
6
+ # @attr_reader subscription_id [String] unique identifier (prefixed +sub_+)
7
+ # @attr_reader customer_id [String] owning customer
8
+ # @attr_reader plan_id [String] associated plan
9
+ # @attr_reader status [String] subscription status
10
+ # @attr_reader current_period_start [String, nil] ISO-8601 current period start
11
+ # @attr_reader current_period_end [String, nil] ISO-8601 current period end
12
+ # @attr_reader canceled_at [String, nil] ISO-8601 cancellation timestamp
13
+ # @attr_reader metadata [Hash, nil] arbitrary key-value pairs
14
+ # @attr_reader created_at [String] ISO-8601 creation timestamp
15
+ # @attr_reader updated_at [String] ISO-8601 last-update timestamp
16
+ class Subscription
17
+ ATTRS = %i[
18
+ subscription_id customer_id plan_id status
19
+ current_period_start current_period_end
20
+ canceled_at metadata created_at updated_at
21
+ ].freeze
22
+
23
+ attr_reader(*ATTRS)
24
+
25
+ # @param attrs [Hash{String,Symbol => Object}]
26
+ def initialize(attrs = {})
27
+ ATTRS.each do |attr|
28
+ value = attrs[attr.to_s] || attrs[attr]
29
+ instance_variable_set(:"@#{attr}", value)
30
+ end
31
+ end
32
+
33
+ # @param hash [Hash]
34
+ # @return [BillingIO::Subscription]
35
+ def self.from_hash(hash)
36
+ new(hash)
37
+ end
38
+
39
+ # @return [Hash{String => Object}]
40
+ def to_h
41
+ ATTRS.each_with_object({}) do |attr, h|
42
+ h[attr.to_s] = instance_variable_get(:"@#{attr}")
43
+ end
44
+ end
45
+
46
+ def inspect
47
+ "#<BillingIO::Subscription subscription_id=#{@subscription_id.inspect} plan_id=#{@plan_id.inspect} status=#{@status.inspect}>"
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BillingIO
4
+ # Represents a subscription plan template.
5
+ #
6
+ # @attr_reader plan_id [String] unique identifier (prefixed +plan_+)
7
+ # @attr_reader name [String] human-readable plan name
8
+ # @attr_reader amount_usd [Float] recurring amount in USD
9
+ # @attr_reader interval [String] billing interval (e.g. "monthly", "yearly")
10
+ # @attr_reader interval_count [Integer] number of intervals between billings
11
+ # @attr_reader chain [String, nil] blockchain network
12
+ # @attr_reader token [String, nil] stablecoin token
13
+ # @attr_reader metadata [Hash, nil] arbitrary key-value pairs
14
+ # @attr_reader status [String] plan status
15
+ # @attr_reader created_at [String] ISO-8601 creation timestamp
16
+ # @attr_reader updated_at [String] ISO-8601 last-update timestamp
17
+ class SubscriptionPlan
18
+ ATTRS = %i[
19
+ plan_id name amount_usd interval interval_count
20
+ chain token metadata status
21
+ created_at updated_at
22
+ ].freeze
23
+
24
+ attr_reader(*ATTRS)
25
+
26
+ # @param attrs [Hash{String,Symbol => Object}]
27
+ def initialize(attrs = {})
28
+ ATTRS.each do |attr|
29
+ value = attrs[attr.to_s] || attrs[attr]
30
+ instance_variable_set(:"@#{attr}", value)
31
+ end
32
+ end
33
+
34
+ # @param hash [Hash]
35
+ # @return [BillingIO::SubscriptionPlan]
36
+ def self.from_hash(hash)
37
+ new(hash)
38
+ end
39
+
40
+ # @return [Hash{String => Object}]
41
+ def to_h
42
+ ATTRS.each_with_object({}) do |attr, h|
43
+ h[attr.to_s] = instance_variable_get(:"@#{attr}")
44
+ end
45
+ end
46
+
47
+ def inspect
48
+ "#<BillingIO::SubscriptionPlan plan_id=#{@plan_id.inspect} name=#{@name.inspect} amount_usd=#{@amount_usd.inspect}>"
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BillingIO
4
+ # Represents a subscription renewal attempt.
5
+ #
6
+ # @attr_reader renewal_id [String] unique identifier (prefixed +ren_+)
7
+ # @attr_reader subscription_id [String] parent subscription
8
+ # @attr_reader status [String] renewal status
9
+ # @attr_reader amount_usd [Float] renewal amount in USD
10
+ # @attr_reader attempt_count [Integer] number of attempts made
11
+ # @attr_reader next_retry_at [String, nil] ISO-8601 next retry timestamp
12
+ # @attr_reader checkout_id [String, nil] checkout created for this renewal
13
+ # @attr_reader created_at [String] ISO-8601 creation timestamp
14
+ # @attr_reader updated_at [String] ISO-8601 last-update timestamp
15
+ class SubscriptionRenewal
16
+ ATTRS = %i[
17
+ renewal_id subscription_id status amount_usd
18
+ attempt_count next_retry_at checkout_id
19
+ created_at updated_at
20
+ ].freeze
21
+
22
+ attr_reader(*ATTRS)
23
+
24
+ # @param attrs [Hash{String,Symbol => Object}]
25
+ def initialize(attrs = {})
26
+ ATTRS.each do |attr|
27
+ value = attrs[attr.to_s] || attrs[attr]
28
+ instance_variable_set(:"@#{attr}", value)
29
+ end
30
+ end
31
+
32
+ # @param hash [Hash]
33
+ # @return [BillingIO::SubscriptionRenewal]
34
+ def self.from_hash(hash)
35
+ new(hash)
36
+ end
37
+
38
+ # @return [Hash{String => Object}]
39
+ def to_h
40
+ ATTRS.each_with_object({}) do |attr, h|
41
+ h[attr.to_s] = instance_variable_get(:"@#{attr}")
42
+ end
43
+ end
44
+
45
+ def inspect
46
+ "#<BillingIO::SubscriptionRenewal renewal_id=#{@renewal_id.inspect} subscription_id=#{@subscription_id.inspect} status=#{@status.inspect}>"
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BillingIO
4
+ # Provides access to revenue adjustment endpoints.
5
+ #
6
+ # client.adjustments.list
7
+ # client.adjustments.create(type: "credit", amount_usd: 10.00, reason: "Goodwill credit")
8
+ class Adjustments
9
+ # @api private
10
+ def initialize(http_client)
11
+ @http = http_client
12
+ end
13
+
14
+ # List adjustments with cursor-based pagination.
15
+ #
16
+ # @param cursor [String, nil] opaque cursor for the next page
17
+ # @param limit [Integer] items per page (1..100, default 25)
18
+ # @param customer_id [String, nil] filter by customer
19
+ # @return [BillingIO::PaginatedList<BillingIO::Adjustment>]
20
+ # @raise [BillingIO::Error]
21
+ def list(cursor: nil, limit: 25, customer_id: nil)
22
+ params = { limit: limit }
23
+ params[:cursor] = cursor if cursor
24
+ params[:customer_id] = customer_id if customer_id
25
+
26
+ data = @http.get("/revenue/adjustments", params)
27
+ PaginatedList.from_hash(data, Adjustment)
28
+ end
29
+
30
+ # Create a new revenue adjustment.
31
+ #
32
+ # @param type [String] adjustment type ("credit", "debit", "correction")
33
+ # @param amount_usd [Float] adjustment amount in USD
34
+ # @param reason [String, nil] human-readable reason
35
+ # @param customer_id [String, nil] related customer
36
+ # @param metadata [Hash, nil] arbitrary key-value pairs
37
+ # @return [BillingIO::Adjustment]
38
+ # @raise [BillingIO::Error]
39
+ def create(type:, amount_usd:, reason: nil, customer_id: nil, metadata: nil)
40
+ body = {
41
+ "type" => type,
42
+ "amount_usd" => amount_usd
43
+ }
44
+ body["reason"] = reason if reason
45
+ body["customer_id"] = customer_id if customer_id
46
+ body["metadata"] = metadata if metadata
47
+
48
+ data = @http.post("/revenue/adjustments", body)
49
+ Adjustment.from_hash(data)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BillingIO
4
+ # Provides access to customer management endpoints.
5
+ #
6
+ # client.customers.create(email: "user@example.com")
7
+ # client.customers.list
8
+ # client.customers.get("cus_abc123")
9
+ # client.customers.update("cus_abc123", name: "Jane Doe")
10
+ class Customers
11
+ # @api private
12
+ def initialize(http_client)
13
+ @http = http_client
14
+ end
15
+
16
+ # Create a new customer.
17
+ #
18
+ # @param email [String, nil] customer email address
19
+ # @param name [String, nil] customer display name
20
+ # @param metadata [Hash, nil] arbitrary key-value pairs
21
+ # @return [BillingIO::Customer]
22
+ # @raise [BillingIO::Error]
23
+ def create(email: nil, name: nil, metadata: nil)
24
+ body = {}
25
+ body["email"] = email if email
26
+ body["name"] = name if name
27
+ body["metadata"] = metadata if metadata
28
+
29
+ data = @http.post("/customers", body)
30
+ Customer.from_hash(data)
31
+ end
32
+
33
+ # List customers with cursor-based pagination.
34
+ #
35
+ # @param cursor [String, nil] opaque cursor for the next page
36
+ # @param limit [Integer] items per page (1..100, default 25)
37
+ # @return [BillingIO::PaginatedList<BillingIO::Customer>]
38
+ # @raise [BillingIO::Error]
39
+ def list(cursor: nil, limit: 25)
40
+ params = { limit: limit }
41
+ params[:cursor] = cursor if cursor
42
+
43
+ data = @http.get("/customers", params)
44
+ PaginatedList.from_hash(data, Customer)
45
+ end
46
+
47
+ # Retrieve a single customer by ID.
48
+ #
49
+ # @param customer_id [String] customer identifier (prefixed +cus_+)
50
+ # @return [BillingIO::Customer]
51
+ # @raise [BillingIO::Error]
52
+ def get(customer_id)
53
+ data = @http.get("/customers/#{customer_id}")
54
+ Customer.from_hash(data)
55
+ end
56
+
57
+ # Update an existing customer.
58
+ #
59
+ # @param customer_id [String] customer identifier (prefixed +cus_+)
60
+ # @param email [String, nil] new email address
61
+ # @param name [String, nil] new display name
62
+ # @param metadata [Hash, nil] new metadata (replaces existing)
63
+ # @return [BillingIO::Customer]
64
+ # @raise [BillingIO::Error]
65
+ def update(customer_id, email: nil, name: nil, metadata: nil)
66
+ body = {}
67
+ body["email"] = email if email
68
+ body["name"] = name if name
69
+ body["metadata"] = metadata if metadata
70
+
71
+ data = @http.patch("/customers/#{customer_id}", body)
72
+ Customer.from_hash(data)
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BillingIO
4
+ # Provides access to subscription entitlement endpoints.
5
+ #
6
+ # client.entitlements.list(subscription_id: "sub_abc123")
7
+ # client.entitlements.create(subscription_id: "sub_abc123", feature_key: "api_calls")
8
+ # client.entitlements.update("ent_abc123", value: 1000)
9
+ # client.entitlements.delete("ent_abc123")
10
+ # client.entitlements.check(customer_id: "cus_abc123", feature_key: "api_calls")
11
+ class Entitlements
12
+ # @api private
13
+ def initialize(http_client)
14
+ @http = http_client
15
+ end
16
+
17
+ # List entitlements with cursor-based pagination.
18
+ #
19
+ # @param cursor [String, nil] opaque cursor for the next page
20
+ # @param limit [Integer] items per page (1..100, default 25)
21
+ # @param subscription_id [String, nil] filter by subscription
22
+ # @return [BillingIO::PaginatedList<BillingIO::Entitlement>]
23
+ # @raise [BillingIO::Error]
24
+ def list(cursor: nil, limit: 25, subscription_id: nil)
25
+ params = { limit: limit }
26
+ params[:cursor] = cursor if cursor
27
+ params[:subscription_id] = subscription_id if subscription_id
28
+
29
+ data = @http.get("/subscriptions/entitlements", params)
30
+ PaginatedList.from_hash(data, Entitlement)
31
+ end
32
+
33
+ # Create a new entitlement.
34
+ #
35
+ # @param subscription_id [String] parent subscription
36
+ # @param feature_key [String] machine-readable feature identifier
37
+ # @param value [Object, nil] entitlement value
38
+ # @param metadata [Hash, nil] arbitrary key-value pairs
39
+ # @return [BillingIO::Entitlement]
40
+ # @raise [BillingIO::Error]
41
+ def create(subscription_id:, feature_key:, value: nil, metadata: nil)
42
+ body = {
43
+ "subscription_id" => subscription_id,
44
+ "feature_key" => feature_key
45
+ }
46
+ body["value"] = value unless value.nil?
47
+ body["metadata"] = metadata if metadata
48
+
49
+ data = @http.post("/subscriptions/entitlements", body)
50
+ Entitlement.from_hash(data)
51
+ end
52
+
53
+ # Update an existing entitlement.
54
+ #
55
+ # @param entitlement_id [String] entitlement identifier (prefixed +ent_+)
56
+ # @param value [Object, nil] new entitlement value
57
+ # @param metadata [Hash, nil] new metadata (replaces existing)
58
+ # @return [BillingIO::Entitlement]
59
+ # @raise [BillingIO::Error]
60
+ def update(entitlement_id, value: nil, metadata: nil)
61
+ body = {}
62
+ body["value"] = value unless value.nil?
63
+ body["metadata"] = metadata if metadata
64
+
65
+ data = @http.patch("/subscriptions/entitlements/#{entitlement_id}", body)
66
+ Entitlement.from_hash(data)
67
+ end
68
+
69
+ # Delete an entitlement.
70
+ #
71
+ # @param entitlement_id [String] entitlement identifier (prefixed +ent_+)
72
+ # @return [nil]
73
+ # @raise [BillingIO::Error]
74
+ def delete(entitlement_id)
75
+ @http.delete("/subscriptions/entitlements/#{entitlement_id}")
76
+ nil
77
+ end
78
+
79
+ # Check whether a customer has a specific entitlement.
80
+ #
81
+ # @param customer_id [String] customer identifier
82
+ # @param feature_key [String] feature key to check
83
+ # @return [BillingIO::EntitlementCheck]
84
+ # @raise [BillingIO::Error]
85
+ def check(customer_id:, feature_key:)
86
+ params = {
87
+ customer_id: customer_id,
88
+ feature_key: feature_key
89
+ }
90
+
91
+ data = @http.get("/subscriptions/entitlements/check", params)
92
+ EntitlementCheck.from_hash(data)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BillingIO
4
+ # Provides access to payment link endpoints.
5
+ #
6
+ # client.payment_links.create(amount_usd: 25.00, chain: "tron", token: "USDT")
7
+ # client.payment_links.list
8
+ class PaymentLinks
9
+ # @api private
10
+ def initialize(http_client)
11
+ @http = http_client
12
+ end
13
+
14
+ # Create a new payment link.
15
+ #
16
+ # @param amount_usd [Float, nil] fixed amount in USD (nil for open-amount)
17
+ # @param chain [String, nil] blockchain network
18
+ # @param token [String, nil] stablecoin token
19
+ # @param metadata [Hash, nil] arbitrary key-value pairs
20
+ # @return [BillingIO::PaymentLink]
21
+ # @raise [BillingIO::Error]
22
+ def create(amount_usd: nil, chain: nil, token: nil, metadata: nil)
23
+ body = {}
24
+ body["amount_usd"] = amount_usd if amount_usd
25
+ body["chain"] = chain if chain
26
+ body["token"] = token if token
27
+ body["metadata"] = metadata if metadata
28
+
29
+ data = @http.post("/payment-links", body)
30
+ PaymentLink.from_hash(data)
31
+ end
32
+
33
+ # List payment links with cursor-based pagination.
34
+ #
35
+ # @param cursor [String, nil] opaque cursor for the next page
36
+ # @param limit [Integer] items per page (1..100, default 25)
37
+ # @return [BillingIO::PaginatedList<BillingIO::PaymentLink>]
38
+ # @raise [BillingIO::Error]
39
+ def list(cursor: nil, limit: 25)
40
+ params = { limit: limit }
41
+ params[:cursor] = cursor if cursor
42
+
43
+ data = @http.get("/payment-links", params)
44
+ PaginatedList.from_hash(data, PaymentLink)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BillingIO
4
+ # Provides access to payment method management endpoints.
5
+ #
6
+ # client.payment_methods.create(customer_id: "cus_abc123", type: "wallet")
7
+ # client.payment_methods.list
8
+ # client.payment_methods.update("pm_abc123", metadata: { "label" => "main" })
9
+ # client.payment_methods.delete("pm_abc123")
10
+ # client.payment_methods.set_default("pm_abc123")
11
+ class PaymentMethods
12
+ # @api private
13
+ def initialize(http_client)
14
+ @http = http_client
15
+ end
16
+
17
+ # Register a new payment method.
18
+ #
19
+ # @param customer_id [String] owning customer
20
+ # @param type [String] method type (e.g. "wallet")
21
+ # @param chain [String, nil] blockchain network
22
+ # @param token [String, nil] stablecoin token
23
+ # @param address [String, nil] wallet address
24
+ # @param metadata [Hash, nil] arbitrary key-value pairs
25
+ # @return [BillingIO::PaymentMethod]
26
+ # @raise [BillingIO::Error]
27
+ def create(customer_id:, type:, chain: nil, token: nil, address: nil, metadata: nil)
28
+ body = {
29
+ "customer_id" => customer_id,
30
+ "type" => type
31
+ }
32
+ body["chain"] = chain if chain
33
+ body["token"] = token if token
34
+ body["address"] = address if address
35
+ body["metadata"] = metadata if metadata
36
+
37
+ data = @http.post("/payment-methods", body)
38
+ PaymentMethod.from_hash(data)
39
+ end
40
+
41
+ # List payment methods with cursor-based pagination.
42
+ #
43
+ # @param cursor [String, nil] opaque cursor for the next page
44
+ # @param limit [Integer] items per page (1..100, default 25)
45
+ # @param customer_id [String, nil] filter by customer
46
+ # @return [BillingIO::PaginatedList<BillingIO::PaymentMethod>]
47
+ # @raise [BillingIO::Error]
48
+ def list(cursor: nil, limit: 25, customer_id: nil)
49
+ params = { limit: limit }
50
+ params[:cursor] = cursor if cursor
51
+ params[:customer_id] = customer_id if customer_id
52
+
53
+ data = @http.get("/payment-methods", params)
54
+ PaginatedList.from_hash(data, PaymentMethod)
55
+ end
56
+
57
+ # Update an existing payment method.
58
+ #
59
+ # @param payment_method_id [String] payment method identifier (prefixed +pm_+)
60
+ # @param metadata [Hash, nil] new metadata (replaces existing)
61
+ # @return [BillingIO::PaymentMethod]
62
+ # @raise [BillingIO::Error]
63
+ def update(payment_method_id, metadata: nil)
64
+ body = {}
65
+ body["metadata"] = metadata if metadata
66
+
67
+ data = @http.patch("/payment-methods/#{payment_method_id}", body)
68
+ PaymentMethod.from_hash(data)
69
+ end
70
+
71
+ # Delete a payment method.
72
+ #
73
+ # @param payment_method_id [String] payment method identifier (prefixed +pm_+)
74
+ # @return [nil]
75
+ # @raise [BillingIO::Error]
76
+ def delete(payment_method_id)
77
+ @http.delete("/payment-methods/#{payment_method_id}")
78
+ nil
79
+ end
80
+
81
+ # Set a payment method as the customer's default.
82
+ #
83
+ # @param payment_method_id [String] payment method identifier (prefixed +pm_+)
84
+ # @return [BillingIO::PaymentMethod]
85
+ # @raise [BillingIO::Error]
86
+ def set_default(payment_method_id)
87
+ data = @http.post("/payment-methods/#{payment_method_id}/default")
88
+ PaymentMethod.from_hash(data)
89
+ end
90
+ end
91
+ end