airwallex 0.12.0 → 0.13.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: 20abbd73aa43d82620559c0f067a6236619d3dad597b778b41b75af6d87fb225
4
- data.tar.gz: 6a477ebe40ec72d267d42f9b98669d783dd7db32c9cf9d30ed0b671c07810252
3
+ metadata.gz: db311617af38ee6ed53131e0342f3614f7f0acfbe5e85d1b215995d2dd58086d
4
+ data.tar.gz: 393fab63946953d355e0b20796693c6177df6d8cc30b666ee755ab1c9c57160f
5
5
  SHA512:
6
- metadata.gz: ac0aa15ebc45b61bbd7004010bbdfc261c1243d373cbd59b4dbb141e680b0d46ca079ab25f2d4c4e9017f5d4a4730fff4950f632e5415c82de0728cd3e3837b8
7
- data.tar.gz: 948df17c305f0ab1c88791b29afe1df2218197c12512cbb52c7f80cb0524c9e1903a7e4b1b25597c2ed447d010fed846df94e48ec988ccdf85019913318fa561
6
+ metadata.gz: 381883a72671f0c450ff93504c1988b14c215c986d403536db5e3df3210b4734466b0a7c91474458500c8ff390187d15163387b104e9df50ced3f498ca2afb5e
7
+ data.tar.gz: 6d0bc5fcb4e76857711cff2b6503515f2907895bdb6eadb778787647914a5d739450486ad394ab2ce718ff1ea3687badf2c9b63a4c2b4796480ee7f66f1619cc
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.13.0] - 2026-10-21
4
+
5
+ ### Added
6
+
7
+ - `EmbeddedComponent.authorize(code_challenge:, scope:, identity: nil, headers: {})`
8
+ for `POST /api/v1/authentication/authorize`. It returns a symbolized Hash,
9
+ `{ authorization_code: }`, for the embedded component SDK. The code is
10
+ single use and expires in 30 seconds. Pass `headers:` with `x-on-behalf-of`
11
+ to issue it for a connected account
12
+ - `APIResource.symbolized_post` takes an optional `headers` argument
13
+
14
+ ### Changed
15
+
16
+ - `RFI.respond` and `RFI#respond` now send a normal JSON body, so the
17
+ Idempotency middleware adds a `request_id` like it does for other POSTs.
18
+ 0.12.0 left it out because the endpoint doesn't document one, but a sandbox
19
+ test confirmed Airwallex accepts it
20
+
3
21
  ## [0.12.0] - 2026-10-06
4
22
 
5
23
  ### Added
data/README.md CHANGED
@@ -16,6 +16,7 @@ This gem provides a Ruby interface to Airwallex's payment infrastructure, design
16
16
  - **Billing**: Products, prices, billing customers, and subscriptions for recurring/instalment billing
17
17
  - **Recurring Payments**: Payment consents and payment sources for merchant-initiated (off-session) charges
18
18
  - **Scale**: Connected accounts, funds splits, and charges for platforms onboarding sub-merchants
19
+ - **Embedded Components**: Authorization codes for Airwallex's embedded UI components, including for connected accounts
19
20
  - **Compliance**: Retrieve, list and respond to Requests for Information (RFIs), and upload supporting documents, including for connected accounts
20
21
  - **Sandbox Simulations**: Deposits, issuing transactions, disputes, transfer status, Direct Debit mandates, connected account/offboarding review outcomes, RFIs, and POS terminals — see [Sandbox Simulations](#sandbox-simulations)
21
22
  - **Idempotency**: Automatic request deduplication for safe retries
@@ -521,6 +522,32 @@ has the wrong answer shape), and `PermissionError` with
521
522
  answering RFIs for connected accounts through the API hasn't been enabled
522
523
  for your platform; ask your Airwallex Account Manager to turn it on.
523
524
 
525
+ ### Embedded Components
526
+
527
+ Airwallex's embedded UI components (beneficiary, payout, onboarding, KYB, RFI,
528
+ SCA and tax forms) need an authorization code from your backend.
529
+ `EmbeddedComponent.authorize` mints one using a PKCE S256 challenge. Pass
530
+ `x-on-behalf-of` to issue it for a connected account; without it the code is
531
+ for the platform account. The code is single use and expires in 30 seconds,
532
+ so give it and the `code_verifier` to the browser SDK straight away.
533
+
534
+ ```ruby
535
+ code_verifier = SecureRandom.urlsafe_base64(64)
536
+ code_challenge = Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier), padding: false)
537
+
538
+ Airwallex::EmbeddedComponent.authorize(
539
+ code_challenge: code_challenge,
540
+ scope: ['transfer:write'], # beneficiary and payout components
541
+ headers: { 'x-on-behalf-of' => 'acct_123' }
542
+ )
543
+ # => { authorization_code: "..." }
544
+ ```
545
+
546
+ The other scopes are `onboarding:write`, `kyb:write`, `rfi:read`, `rfi:write`,
547
+ `sca:read`, `sca:write`, `tax_form:read` and `tax_form:write`. `identity:` is
548
+ only used by embedded SCA. A bad `code_challenge` or `scope` raises
549
+ `BadRequestError` (`field_required`, `invalid_argument` or `validation_failed`).
550
+
524
551
  ### Sandbox Simulations
525
552
 
526
553
  Sandbox-only endpoints (`/api/v1/simulation/...`) that stand in for the bank,
@@ -31,9 +31,10 @@ module Airwallex
31
31
  #
32
32
  # @param path [String] the request path
33
33
  # @param params [Hash] request body
34
+ # @param headers [Hash] e.g. { "x-on-behalf-of" => account_id }
34
35
  # @return [Hash] symbolized response
