zai_payment 1.1.0 → 1.3.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.
@@ -0,0 +1,383 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ZaiPayment
4
+ module Resources
5
+ # User resource for managing Zai users (payin and payout)
6
+ #
7
+ # @see https://developer.hellozai.com/docs/onboarding-a-payin-user
8
+ # @see https://developer.hellozai.com/docs/onboarding-a-payout-user
9
+ class User
10
+ attr_reader :client
11
+
12
+ # User types
13
+ USER_TYPE_PAYIN = 'payin'
14
+ USER_TYPE_PAYOUT = 'payout'
15
+
16
+ # Valid user types
17
+ VALID_USER_TYPES = [USER_TYPE_PAYIN, USER_TYPE_PAYOUT].freeze
18
+
19
+ # Map of attribute keys to API field names
20
+ FIELD_MAPPING = {
21
+ id: :id,
22
+ email: :email,
23
+ first_name: :first_name,
24
+ last_name: :last_name,
25
+ mobile: :mobile,
26
+ phone: :phone,
27
+ address_line1: :address_line1,
28
+ address_line2: :address_line2,
29
+ city: :city,
30
+ state: :state,
31
+ zip: :zip,
32
+ country: :country,
33
+ dob: :dob,
34
+ government_number: :government_number,
35
+ drivers_license_number: :drivers_license_number,
36
+ drivers_license_state: :drivers_license_state,
37
+ logo_url: :logo_url,
38
+ color_1: :color_1,
39
+ color_2: :color_2,
40
+ custom_descriptor: :custom_descriptor,
41
+ authorized_signer_title: :authorized_signer_title,
42
+ user_type: :user_type,
43
+ device_id: :device_id,
44
+ ip_address: :ip_address
45
+ }.freeze
46
+
47
+ # Map of company attribute keys to API field names
48
+ COMPANY_FIELD_MAPPING = {
49
+ name: :name,
50
+ legal_name: :legal_name,
51
+ tax_number: :tax_number,
52
+ business_email: :business_email,
53
+ charge_tax: :charge_tax,
54
+ address_line1: :address_line1,
55
+ address_line2: :address_line2,
56
+ city: :city,
57
+ state: :state,
58
+ zip: :zip,
59
+ country: :country,
60
+ phone: :phone
61
+ }.freeze
62
+
63
+ def initialize(client: nil)
64
+ @client = client || Client.new
65
+ end
66
+
67
+ # List all users
68
+ #
69
+ # @param limit [Integer] number of records to return (default: 10)
70
+ # @param offset [Integer] number of records to skip (default: 0)
71
+ # @return [Response] the API response containing users array
72
+ #
73
+ # @example
74
+ # users = ZaiPayment::Resources::User.new
75
+ # response = users.list
76
+ # response.data # => [{"id" => "...", "email" => "..."}, ...]
77
+ #
78
+ # @see https://developer.hellozai.com/reference/getallusers
79
+ def list(limit: 10, offset: 0)
80
+ params = {
81
+ limit: limit,
82
+ offset: offset
83
+ }
84
+
85
+ client.get('/users', params: params)
86
+ end
87
+
88
+ # Get a specific user by ID
89
+ #
90
+ # @param user_id [String] the user ID
91
+ # @return [Response] the API response containing user details
92
+ #
93
+ # @example
94
+ # users = ZaiPayment::Resources::User.new
95
+ # response = users.show("user_id")
96
+ # response.data # => {"id" => "user_id", "email" => "...", ...}
97
+ #
98
+ # @see https://developer.hellozai.com/reference/getuserbyid
99
+ def show(user_id)
100
+ validate_id!(user_id, 'user_id')
101
+ client.get("/users/#{user_id}")
102
+ end
103
+
104
+ # Create a new user (payin or payout)
105
+ #
106
+ # @param attributes [Hash] user attributes
107
+ # @option attributes [String] :id Optional unique ID for the user. If not provided,
108
+ # Zai will generate one automatically. Cannot contain '.' character.
109
+ # Useful for mapping to your existing system's user IDs.
110
+ # @option attributes [String] :email (Required) user's email address
111
+ # @option attributes [String] :first_name (Required) user's first name
112
+ # @option attributes [String] :last_name (Required) user's last name
113
+ # @option attributes [String] :country (Required) user's country code (ISO 3166-1 alpha-3)
114
+ # @option attributes [String] :user_type Optional user type ('payin' or 'payout')
115
+ # @option attributes [String] :mobile user's mobile phone number (international format with '+')
116
+ # @option attributes [String] :phone user's phone number
117
+ # @option attributes [String] :address_line1 user's address line 1
118
+ # @option attributes [String] :address_line2 user's address line 2
119
+ # @option attributes [String] :city user's city
120
+ # @option attributes [String] :state user's state
121
+ # @option attributes [String] :zip user's postal/zip code
122
+ # @option attributes [String] :dob user's date of birth (DD/MM/YYYY)
123
+ # @option attributes [String] :government_number user's government ID number (SSN, TFN, etc.)
124
+ # @option attributes [String] :drivers_license_number driving license number
125
+ # @option attributes [String] :drivers_license_state state section of the user's driving license
126
+ # @option attributes [String] :logo_url URL link to the logo
127
+ # @option attributes [String] :color_1 color code number 1
128
+ # @option attributes [String] :color_2 color code number 2
129
+ # @option attributes [String] :custom_descriptor custom descriptor for bundle direct debit statements
130
+ # @option attributes [String] :authorized_signer_title job title for AMEX merchants (e.g., Director)
131
+ # @option attributes [Hash] :company company details (creates a company for the user)
132
+ # @option attributes [String] :device_id device ID for fraud prevention
133
+ # @option attributes [String] :ip_address IP address for fraud prevention
134
+ # @return [Response] the API response containing created user
135
+ #
136
+ # @example Create a payin user (buyer) with auto-generated ID
137
+ # users = ZaiPayment::Resources::User.new
138
+ # response = users.create(
139
+ # email: "buyer@example.com",
140
+ # first_name: "John",
141
+ # last_name: "Doe",
142
+ # country: "USA",
143
+ # mobile: "+1234567890",
144
+ # address_line1: "123 Main St",
145
+ # city: "New York",
146
+ # state: "NY",
147
+ # zip: "10001"
148
+ # )
149
+ #
150
+ # @example Create a payin user with custom ID
151
+ # users = ZaiPayment::Resources::User.new
152
+ # response = users.create(
153
+ # id: "buyer-#{your_user_id}",
154
+ # email: "buyer@example.com",
155
+ # first_name: "John",
156
+ # last_name: "Doe",
157
+ # country: "USA"
158
+ # )
159
+ #
160
+ # @example Create a payout user (seller/merchant)
161
+ # users = ZaiPayment::Resources::User.new
162
+ # response = users.create(
163
+ # email: "seller@example.com",
164
+ # first_name: "Jane",
165
+ # last_name: "Smith",
166
+ # country: "AUS",
167
+ # dob: "19900101",
168
+ # address_line1: "456 Market St",
169
+ # city: "Sydney",
170
+ # state: "NSW",
171
+ # zip: "2000",
172
+ # mobile: "+61412345678"
173
+ # )
174
+ #
175
+ # @example Create a user with company details
176
+ # users = ZaiPayment::Resources::User.new
177
+ # response = users.create(
178
+ # email: "business@example.com",
179
+ # first_name: "John",
180
+ # last_name: "Doe",
181
+ # country: "AUS",
182
+ # mobile: "+61412345678",
183
+ # authorized_signer_title: "Director",
184
+ # company: {
185
+ # name: "ABC Company",
186
+ # legal_name: "ABC Pty Ltd",
187
+ # tax_number: "123456789",
188
+ # business_email: "admin@abc.com",
189
+ # country: "AUS",
190
+ # charge_tax: true,
191
+ # address_line1: "123 Business St",
192
+ # city: "Melbourne",
193
+ # state: "VIC",
194
+ # zip: "3000",
195
+ # phone: "+61398765432"
196
+ # }
197
+ # )
198
+ #
199
+ # @see https://developer.hellozai.com/reference/createuser
200
+ # @see https://developer.hellozai.com/docs/onboarding-a-payin-user
201
+ # @see https://developer.hellozai.com/docs/onboarding-a-payout-user
202
+ def create(**attributes)
203
+ validate_create_attributes!(attributes)
204
+
205
+ body = build_user_body(attributes)
206
+ client.post('/users', body: body)
207
+ end
208
+
209
+ # Update an existing user
210
+ #
211
+ # @param user_id [String] the user ID
212
+ # @param attributes [Hash] user attributes to update
213
+ # @option attributes [String] :email user's email address
214
+ # @option attributes [String] :first_name user's first name
215
+ # @option attributes [String] :last_name user's last name
216
+ # @option attributes [String] :mobile user's mobile phone number (international format with '+')
217
+ # @option attributes [String] :phone user's phone number
218
+ # @option attributes [String] :address_line1 user's address line 1
219
+ # @option attributes [String] :address_line2 user's address line 2
220
+ # @option attributes [String] :city user's city
221
+ # @option attributes [String] :state user's state
222
+ # @option attributes [String] :zip user's postal/zip code
223
+ # @option attributes [String] :dob user's date of birth (DD/MM/YYYY)
224
+ # @option attributes [String] :government_number user's government ID number (SSN, TFN, etc.)
225
+ # @option attributes [String] :drivers_license_number driving license number
226
+ # @option attributes [String] :drivers_license_state state section of the user's driving license
227
+ # @option attributes [String] :logo_url URL link to the logo
228
+ # @option attributes [String] :color_1 color code number 1
229
+ # @option attributes [String] :color_2 color code number 2
230
+ # @option attributes [String] :custom_descriptor custom descriptor for bundle direct debit statements
231
+ # @option attributes [String] :authorized_signer_title job title for AMEX merchants (e.g., Director)
232
+ # @return [Response] the API response containing updated user
233
+ #
234
+ # @example
235
+ # users = ZaiPayment::Resources::User.new
236
+ # response = users.update(
237
+ # "user_id",
238
+ # mobile: "+1234567890",
239
+ # address_line1: "789 New St"
240
+ # )
241
+ #
242
+ # @see https://developer.hellozai.com/reference/updateuser
243
+ def update(user_id, **attributes)
244
+ validate_id!(user_id, 'user_id')
245
+
246
+ body = build_user_body(attributes)
247
+
248
+ validate_email!(attributes[:email]) if attributes[:email]
249
+ validate_dob!(attributes[:dob]) if attributes[:dob]
250
+
251
+ raise Errors::ValidationError, 'At least one attribute must be provided for update' if body.empty?
252
+
253
+ client.patch("/users/#{user_id}", body: body)
254
+ end
255
+
256
+ private
257
+
258
+ def validate_id!(value, field_name)
259
+ return unless value.nil? || value.to_s.strip.empty?
260
+
261
+ raise Errors::ValidationError, "#{field_name} is required and cannot be blank"
262
+ end
263
+
264
+ def validate_presence!(value, field_name)
265
+ return unless value.nil? || value.to_s.strip.empty?
266
+
267
+ raise Errors::ValidationError, "#{field_name} is required and cannot be blank"
268
+ end
269
+
270
+ def validate_create_attributes!(attributes) # rubocop:disable Metrics/AbcSize
271
+ validate_required_attributes!(attributes)
272
+ validate_user_type!(attributes[:user_type]) if attributes[:user_type]
273
+ validate_email!(attributes[:email])
274
+ validate_country!(attributes[:country])
275
+ validate_dob!(attributes[:dob]) if attributes[:dob]
276
+ validate_user_id!(attributes[:id]) if attributes[:id]
277
+ validate_company!(attributes[:company]) if attributes[:company]
278
+ end
279
+
280
+ def validate_required_attributes!(attributes)
281
+ required_fields = %i[email first_name last_name country]
282
+
283
+ missing_fields = required_fields.select do |field|
284
+ attributes[field].nil? || attributes[field].to_s.strip.empty?
285
+ end
286
+
287
+ return if missing_fields.empty?
288
+
289
+ raise Errors::ValidationError,
290
+ "Missing required fields: #{missing_fields.join(', ')}"
291
+ end
292
+
293
+ def validate_user_type!(user_type)
294
+ return if VALID_USER_TYPES.include?(user_type.to_s.downcase)
295
+
296
+ raise Errors::ValidationError,
297
+ "user_type must be one of: #{VALID_USER_TYPES.join(', ')}"
298
+ end
299
+
300
+ def validate_email!(email)
301
+ # Basic email format validation
302
+ email_regex = /\A[^@\s]+@[^@\s]+\.[^@\s]+\z/
303
+ return if email&.match?(email_regex)
304
+
305
+ raise Errors::ValidationError, 'email must be a valid email address'
306
+ end
307
+
308
+ def validate_country!(country)
309
+ # Country should be ISO 3166-1 alpha-3 code (3 letters)
310
+ return if country.to_s.match?(/\A[A-Z]{3}\z/i)
311
+
312
+ raise Errors::ValidationError, 'country must be a valid ISO 3166-1 alpha-3 code (e.g., USA, AUS, GBR)'
313
+ end
314
+
315
+ def validate_dob!(dob)
316
+ # Date of birth should be in DD/MM/YYYY format
317
+ return if dob.to_s.match?(%r{\A\d{2}/\d{2}/\d{4}\z})
318
+
319
+ raise Errors::ValidationError, 'dob must be in DD/MM/YYYY format (e.g., 15/01/1990)'
320
+ end
321
+
322
+ def validate_user_id!(user_id)
323
+ # User ID cannot contain '.' character
324
+ raise Errors::ValidationError, "id cannot contain '.' character" if user_id.to_s.include?('.')
325
+
326
+ # Check if empty
327
+ return unless user_id.nil? || user_id.to_s.strip.empty?
328
+
329
+ raise Errors::ValidationError, 'id cannot be blank if provided'
330
+ end
331
+
332
+ def validate_company!(company)
333
+ return unless company.is_a?(Hash)
334
+
335
+ # Required company fields
336
+ required_company_fields = %i[name legal_name tax_number business_email country]
337
+
338
+ missing_fields = required_company_fields.select do |field|
339
+ company[field].nil? || company[field].to_s.strip.empty?
340
+ end
341
+
342
+ return if missing_fields.empty?
343
+
344
+ raise Errors::ValidationError,
345
+ "Company is missing required fields: #{missing_fields.join(', ')}"
346
+ end
347
+
348
+ def build_user_body(attributes) # rubocop:disable Metrics/CyclomaticComplexity
349
+ body = {}
350
+
351
+ attributes.each do |key, value|
352
+ next if value.nil? || (value.respond_to?(:empty?) && value.empty?)
353
+
354
+ # Handle company object separately
355
+ if key == :company
356
+ body[:company] = build_company_body(value) if value.is_a?(Hash)
357
+ next
358
+ end
359
+
360
+ api_field = FIELD_MAPPING[key]
361
+ body[api_field] = value if api_field
362
+ end
363
+
364
+ body
365
+ end
366
+
367
+ def build_company_body(company_attributes)
368
+ company = {}
369
+
370
+ company_attributes.each do |key, value|
371
+ # Don't skip false values for charge_tax
372
+ next if value.nil?
373
+ next if key != :charge_tax && value.respond_to?(:empty?) && value.empty?
374
+
375
+ api_field = COMPANY_FIELD_MAPPING[key]
376
+ company[api_field] = value if api_field
377
+ end
378
+
379
+ company
380
+ end
381
+ end
382
+ end
383
+ end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'openssl'
4
+ require 'base64'
5
+
3
6
  module ZaiPayment
