airwallex 0.6.0 → 0.8.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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +76 -0
  3. data/README.md +211 -25
  4. data/lib/airwallex/api_operations/delete.rb +3 -3
  5. data/lib/airwallex/api_operations/update.rb +4 -4
  6. data/lib/airwallex/api_resource.rb +22 -0
  7. data/lib/airwallex/client.rb +1 -1
  8. data/lib/airwallex/configuration.rb +6 -2
  9. data/lib/airwallex/errors.rb +6 -1
  10. data/lib/airwallex/resources/account_amendment.rb +29 -0
  11. data/lib/airwallex/resources/beneficiary.rb +96 -0
  12. data/lib/airwallex/resources/billing_customer.rb +48 -0
  13. data/lib/airwallex/resources/billing_price.rb +30 -0
  14. data/lib/airwallex/resources/billing_product.rb +23 -0
  15. data/lib/airwallex/resources/billing_subscription.rb +93 -0
  16. data/lib/airwallex/resources/billing_subscription_item.rb +7 -0
  17. data/lib/airwallex/resources/charge.rb +19 -0
  18. data/lib/airwallex/resources/connected_account.rb +136 -0
  19. data/lib/airwallex/resources/conversion.rb +1 -1
  20. data/lib/airwallex/resources/customer.rb +5 -2
  21. data/lib/airwallex/resources/dispute.rb +48 -28
  22. data/lib/airwallex/resources/funds_split.rb +37 -0
  23. data/lib/airwallex/resources/global_account.rb +137 -0
  24. data/lib/airwallex/resources/global_account_alias.rb +62 -0
  25. data/lib/airwallex/resources/global_account_mandate.rb +26 -0
  26. data/lib/airwallex/resources/global_account_transaction.rb +7 -0
  27. data/lib/airwallex/resources/payment_consent.rb +68 -0
  28. data/lib/airwallex/resources/payment_method.rb +13 -5
  29. data/lib/airwallex/resources/payment_source.rb +52 -0
  30. data/lib/airwallex/resources/quote.rb +5 -3
  31. data/lib/airwallex/resources/rate.rb +2 -7
  32. data/lib/airwallex/util.rb +8 -5
  33. data/lib/airwallex/version.rb +1 -1
  34. data/lib/airwallex.rb +15 -0
  35. metadata +18 -3
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airwallex
4
+ # Represents an alias (e.g. PayID, email, or phone-linked VAN) attached to
5
+ # a GlobalAccount. Always accessed through its parent GlobalAccount, since
6
+ # its API path is scoped by global_account_id.
7
+ class GlobalAccountAlias < APIResource
8
+ # @param global_account_id [String] the parent GlobalAccount's id
9
+ # @return [String] API resource path for this account's aliases
10
+ def self.resource_path(global_account_id)
11
+ "/api/v1/global_accounts/#{global_account_id}/aliases"
12
+ end
13
+
14
+ # Begin porting this alias in from another provider
15
+ #
16
+ # @param params [Hash] additional porting params
17
+ # @return [GlobalAccountAlias] self
18
+ def initiate_port(params = {})
19
+ response = Airwallex.client.post(
20
+ "#{self.class.resource_path(global_account_id)}/#{id}/initiate_port", params
21
+ )
22
+ refresh_from(response)
23
+ self
24
+ end
25
+
26
+ # Submit the verification code sent to confirm this alias
27
+ #
28
+ # @param params [Hash] e.g. code:
29
+ # @return [GlobalAccountAlias] self
30
+ def submit_verification_code(params = {})
31
+ response = Airwallex.client.post(
32
+ "#{self.class.resource_path(global_account_id)}/#{id}/submit_verification_code", params
33
+ )
34
+ refresh_from(response)
35
+ self
36
+ end
37
+
38
+ # Request a new verification code for this alias
39
+ #
40
+ # @param params [Hash] additional params
41
+ # @return [GlobalAccountAlias] self
42
+ def request_new_verification_code(params = {})
43
+ response = Airwallex.client.post(
44
+ "#{self.class.resource_path(global_account_id)}/#{id}/request_new_verification_code", params
45
+ )
46
+ refresh_from(response)
47
+ self
48
+ end
49
+
50
+ # Cancel this alias
51
+ #
52
+ # @param params [Hash] additional params
53
+ # @return [GlobalAccountAlias] self
54
+ def cancel(params = {})
55
+ response = Airwallex.client.post(
56
+ "#{self.class.resource_path(global_account_id)}/#{id}/cancel", params
57
+ )
58
+ refresh_from(response)
59
+ self
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airwallex
4
+ # Represents a direct debit mandate on a GlobalAccount. Always accessed
5
+ # through its parent GlobalAccount, since its API path is scoped by
6
+ # global_account_id.
7
+ class GlobalAccountMandate < APIResource
8
+ # @param global_account_id [String] the parent GlobalAccount's id
9
+ # @return [String] API resource path for this account's mandates
10
+ def self.resource_path(global_account_id)
11
+ "/api/v1/global_accounts/#{global_account_id}/mandates"
12
+ end
13
+
14
+ # Cancel this mandate
15
+ #
16
+ # @param params [Hash] additional params
17
+ # @return [GlobalAccountMandate] self
18
+ def cancel(params = {})
19
+ response = Airwallex.client.post(
20
+ "#{self.class.resource_path(global_account_id)}/#{id}/cancel", params
21
+ )
22
+ refresh_from(response)
23
+ self
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airwallex
4
+ # Read-only representation of a single Global Account inbound transaction
5
+ class GlobalAccountTransaction < APIResource
6
+ end
7
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airwallex
4
+ # Represents a Payment Consent — a saved card/payment method authorized for
5
+ # future off-session charges without re-prompting the customer.
6
+ #
7
+ # Does NOT attach directly to a BillingSubscription — a subscription's
8
+ # payment_source_id references a PaymentSource (see Airwallex::PaymentSource),
9
+ # a separate Billing object created FROM a verified, merchant-initiated
10
+ # PaymentConsent. See PaymentSource's docstring for the full chain.
11
+ #
12
+ # @example Create and verify a consent for merchant-initiated (unscheduled) charges
13
+ # # next_triggered_by/merchant_trigger_reason are required for the
14
+ # # consent to later be usable to create a PaymentSource.
15
+ # consent = Airwallex::PaymentConsent.create(
16
+ # customer_id: customer.id,
17
+ # payment_method: { type: "card", card: { ... } },
18
+ # next_triggered_by: "merchant",
19
+ # merchant_trigger_reason: "unscheduled"
20
+ # )
21
+ # consent.verify(payment_method: { card: { cvc: "123" } })
22
+ #
23
+ # @example Disable a consent
24
+ # consent.disable
25
+ class PaymentConsent < APIResource
26
+ extend APIOperations::Create
27
+ extend APIOperations::Retrieve
28
+ extend APIOperations::List
29
+ include APIOperations::Update
30
+
31
+ # @return [String] API resource path for payment consents
32
+ def self.resource_path
33
+ "/api/v1/pa/payment_consents"
34
+ end
35
+
36
+ # Verify this consent (e.g. via a zero/low-value authorization) before
37
+ # it can be used for off-session charges
38
+ #
39
+ # @param params [Hash] verification params (e.g. payment_method details)
40
+ # @return [PaymentConsent] self
41
+ def verify(params = {})
42
+ response = Airwallex.client.post("#{self.class.resource_path}/#{id}/verify", params)
43
+ refresh_from(response)
44
+ self
45
+ end
46
+
47
+ # Continue a verification that requires further customer action
48
+ # (e.g. completing 3DS)
49
+ #
50
+ # @param params [Hash] continuation params
51
+ # @return [PaymentConsent] self
52
+ def verify_continue(params = {})
53
+ response = Airwallex.client.post("#{self.class.resource_path}/#{id}/verify_continue", params)
54
+ refresh_from(response)
55
+ self
56
+ end
57
+
58
+ # Disable this consent so it can no longer be charged
59
+ #
60
+ # @param params [Hash] additional params
61
+ # @return [PaymentConsent] self
62
+ def disable(params = {})
63
+ response = Airwallex.client.post("#{self.class.resource_path}/#{id}/disable", params)
64
+ refresh_from(response)
65
+ self
66
+ end
67
+ end
68
+ end
@@ -6,6 +6,11 @@ module Airwallex
6
6
  # Payment methods allow you to store customer payment credentials securely
