zai_payment 2.0.1 → 2.1.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 +36 -1
- 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 +3 -3
- data/examples/token_auths.md +687 -0
- data/lib/zai_payment/resources/token_auth.rb +75 -0
- data/lib/zai_payment/version.rb +1 -1
- data/lib/zai_payment.rb +7 -1
- data/readme.md +31 -0
- data/token_auth_implementation_summary.md +249 -0
- metadata +5 -1
data/docs/token_auths.md
ADDED
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
# Token Auth API
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The TokenAuth resource provides secure token generation for collecting bank account and credit card information. These tokens are used with the PromisePay.js library to securely transmit sensitive payment data without it ever touching your server.
|
|
6
|
+
|
|
7
|
+
This is particularly useful for PCI compliance when collecting credit card information, and for securely collecting bank account details.
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [When to Use Token Auth](#when-to-use-token-auth)
|
|
12
|
+
- [How It Works](#how-it-works)
|
|
13
|
+
- [API Methods](#api-methods)
|
|
14
|
+
- [Token Types](#token-types)
|
|
15
|
+
- [Security Considerations](#security-considerations)
|
|
16
|
+
- [Integration Guide](#integration-guide)
|
|
17
|
+
- [Error Handling](#error-handling)
|
|
18
|
+
- [Best Practices](#best-practices)
|
|
19
|
+
|
|
20
|
+
## When to Use Token Auth
|
|
21
|
+
|
|
22
|
+
You should use Token Auth when you need to:
|
|
23
|
+
|
|
24
|
+
1. **Collect Credit Card Information** - Generate a card token for buyers to securely enter their credit card details
|
|
25
|
+
2. **Collect Bank Account Details** - Generate a bank token for sellers to securely provide their bank account information
|
|
26
|
+
3. **PCI Compliance** - Ensure sensitive payment data never touches your server
|
|
27
|
+
4. **Frontend Integration** - Use with PromisePay.js to handle payment data collection on the client side
|
|
28
|
+
|
|
29
|
+
## How It Works
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
1. Backend (Your Server)
|
|
33
|
+
↓
|
|
34
|
+
Generate token using ZaiPayment.token_auths.generate()
|
|
35
|
+
↓
|
|
36
|
+
Return token to frontend
|
|
37
|
+
|
|
38
|
+
2. Frontend (Browser/App)
|
|
39
|
+
↓
|
|
40
|
+
Use PromisePay.js with the token
|
|
41
|
+
↓
|
|
42
|
+
User enters payment details
|
|
43
|
+
↓
|
|
44
|
+
PromisePay.js sends data directly to Zai (not your server)
|
|
45
|
+
↓
|
|
46
|
+
Returns payment account ID
|
|
47
|
+
|
|
48
|
+
3. Backend (Your Server)
|
|
49
|
+
↓
|
|
50
|
+
Use payment account ID to create items/transactions
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## API Methods
|
|
54
|
+
|
|
55
|
+
### `generate(user_id:, token_type:)`
|
|
56
|
+
|
|
57
|
+
Generate a token for bank or card account data collection.
|
|
58
|
+
|
|
59
|
+
**Parameters:**
|
|
60
|
+
- `user_id` (String, required) - The ID of the buyer or seller user (already created)
|
|
61
|
+
- `token_type` (String, optional) - Type of token to generate: `'bank'` or `'card'` (default: `'bank'`)
|
|
62
|
+
|
|
63
|
+
**Returns:**
|
|
64
|
+
- `Response` object containing the generated token and metadata
|
|
65
|
+
|
|
66
|
+
**Example:**
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
# Generate a bank token
|
|
70
|
+
response = ZaiPayment.token_auths.generate(
|
|
71
|
+
user_id: "seller-68611249",
|
|
72
|
+
token_type: "bank"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
token = response.data['token_auth']['token']
|
|
76
|
+
# => "tok_bank_abc123xyz..."
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Token Types
|
|
80
|
+
|
|
81
|
+
### Bank Tokens
|
|
82
|
+
|
|
83
|
+
Bank tokens are used to collect bank account information from payout users (sellers/merchants).
|
|
84
|
+
|
|
85
|
+
**Use Case:** Collecting bank account details for disbursements to sellers.
|
|
86
|
+
|
|
87
|
+
**Typical Flow:**
|
|
88
|
+
1. Create a payout user (seller)
|
|
89
|
+
2. Generate a bank token for the seller
|
|
90
|
+
3. Send token to frontend
|
|
91
|
+
4. Use PromisePay.js to collect bank account details
|
|
92
|
+
5. Receive bank account ID from Zai
|
|
93
|
+
6. Associate bank account with items/transactions
|
|
94
|
+
|
|
95
|
+
**Example:**
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
# Step 1: Create seller
|
|
99
|
+
seller = ZaiPayment.users.create(
|
|
100
|
+
user_type: "payout",
|
|
101
|
+
email: "seller@example.com",
|
|
102
|
+
first_name: "Jane",
|
|
103
|
+
last_name: "Smith",
|
|
104
|
+
country: "AUS",
|
|
105
|
+
dob: "01/01/1990",
|
|
106
|
+
address_line1: "456 Market St",
|
|
107
|
+
city: "Sydney",
|
|
108
|
+
state: "NSW",
|
|
109
|
+
zip: "2000"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
seller_id = seller.data['users']['id']
|
|
113
|
+
|
|
114
|
+
# Step 2: Generate bank token
|
|
115
|
+
token_response = ZaiPayment.token_auths.generate(
|
|
116
|
+
user_id: seller_id,
|
|
117
|
+
token_type: "bank"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
bank_token = token_response.data['token_auth']['token']
|
|
121
|
+
|
|
122
|
+
# Step 3: Send to frontend for PromisePay.js integration
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Card Tokens
|
|
126
|
+
|
|
127
|
+
Card tokens are used to collect credit card information from payin users (buyers).
|
|
128
|
+
|
|
129
|
+
**Use Case:** Collecting credit card details for payments from buyers.
|
|
130
|
+
|
|
131
|
+
**Typical Flow:**
|
|
132
|
+
1. Create a payin user (buyer)
|
|
133
|
+
2. Generate a card token for the buyer
|
|
134
|
+
3. Send token to frontend
|
|
135
|
+
4. Use PromisePay.js to collect credit card details
|
|
136
|
+
5. Receive card account ID from Zai
|
|
137
|
+
6. Use card account to process payments
|
|
138
|
+
|
|
139
|
+
**Example:**
|
|
140
|
+
|
|
141
|
+
```ruby
|
|
142
|
+
# Step 1: Create buyer
|
|
143
|
+
buyer = ZaiPayment.users.create(
|
|
144
|
+
user_type: "payin",
|
|
145
|
+
email: "buyer@example.com",
|
|
146
|
+
first_name: "John",
|
|
147
|
+
last_name: "Doe",
|
|
148
|
+
country: "USA"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
buyer_id = buyer.data['users']['id']
|
|
152
|
+
|
|
153
|
+
# Step 2: Generate card token
|
|
154
|
+
token_response = ZaiPayment.token_auths.generate(
|
|
155
|
+
user_id: buyer_id,
|
|
156
|
+
token_type: "card"
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
card_token = token_response.data['token_auth']['token']
|
|
160
|
+
|
|
161
|
+
# Step 3: Send to frontend for PromisePay.js integration
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Security Considerations
|
|
165
|
+
|
|
166
|
+
### Token Expiration
|
|
167
|
+
|
|
168
|
+
Tokens have a limited lifespan (typically 1 hour). Always:
|
|
169
|
+
- Check the `expires_at` field in the response
|
|
170
|
+
- Generate fresh tokens for each payment session
|
|
171
|
+
- Don't store tokens for later use
|
|
172
|
+
- Handle token expiration gracefully on the frontend
|
|
173
|
+
|
|
174
|
+
### Token Scope
|
|
175
|
+
|
|
176
|
+
Each token is:
|
|
177
|
+
- **User-specific**: Tied to a single user ID
|
|
178
|
+
- **Single-use**: Should be used once per payment session
|
|
179
|
+
- **Type-specific**: Bank tokens only for bank accounts, card tokens only for cards
|
|
180
|
+
|
|
181
|
+
### PCI Compliance
|
|
182
|
+
|
|
183
|
+
Token Auth helps maintain PCI compliance by:
|
|
184
|
+
- Preventing card data from touching your server
|
|
185
|
+
- Using secure HTTPS transmission
|
|
186
|
+
- Leveraging Zai's PCI-compliant infrastructure
|
|
187
|
+
- Minimizing your PCI scope
|
|
188
|
+
|
|
189
|
+
## Integration Guide
|
|
190
|
+
|
|
191
|
+
### Backend Integration
|
|
192
|
+
|
|
193
|
+
```ruby
|
|
194
|
+
# app/controllers/payment_tokens_controller.rb
|
|
195
|
+
class PaymentTokensController < ApplicationController
|
|
196
|
+
before_action :authenticate_user!
|
|
197
|
+
|
|
198
|
+
def create
|
|
199
|
+
user_id = current_user.zai_user_id
|
|
200
|
+
token_type = params[:token_type] || 'card'
|
|
201
|
+
|
|
202
|
+
response = ZaiPayment.token_auths.generate(
|
|
203
|
+
user_id: user_id,
|
|
204
|
+
token_type: token_type
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
render json: {
|
|
208
|
+
token: response.data['token_auth']['token'],
|
|
209
|
+
expires_at: response.data['token_auth']['expires_at']
|
|
210
|
+
}
|
|
211
|
+
rescue ZaiPayment::Errors::ApiError => e
|
|
212
|
+
render json: { error: e.message }, status: :bad_gateway
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Frontend Integration (JavaScript)
|
|
218
|
+
|
|
219
|
+
```html
|
|
220
|
+
<!-- Include PromisePay.js -->
|
|
221
|
+
<script src="https://cdn.assemblypay.com/promisepay.js"></script>
|
|
222
|
+
|
|
223
|
+
<script>
|
|
224
|
+
// 1. Fetch token from your backend
|
|
225
|
+
async function getPaymentToken(tokenType) {
|
|
226
|
+
const response = await fetch('/api/payment_tokens', {
|
|
227
|
+
method: 'POST',
|
|
228
|
+
headers: { 'Content-Type': 'application/json' },
|
|
229
|
+
body: JSON.stringify({ token_type: tokenType })
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const data = await response.json();
|
|
233
|
+
return data.token;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 2. Use token with PromisePay.js to collect card details
|
|
237
|
+
async function collectCardDetails() {
|
|
238
|
+
const token = await getPaymentToken('card');
|
|
239
|
+
|
|
240
|
+
PromisePay.setToken(token);
|
|
241
|
+
|
|
242
|
+
PromisePay.createCardAccount({
|
|
243
|
+
card_number: document.getElementById('card_number').value,
|
|
244
|
+
expiry_month: document.getElementById('expiry_month').value,
|
|
245
|
+
expiry_year: document.getElementById('expiry_year').value,
|
|
246
|
+
cvv: document.getElementById('cvv').value
|
|
247
|
+
}, function(response) {
|
|
248
|
+
if (response.error) {
|
|
249
|
+
console.error('Error:', response.error);
|
|
250
|
+
} else {
|
|
251
|
+
// Card account created successfully
|
|
252
|
+
const cardAccountId = response.card_accounts.id;
|
|
253
|
+
// Send cardAccountId to your backend to create item/transaction
|
|
254
|
+
processPayment(cardAccountId);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// 3. Use token with PromisePay.js to collect bank details
|
|
260
|
+
async function collectBankDetails() {
|
|
261
|
+
const token = await getPaymentToken('bank');
|
|
262
|
+
|
|
263
|
+
PromisePay.setToken(token);
|
|
264
|
+
|
|
265
|
+
PromisePay.createBankAccount({
|
|
266
|
+
account_name: document.getElementById('account_name').value,
|
|
267
|
+
account_number: document.getElementById('account_number').value,
|
|
268
|
+
routing_number: document.getElementById('routing_number').value,
|
|
269
|
+
account_type: 'savings' // or 'checking'
|
|
270
|
+
}, function(response) {
|
|
271
|
+
if (response.error) {
|
|
272
|
+
console.error('Error:', response.error);
|
|
273
|
+
} else {
|
|
274
|
+
// Bank account created successfully
|
|
275
|
+
const bankAccountId = response.bank_accounts.id;
|
|
276
|
+
// Send bankAccountId to your backend
|
|
277
|
+
saveBankAccount(bankAccountId);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
</script>
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Complete Payment Flow
|
|
285
|
+
|
|
286
|
+
```ruby
|
|
287
|
+
# 1. Create users (buyer and seller)
|
|
288
|
+
buyer = ZaiPayment.users.create(
|
|
289
|
+
user_type: "payin",
|
|
290
|
+
email: "buyer@example.com",
|
|
291
|
+
first_name: "John",
|
|
292
|
+
last_name: "Doe",
|
|
293
|
+
country: "USA"
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
seller = ZaiPayment.users.create(
|
|
297
|
+
user_type: "payout",
|
|
298
|
+
email: "seller@example.com",
|
|
299
|
+
first_name: "Jane",
|
|
300
|
+
last_name: "Smith",
|
|
301
|
+
country: "AUS",
|
|
302
|
+
dob: "01/01/1990",
|
|
303
|
+
address_line1: "456 Market St",
|
|
304
|
+
city: "Sydney",
|
|
305
|
+
state: "NSW",
|
|
306
|
+
zip: "2000"
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
# 2. Generate card token for buyer
|
|
310
|
+
card_token_response = ZaiPayment.token_auths.generate(
|
|
311
|
+
user_id: buyer.data['users']['id'],
|
|
312
|
+
token_type: "card"
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
# Send card_token to frontend, collect card details, get card_account_id
|
|
316
|
+
|
|
317
|
+
# 3. Generate bank token for seller
|
|
318
|
+
bank_token_response = ZaiPayment.token_auths.generate(
|
|
319
|
+
user_id: seller.data['users']['id'],
|
|
320
|
+
token_type: "bank"
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
# Send bank_token to frontend, collect bank details, get bank_account_id
|
|
324
|
+
|
|
325
|
+
# 4. Create item for payment
|
|
326
|
+
item = ZaiPayment.items.create(
|
|
327
|
+
name: "Product Purchase",
|
|
328
|
+
amount: 10000, # $100.00
|
|
329
|
+
payment_type: 2, # Credit card
|
|
330
|
+
buyer_id: buyer.data['users']['id'],
|
|
331
|
+
seller_id: seller.data['users']['id']
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
# 5. Process payment using card_account_id
|
|
335
|
+
# (Use Items Actions API or Payment API - to be implemented)
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Error Handling
|
|
339
|
+
|
|
340
|
+
### Common Errors
|
|
341
|
+
|
|
342
|
+
```ruby
|
|
343
|
+
begin
|
|
344
|
+
response = ZaiPayment.token_auths.generate(
|
|
345
|
+
user_id: user_id,
|
|
346
|
+
token_type: token_type
|
|
347
|
+
)
|
|
348
|
+
rescue ZaiPayment::Errors::ValidationError => e
|
|
349
|
+
# Invalid user_id or token_type
|
|
350
|
+
{ error: "Validation error: #{e.message}", retryable: false }
|
|
351
|
+
rescue ZaiPayment::Errors::NotFoundError => e
|
|
352
|
+
# User not found
|
|
353
|
+
{ error: "User not found: #{user_id}", retryable: false }
|
|
354
|
+
rescue ZaiPayment::Errors::UnauthorizedError => e
|
|
355
|
+
# Authentication failed
|
|
356
|
+
{ error: "Authentication failed", retryable: false }
|
|
357
|
+
rescue ZaiPayment::Errors::RateLimitError => e
|
|
358
|
+
# Rate limit exceeded
|
|
359
|
+
{ error: "Rate limit exceeded", retryable: true, retry_after: 60 }
|
|
360
|
+
rescue ZaiPayment::Errors::ServerError => e
|
|
361
|
+
# Server error (5xx)
|
|
362
|
+
{ error: "Server error", retryable: true }
|
|
363
|
+
rescue ZaiPayment::Errors::TimeoutError => e
|
|
364
|
+
# Request timeout
|
|
365
|
+
{ error: "Timeout", retryable: true }
|
|
366
|
+
end
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Validation Errors
|
|
370
|
+
|
|
371
|
+
| Error | Cause | Solution |
|
|
372
|
+
|-------|-------|----------|
|
|
373
|
+
| `user_id is required and cannot be blank` | Missing or empty user_id | Provide a valid user ID |
|
|
374
|
+
| `token_type must be one of: bank, card` | Invalid token_type | Use 'bank' or 'card' |
|
|
375
|
+
| `User not found` | User doesn't exist | Create user first |
|
|
376
|
+
|
|
377
|
+
## Best Practices
|
|
378
|
+
|
|
379
|
+
### 1. Token Lifecycle Management
|
|
380
|
+
|
|
381
|
+
```ruby
|
|
382
|
+
class TokenManager
|
|
383
|
+
def initialize(user_id)
|
|
384
|
+
@user_id = user_id
|
|
385
|
+
@cache = {}
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def get_token(type)
|
|
389
|
+
cache_key = "#{@user_id}_#{type}"
|
|
390
|
+
|
|
391
|
+
# Don't reuse expired tokens
|
|
392
|
+
if @cache[cache_key] && !token_expired?(@cache[cache_key][:expires_at])
|
|
393
|
+
return @cache[cache_key][:token]
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# Generate fresh token
|
|
397
|
+
response = ZaiPayment.token_auths.generate(
|
|
398
|
+
user_id: @user_id,
|
|
399
|
+
token_type: type
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
token_data = response.data['token_auth']
|
|
403
|
+
|
|
404
|
+
@cache[cache_key] = {
|
|
405
|
+
token: token_data['token'],
|
|
406
|
+
expires_at: Time.parse(token_data['expires_at'])
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
token_data['token']
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
private
|
|
413
|
+
|
|
414
|
+
def token_expired?(expires_at)
|
|
415
|
+
# Consider expired 5 minutes before actual expiry
|
|
416
|
+
expires_at < Time.now + 300
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### 2. Audit Logging
|
|
422
|
+
|
|
423
|
+
```ruby
|
|
424
|
+
def generate_token_with_audit(user_id:, token_type:, context: {})
|
|
425
|
+
start_time = Time.now
|
|
426
|
+
|
|
427
|
+
begin
|
|
428
|
+
response = ZaiPayment.token_auths.generate(
|
|
429
|
+
user_id: user_id,
|
|
430
|
+
token_type: token_type
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
log_event(
|
|
434
|
+
event: 'token_generated',
|
|
435
|
+
user_id: user_id,
|
|
436
|
+
token_type: token_type,
|
|
437
|
+
success: true,
|
|
438
|
+
duration: Time.now - start_time,
|
|
439
|
+
context: context
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
response
|
|
443
|
+
rescue => e
|
|
444
|
+
log_event(
|
|
445
|
+
event: 'token_generation_failed',
|
|
446
|
+
user_id: user_id,
|
|
447
|
+
token_type: token_type,
|
|
448
|
+
success: false,
|
|
449
|
+
error: e.message,
|
|
450
|
+
duration: Time.now - start_time,
|
|
451
|
+
context: context
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
raise
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### 3. Rate Limiting
|
|
460
|
+
|
|
461
|
+
```ruby
|
|
462
|
+
class RateLimitedTokenGenerator
|
|
463
|
+
def initialize(user_id)
|
|
464
|
+
@user_id = user_id
|
|
465
|
+
@redis = Redis.new
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
def generate(token_type:, limit: 10, window: 3600)
|
|
469
|
+
rate_limit_key = "token_gen:#{@user_id}:#{Time.now.to_i / window}"
|
|
470
|
+
current_count = @redis.incr(rate_limit_key)
|
|
471
|
+
@redis.expire(rate_limit_key, window)
|
|
472
|
+
|
|
473
|
+
if current_count > limit
|
|
474
|
+
raise "Rate limit exceeded: #{limit} tokens per #{window} seconds"
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
ZaiPayment.token_auths.generate(
|
|
478
|
+
user_id: @user_id,
|
|
479
|
+
token_type: token_type
|
|
480
|
+
)
|
|
481
|
+
end
|
|
482
|
+
end
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### 4. Retry Logic
|
|
486
|
+
|
|
487
|
+
```ruby
|
|
488
|
+
def generate_token_with_retry(user_id, token_type, max_retries: 3)
|
|
489
|
+
retries = 0
|
|
490
|
+
|
|
491
|
+
begin
|
|
492
|
+
ZaiPayment.token_auths.generate(
|
|
493
|
+
user_id: user_id,
|
|
494
|
+
token_type: token_type
|
|
495
|
+
)
|
|
496
|
+
rescue ZaiPayment::Errors::RateLimitError,
|
|
497
|
+
ZaiPayment::Errors::ServerError,
|
|
498
|
+
ZaiPayment::Errors::TimeoutError => e
|
|
499
|
+
retries += 1
|
|
500
|
+
|
|
501
|
+
if retries < max_retries
|
|
502
|
+
sleep_time = 2 ** retries # Exponential backoff
|
|
503
|
+
sleep(sleep_time)
|
|
504
|
+
retry
|
|
505
|
+
else
|
|
506
|
+
raise
|
|
507
|
+
end
|
|
508
|
+
end
|
|
509
|
+
end
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
## API Reference
|
|
513
|
+
|
|
514
|
+
For complete API documentation, see:
|
|
515
|
+
- [Zai: Generate Token API Reference](https://developer.hellozai.com/reference/generatetoken)
|
|
516
|
+
- [Token Auth Examples](../examples/token_auths.md)
|
|
517
|
+
|
|
518
|
+
## Related Resources
|
|
519
|
+
|
|
520
|
+
- [User Management](users.md) - Create users before generating tokens
|
|
521
|
+
- [Item Management](items.md) - Use payment accounts to create items
|
|
522
|
+
- [PromisePay.js Documentation](https://developer.hellozai.com/docs/promisepay-js)
|
|
523
|
+
|
data/docs/user_id_field.md
CHANGED
|
@@ -271,7 +271,7 @@ old_user.update(zai_user_id: new_response.data['id'])
|
|
|
271
271
|
|
|
272
272
|
- [Zai Developer Documentation](https://developer.hellozai.com/docs/onboarding-a-pay-in-user)
|
|
273
273
|
- [Zai API Reference](https://developer.hellozai.com/reference/createuser)
|
|
274
|
-
- [User Management Guide](
|
|
274
|
+
- [User Management Guide](users.md)
|
|
275
275
|
|
|
276
276
|
## Summary
|
|
277
277
|
|
data/docs/users.md
CHANGED
|
@@ -408,7 +408,7 @@ bundle exec rspec spec/zai_payment/resources/user_spec.rb
|
|
|
408
408
|
|
|
409
409
|
## See Also
|
|
410
410
|
|
|
411
|
-
- [Webhook Documentation](
|
|
412
|
-
- [Authentication Documentation](
|
|
413
|
-
- [Architecture Documentation](
|
|
411
|
+
- [Webhook Documentation](webhooks.md)
|
|
412
|
+
- [Authentication Documentation](authentication.md)
|
|
413
|
+
- [Architecture Documentation](architecture.md)
|
|
414
414
|
|