4
7
  module Resources
5
8
  # Webhook resource for managing Zai webhooks
@@ -130,6 +133,102 @@ module ZaiPayment
130
133
  client.delete("/webhooks/#{webhook_id}")
131
134
  end
132
135
 
136
+ # Create a secret key for webhook signature verification
137
+ #
138
+ # @param secret_key [String] the secret key to use for HMAC signature generation
139
+ # Must be ASCII characters and at least 32 bytes in size
140
+ # @return [Response] the API response
141
+ #
142
+ # @example
143
+ # webhooks = ZaiPayment::Resources::Webhook.new
144
+ # secret_key = SecureRandom.alphanumeric(32)
145
+ # response = webhooks.create_secret_key(secret_key: secret_key)
146
+ #
147
+ # @see https://developer.hellozai.com/reference/createsecretkey
148
+ # @see https://developer.hellozai.com/docs/verify-webhook-signatures
149
+ def create_secret_key(secret_key:)
150
+ validate_presence!(secret_key, 'secret_key')
151
+ validate_secret_key!(secret_key)
152
+
153
+ body = { secret_key: secret_key }
154
+ client.post('/webhooks/secret_key', body: body)
155
+ end
156
+
157
+ # Verify webhook signature
158
+ #
159
+ # This method verifies that a webhook request came from Zai by validating
160
+ # the HMAC SHA256 signature in the Webhooks-signature header.
161
+ #
162
+ # @param payload [String] the raw request body (JSON string)
163
+ # @param signature_header [String] the Webhooks-signature header value
164
+ # @param secret_key [String] your secret key used for signature generation
165
+ # @param tolerance [Integer] maximum age of webhook in seconds (default: 300 = 5 minutes)
166
+ # @return [Boolean] true if signature is valid and within tolerance
167
+ # @raise [Errors::ValidationError] if signature is invalid or timestamp is outside tolerance
168
+ #
169
+ # @example
170
+ # # In your webhook endpoint (e.g., Rails controller)
171
+ # def webhook
172
+ # payload = request.body.read
173
+ # signature_header = request.headers['Webhooks-signature']
174
+ # secret_key = ENV['ZAI_WEBHOOK_SECRET']
175
+ #
176
+ # if ZaiPayment.webhooks.verify_signature(
177
+ # payload: payload,
178
+ # signature_header: signature_header,
179
+ # secret_key: secret_key
180
+ # )
181
+ # # Process webhook
182
+ # render json: { status: 'success' }
183
+ # else
184
+ # render json: { error: 'Invalid signature' }, status: :unauthorized
185
+ # end
186
+ # end
187
+ #
188
+ # @see https://developer.hellozai.com/docs/verify-webhook-signatures
189
+ def verify_signature(payload:, signature_header:, secret_key:, tolerance: 300)
190
+ validate_presence!(payload, 'payload')
191
+ validate_presence!(signature_header, 'signature_header')
192
+ validate_presence!(secret_key, 'secret_key')
193
+
194
+ # Extract timestamp and signature from header
195
+ timestamp, signatures = parse_signature_header(signature_header)
196
+
197
+ # Verify timestamp is within tolerance (prevent replay attacks)
198
+ verify_timestamp!(timestamp, tolerance)
199
+
200
+ # Generate expected signature
201
+ expected_signature = generate_signature(payload, secret_key, timestamp)
202
+
203
+ # Compare signatures using constant-time comparison
204
+ signatures.any? { |sig| secure_compare(expected_signature, sig) }
205
+ end
206
+
207
+ # Generate a signature for webhook verification
208
+ #
209
+ # This is a utility method that can be used for testing or generating
210
+ # signatures for webhook simulation.
211
+ #
212
+ # @param payload [String] the request body (JSON string)
213
+ # @param secret_key [String] the secret key
214
+ # @param timestamp [Integer] the Unix timestamp (defaults to current time)
215
+ # @return [String] the base64url-encoded HMAC SHA256 signature
216
+ #
217
+ # @example
218
+ # webhooks = ZaiPayment::Resources::Webhook.new
219
+ # signature = webhooks.generate_signature(
220
+ # '{"event": "status_updated"}',
221
+ # 'my_secret_key'
222
+ # )
223
+ #
224
+ # @see https://developer.hellozai.com/docs/verify-webhook-signatures
225
+ def generate_signature(payload, secret_key, timestamp = Time.now.to_i)
226
+ signed_payload = "#{timestamp}.#{payload}"
227
+ digest = OpenSSL::Digest.new('sha256')
228
+ hash = OpenSSL::HMAC.digest(digest, secret_key, signed_payload)
229
+ Base64.urlsafe_encode64(hash, padding: false)
230
+ end
231
+
133
232
  private
