zai_payment 2.0.2 → 2.2.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 +4 -4
- data/badges/coverage.json +1 -1
- data/changelog.md +75 -0
- data/docs/readme.md +55 -25
- data/docs/token_auths.md +523 -0
- data/docs/user_id_field.md +1 -1
- data/docs/users.md +303 -6
- data/examples/rails_card_payment.md +716 -0
- data/examples/token_auths.md +687 -0
- data/lib/zai_payment/resources/token_auth.rb +75 -0
- data/lib/zai_payment/resources/user.rb +131 -3
- data/lib/zai_payment/response.rb +10 -4
- data/lib/zai_payment/version.rb +1 -1
- data/lib/zai_payment.rb +6 -0
- data/readme.md +55 -0
- data/token_auth_implementation_summary.md +249 -0
- metadata +7 -2
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ZaiPayment
|
|
4
|
+
module Resources
|
|
5
|
+
# TokenAuth resource for generating tokens for bank or card accounts
|
|
6
|
+
#
|
|
7
|
+
# @see https://developer.hellozai.com/reference/generatetoken
|
|
8
|
+
class TokenAuth
|
|
9
|
+
attr_reader :client
|
|
10
|
+
|
|
11
|
+
# Token types
|
|
12
|
+
TOKEN_TYPE_BANK = 'bank'
|
|
13
|
+
TOKEN_TYPE_CARD = 'card'
|
|
14
|
+
|
|
15
|
+
# Valid token types
|
|
16
|
+
VALID_TOKEN_TYPES = [TOKEN_TYPE_BANK, TOKEN_TYPE_CARD].freeze
|
|
17
|
+
|
|
18
|
+
def initialize(client: nil)
|
|
19
|
+
@client = client || Client.new(base_endpoint: :core_base)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Generate a token for bank or card account
|
|
23
|
+
#
|
|
24
|
+
# Create a token, either for a bank or a card account, that can be used with the
|
|
25
|
+
# PromisePay.js package to securely send Assembly credit card details.
|
|
26
|
+
#
|
|
27
|
+
# @param user_id [String] (Required) Buyer or Seller ID (already created)
|
|
28
|
+
# @param token_type [String] Token type ID, use 'bank' or 'card' (default: 'bank')
|
|
29
|
+
# @return [Response] the API response containing generated token
|
|
30
|
+
#
|
|
31
|
+
# @example Generate a bank token
|
|
32
|
+
# token_auth = ZaiPayment::Resources::TokenAuth.new
|
|
33
|
+
# response = token_auth.generate(
|
|
34
|
+
# user_id: "seller-68611249",
|
|
35
|
+
# token_type: "bank"
|
|
36
|
+
# )
|
|
37
|
+
# response.data # => {"token_auth" => {"token" => "...", "user_id" => "...", ...}}
|
|
38
|
+
#
|
|
39
|
+
# @example Generate a card token
|
|
40
|
+
# token_auth = ZaiPayment::Resources::TokenAuth.new
|
|
41
|
+
# response = token_auth.generate(
|
|
42
|
+
# user_id: "buyer-12345",
|
|
43
|
+
# token_type: "card"
|
|
44
|
+
# )
|
|
45
|
+
#
|
|
46
|
+
# @see https://developer.hellozai.com/reference/generatetoken
|
|
47
|
+
def generate(user_id:, token_type: TOKEN_TYPE_BANK)
|
|
48
|
+
validate_user_id!(user_id)
|
|
49
|
+
validate_token_type!(token_type)
|
|
50
|
+
|
|
51
|
+
body = {
|
|
52
|
+
token_type: token_type,
|
|
53
|
+
user_id: user_id
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
client.post('/token_auths', body: body)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def validate_user_id!(user_id)
|
|
62
|
+
return unless user_id.nil? || user_id.to_s.strip.empty?
|
|
63
|
+
|
|
64
|
+
raise Errors::ValidationError, 'user_id is required and cannot be blank'
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def validate_token_type!(token_type)
|
|
68
|
+
return if VALID_TOKEN_TYPES.include?(token_type.to_s.downcase)
|
|
69
|
+
|
|
70
|
+
raise Errors::ValidationError,
|
|
71
|
+
"token_type must be one of: #{VALID_TOKEN_TYPES.join(', ')}"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -107,7 +107,7 @@ module ZaiPayment
|
|
|
107
107
|
# @option attributes [String] :id Optional unique ID for the user. If not provided,
|
|
108
108
|
# Zai will generate one automatically. Cannot contain '.' character.
|
|
109
109
|
# Useful for mapping to your existing system's user IDs.
|
|
110
|
-
# @option attributes [String] :user_type User type ('payin' or 'payout').
|
|
110
|
+
# @option attributes [String] :user_type (Required) User type ('payin' or 'payout').
|
|
111
111
|
# This determines which fields are required.
|
|
112
112
|
# @option attributes [String] :email (Required) user's email address
|
|
113
113
|
# @option attributes [String] :first_name (Required) user's first name
|
|
@@ -264,6 +264,134 @@ module ZaiPayment
|
|
|
264
264
|
client.patch("/users/#{user_id}", body: body)
|
|
265
265
|
end
|
|
266
266
|
|
|
267
|
+
# Show the user's wallet account
|
|
268
|
+
#
|
|
269
|
+
# @param user_id [String] the user ID
|
|
270
|
+
# @return [Response] the API response containing wallet account details
|
|
271
|
+
#
|
|
272
|
+
# @example
|
|
273
|
+
# users = ZaiPayment::Resources::User.new
|
|
274
|
+
# response = users.wallet_account("user_id")
|
|
275
|
+
# response.data # => {"id" => "...", "balance" => ..., ...}
|
|
276
|
+
#
|
|
277
|
+
# @see https://developer.hellozai.com/reference/showuserwalletaccounts
|
|
278
|
+
def wallet_account(user_id)
|
|
279
|
+
validate_id!(user_id, 'user_id')
|
|
280
|
+
client.get("/users/#{user_id}/wallet_accounts")
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# List items associated with the user
|
|
284
|
+
#
|
|
285
|
+
# @param user_id [String] the user ID
|
|
286
|
+
# @param limit [Integer] number of records to return (default: 10, max: 200)
|
|
287
|
+
# @param offset [Integer] number of records to skip (default: 0)
|
|
288
|
+
# @return [Response] the API response containing items array
|
|
289
|
+
#
|
|
290
|
+
# @example
|
|
291
|
+
# users = ZaiPayment::Resources::User.new
|
|
292
|
+
# response = users.items("user_id")
|
|
293
|
+
# response.data # => [{"id" => "...", "name" => "..."}, ...]
|
|
294
|
+
#
|
|
295
|
+
# @example with custom pagination
|
|
296
|
+
# response = users.items("user_id", limit: 50, offset: 10)
|
|
297
|
+
#
|
|
298
|
+
# @see https://developer.hellozai.com/reference/listuseritems
|
|
299
|
+
def items(user_id, limit: 10, offset: 0)
|
|
300
|
+
validate_id!(user_id, 'user_id')
|
|
301
|
+
params = {
|
|
302
|
+
limit: limit,
|
|
303
|
+
offset: offset
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
client.get("/users/#{user_id}/items", params: params)
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# Set the user's disbursement account
|
|
310
|
+
#
|
|
311
|
+
# @param user_id [String] the user ID
|
|
312
|
+
# @param account_id [String] the bank account ID to use for disbursements
|
|
313
|
+
# @return [Response] the API response
|
|
314
|
+
#
|
|
315
|
+
# @example
|
|
316
|
+
# users = ZaiPayment::Resources::User.new
|
|
317
|
+
# response = users.set_disbursement_account("user_id", "account_id")
|
|
318
|
+
#
|
|
319
|
+
# @see https://developer.hellozai.com/reference/setuserdisbursementaccount
|
|
320
|
+
def set_disbursement_account(user_id, account_id)
|
|
321
|
+
validate_id!(user_id, 'user_id')
|
|
322
|
+
validate_id!(account_id, 'account_id')
|
|
323
|
+
|
|
324
|
+
body = { account_id: account_id }
|
|
325
|
+
client.patch("/users/#{user_id}/disbursement_account", body: body)
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# Show the user's bank account
|
|
329
|
+
#
|
|
330
|
+
# @param user_id [String] the user ID
|
|
331
|
+
# @return [Response] the API response containing bank account details
|
|
332
|
+
#
|
|
333
|
+
# @example
|
|
334
|
+
# users = ZaiPayment::Resources::User.new
|
|
335
|
+
# response = users.bank_account("user_id")
|
|
336
|
+
# response.data # => {"id" => "...", "account_name" => "...", ...}
|
|
337
|
+
#
|
|
338
|
+
# @see https://developer.hellozai.com/reference/showuserbankaccount
|
|
339
|
+
def bank_account(user_id)
|
|
340
|
+
validate_id!(user_id, 'user_id')
|
|
341
|
+
client.get("/users/#{user_id}/bank_accounts")
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Verify user (Prelive Only)
|
|
345
|
+
# Sets a user's verification state to approved on pre-live environment
|
|
346
|
+
#
|
|
347
|
+
# @param user_id [String] the user ID
|
|
348
|
+
# @return [Response] the API response
|
|
349
|
+
#
|
|
350
|
+
# @example
|
|
351
|
+
# users = ZaiPayment::Resources::User.new
|
|
352
|
+
# response = users.verify("user_id")
|
|
353
|
+
#
|
|
354
|
+
# @note This endpoint only works in the pre-live environment.
|
|
355
|
+
# The user verification workflow holds for all users in production.
|
|
356
|
+
#
|
|
357
|
+
# @see https://developer.hellozai.com/reference/verifyuser
|
|
358
|
+
def verify(user_id)
|
|
359
|
+
validate_id!(user_id, 'user_id')
|
|
360
|
+
client.patch("/users/#{user_id}/identity_verified")
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
# Show the user's card account
|
|
364
|
+
#
|
|
365
|
+
# @param user_id [String] the user ID
|
|
366
|
+
# @return [Response] the API response containing card account details
|
|
367
|
+
#
|
|
368
|
+
# @example
|
|
369
|
+
# users = ZaiPayment::Resources::User.new
|
|
370
|
+
# response = users.card_account("user_id")
|
|
371
|
+
# response.data # => {"id" => "...", "card" => {...}, ...}
|
|
372
|
+
#
|
|
373
|
+
# @see https://developer.hellozai.com/reference/showusercardaccount
|
|
374
|
+
def card_account(user_id)
|
|
375
|
+
validate_id!(user_id, 'user_id')
|
|
376
|
+
client.get("/users/#{user_id}/card_accounts")
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
# List BPay accounts associated with the user
|
|
380
|
+
#
|
|
381
|
+
# @param user_id [String] the user ID
|
|
382
|
+
# @return [Response] the API response containing BPay accounts array
|
|
383
|
+
#
|
|
384
|
+
# @example
|
|
385
|
+
# users = ZaiPayment::Resources::User.new
|
|
386
|
+
# response = users.bpay_accounts("user_id")
|
|
387
|
+
# response.data # => [{"id" => "...", "biller_code" => "..."}, ...]
|
|
388
|
+
#
|
|
389
|
+
# @see https://developer.hellozai.com/reference/listuserbpayaccounts
|
|
390
|
+
def bpay_accounts(user_id)
|
|
391
|
+
validate_id!(user_id, 'user_id')
|
|
392
|
+
client.get("/users/#{user_id}/bpay_accounts")
|
|
393
|
+
end
|
|
394
|
+
|
|
267
395
|
private
|
|
268
396
|
|
|
269
397
|
def validate_id!(value, field_name)
|
|
@@ -280,7 +408,7 @@ module ZaiPayment
|
|
|
280
408
|
|
|
281
409
|
def validate_create_attributes!(attributes) # rubocop:disable Metrics/AbcSize
|
|
282
410
|
validate_required_attributes!(attributes)
|
|
283
|
-
validate_user_type!(attributes[:user_type])
|
|
411
|
+
validate_user_type!(attributes[:user_type])
|
|
284
412
|
validate_email!(attributes[:email])
|
|
285
413
|
validate_country!(attributes[:country])
|
|
286
414
|
validate_dob!(attributes[:dob]) if attributes[:dob]
|
|
@@ -290,7 +418,7 @@ module ZaiPayment
|
|
|
290
418
|
|
|
291
419
|
def validate_required_attributes!(attributes)
|
|
292
420
|
# Base required fields for all users
|
|
293
|
-
required_fields = %i[email first_name last_name country]
|
|
421
|
+
required_fields = %i[email first_name last_name country user_type]
|
|
294
422
|
|
|
295
423
|
# Additional required fields for payout users
|
|
296
424
|
user_type = attributes[:user_type]&.to_s&.downcase
|
data/lib/zai_payment/response.rb
CHANGED
|
@@ -5,6 +5,11 @@ module ZaiPayment
|
|
|
5
5
|
class Response
|
|
6
6
|
attr_reader :status, :body, :headers, :raw_response
|
|
7
7
|
|
|
8
|
+
RESPONSE_DATA_KEYS = %w[
|
|
9
|
+
webhooks users items fees transactions
|
|
10
|
+
batch_transactions bpay_accounts bank_accounts card_accounts
|
|
11
|
+
].freeze
|
|
12
|
+
|
|
8
13
|
def initialize(faraday_response)
|
|
9
14
|
@raw_response = faraday_response
|
|
10
15
|
@status = faraday_response.status
|
|
@@ -30,14 +35,15 @@ module ZaiPayment
|
|
|
30
35
|
end
|
|
31
36
|
|
|
32
37
|
# Get the data from the response body
|
|
33
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
34
38
|
def data
|
|
35
39
|
return body unless body.is_a?(Hash)
|
|
36
40
|
|
|
37
|
-
|
|
38
|
-
body[
|
|
41
|
+
RESPONSE_DATA_KEYS.each do |key|
|
|
42
|
+
return body[key] if body[key]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
body
|
|
39
46
|
end
|
|
40
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
41
47
|
|
|
42
48
|
# Get pagination or metadata info
|
|
43
49
|
def meta
|
data/lib/zai_payment/version.rb
CHANGED
data/lib/zai_payment.rb
CHANGED
|
@@ -13,6 +13,7 @@ require_relative 'zai_payment/response'
|
|
|
13
13
|
require_relative 'zai_payment/resources/webhook'
|
|
14
14
|
require_relative 'zai_payment/resources/user'
|
|
15
15
|
require_relative 'zai_payment/resources/item'
|
|
16
|
+
require_relative 'zai_payment/resources/token_auth'
|
|
16
17
|
|
|
17
18
|
module ZaiPayment
|
|
18
19
|
class << self
|
|
@@ -51,5 +52,10 @@ module ZaiPayment
|
|
|
51
52
|
def items
|
|
52
53
|
@items ||= Resources::Item.new(client: Client.new(base_endpoint: :core_base))
|
|
53
54
|
end
|
|
55
|
+
|
|
56
|
+
# @return [ZaiPayment::Resources::TokenAuth] token_auth resource instance
|
|
57
|
+
def token_auths
|
|
58
|
+
@token_auths ||= Resources::TokenAuth.new(client: Client.new(base_endpoint: :core_base))
|
|
59
|
+
end
|
|
54
60
|
end
|
|
55
61
|
end
|
data/readme.md
CHANGED
|
@@ -21,6 +21,7 @@ A lightweight and extensible Ruby client for the **Zai (AssemblyPay)** API — s
|
|
|
21
21
|
- 🧠 **Smart Token Caching** - Auto-refresh before expiration, thread-safe storage
|
|
22
22
|
- 👥 **User Management** - Create and manage payin (buyers) & payout (sellers) users
|
|
23
23
|
- 📦 **Item Management** - Full CRUD for transactions/payments between buyers and sellers
|
|
24
|
+
- 🎫 **Token Auth** - Generate secure tokens for bank and card account data collection
|
|
24
25
|
- 🪝 **Webhooks** - Full CRUD + secure signature verification (HMAC SHA256)
|
|
25
26
|
- ⚙️ **Environment-Aware** - Seamless Pre-live / Production switching
|
|
26
27
|
- 🧱 **Modular & Extensible** - Clean resource-based architecture
|
|
@@ -87,6 +88,7 @@ Manage payin (buyer) and payout (seller/merchant) users:
|
|
|
87
88
|
```ruby
|
|
88
89
|
# Create a payin user (buyer)
|
|
89
90
|
response = ZaiPayment.users.create(
|
|
91
|
+
user_type: 'payin',
|
|
90
92
|
email: 'buyer@example.com',
|
|
91
93
|
first_name: 'John',
|
|
92
94
|
last_name: 'Doe',
|
|
@@ -96,6 +98,7 @@ response = ZaiPayment.users.create(
|
|
|
96
98
|
|
|
97
99
|
# Create a payout user (seller/merchant)
|
|
98
100
|
response = ZaiPayment.users.create(
|
|
101
|
+
user_type: 'payout',
|
|
99
102
|
email: 'seller@example.com',
|
|
100
103
|
first_name: 'Jane',
|
|
101
104
|
last_name: 'Smith',
|
|
@@ -109,6 +112,7 @@ response = ZaiPayment.users.create(
|
|
|
109
112
|
|
|
110
113
|
# Create a business user with company details
|
|
111
114
|
response = ZaiPayment.users.create(
|
|
115
|
+
user_type: 'payout',
|
|
112
116
|
email: 'director@company.com',
|
|
113
117
|
first_name: 'John',
|
|
114
118
|
last_name: 'Director',
|
|
@@ -133,6 +137,27 @@ response = ZaiPayment.users.show('user_id')
|
|
|
133
137
|
|
|
134
138
|
# Update user
|
|
135
139
|
response = ZaiPayment.users.update('user_id', mobile: '+9876543210')
|
|
140
|
+
|
|
141
|
+
# Show user wallet account
|
|
142
|
+
response = ZaiPayment.users.wallet_account('user_id')
|
|
143
|
+
|
|
144
|
+
# List user items with pagination
|
|
145
|
+
response = ZaiPayment.users.items('user_id', limit: 50, offset: 10)
|
|
146
|
+
|
|
147
|
+
# Set user disbursement account
|
|
148
|
+
response = ZaiPayment.users.set_disbursement_account('user_id', 'bank_account_id')
|
|
149
|
+
|
|
150
|
+
# Show user bank account
|
|
151
|
+
response = ZaiPayment.users.bank_account('user_id')
|
|
152
|
+
|
|
153
|
+
# Verify user (prelive only)
|
|
154
|
+
response = ZaiPayment.users.verify('user_id')
|
|
155
|
+
|
|
156
|
+
# Show user card account
|
|
157
|
+
response = ZaiPayment.users.card_account('user_id')
|
|
158
|
+
|
|
159
|
+
# List user's BPay accounts
|
|
160
|
+
response = ZaiPayment.users.bpay_accounts('user_id')
|
|
136
161
|
```
|
|
137
162
|
|
|
138
163
|
**📚 Documentation:**
|
|
@@ -183,6 +208,34 @@ response = ZaiPayment.items.list_transactions('item_id')
|
|
|
183
208
|
- 💡 [Item Examples](examples/items.md) - Real-world usage patterns and complete workflows
|
|
184
209
|
- 🔗 [Zai: Items API Reference](https://developer.hellozai.com/reference/listitems)
|
|
185
210
|
|
|
211
|
+
### Token Auth
|
|
212
|
+
|
|
213
|
+
Generate secure tokens for collecting bank and card account information:
|
|
214
|
+
|
|
215
|
+
```ruby
|
|
216
|
+
# Generate a bank token (for collecting bank account details)
|
|
217
|
+
response = ZaiPayment.token_auths.generate(
|
|
218
|
+
user_id: "seller-68611249",
|
|
219
|
+
token_type: "bank"
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
token = response.data['token_auth']['token']
|
|
223
|
+
# Use this token with PromisePay.js on the frontend
|
|
224
|
+
|
|
225
|
+
# Generate a card token (for collecting credit card details)
|
|
226
|
+
response = ZaiPayment.token_auths.generate(
|
|
227
|
+
user_id: "buyer-12345",
|
|
228
|
+
token_type: "card"
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
token = response.data['token_auth']['token']
|
|
232
|
+
# Use this token with PromisePay.js on the frontend
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**📚 Documentation:**
|
|
236
|
+
- 💡 [Token Auth Examples](examples/token_auths.md) - Complete integration guide with PromisePay.js
|
|
237
|
+
- 🔗 [Zai: Generate Token API Reference](https://developer.hellozai.com/reference/generatetoken)
|
|
238
|
+
|
|
186
239
|
### Webhooks
|
|
187
240
|
|
|
188
241
|
Manage webhook endpoints:
|
|
@@ -243,6 +296,7 @@ end
|
|
|
243
296
|
| ✅ Webhooks | CRUD for webhook endpoints | Done |
|
|
244
297
|
| ✅ Users | Manage PayIn / PayOut users | Done |
|
|
245
298
|
| ✅ Items | Transactions/payments (CRUD) | Done |
|
|
299
|
+
| ✅ Token Auth | Generate bank/card tokens | Done |
|
|
246
300
|
| 💳 Payments | Single and recurring payments | 🚧 In progress |
|
|
247
301
|
| 🏦 Virtual Accounts (VA / PIPU) | Manage virtual accounts & PayTo | ⏳ Planned |
|
|
248
302
|
| 💼 Wallets | Create and manage wallet accounts | ⏳ Planned |
|
|
@@ -307,6 +361,7 @@ Everyone interacting in the ZaiPayment project's codebases, issue trackers, chat
|
|
|
307
361
|
### Examples & Patterns
|
|
308
362
|
- [User Examples](examples/users.md) - Real-world user management patterns
|
|
309
363
|
- [Item Examples](examples/items.md) - Transaction and payment workflows
|
|
364
|
+
- [Token Auth Examples](examples/token_auths.md) - Secure token generation and integration
|
|
310
365
|
- [Webhook Examples](examples/webhooks.md) - Webhook integration patterns
|
|
311
366
|
|
|
312
367
|
### Technical Guides
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# Token Auth API Implementation Summary
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Successfully implemented the **Generate Token** endpoint from the Zai API (https://developer.hellozai.com/reference/generatetoken) to enable secure bank and card account data collection.
|
|
6
|
+
|
|
7
|
+
## What Was Implemented
|
|
8
|
+
|
|
9
|
+
### 1. Core Resource Implementation
|
|
10
|
+
|
|
11
|
+
**File:** `lib/zai_payment/resources/token_auth.rb`
|
|
12
|
+
|
|
13
|
+
- Created `TokenAuth` resource class following the project's resource pattern
|
|
14
|
+
- Implemented `generate(user_id:, token_type:)` method
|
|
15
|
+
- Added token type validation (bank or card)
|
|
16
|
+
- Added user ID validation
|
|
17
|
+
- Support for case-insensitive token types
|
|
18
|
+
- Default token type: 'bank'
|
|
19
|
+
|
|
20
|
+
**Key Features:**
|
|
21
|
+
```ruby
|
|
22
|
+
# Generate a bank token (default)
|
|
23
|
+
ZaiPayment.token_auths.generate(user_id: "seller-123")
|
|
24
|
+
|
|
25
|
+
# Generate a card token
|
|
26
|
+
ZaiPayment.token_auths.generate(user_id: "buyer-123", token_type: "card")
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Module Integration
|
|
30
|
+
|
|
31
|
+
**File:** `lib/zai_payment.rb`
|
|
32
|
+
|
|
33
|
+
- Added `require_relative` for token_auth resource
|
|
34
|
+
- Added `token_auths` accessor method
|
|
35
|
+
- Configured to use `core_base` endpoint (https://test.api.promisepay.com)
|
|
36
|
+
|
|
37
|
+
### 3. Test Suite
|
|
38
|
+
|
|
39
|
+
**File:** `spec/zai_payment/resources/token_auth_spec.rb`
|
|
40
|
+
|
|
41
|
+
- 15 comprehensive test cases covering:
|
|
42
|
+
- Bank token generation
|
|
43
|
+
- Card token generation
|
|
44
|
+
- Default token type behavior
|
|
45
|
+
- Validation errors (nil, empty, whitespace, invalid types)
|
|
46
|
+
- Case-insensitive token types
|
|
47
|
+
- Client initialization
|
|
48
|
+
- Constants verification
|
|
49
|
+
- All tests passing with 95.22% line coverage
|
|
50
|
+
- Follows project's testing pattern using Faraday test stubs
|
|
51
|
+
- RuboCop compliant
|
|
52
|
+
|
|
53
|
+
### 4. Documentation
|
|
54
|
+
|
|
55
|
+
**File:** `examples/token_auths.md` (600+ lines)
|
|
56
|
+
|
|
57
|
+
Comprehensive examples including:
|
|
58
|
+
- Basic usage patterns
|
|
59
|
+
- Bank token collection workflows
|
|
60
|
+
- Card token collection workflows
|
|
61
|
+
- Rails controller integration
|
|
62
|
+
- Service object pattern
|
|
63
|
+
- Frontend integration with PromisePay.js
|
|
64
|
+
- Complete payment flow examples
|
|
65
|
+
- Error handling strategies
|
|
66
|
+
- Retry logic with exponential backoff
|
|
67
|
+
- Security best practices:
|
|
68
|
+
- Token expiry management
|
|
69
|
+
- Audit logging
|
|
70
|
+
- Rate limiting protection
|
|
71
|
+
|
|
72
|
+
**File:** `docs/token_auths.md` (500+ lines)
|
|
73
|
+
|
|
74
|
+
Complete technical guide covering:
|
|
75
|
+
- When to use Token Auth
|
|
76
|
+
- How it works (flow diagram)
|
|
77
|
+
- API methods reference
|
|
78
|
+
- Token types (bank vs card) with use cases
|
|
79
|
+
- Security considerations (PCI compliance, token lifecycle)
|
|
80
|
+
- Integration guide (backend + frontend)
|
|
81
|
+
- Error handling patterns
|
|
82
|
+
- Best practices with code examples
|
|
83
|
+
- Related resources and API references
|
|
84
|
+
|
|
85
|
+
### 5. Version Updates
|
|
86
|
+
|
|
87
|
+
**File:** `lib/zai_payment/version.rb`
|
|
88
|
+
|
|
89
|
+
- Updated version from `2.0.2` to `2.1.0`
|
|
90
|
+
- Follows semantic versioning (minor version bump for new feature)
|
|
91
|
+
|
|
92
|
+
### 6. Changelog
|
|
93
|
+
|
|
94
|
+
**File:** `changelog.md`
|
|
95
|
+
|
|
96
|
+
Added comprehensive release notes for version 2.1.0:
|
|
97
|
+
- Feature description
|
|
98
|
+
- API methods
|
|
99
|
+
- Documentation additions
|
|
100
|
+
- Testing coverage
|
|
101
|
+
- Link to full changelog
|
|
102
|
+
|
|
103
|
+
### 7. README Updates
|
|
104
|
+
|
|
105
|
+
**File:** `readme.md`
|
|
106
|
+
|
|
107
|
+
- Added Token Auth to features list (🎫 emoji)
|
|
108
|
+
- Added Token Auth section with quick examples
|
|
109
|
+
- Updated roadmap (marked Token Auth as Done ✅)
|
|
110
|
+
- Added documentation links in Examples & Patterns section
|
|
111
|
+
|
|
112
|
+
### 8. Documentation Index
|
|
113
|
+
|
|
114
|
+
**File:** `docs/readme.md`
|
|
115
|
+
|
|
116
|
+
- Added token_auths.md to Architecture & Design section
|
|
117
|
+
- Added Token Auth Examples to Examples section
|
|
118
|
+
- Added Token Auth to Quick Links with guide, examples, and API reference
|
|
119
|
+
- Updated documentation structure tree
|
|
120
|
+
- Added tips for collecting payment data
|
|
121
|
+
|
|
122
|
+
## API Endpoint
|
|
123
|
+
|
|
124
|
+
**POST** `https://test.api.promisepay.com/token_auths`
|
|
125
|
+
|
|
126
|
+
**Request Body:**
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"token_type": "bank", // or "card"
|
|
130
|
+
"user_id": "seller-68611249"
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Response:**
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"token_auth": {
|
|
138
|
+
"token": "tok_bank_abc123...",
|
|
139
|
+
"user_id": "seller-68611249",
|
|
140
|
+
"token_type": "bank",
|
|
141
|
+
"created_at": "2025-10-24T12:00:00Z",
|
|
142
|
+
"expires_at": "2025-10-24T13:00:00Z"
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Usage Example
|
|
148
|
+
|
|
149
|
+
```ruby
|
|
150
|
+
# Configure the gem
|
|
151
|
+
ZaiPayment.configure do |c|
|
|
152
|
+
c.environment = :prelive
|
|
153
|
+
c.client_id = ENV['ZAI_CLIENT_ID']
|
|
154
|
+
c.client_secret = ENV['ZAI_CLIENT_SECRET']
|
|
155
|
+
c.scope = ENV['ZAI_OAUTH_SCOPE']
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Generate a card token for buyer
|
|
159
|
+
response = ZaiPayment.token_auths.generate(
|
|
160
|
+
user_id: "buyer-12345",
|
|
161
|
+
token_type: "card"
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
token = response.data['token_auth']['token']
|
|
165
|
+
# Send token to frontend for use with PromisePay.js
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Integration with PromisePay.js
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
// Frontend (JavaScript)
|
|
172
|
+
PromisePay.setToken(token_from_backend);
|
|
173
|
+
|
|
174
|
+
PromisePay.createCardAccount({
|
|
175
|
+
card_number: '4111111111111111',
|
|
176
|
+
expiry_month: '12',
|
|
177
|
+
expiry_year: '2025',
|
|
178
|
+
cvv: '123'
|
|
179
|
+
}, function(response) {
|
|
180
|
+
if (response.error) {
|
|
181
|
+
console.error('Error:', response.error);
|
|
182
|
+
} else {
|
|
183
|
+
const cardAccountId = response.card_accounts.id;
|
|
184
|
+
// Send cardAccountId back to backend
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Test Results
|
|
190
|
+
|
|
191
|
+
- **Total Tests:** 272 examples
|
|
192
|
+
- **Failures:** 0
|
|
193
|
+
- **Line Coverage:** 95.22% (518 / 544)
|
|
194
|
+
- **Branch Coverage:** 80.79% (143 / 177)
|
|
195
|
+
- **RuboCop:** No offenses detected
|
|
196
|
+
|
|
197
|
+
## Files Created
|
|
198
|
+
|
|
199
|
+
1. `lib/zai_payment/resources/token_auth.rb` - Core resource implementation
|
|
200
|
+
2. `spec/zai_payment/resources/token_auth_spec.rb` - Test suite
|
|
201
|
+
3. `examples/token_auths.md` - Comprehensive usage examples
|
|
202
|
+
4. `docs/token_auths.md` - Technical documentation
|
|
203
|
+
|
|
204
|
+
## Files Modified
|
|
205
|
+
|
|
206
|
+
1. `lib/zai_payment.rb` - Added token_auths accessor
|
|
207
|
+
2. `lib/zai_payment/version.rb` - Version bump to 2.1.0
|
|
208
|
+
3. `changelog.md` - Added 2.1.0 release notes
|
|
209
|
+
4. `readme.md` - Added Token Auth documentation
|
|
210
|
+
5. `docs/readme.md` - Updated documentation index
|
|
211
|
+
|
|
212
|
+
## Security Considerations
|
|
213
|
+
|
|
214
|
+
- **PCI Compliance:** Tokens enable PCI-compliant card data collection without sensitive data touching your server
|
|
215
|
+
- **Token Expiration:** Tokens have limited lifespan (typically 1 hour)
|
|
216
|
+
- **Single-use:** Tokens should be generated fresh for each session
|
|
217
|
+
- **User-specific:** Each token is tied to a specific user ID
|
|
218
|
+
- **Type-specific:** Bank tokens only for bank accounts, card tokens only for cards
|
|
219
|
+
- **HTTPS Required:** All communication over secure HTTPS
|
|
220
|
+
|
|
221
|
+
## Next Steps
|
|
222
|
+
|
|
223
|
+
The Token Auth implementation is complete and ready for use. Developers can now:
|
|
224
|
+
|
|
225
|
+
1. Generate tokens for buyers to collect credit card information
|
|
226
|
+
2. Generate tokens for sellers to collect bank account details
|
|
227
|
+
3. Integrate with PromisePay.js for secure frontend data collection
|
|
228
|
+
4. Process payments without handling sensitive payment data directly
|
|
229
|
+
|
|
230
|
+
## Related APIs
|
|
231
|
+
|
|
232
|
+
This implementation complements existing resources:
|
|
233
|
+
- **Users API** - Create users before generating tokens
|
|
234
|
+
- **Items API** - Use payment accounts to create transactions
|
|
235
|
+
- **Webhooks API** - Receive notifications about payment events
|
|
236
|
+
|
|
237
|
+
## Documentation Links
|
|
238
|
+
|
|
239
|
+
- **API Reference:** https://developer.hellozai.com/reference/generatetoken
|
|
240
|
+
- **Examples:** [examples/token_auths.md](examples/token_auths.md)
|
|
241
|
+
- **Guide:** [docs/token_auths.md](docs/token_auths.md)
|
|
242
|
+
- **PromisePay.js:** https://developer.hellozai.com/docs/promisepay-js
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
**Implementation Date:** October 24, 2025
|
|
247
|
+
**Version:** 2.1.0
|
|
248
|
+
**Status:** ✅ Complete and tested
|
|
249
|
+
|