7
7
  # and reuse them for future payments without collecting details again.
8
8
  #
9
+ # Note: raw card tokenization via .create requires PCI-scoped "Native API"
10
+ # account access, which isn't enabled by default — if your account isn't
11
+ # provisioned for it, collect cards via Airwallex's hosted checkout or
12
+ # Embedded Elements instead.
13
+ #
9
14
  # @example Create a card payment method
10
15
  # pm = Airwallex::PaymentMethod.create(
11
16
  # type: "card",
@@ -26,24 +31,27 @@ module Airwallex
26
31
  #
27
32
  # @example Update billing details
28
33
  # pm.update(billing: { address: { postal_code: "10001" } })
34
+ #
35
+ # @example Disable a payment method
36
+ # pm.disable
29
37
  class PaymentMethod < APIResource
30
38
  extend APIOperations::Create
31
39
  extend APIOperations::Retrieve
32
40
  extend APIOperations::List
33
- extend APIOperations::Update
34
41
  include APIOperations::Update
35
- extend APIOperations::Delete
36
42
 
37
43
  # @return [String] API resource path for payment methods
38
44
  def self.resource_path
39
45
  "/api/v1/pa/payment_methods"
40
46
  end
41
47
 
42
- # Detach this payment method from its customer
48
+ # Disable this payment method (Airwallex has no delete/detach endpoint;
49
+ # disabling is the real lifecycle operation and preserves history)
43
50
  #