134
233
 
135
234
  def validate_id!(value, field_name)
@@ -152,6 +251,81 @@ module ZaiPayment
152
251
  rescue URI::InvalidURIError
153
252
  raise Errors::ValidationError, 'url must be a valid URL'
154
253
  end
254
+
255
+ def validate_secret_key!(secret_key)
256
+ # Check if it's ASCII
257
+ raise Errors::ValidationError, 'secret_key must contain only ASCII characters' unless secret_key.ascii_only?
258
+
259
+ # Check minimum length (32 bytes)
260
+ return unless secret_key.bytesize < 32
261
+
262
+ raise Errors::ValidationError, 'secret_key must be at least 32 bytes in size'
263
+ end
264
+
265
+ def parse_signature_header(header)
266
+ # Format: "t=1257894000,v=signature1,v=signature2"
267
+ parts = header.split(',').map(&:strip)
268
+
269
+ timestamp, signatures = extract_timestamp_and_signatures(parts)
270
+
271
+ validate_timestamp_presence!(timestamp)
272
+ validate_signatures_presence!(signatures)
273
+
274
+ [timestamp, signatures]
275
+ end
276
+
277
+ def extract_timestamp_and_signatures(parts)
278
+ timestamp = nil
279
+ signatures = []
280
+
281
+ parts.each do |part|
282
+ key, value = part.split('=', 2)
283
+ case key
284
+ when 't'
285
+ timestamp = value.to_i
286
+ when 'v'
287
+ signatures << value
288
+ end
289
+ end
290
+
291
+ [timestamp, signatures]
292
+ end
293
+
294
+ def validate_timestamp_presence!(timestamp)
295
+ return unless timestamp.nil? || timestamp.zero?
296
+
297
+ raise Errors::ValidationError, 'Invalid signature header: missing or invalid timestamp'
298
+ end
299
+
300
+ def validate_signatures_presence!(signatures)
301
+ raise Errors::ValidationError, 'Invalid signature header: missing signature' if signatures.empty?
302
+ end
303
+
304
+ def verify_timestamp!(timestamp, tolerance)
305
+ current_time = Time.now.to_i
306
+ time_diff = (current_time - timestamp).abs
307
+
308
+ return unless time_diff > tolerance
309
+
310
+ raise Errors::ValidationError,
311
+ "Webhook timestamp is outside tolerance (#{time_diff}s vs #{tolerance}s max). " \
312
+ 'This may be a replay attack.'
313
+ end
314
+
315
+ # Constant-time string comparison to prevent timing attacks
316
+ # Uses OpenSSL's secure_compare if available, otherwise falls back to manual comparison
317
+ def secure_compare(str_a, str_b)
318
+ return false unless str_a.bytesize == str_b.bytesize
319
+
320
+ if defined?(OpenSSL.fixed_length_secure_compare)
321
+ OpenSSL.fixed_length_secure_compare(str_a, str_b)
322
+ else
323
+ # Fallback for older Ruby versions
324
+ result = 0
325
+ str_a.bytes.zip(str_b.bytes) { |x, y| result |= x ^ y }
326
+ result.zero?
327
+ end
328
+ end
155
329
  end