35
- def self.symbolized_post(path, params = {})
36
- Util.deep_symbolize_keys(Airwallex.client.post(path, params))
36
+ def self.symbolized_post(path, params = {}, headers = {})
37
+ Util.deep_symbolize_keys(Airwallex.client.post(path, params, headers))
37
38
  end
38
39
 
39
40
  # Perform a one-off GET that returns a plain, symbolized Hash rather
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airwallex
4
+ # Server-side support for Airwallex embedded components (the beneficiary,
5
+ # payout, onboarding, KYB, RFI, SCA and tax form UI components). The
6
+ # browser SDK needs an authorization code minted by your backend; this
7
+ # class mints it. See
8
+ # https://www.airwallex.com/docs/api/authentication/embedded_components/authorize
9
+ #
10
+ # Scopes: transfer:write (beneficiary and payout components),
11
+ # onboarding:write, kyb:write, rfi:read, rfi:write, sca:read, sca:write,
12
+ # tax_form:read, tax_form:write.
13
+ #
14
+ # @example Authorize the payout component for a connected account
15
+ # code_verifier = SecureRandom.urlsafe_base64(64)
16
+ # code_challenge = Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier), padding: false)
17
+ #
18
+ # Airwallex::EmbeddedComponent.authorize(
19
+ # code_challenge: code_challenge,
20
+ # scope: ["transfer:write"],
21
+ # headers: { "x-on-behalf-of" => "acct_123" }
22
+ # )
23
+ # # => { authorization_code: "..." }
24
+ class EmbeddedComponent < APIResource
25
+ AUTHORIZE_PATH = "/api/v1/authentication/authorize"
26
+
27
+ # Issue a single-use authorization code for an embedded component. The
28
+ # code expires in 30 seconds; hand it, with the code_verifier, to the
29
+ # browser SDK straight away.
30
+ #
31
+ # @param code_challenge [String] BASE64URL(SHA256(code_verifier)), the
32
+ # PKCE S256 challenge (RFC 7636 section 4)
33
+ # @param scope [Array<String>] e.g. ["transfer:write"]
34
+ # @param identity [String, nil] only used by embedded SCA
35
+ # @param headers [Hash] e.g. { "x-on-behalf-of" => account_id }; without
36
+ # it the code is issued for the platform account
37
+ # @return [Hash] { authorization_code: }
38
+ def self.authorize(code_challenge:, scope:, identity: nil, headers: {})
39
+ params = { code_challenge: code_challenge, scope: scope }
40
+ params[:identity] = identity if identity
41
+ symbolized_post(AUTHORIZE_PATH, params, headers)
42
+ end
43
+ end
44
+ end
@@ -110,31 +110,17 @@ module Airwallex
110
110
  )
111
111
  end
112
112
 
113
- # Respond to an RFI. params are sent as-is (see the class docs for the
114
- # body shape). Unlike other POSTs, no request_id is added: the endpoint
115
- # doesn't document one.
113
+ # Respond to an RFI. See the class docs for the body shape.
116
114
  #
117
115
  # @param rfi_id [String]
118
116
  # @param params [Hash] questions: (required) array of { id:, answer: { type:, ... } }
119
117
  # @param opts [Hash] headers: (e.g. { "x-on-behalf-of" => account_id })
120
118
  # @return [RFI]
121
119
  def self.respond(rfi_id, params = {}, opts = {})
122
- response = Airwallex.client.post("#{resource_path}/#{rfi_id}/respond", without_request_id(params),
123
- opts[:headers] || {})
120
+ response = Airwallex.client.post("#{resource_path}/#{rfi_id}/respond", params, opts[:headers] || {})
124
121
  new(response)
125
122
  end
126
123
 
127
- # Pre-encode the body as JSON: the Idempotency middleware only adds
128
- # request_id to Hash bodies, and the JSON middleware passes strings on
129
- # unchanged
130
- #
131
- # @param params [Hash]
132
- # @return [String]
133
- def self.without_request_id(params)
134
- JSON.generate(params)
135
- end
136
- private_class_method :without_request_id
137
-
138
124
  # Simulate Airwallex raising an RFI
139
125
  #
140
126
  # @param params [Hash] type: (required, one of "KYC", "KYC_ONGOING",
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Airwallex
4
- VERSION = "0.12.0"
4
+ VERSION = "0.13.0"
5
5
  end
data/lib/airwallex.rb CHANGED
@@ -57,6 +57,7 @@ require_relative "airwallex/resources/linked_account"
57
57
  require_relative "airwallex/resources/account_offboarding"
58
58
  require_relative "airwallex/resources/rfi"
59
59
  require_relative "airwallex/resources/uploaded_file"
60
+ require_relative "airwallex/resources/embedded_component"
60
61
  require_relative "airwallex/resources/pos_terminal"
61
62
 
62
63
  module Airwallex
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.12.0
4
+ version: 0.13.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-10-06 00:00:00.000000000 Z
11
+ date: 2026-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -100,6 +100,7 @@ files:
100
100
  - lib/airwallex/resources/customer.rb
101
101
  - lib/airwallex/resources/deposit.rb
102
102
  - lib/airwallex/resources/dispute.rb
103
+ - lib/airwallex/resources/embedded_component.rb
103
104
  - lib/airwallex/resources/funds_split.rb
104
105
  - lib/airwallex/resources/funds_split_reversal.rb
105
106
  - lib/airwallex/resources/global_account.rb
@@ -149,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
150
  - !ruby/object:Gem::Version
150
151
  version: '0'
151
152
  requirements: []
152
- rubygems_version: 3.5.16
153
+ rubygems_version: 3.5.22
153
154
  signing_key:
154
155
  specification_version: 4
155
156
  summary: Production-grade Ruby client for the Airwallex API