51
+ # @param params [Hash] additional params
44
52
  # @return [PaymentMethod] self
45
- def detach
46
- response = Airwallex.client.post("#{self.class.resource_path}/#{id}/detach", {})
53
+ def disable(params = {})
54
+ response = Airwallex.client.post("#{self.class.resource_path}/#{id}/disable", params)
47
55
  refresh_from(response)
48
56
  self
49
57
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airwallex
4
+ # Represents a Billing Payment Source — the object a BillingSubscription's
5
+ # payment_source_id actually references. NOT the same object as
6
+ # PaymentConsent (/pa/payment_consents).
7
+ #
8
+ # external_id is the id of a PaymentMethod (/pa/payment_methods), not a
9
+ # PaymentConsent's own id. The PaymentConsent is still part of the flow —
10
+ # it's what authorizes that PaymentMethod for merchant-initiated
11
+ # (unscheduled) charges — but the id PaymentSource wants is the underlying
12
+ # PaymentMethod's.
13
+ #
14
+ # @example Full flow: PaymentMethod -> PaymentConsent -> PaymentSource -> BillingSubscription
15
+ # payment_method = Airwallex::PaymentMethod.create(
16
+ # customer_id: customer.id,
17
+ # type: "card",
18
+ # card: { ... } # a real test card in sandbox
19
+ # )
20
+ #
21
+ # consent = Airwallex::PaymentConsent.create(
22
+ # customer_id: customer.id,
23
+ # payment_method: { id: payment_method.id },
24
+ # next_triggered_by: "merchant",
25
+ # merchant_trigger_reason: "unscheduled"
26
+ # )
27
+ # consent.verify(...)
28
+ #
29
+ # source = Airwallex::PaymentSource.create(
30
+ # billing_customer_id: billing_customer.id,
31
+ # external_id: payment_method.id,
32
+ # linked_payment_account_id: connected_account.id
33
+ # )
34
+ #
35
+ # Airwallex::BillingSubscription.create(
36
+ # billing_customer_id: billing_customer.id,
37
+ # legal_entity_id: connected_account.legal_entity_id,
38
+ # collection_method: "AUTO_CHARGE",
39
+ # payment_source_id: source.id,
40
+ # items: [{ price_id: price.id, quantity: 1 }]
41
+ # )
42
+ class PaymentSource < APIResource
43
+ extend APIOperations::Create
44
+ extend APIOperations::Retrieve
45
+ extend APIOperations::List
46
+
47
+ # @return [String] API resource path for billing payment sources
48
+ def self.resource_path
49
+ "/api/v1/billing/payment_sources"
50
+ end
51
+ end
52
+ end
@@ -3,14 +3,16 @@
3
3
  module Airwallex
4
4
  # Quote resource for locked exchange rates
5
5
  #
6
- # Create quotes to lock exchange rates for a short period (typically 30-60 seconds).
7
- # Use quotes to guarantee the rate when executing conversions.
6
+ # Create quotes to lock exchange rates for a period you choose (validity:
7
+ # MIN_1 through HR_24 — see .create). Use quotes to guarantee the rate when
8
+ # executing conversions.
8
9
  #
9
10
  # @example Create a quote
10
11
  # quote = Airwallex::Quote.create(
11
12
  # buy_currency: 'EUR',
12
13
  # sell_currency: 'USD',
13
- # sell_amount: 1000.00
14
+ # sell_amount: 1000.00,
15
+ # validity: "MIN_1"
14
16
  # )
15
17
  # puts "Locked rate: #{quote.client_rate}, expires: #{quote.expires_at}"
16
18
  #
@@ -10,15 +10,10 @@ module Airwallex
10
10
  # rate = Airwallex::Rate.retrieve(buy_currency: 'EUR', sell_currency: 'USD')
11
11
  # puts "1 USD = #{rate.client_rate} EUR"
12
12
  #
13
- # @example Get multiple rates (Note: API may not support multiple at once)
14
- # rate = Airwallex::Rate.retrieve(
15
- # buy_currency: 'EUR',
16
- # sell_currency: 'USD'
17
- # )
18
- #
13
+ # There is no .list /fx/rates/current always returns the rate for one
14
+ # specific currency pair, not a collection.
19
15
  class Rate < APIResource
20
16
  extend APIOperations::Retrieve
21
- extend APIOperations::List
22
17
 
23
18
  def self.resource_path
24
19
  "/api/v1/fx/rates/current"
@@ -40,11 +40,14 @@ module Airwallex
40
40
  hash.transform_keys(&:to_sym)