156
330
  end
157
331
  end
@@ -31,7 +31,7 @@ module ZaiPayment
31
31
 
32
32
  # Get the data from the response body
33
33
  def data
34
- body.is_a?(Hash) ? body['webhooks'] || body : body
34
+ body.is_a?(Hash) ? body['webhooks'] || body['users'] || body : body
35
35
  end
36
36
 
37
37
  # Get pagination or metadata info
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ZaiPayment
4
- VERSION = '1.1.0'
4
+ VERSION = '1.3.0'
5
5
  end
data/lib/zai_payment.rb CHANGED
@@ -11,6 +11,7 @@ require_relative 'zai_payment/auth/token_stores/memory_store'
11
11
  require_relative 'zai_payment/client'
12
12
  require_relative 'zai_payment/response'
13
13
  require_relative 'zai_payment/resources/webhook'
14
+ require_relative 'zai_payment/resources/user'
14
15
 
15
16
  module ZaiPayment
16
17
  class << self
@@ -39,5 +40,10 @@ module ZaiPayment
39
40
  def webhooks
40
41
  @webhooks ||= Resources::Webhook.new
41
42
  end
43
+
44
+ # @return [ZaiPayment::Resources::User] user resource instance
45
+ def users
46
+ @users ||= Resources::User.new(client: Client.new(base_endpoint: :core_base))
47
+ end
42
48
  end
43
49
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zai_payment
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eddy Jaga
@@ -9,6 +9,20 @@ bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: base64
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: 0.3.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: 0.3.0
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: faraday
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -23,6 +37,20 @@ dependencies:
23
37
  - - "~>"
24
38
  - !ruby/object:Gem::Version
25
39
  version: '2.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: openssl
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.3'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.3'
26
54
  description: A Ruby gem for integrating with Zai payment platform APIs.
27
55
  email:
28
56
  - eddy.jaga@sentia.com.au
@@ -32,12 +60,24 @@ extra_rdoc_files: []
32
60
  files:
33
61
  - CHANGELOG.md
34
62
  - CODE_OF_CONDUCT.md
63
+ - CONTRIBUTING.md
35
64
  - IMPLEMENTATION.md
65
+ - IMPLEMENTATION_SUMMARY.md
36
66
  - LICENSE.txt
37
67
  - README.md
38
68
  - Rakefile
69
+ - badges/.gitkeep
70
+ - badges/coverage.json
39
71
  - docs/ARCHITECTURE.md
72
+ - docs/AUTHENTICATION.md
73
+ - docs/README.md
74
+ - docs/USERS.md
75
+ - docs/USER_ID_FIELD.md
76
+ - docs/USER_QUICK_REFERENCE.md
40
77
  - docs/WEBHOOKS.md
78
+ - docs/WEBHOOK_SECURITY_QUICKSTART.md
79
+ - docs/WEBHOOK_SIGNATURE.md
80
+ - examples/users.md
41
81
  - examples/webhooks.md
42
82
  - lib/zai_payment.rb
43
83
  - lib/zai_payment/auth/token_provider.rb
@@ -46,6 +86,7 @@ files:
46
86
  - lib/zai_payment/client.rb
47
87
  - lib/zai_payment/config.rb
48
88
  - lib/zai_payment/errors.rb
89
+ - lib/zai_payment/resources/user.rb
49
90
  - lib/zai_payment/resources/webhook.rb
50
91
  - lib/zai_payment/response.rb
51
92
  - lib/zai_payment/version.rb