41
41
  end
42
42
 
43
- def deep_symbolize_keys(hash)
44
- return hash unless hash.is_a?(Hash)
45
-
46
- hash.each_with_object({}) do |(key, value), result|
47
- result[key.to_sym] = value.is_a?(Hash) ? deep_symbolize_keys(value) : value
43
+ def deep_symbolize_keys(value)
44
+ case value
45
+ when Hash
46
+ value.each_with_object({}) { |(k, v), result| result[k.to_sym] = deep_symbolize_keys(v) }
47
+ when Array
48
+ value.map { |v| deep_symbolize_keys(v) }
49
+ else
50
+ value
48
51
  end
49
52
  end
50
53
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Airwallex
4
- VERSION = "0.6.0"
4
+ VERSION = "0.8.0"
5
5
  end
data/lib/airwallex.rb CHANGED
@@ -26,6 +26,7 @@ require_relative "airwallex/resources/transfer"
26
26
  require_relative "airwallex/resources/beneficiary"
27
27
  require_relative "airwallex/resources/refund"
28
28
  require_relative "airwallex/resources/payment_method"
29
+ require_relative "airwallex/resources/payment_consent"
29
30
  require_relative "airwallex/resources/customer"
30
31
  require_relative "airwallex/resources/batch_transfer"
31
32
  require_relative "airwallex/resources/dispute"
@@ -33,6 +34,20 @@ require_relative "airwallex/resources/rate"
33
34
  require_relative "airwallex/resources/quote"
34
35
  require_relative "airwallex/resources/conversion"
35
36
  require_relative "airwallex/resources/balance"
37
+ require_relative "airwallex/resources/global_account"
38
+ require_relative "airwallex/resources/global_account_transaction"
39
+ require_relative "airwallex/resources/global_account_alias"
40
+ require_relative "airwallex/resources/global_account_mandate"
41
+ require_relative "airwallex/resources/billing_product"
42
+ require_relative "airwallex/resources/billing_price"
43
+ require_relative "airwallex/resources/billing_customer"
44
+ require_relative "airwallex/resources/billing_subscription"
45
+ require_relative "airwallex/resources/billing_subscription_item"
46
+ require_relative "airwallex/resources/payment_source"
47
+ require_relative "airwallex/resources/connected_account"
48
+ require_relative "airwallex/resources/account_amendment"
49
+ require_relative "airwallex/resources/funds_split"
50
+ require_relative "airwallex/resources/charge"
36
51
 
37
52
  module Airwallex
38
53
  class << self
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: airwallex
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chayut Orapinpatipat
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-08-28 00:00:00.000000000 Z
11
+ date: 2026-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -80,14 +80,29 @@ files:
80
80
  - lib/airwallex/list_object.rb
81
81
  - lib/airwallex/middleware/auth_refresh.rb
82
82
  - lib/airwallex/middleware/idempotency.rb
83
+ - lib/airwallex/resources/account_amendment.rb
83
84
  - lib/airwallex/resources/balance.rb
84
85
  - lib/airwallex/resources/batch_transfer.rb
85
86
  - lib/airwallex/resources/beneficiary.rb
87
+ - lib/airwallex/resources/billing_customer.rb
88
+ - lib/airwallex/resources/billing_price.rb
89
+ - lib/airwallex/resources/billing_product.rb
90
+ - lib/airwallex/resources/billing_subscription.rb
91
+ - lib/airwallex/resources/billing_subscription_item.rb
92
+ - lib/airwallex/resources/charge.rb
93
+ - lib/airwallex/resources/connected_account.rb
86
94
  - lib/airwallex/resources/conversion.rb
87
95
  - lib/airwallex/resources/customer.rb
88
96
  - lib/airwallex/resources/dispute.rb
97
+ - lib/airwallex/resources/funds_split.rb
98
+ - lib/airwallex/resources/global_account.rb
99
+ - lib/airwallex/resources/global_account_alias.rb
100
+ - lib/airwallex/resources/global_account_mandate.rb
101
+ - lib/airwallex/resources/global_account_transaction.rb
102
+ - lib/airwallex/resources/payment_consent.rb
89
103
  - lib/airwallex/resources/payment_intent.rb
90
104
  - lib/airwallex/resources/payment_method.rb
105
+ - lib/airwallex/resources/payment_source.rb
91
106
  - lib/airwallex/resources/quote.rb
92
107
  - lib/airwallex/resources/rate.rb
93
108
  - lib/airwallex/resources/refund.rb
@@ -122,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
137
  - !ruby/object:Gem::Version
123
138
  version: '0'
124
139
  requirements: []
125
- rubygems_version: 3.4.10
140
+ rubygems_version: 3.5.22
126
141
  signing_key:
127
142
  specification_version: 4
128
143
  summary: Production-grade Ruby client for the Airwallex API