@yuno-payments/yuno-sdk-react-native 1.0.21 → 1.0.23
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.
package/README.md
CHANGED
|
@@ -1,122 +1,85 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
<img alt="Yuno React Native SDK" src="https://files.readme.io/2e1d03a6eec5051a64763f36225454778d7125c344f1d741d0c01cfcdafe4186-flutter-image.png" width="600">
|
|
5
|
-
</p>
|
|
6
|
-
|
|
7
|
-
<div align="center">
|
|
8
|
-
<a href="https://www.y.uno/">
|
|
9
|
-
<img alt="Maintained by Yuno" src="https://img.shields.io/badge/maintained_by-Yuno-4E3DD8?style=for-the-badge">
|
|
10
|
-
</a>
|
|
11
|
-
<a href="https://www.npmjs.com/package/@yuno/yuno-sdk-react-native">
|
|
12
|
-
<img alt="npm version" src="https://img.shields.io/npm/v/@yuno/yuno-sdk-react-native?style=for-the-badge">
|
|
13
|
-
</a>
|
|
14
|
-
<a href="https://opensource.org/licenses/MIT">
|
|
15
|
-
<img src="https://img.shields.io/badge/license-MIT-purple.svg?style=for-the-badge" alt="License: MIT">
|
|
16
|
-
</a>
|
|
17
|
-
</div>
|
|
18
|
-
|
|
19
|
-
<br>
|
|
20
|
-
|
|
21
|
-
> **⚠️ Open Source Project Notice**
|
|
1
|
+
# React Native SDKs
|
|
2
|
+
|
|
3
|
+
> ### ELF page size support
|
|
22
4
|
>
|
|
23
|
-
>
|
|
24
|
-
|
|
25
|
-
## 📖 Table of Contents
|
|
26
|
-
|
|
27
|
-
- [Overview](#-overview)
|
|
28
|
-
- [Features](#-features)
|
|
29
|
-
- [Platform Support](#-platform-support)
|
|
30
|
-
- [Installation](#-installation)
|
|
31
|
-
- [Setup](#%EF%B8%8F-setup)
|
|
32
|
-
- [Android Setup](#android-setup)
|
|
33
|
-
- [iOS Setup](#ios-setup)
|
|
34
|
-
- [Quick Start](#-quick-start)
|
|
35
|
-
- [Usage](#-usage)
|
|
36
|
-
- [Initialization](#1-initialize-the-sdk)
|
|
37
|
-
- [Payment Events](#2-subscribe-to-payment-events)
|
|
38
|
-
- [Full Payment Flow](#3-start-full-payment-flow)
|
|
39
|
-
- [Payment Lite](#4-payment-lite-flow)
|
|
40
|
-
- [Seamless Payment](#5-seamless-payment-flow)
|
|
41
|
-
- [Enrollment](#6-enrollment-flow)
|
|
42
|
-
- [Deep Links](#7-handle-deep-links)
|
|
43
|
-
- [API Reference](#-api-reference)
|
|
44
|
-
- [TypeScript Support](#-typescript-support)
|
|
45
|
-
- [Example App](#-example-app)
|
|
46
|
-
- [Troubleshooting](#-troubleshooting)
|
|
47
|
-
- [Contributing](#-contributing)
|
|
48
|
-
- [License](#-license)
|
|
49
|
-
|
|
50
|
-
## 🌟 Overview
|
|
51
|
-
|
|
52
|
-
The **Yuno SDK for React Native** enables you to build powerful, secure, and seamless payment experiences in your React Native applications for both Android and iOS platforms. Designed with developers in mind, it provides a comprehensive set of tools to integrate multiple payment methods, handle tokenization, and manage the complete payment lifecycle.
|
|
53
|
-
|
|
54
|
-
### Why Choose Yuno SDK?
|
|
55
|
-
|
|
56
|
-
- ✅ **Unified API**: Single integration for multiple payment providers
|
|
57
|
-
- ✅ **PCI Compliance**: Reduce your PCI scope with secure tokenization
|
|
58
|
-
- ✅ **Flexible Flows**: Full, lite, and seamless payment options
|
|
59
|
-
- ✅ **Production Ready**: Battle-tested in high-volume production environments
|
|
60
|
-
- ✅ **Developer Friendly**: TypeScript support, clear documentation, and extensive examples
|
|
61
|
-
|
|
62
|
-
## ✨ Features
|
|
63
|
-
|
|
64
|
-
### 🔐 Security First
|
|
65
|
-
- **PCI DSS Compliant**: Adheres to Payment Card Industry Data Security Standards
|
|
66
|
-
- **Tokenization**: Secure handling of sensitive payment data
|
|
67
|
-
- **3D Secure Support**: Built-in Strong Customer Authentication (SCA)
|
|
68
|
-
- **End-to-End Encryption**: All transactions are encrypted
|
|
69
|
-
|
|
70
|
-
### 💳 Payment Capabilities
|
|
71
|
-
- **Multiple Payment Methods**: Credit/debit cards, digital wallets, and alternative payment methods
|
|
72
|
-
- **Save Cards**: Enable customers to save payment methods for future purchases
|
|
73
|
-
- **One-Tap Payments**: Quick checkout for returning customers
|
|
74
|
-
- **Split Payments**: Support for multiple payment instruments
|
|
75
|
-
|
|
76
|
-
### 🎨 Customizable Flows
|
|
77
|
-
- **Full Payment Flow**: Complete payment UI managed by the SDK
|
|
78
|
-
- **Payment Lite**: Lightweight flow for custom integrations
|
|
79
|
-
- **Seamless Payment**: Headless flow for maximum UI control
|
|
80
|
-
- **Enrollment Flow**: Save payment methods without processing a payment
|
|
81
|
-
|
|
82
|
-
### 🌍 Global Support
|
|
83
|
-
- **18 Languages**: EN, ES, PT, ID, MS, FR, PL, IT, DE, RU, TR, NL, SV, TH, FIL, VI, ZH-CN, ZH-TW
|
|
84
|
-
- **Multi-Currency**: Support for multiple currencies
|
|
85
|
-
- **Regional Payment Methods**: Country-specific payment options
|
|
86
|
-
|
|
87
|
-
### 🛠️ Developer Experience
|
|
88
|
-
- **TypeScript**: Full type definitions included
|
|
89
|
-
- **Event-Driven**: Real-time payment status updates
|
|
90
|
-
- **Error Handling**: Comprehensive error messages
|
|
91
|
-
- **Testing Tools**: Sandbox environment for development
|
|
92
|
-
|
|
93
|
-
## 📱 Platform Support
|
|
94
|
-
|
|
95
|
-
| Platform | Minimum Version | Supported |
|
|
96
|
-
|----------|----------------|-----------|
|
|
97
|
-
| **Android** | SDK 21+ (Android 5.0) | ✅ |
|
|
98
|
-
| **iOS** | 14.0+ | ✅ |
|
|
99
|
-
| **React Native** | 0.70+ | ✅ |
|
|
100
|
-
|
|
101
|
-
## 📦 Installation
|
|
102
|
-
|
|
103
|
-
Install the package using npm or yarn:
|
|
5
|
+
> The Yuno React Native SDK fully supports Google's 16 KB ELF page alignment requirements through its underlying Android SDK. All native libraries are built and verified for 16 KB memory pages, ensuring compatibility with Android 15 (API Level 35) and ARMv9 devices.
|
|
104
6
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
7
|
+
Yuno's React Native SDK is specifically designed to simplify the integration of payment processing functionality in your React Native applications for both Android and iOS platforms. Developers can implement features more efficiently, reducing the need for extensive knowledge of payment protocols and infrastructure.
|
|
8
|
+
|
|
9
|
+
## Integrations
|
|
10
|
+
|
|
11
|
+
Select one of the user-friendly React Native integration options available and kickstart your journey toward efficient payment processing:
|
|
12
|
+
|
|
13
|
+
| Integration | Description |
|
|
14
|
+
|-------------|-------------|
|
|
15
|
+
| [Full SDK](#full-sdk-react-native) | Render the payment methods your company has available in the checkout and for user enrollment. |
|
|
16
|
+
| [Lite SDK (Payment)](#lite-sdk-payment-react-native) | Control which payment methods will be shown to the user during checkout. |
|
|
17
|
+
| [Lite SDK (Enrollment)](#lite-sdk-enrollment-react-native) | Simplify the user enrollment of payment methods. |
|
|
18
|
+
| [Seamless Payment](#seamless-payment-react-native) | Headless flow for maximum UI control. |
|
|
19
|
+
| [Headless SDK (Payment)](#headless-sdk-payment-react-native) | Customize the checkout without having to be PCI compliant. |
|
|
20
|
+
| [Headless SDK (Enrollment)](#headless-sdk-enrollment-react-native) | Customize the enrollment of new payment methods. |
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# Requirements
|
|
24
|
+
|
|
25
|
+
To use the Yuno React Native SDK, you need to meet the following requirements:
|
|
26
|
+
|
|
27
|
+
## General Requirements
|
|
28
|
+
|
|
29
|
+
| Requirement | Version |
|
|
30
|
+
|-------------|---------|
|
|
31
|
+
| **Node.js** | 16.0.0 or above |
|
|
32
|
+
| **React Native** | 0.70 or above |
|
|
33
|
+
|
|
34
|
+
## Android Requirements
|
|
35
|
+
|
|
36
|
+
| Requirement | Version |
|
|
37
|
+
|-------------|---------|
|
|
38
|
+
| **Minimum SDK Version** | 21 or above (Android 5.0) |
|
|
39
|
+
| **Target SDK Version** | 33 or above |
|
|
40
|
+
| **Java Version** | 17 |
|
|
41
|
+
| **Kotlin Version** | 1.9.24 or above |
|
|
42
|
+
| **Android Gradle Plugin** | 8.1.0 or above |
|
|
43
|
+
| **Jetpack Compose** | Required for native views |
|
|
44
|
+
|
|
45
|
+
## iOS Requirements
|
|
46
|
+
|
|
47
|
+
| Requirement | Version |
|
|
48
|
+
|-------------|---------|
|
|
49
|
+
| **Minimum iOS Version** | 14.0 or above |
|
|
50
|
+
| **Swift Version** | 5.0 or above |
|
|
51
|
+
| **Xcode** | 14.0 or above |
|
|
52
|
+
|
|
53
|
+
## SDK Dependencies
|
|
108
54
|
|
|
109
|
-
|
|
55
|
+
The React Native SDK depends on the following native SDKs:
|
|
56
|
+
|
|
57
|
+
| Platform | SDK | Version |
|
|
58
|
+
|----------|-----|---------|
|
|
59
|
+
| Android | `com.yuno.payments:android-sdk` | 2.8.1 |
|
|
60
|
+
| iOS | `YunoSDK` | 2.9.0 |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
# Installation
|
|
65
|
+
|
|
66
|
+
## Step 1: Install the Package
|
|
67
|
+
|
|
68
|
+
Install the Yuno SDK package using npm or yarn:
|
|
110
69
|
|
|
111
70
|
```bash
|
|
112
|
-
|
|
71
|
+
# Using npm
|
|
72
|
+
npm install @yuno-payments/yuno-sdk-react-native
|
|
73
|
+
|
|
74
|
+
# Using yarn
|
|
75
|
+
yarn add @yuno-payments/yuno-sdk-react-native
|
|
113
76
|
```
|
|
114
77
|
|
|
115
|
-
##
|
|
78
|
+
## Step 2: Platform-Specific Setup
|
|
116
79
|
|
|
117
80
|
### Android Setup
|
|
118
81
|
|
|
119
|
-
####
|
|
82
|
+
#### 2.1 Add Yuno Maven Repository
|
|
120
83
|
|
|
121
84
|
Update your project-level `android/build.gradle`:
|
|
122
85
|
|
|
@@ -134,9 +97,28 @@ allprojects {
|
|
|
134
97
|
}
|
|
135
98
|
```
|
|
136
99
|
|
|
137
|
-
####
|
|
100
|
+
#### 2.2 Set Minimum SDK Version
|
|
101
|
+
|
|
102
|
+
Ensure your `android/app/build.gradle` has the correct minimum SDK:
|
|
103
|
+
|
|
104
|
+
```gradle
|
|
105
|
+
android {
|
|
106
|
+
defaultConfig {
|
|
107
|
+
minSdkVersion 21
|
|
108
|
+
targetSdkVersion 33
|
|
109
|
+
// ...
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
compileOptions {
|
|
113
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
114
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### 2.3 Initialize SDK in Application Class
|
|
138
120
|
|
|
139
|
-
|
|
121
|
+
Update your `android/app/src/main/java/[your-package]/MainApplication.kt`:
|
|
140
122
|
|
|
141
123
|
```kotlin
|
|
142
124
|
package com.yourapp
|
|
@@ -163,9 +145,7 @@ class MainApplication : Application(), ReactApplication {
|
|
|
163
145
|
}
|
|
164
146
|
|
|
165
147
|
override fun getJSMainModuleName(): String = "index"
|
|
166
|
-
|
|
167
148
|
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
|
|
168
|
-
|
|
169
149
|
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
|
|
170
150
|
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
|
|
171
151
|
}
|
|
@@ -179,10 +159,7 @@ class MainApplication : Application(), ReactApplication {
|
|
|
179
159
|
// Initialize Yuno SDK
|
|
180
160
|
YunoSdkModule.initialize(
|
|
181
161
|
applicationContext = this,
|
|
182
|
-
apiKey = "YOUR_YUNO_API_KEY"
|
|
183
|
-
language = "en", // Optional: default language
|
|
184
|
-
cardType = "ONE_STEP", // Optional: "ONE_STEP" or "STEP_BY_STEP"
|
|
185
|
-
savedCardEnable = true // Optional: enable save card feature
|
|
162
|
+
apiKey = "YOUR_YUNO_API_KEY"
|
|
186
163
|
)
|
|
187
164
|
|
|
188
165
|
SoLoader.init(this, false)
|
|
@@ -193,29 +170,23 @@ class MainApplication : Application(), ReactApplication {
|
|
|
193
170
|
}
|
|
194
171
|
```
|
|
195
172
|
|
|
196
|
-
|
|
173
|
+
### iOS Setup
|
|
197
174
|
|
|
198
|
-
|
|
175
|
+
#### 2.1 Install CocoaPods Dependencies
|
|
199
176
|
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
defaultConfig {
|
|
203
|
-
minSdkVersion 21
|
|
204
|
-
targetSdkVersion 33
|
|
205
|
-
// ...
|
|
206
|
-
}
|
|
207
|
-
}
|
|
177
|
+
```bash
|
|
178
|
+
cd ios && pod install && cd ..
|
|
208
179
|
```
|
|
209
180
|
|
|
210
|
-
|
|
181
|
+
#### 2.2 Set Minimum iOS Version
|
|
211
182
|
|
|
212
|
-
|
|
183
|
+
Ensure your `ios/Podfile` has the correct minimum iOS version:
|
|
213
184
|
|
|
214
|
-
```
|
|
215
|
-
|
|
185
|
+
```ruby
|
|
186
|
+
platform :ios, '14.0'
|
|
216
187
|
```
|
|
217
188
|
|
|
218
|
-
####
|
|
189
|
+
#### 2.3 Configure Deep Links (Optional)
|
|
219
190
|
|
|
220
191
|
If you need to handle payment redirects, update your `ios/[YourApp]/Info.plist`:
|
|
221
192
|
|
|
@@ -235,83 +206,16 @@ If you need to handle payment redirects, update your `ios/[YourApp]/Info.plist`:
|
|
|
235
206
|
</array>
|
|
236
207
|
```
|
|
237
208
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
Ensure your `ios/Podfile` has the correct minimum iOS version:
|
|
241
|
-
|
|
242
|
-
```ruby
|
|
243
|
-
platform :ios, '14.0'
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
## 🚀 Quick Start
|
|
247
|
-
|
|
248
|
-
Here's a minimal example to get you started:
|
|
249
|
-
|
|
250
|
-
```typescript
|
|
251
|
-
import React, { useEffect } from 'react';
|
|
252
|
-
import { View, Button, Alert } from 'react-native';
|
|
253
|
-
import { YunoSdk, YunoLanguage, CardFlow, YunoStatus } from '@yuno/yuno-sdk-react-native';
|
|
254
|
-
|
|
255
|
-
function PaymentScreen() {
|
|
256
|
-
useEffect(() => {
|
|
257
|
-
// Initialize SDK
|
|
258
|
-
initializeYuno();
|
|
259
|
-
|
|
260
|
-
// Subscribe to payment events
|
|
261
|
-
const paymentSubscription = YunoSdk.onPaymentStatus((state) => {
|
|
262
|
-
if (state.status === YunoStatus.SUCCEEDED) {
|
|
263
|
-
Alert.alert('Success', 'Payment completed successfully!');
|
|
264
|
-
} else if (state.status === YunoStatus.FAILED) {
|
|
265
|
-
Alert.alert('Error', 'Payment failed');
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
return () => {
|
|
270
|
-
paymentSubscription.remove();
|
|
271
|
-
};
|
|
272
|
-
}, []);
|
|
273
|
-
|
|
274
|
-
const initializeYuno = async () => {
|
|
275
|
-
try {
|
|
276
|
-
await YunoSdk.initialize({
|
|
277
|
-
apiKey: 'YOUR_API_KEY',
|
|
278
|
-
countryCode: 'US',
|
|
279
|
-
yunoConfig: {
|
|
280
|
-
lang: YunoLanguage.EN,
|
|
281
|
-
cardFlow: CardFlow.ONE_STEP,
|
|
282
|
-
},
|
|
283
|
-
});
|
|
284
|
-
} catch (error) {
|
|
285
|
-
console.error('Yuno initialization error:', error);
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
const handlePayment = async () => {
|
|
290
|
-
try {
|
|
291
|
-
await YunoSdk.startPayment(true);
|
|
292
|
-
} catch (error) {
|
|
293
|
-
console.error('Payment error:', error);
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
return (
|
|
298
|
-
<View style={{ flex: 1, justifyContent: 'center', padding: 20 }}>
|
|
299
|
-
<Button title="Start Payment" onPress={handlePayment} />
|
|
300
|
-
</View>
|
|
301
|
-
);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
export default PaymentScreen;
|
|
305
|
-
```
|
|
209
|
+
---
|
|
306
210
|
|
|
307
|
-
|
|
211
|
+
# SDK Initialization
|
|
308
212
|
|
|
309
|
-
|
|
213
|
+
Before using any SDK features, you must initialize the SDK in your React Native application.
|
|
310
214
|
|
|
311
|
-
Initialize
|
|
215
|
+
## Initialize Method
|
|
312
216
|
|
|
313
217
|
```typescript
|
|
314
|
-
import { YunoSdk,
|
|
218
|
+
import { YunoSdk, CardFlow } from '@yuno-payments/yuno-sdk-react-native';
|
|
315
219
|
|
|
316
220
|
const initializeYuno = async () => {
|
|
317
221
|
try {
|
|
@@ -319,7 +223,7 @@ const initializeYuno = async () => {
|
|
|
319
223
|
apiKey: 'YOUR_YUNO_API_KEY',
|
|
320
224
|
countryCode: 'US', // ISO 3166-1 alpha-2 country code
|
|
321
225
|
yunoConfig: {
|
|
322
|
-
|
|
226
|
+
language: 'en',
|
|
323
227
|
cardFlow: CardFlow.ONE_STEP,
|
|
324
228
|
saveCardEnabled: true,
|
|
325
229
|
keepLoader: false,
|
|
@@ -333,15 +237,77 @@ const initializeYuno = async () => {
|
|
|
333
237
|
};
|
|
334
238
|
```
|
|
335
239
|
|
|
336
|
-
|
|
240
|
+
## Initialization Parameters
|
|
241
|
+
|
|
242
|
+
| Parameter | Type | Required | Description |
|
|
243
|
+
|-----------|------|----------|-------------|
|
|
244
|
+
| `apiKey` | `string` | ✓ | Your Yuno API key from the Dashboard |
|
|
245
|
+
| `countryCode` | `string` | ✓ | ISO 3166-1 alpha-2 country code (e.g., 'US', 'BR', 'CO') |
|
|
246
|
+
| `yunoConfig` | `YunoConfig` | | SDK configuration options |
|
|
247
|
+
| `iosConfig` | `IosConfig` | | iOS-specific configuration |
|
|
248
|
+
| `androidConfig` | `AndroidConfig` | | Android-specific configuration |
|
|
249
|
+
|
|
250
|
+
## YunoConfig Properties
|
|
251
|
+
|
|
252
|
+
| Property | Type | Default | Description |
|
|
253
|
+
|----------|------|---------|-------------|
|
|
254
|
+
| `language` | `string` | `'en'` | UI language code. See [Supported Languages](#supported-languages) |
|
|
255
|
+
| `cardFlow` | `CardFlow` | `ONE_STEP` | Card input flow type (`ONE_STEP` or `STEP_BY_STEP`) |
|
|
256
|
+
| `saveCardEnabled` | `boolean` | `false` | Enable the save card checkbox |
|
|
257
|
+
| `keepLoader` | `boolean` | `false` | Keep loader visible after operations |
|
|
258
|
+
| `isDynamicViewEnabled` | `boolean` | `false` | Enable dynamic views |
|
|
259
|
+
| `cardFormDeployed` | `boolean` | `false` | Card form deployed state |
|
|
260
|
+
|
|
261
|
+
## Supported Languages
|
|
262
|
+
|
|
263
|
+
The SDK supports the following languages:
|
|
264
|
+
|
|
265
|
+
| Code | Language |
|
|
266
|
+
|------|----------|
|
|
267
|
+
| `en` | English |
|
|
268
|
+
| `es` | Spanish |
|
|
269
|
+
| `pt` | Portuguese |
|
|
270
|
+
| `fr` | French |
|
|
271
|
+
| `de` | German |
|
|
272
|
+
| `it` | Italian |
|
|
273
|
+
| `id` | Indonesian |
|
|
274
|
+
| `ms` | Malay |
|
|
275
|
+
| `pl` | Polish |
|
|
276
|
+
| `ru` | Russian |
|
|
277
|
+
| `tr` | Turkish |
|
|
278
|
+
| `nl` | Dutch |
|
|
279
|
+
| `sv` | Swedish |
|
|
280
|
+
| `th` | Thai |
|
|
281
|
+
| `fil` | Filipino |
|
|
282
|
+
| `vi` | Vietnamese |
|
|
283
|
+
| `zh-cn` | Chinese (Simplified) |
|
|
284
|
+
| `zh-tw` | Chinese (Traditional) |
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
# Full SDK (React Native)
|
|
289
|
+
|
|
290
|
+
The Full SDK integration provides a complete payment UI managed by the SDK. This is the quickest way to integrate Yuno into your React Native application.
|
|
291
|
+
|
|
292
|
+
## Prerequisites
|
|
293
|
+
|
|
294
|
+
Before starting the Full SDK integration, ensure you have:
|
|
295
|
+
|
|
296
|
+
1. Completed the [Installation](#installation) steps
|
|
297
|
+
2. Initialized the SDK with `YunoSdk.initialize()`
|
|
298
|
+
3. Created a checkout session from your backend
|
|
337
299
|
|
|
338
|
-
|
|
300
|
+
## Implementation
|
|
301
|
+
|
|
302
|
+
### Step 1: Subscribe to Payment Events
|
|
303
|
+
|
|
304
|
+
Set up event listeners before starting the payment flow:
|
|
339
305
|
|
|
340
306
|
```typescript
|
|
341
|
-
import { YunoSdk, YunoStatus } from '@yuno/yuno-sdk-react-native';
|
|
307
|
+
import { YunoSdk, YunoStatus } from '@yuno-payments/yuno-sdk-react-native';
|
|
342
308
|
import { useEffect } from 'react';
|
|
343
309
|
|
|
344
|
-
function
|
|
310
|
+
function PaymentScreen() {
|
|
345
311
|
useEffect(() => {
|
|
346
312
|
// Listen to payment status changes
|
|
347
313
|
const paymentSubscription = YunoSdk.onPaymentStatus((state) => {
|
|
@@ -363,7 +329,7 @@ function PaymentComponent() {
|
|
|
363
329
|
// Handle rejection
|
|
364
330
|
break;
|
|
365
331
|
|
|
366
|
-
case YunoStatus.
|
|
332
|
+
case YunoStatus.CANCELLED_BY_USER:
|
|
367
333
|
console.log('⚠️ Payment cancelled by user');
|
|
368
334
|
// Return to previous screen
|
|
369
335
|
break;
|
|
@@ -384,7 +350,6 @@ function PaymentComponent() {
|
|
|
384
350
|
const tokenSubscription = YunoSdk.onOneTimeToken((token) => {
|
|
385
351
|
console.log('Received OTT:', token);
|
|
386
352
|
// Send token to your backend for payment processing
|
|
387
|
-
sendTokenToBackend(token);
|
|
388
353
|
});
|
|
389
354
|
|
|
390
355
|
// Cleanup subscriptions
|
|
@@ -393,21 +358,66 @@ function PaymentComponent() {
|
|
|
393
358
|
tokenSubscription.remove();
|
|
394
359
|
};
|
|
395
360
|
}, []);
|
|
396
|
-
|
|
361
|
+
|
|
397
362
|
return (
|
|
398
|
-
// Your UI
|
|
363
|
+
// Your payment UI
|
|
399
364
|
);
|
|
400
365
|
}
|
|
401
366
|
```
|
|
402
367
|
|
|
403
|
-
###
|
|
368
|
+
### Step 2: Display Payment Methods
|
|
404
369
|
|
|
405
|
-
|
|
370
|
+
Use the `YunoPaymentMethods` component to display available payment methods:
|
|
406
371
|
|
|
407
|
-
```
|
|
408
|
-
import {
|
|
372
|
+
```tsx
|
|
373
|
+
import { YunoPaymentMethods } from '@yuno-payments/yuno-sdk-react-native';
|
|
374
|
+
import { useState } from 'react';
|
|
375
|
+
import { View, Button, StyleSheet } from 'react-native';
|
|
376
|
+
|
|
377
|
+
function CheckoutScreen() {
|
|
378
|
+
const [checkoutSession] = useState('your_checkout_session_id');
|
|
379
|
+
const [isMethodSelected, setIsMethodSelected] = useState(false);
|
|
380
|
+
|
|
381
|
+
return (
|
|
382
|
+
<View style={styles.container}>
|
|
383
|
+
<YunoPaymentMethods
|
|
384
|
+
checkoutSession={checkoutSession}
|
|
385
|
+
countryCode="BR"
|
|
386
|
+
onPaymentMethodSelected={(event) => {
|
|
387
|
+
setIsMethodSelected(event.isSelected);
|
|
388
|
+
}}
|
|
389
|
+
onPaymentMethodError={(event) => {
|
|
390
|
+
console.error('Error loading payment methods:', event.message);
|
|
391
|
+
}}
|
|
392
|
+
style={styles.paymentMethods}
|
|
393
|
+
/>
|
|
394
|
+
|
|
395
|
+
<Button
|
|
396
|
+
title="Pay Now"
|
|
397
|
+
disabled={!isMethodSelected}
|
|
398
|
+
onPress={handlePayment}
|
|
399
|
+
/>
|
|
400
|
+
</View>
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const styles = StyleSheet.create({
|
|
405
|
+
container: {
|
|
406
|
+
flex: 1,
|
|
407
|
+
padding: 16,
|
|
408
|
+
},
|
|
409
|
+
paymentMethods: {
|
|
410
|
+
height: 400,
|
|
411
|
+
},
|
|
412
|
+
});
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Step 3: Start Payment
|
|
416
|
+
|
|
417
|
+
Trigger the payment flow when the user is ready:
|
|
409
418
|
|
|
410
|
-
|
|
419
|
+
```typescript
|
|
420
|
+
const handlePayment = async () => {
|
|
411
421
|
try {
|
|
412
422
|
await YunoSdk.startPayment(true); // true = show payment status screen
|
|
413
423
|
console.log('Payment flow started');
|
|
@@ -417,12 +427,24 @@ const handleFullPayment = async () => {
|
|
|
417
427
|
};
|
|
418
428
|
```
|
|
419
429
|
|
|
420
|
-
|
|
430
|
+
## startPayment Parameters
|
|
431
|
+
|
|
432
|
+
| Parameter | Type | Required | Default | Description |
|
|
433
|
+
|-----------|------|----------|---------|-------------|
|
|
434
|
+
| `showPaymentStatus` | `boolean` | ✓ | - | Whether to show the payment status screen after completion |
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
# Lite SDK (Payment React Native)
|
|
439
|
+
|
|
440
|
+
The Lite SDK provides more control over the payment flow by allowing you to specify which payment method to use.
|
|
421
441
|
|
|
422
|
-
|
|
442
|
+
## Implementation
|
|
443
|
+
|
|
444
|
+
### Step 1: Start Payment Lite
|
|
423
445
|
|
|
424
446
|
```typescript
|
|
425
|
-
import { YunoSdk } from '@yuno/yuno-sdk-react-native';
|
|
447
|
+
import { YunoSdk } from '@yuno-payments/yuno-sdk-react-native';
|
|
426
448
|
|
|
427
449
|
const handlePaymentLite = async () => {
|
|
428
450
|
try {
|
|
@@ -444,384 +466,429 @@ const handlePaymentLite = async () => {
|
|
|
444
466
|
};
|
|
445
467
|
```
|
|
446
468
|
|
|
447
|
-
|
|
469
|
+
## startPaymentLite Parameters
|
|
448
470
|
|
|
449
|
-
|
|
471
|
+
### StartPayment Object
|
|
450
472
|
|
|
451
|
-
|
|
452
|
-
|
|
473
|
+
| Parameter | Type | Required | Description |
|
|
474
|
+
|-----------|------|----------|-------------|
|
|
475
|
+
| `checkoutSession` | `string` | ✓ | Checkout session token from your backend |
|
|
476
|
+
| `methodSelected` | `MethodSelected` | ✓ | Selected payment method details |
|
|
477
|
+
| `showPaymentStatus` | `boolean` | | Show payment status screen (default: `true`) |
|
|
453
478
|
|
|
454
|
-
|
|
455
|
-
try {
|
|
456
|
-
const status = await YunoSdk.startPaymentSeamlessLite({
|
|
457
|
-
checkoutSession: 'checkout_session_token',
|
|
458
|
-
countryCode: 'US',
|
|
459
|
-
methodSelected: {
|
|
460
|
-
vaultedToken: 'payment_method_token',
|
|
461
|
-
paymentMethodType: 'CARD',
|
|
462
|
-
},
|
|
463
|
-
showPaymentStatus: false, // You handle the UI
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
console.log('Seamless payment status:', status);
|
|
467
|
-
|
|
468
|
-
if (status === YunoStatus.SUCCEEDED) {
|
|
469
|
-
// Handle success - navigate to confirmation
|
|
470
|
-
navigateToSuccess();
|
|
471
|
-
} else if (status === YunoStatus.PROCESSING) {
|
|
472
|
-
// Payment is processing
|
|
473
|
-
showProcessingState();
|
|
474
|
-
} else {
|
|
475
|
-
// Handle other statuses
|
|
476
|
-
handlePaymentError(status);
|
|
477
|
-
}
|
|
478
|
-
} catch (error) {
|
|
479
|
-
console.error('Seamless payment error:', error);
|
|
480
|
-
}
|
|
481
|
-
};
|
|
482
|
-
```
|
|
479
|
+
### MethodSelected Object
|
|
483
480
|
|
|
484
|
-
|
|
481
|
+
| Parameter | Type | Required | Description |
|
|
482
|
+
|-----------|------|----------|-------------|
|
|
483
|
+
| `vaultedToken` | `string` | ✓ | Saved payment method token |
|
|
484
|
+
| `paymentMethodType` | `string` | ✓ | Payment method type (e.g., `'CARD'`, `'PIX'`) |
|
|
485
|
+
|
|
486
|
+
---
|
|
485
487
|
|
|
486
|
-
|
|
488
|
+
# Lite SDK (Enrollment React Native)
|
|
489
|
+
|
|
490
|
+
The Enrollment SDK allows users to save payment methods without making a payment.
|
|
491
|
+
|
|
492
|
+
## Implementation
|
|
493
|
+
|
|
494
|
+
### Step 1: Subscribe to Enrollment Events
|
|
487
495
|
|
|
488
496
|
```typescript
|
|
489
|
-
import { YunoSdk, YunoStatus } from '@yuno/yuno-sdk-react-native';
|
|
497
|
+
import { YunoSdk, YunoStatus } from '@yuno-payments/yuno-sdk-react-native';
|
|
490
498
|
import { useEffect } from 'react';
|
|
491
499
|
|
|
492
500
|
function EnrollmentScreen() {
|
|
493
501
|
useEffect(() => {
|
|
494
|
-
// Listen to enrollment status
|
|
495
502
|
const subscription = YunoSdk.onEnrollmentStatus((state) => {
|
|
496
503
|
console.log('Enrollment Status:', state.status);
|
|
497
504
|
|
|
498
505
|
if (state.status === YunoStatus.SUCCEEDED) {
|
|
499
506
|
console.log('✅ Payment method saved successfully!');
|
|
500
|
-
// Navigate back or show success message
|
|
501
507
|
} else if (state.status === YunoStatus.FAILED) {
|
|
502
508
|
console.log('❌ Failed to save payment method');
|
|
503
|
-
// Show error message
|
|
504
509
|
}
|
|
505
510
|
});
|
|
506
511
|
|
|
507
512
|
return () => subscription.remove();
|
|
508
513
|
}, []);
|
|
509
|
-
|
|
510
|
-
const startEnrollment = async () => {
|
|
511
|
-
try {
|
|
512
|
-
await YunoSdk.enrollmentPayment({
|
|
513
|
-
customerSession: 'customer_session_token_from_backend',
|
|
514
|
-
countryCode: 'US',
|
|
515
|
-
showEnrollmentStatus: true,
|
|
516
|
-
});
|
|
517
|
-
console.log('Enrollment flow started');
|
|
518
|
-
} catch (error) {
|
|
519
|
-
console.error('Enrollment error:', error);
|
|
520
|
-
}
|
|
521
|
-
};
|
|
522
|
-
|
|
523
|
-
return (
|
|
524
|
-
// Your enrollment UI
|
|
525
|
-
);
|
|
526
|
-
}
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
### 7. Handle Deep Links
|
|
530
|
-
|
|
531
|
-
For payment methods that redirect to external apps or browsers:
|
|
532
|
-
|
|
533
|
-
```typescript
|
|
534
|
-
import { YunoSdk } from '@yuno/yuno-sdk-react-native';
|
|
535
|
-
import { Linking } from 'react-native';
|
|
536
|
-
import { useEffect } from 'react';
|
|
537
514
|
|
|
538
|
-
function App() {
|
|
539
|
-
useEffect(() => {
|
|
540
|
-
// Handle initial URL (app was opened from a closed state)
|
|
541
|
-
Linking.getInitialURL().then((url) => {
|
|
542
|
-
if (url) {
|
|
543
|
-
handleDeepLink(url);
|
|
544
|
-
}
|
|
545
|
-
});
|
|
546
|
-
|
|
547
|
-
// Handle URL changes (app is running)
|
|
548
|
-
const subscription = Linking.addEventListener('url', (event) => {
|
|
549
|
-
handleDeepLink(event.url);
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
return () => {
|
|
553
|
-
subscription.remove();
|
|
554
|
-
};
|
|
555
|
-
}, []);
|
|
556
|
-
|
|
557
|
-
const handleDeepLink = async (url: string) => {
|
|
558
|
-
console.log('Received deep link:', url);
|
|
559
|
-
|
|
560
|
-
try {
|
|
561
|
-
await YunoSdk.receiveDeeplink(url);
|
|
562
|
-
console.log('Deep link processed');
|
|
563
|
-
} catch (error) {
|
|
564
|
-
console.error('Error processing deep link:', error);
|
|
565
|
-
}
|
|
566
|
-
};
|
|
567
|
-
|
|
568
515
|
return (
|
|
569
|
-
// Your
|
|
516
|
+
// Your enrollment UI
|
|
570
517
|
);
|
|
571
518
|
}
|
|
572
519
|
```
|
|
573
520
|
|
|
574
|
-
###
|
|
575
|
-
|
|
576
|
-
Resume a previously started payment:
|
|
521
|
+
### Step 2: Start Enrollment
|
|
577
522
|
|
|
578
523
|
```typescript
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
const continueExistingPayment = async () => {
|
|
524
|
+
const startEnrollment = async () => {
|
|
582
525
|
try {
|
|
583
|
-
await YunoSdk.
|
|
584
|
-
'
|
|
585
|
-
'US',
|
|
586
|
-
true
|
|
587
|
-
);
|
|
588
|
-
console.log('
|
|
526
|
+
await YunoSdk.enrollmentPayment({
|
|
527
|
+
customerSession: 'customer_session_token_from_backend',
|
|
528
|
+
countryCode: 'US',
|
|
529
|
+
showPaymentStatus: true,
|
|
530
|
+
});
|
|
531
|
+
console.log('Enrollment flow started');
|
|
589
532
|
} catch (error) {
|
|
590
|
-
console.error('
|
|
533
|
+
console.error('Enrollment error:', error);
|
|
591
534
|
}
|
|
592
535
|
};
|
|
593
536
|
```
|
|
594
537
|
|
|
595
|
-
|
|
538
|
+
## enrollmentPayment Parameters
|
|
596
539
|
|
|
597
|
-
|
|
540
|
+
| Parameter | Type | Required | Description |
|
|
541
|
+
|-----------|------|----------|-------------|
|
|
542
|
+
| `customerSession` | `string` | ✓ | Customer session token from your backend |
|
|
543
|
+
| `countryCode` | `string` | | Country code (uses initialized value if not provided) |
|
|
544
|
+
| `showPaymentStatus` | `boolean` | | Show enrollment status (default: `true`) |
|
|
598
545
|
|
|
599
|
-
|
|
600
|
-
import { YunoSdk } from '@yuno/yuno-sdk-react-native';
|
|
546
|
+
---
|
|
601
547
|
|
|
602
|
-
|
|
603
|
-
try {
|
|
604
|
-
await YunoSdk.hideLoader();
|
|
605
|
-
console.log('Loader hidden');
|
|
606
|
-
} catch (error) {
|
|
607
|
-
console.error('Error hiding loader:', error);
|
|
608
|
-
}
|
|
609
|
-
};
|
|
610
|
-
```
|
|
548
|
+
# Seamless Payment (React Native)
|
|
611
549
|
|
|
612
|
-
|
|
550
|
+
The Seamless Payment flow provides maximum control over the UI while still leveraging the SDK for secure payment processing.
|
|
613
551
|
|
|
614
|
-
|
|
552
|
+
## Implementation
|
|
615
553
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
#### Static Methods
|
|
619
|
-
|
|
620
|
-
##### `initialize(params: YunoInitParams): Promise<void>`
|
|
554
|
+
```typescript
|
|
555
|
+
import { YunoSdk, YunoStatus } from '@yuno-payments/yuno-sdk-react-native';
|
|
621
556
|
|
|
622
|
-
|
|
557
|
+
const handleSeamlessPayment = async () => {
|
|
558
|
+
try {
|
|
559
|
+
const status = await YunoSdk.startPaymentSeamlessLite({
|
|
560
|
+
checkoutSession: 'checkout_session_token',
|
|
561
|
+
countryCode: 'US',
|
|
562
|
+
methodSelected: {
|
|
563
|
+
vaultedToken: 'payment_method_token',
|
|
564
|
+
paymentMethodType: 'CARD',
|
|
565
|
+
},
|
|
566
|
+
showPaymentStatus: false, // You handle the UI
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
console.log('Seamless payment status:', status);
|
|
570
|
+
|
|
571
|
+
if (status === YunoStatus.SUCCEEDED) {
|
|
572
|
+
navigateToSuccess();
|
|
573
|
+
} else if (status === YunoStatus.PROCESSING) {
|
|
574
|
+
showProcessingState();
|
|
575
|
+
} else {
|
|
576
|
+
handlePaymentError(status);
|
|
577
|
+
}
|
|
578
|
+
} catch (error) {
|
|
579
|
+
console.error('Seamless payment error:', error);
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
```
|
|
623
583
|
|
|
624
|
-
|
|
584
|
+
## startPaymentSeamlessLite Parameters
|
|
625
585
|
|
|
626
586
|
| Parameter | Type | Required | Description |
|
|
627
587
|
|-----------|------|----------|-------------|
|
|
628
|
-
| `
|
|
629
|
-
| `countryCode` | `string` |
|
|
630
|
-
| `
|
|
631
|
-
| `
|
|
632
|
-
| `androidConfig` | `AndroidConfig` | No | Android-specific configuration |
|
|
588
|
+
| `checkoutSession` | `string` | ✓ | Checkout session token |
|
|
589
|
+
| `countryCode` | `string` | | Country code |
|
|
590
|
+
| `methodSelected` | `MethodSelected` | ✓ | Payment method details |
|
|
591
|
+
| `showPaymentStatus` | `boolean` | | Show status screen (default: `false`) |
|
|
633
592
|
|
|
634
|
-
**
|
|
593
|
+
**Returns:** `Promise<YunoStatus>` - The payment status after completion
|
|
635
594
|
|
|
636
|
-
|
|
637
|
-
|----------|------|---------|-------------|
|
|
638
|
-
| `lang` | `YunoLanguage` | `EN` | UI language |
|
|
639
|
-
| `cardFlow` | `CardFlow` | `ONE_STEP` | Card input flow type |
|
|
640
|
-
| `saveCardEnabled` | `boolean` | `false` | Enable save card option |
|
|
641
|
-
| `keepLoader` | `boolean` | `false` | Keep loader visible after payment |
|
|
642
|
-
| `isDynamicViewEnabled` | `boolean` | `true` | Enable dynamic views |
|
|
595
|
+
---
|
|
643
596
|
|
|
644
|
-
|
|
597
|
+
# Headless SDK (Payment React Native)
|
|
645
598
|
|
|
646
|
-
|
|
647
|
-
await YunoSdk.initialize({
|
|
648
|
-
apiKey: 'your_api_key',
|
|
649
|
-
countryCode: 'US',
|
|
650
|
-
yunoConfig: {
|
|
651
|
-
lang: YunoLanguage.EN,
|
|
652
|
-
cardFlow: CardFlow.ONE_STEP,
|
|
653
|
-
saveCardEnabled: true,
|
|
654
|
-
},
|
|
655
|
-
});
|
|
656
|
-
```
|
|
599
|
+
The Headless SDK provides complete control over the UI while using the SDK for secure tokenization and 3D Secure handling.
|
|
657
600
|
|
|
658
|
-
|
|
601
|
+
## Generate Token
|
|
659
602
|
|
|
660
|
-
|
|
603
|
+
Use `generateToken` to tokenize payment data without the SDK UI:
|
|
661
604
|
|
|
662
|
-
|
|
605
|
+
```typescript
|
|
606
|
+
import { YunoSdk, CardType } from '@yuno-payments/yuno-sdk-react-native';
|
|
663
607
|
|
|
664
|
-
|
|
608
|
+
const handleHeadlessPayment = async () => {
|
|
609
|
+
try {
|
|
610
|
+
const result = await YunoSdk.generateToken(
|
|
611
|
+
{
|
|
612
|
+
checkoutSession: 'checkout_session_id',
|
|
613
|
+
paymentMethod: {
|
|
614
|
+
type: 'CARD',
|
|
615
|
+
vaultedToken: null,
|
|
616
|
+
card: {
|
|
617
|
+
save: false,
|
|
618
|
+
detail: {
|
|
619
|
+
expirationMonth: 11,
|
|
620
|
+
expirationYear: 25,
|
|
621
|
+
number: '4000000000001091',
|
|
622
|
+
securityCode: '123',
|
|
623
|
+
holderName: 'John Doe',
|
|
624
|
+
type: CardType.CREDIT,
|
|
625
|
+
},
|
|
626
|
+
},
|
|
627
|
+
},
|
|
628
|
+
},
|
|
629
|
+
'checkout_session_id',
|
|
630
|
+
'BR'
|
|
631
|
+
);
|
|
665
632
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
633
|
+
console.log('Token:', result.token);
|
|
634
|
+
|
|
635
|
+
// Send token to your backend for payment processing
|
|
636
|
+
await processPaymentOnBackend(result.token);
|
|
637
|
+
} catch (error) {
|
|
638
|
+
console.error('Token generation failed:', error);
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
```
|
|
669
642
|
|
|
670
|
-
|
|
643
|
+
## Handle 3D Secure Challenge
|
|
644
|
+
|
|
645
|
+
After generating a token, handle 3D Secure verification if required:
|
|
671
646
|
|
|
672
647
|
```typescript
|
|
673
|
-
|
|
648
|
+
const handle3DSChallenge = async (checkoutSession: string) => {
|
|
649
|
+
try {
|
|
650
|
+
const challengeResult = await YunoSdk.getThreeDSecureChallenge(
|
|
651
|
+
checkoutSession,
|
|
652
|
+
'BR'
|
|
653
|
+
);
|
|
654
|
+
|
|
655
|
+
if (challengeResult.type === 'URL') {
|
|
656
|
+
console.log('3DS URL:', challengeResult.data);
|
|
657
|
+
// Open this URL in a WebView for the user to complete 3DS verification
|
|
658
|
+
open3DSWebView(challengeResult.data);
|
|
659
|
+
}
|
|
660
|
+
} catch (error) {
|
|
661
|
+
console.error('3DS challenge failed:', error);
|
|
662
|
+
}
|
|
663
|
+
};
|
|
674
664
|
```
|
|
675
665
|
|
|
676
|
-
|
|
666
|
+
## TokenCollectedData Structure
|
|
677
667
|
|
|
678
|
-
|
|
668
|
+
### PaymentMethod Object
|
|
679
669
|
|
|
680
|
-
|
|
670
|
+
| Property | Type | Required | Description |
|
|
671
|
+
|----------|------|----------|-------------|
|
|
672
|
+
| `type` | `string` | ✓ | Payment method type (e.g., `'CARD'`) |
|
|
673
|
+
| `vaultedToken` | `string \| null` | | Token for saved payment method |
|
|
674
|
+
| `card` | `CardData` | | Card details (required for new cards) |
|
|
675
|
+
| `customer` | `Customer` | | Customer information |
|
|
681
676
|
|
|
682
|
-
|
|
677
|
+
### CardData Object
|
|
683
678
|
|
|
684
|
-
|
|
|
685
|
-
|
|
686
|
-
| `
|
|
687
|
-
| `
|
|
688
|
-
| `
|
|
689
|
-
| `params.methodSelected.paymentMethodType` | `string` | Yes | Payment method type (e.g., 'CARD') |
|
|
690
|
-
| `params.showPaymentStatus` | `boolean` | No | Show payment status screen (default: true) |
|
|
691
|
-
| `countryCode` | `string` | No | Country code override |
|
|
679
|
+
| Property | Type | Required | Description |
|
|
680
|
+
|----------|------|----------|-------------|
|
|
681
|
+
| `save` | `boolean` | | Save card for future use |
|
|
682
|
+
| `detail` | `Detail` | | Card details |
|
|
683
|
+
| `installment` | `Installment` | | Installment information |
|
|
692
684
|
|
|
693
|
-
|
|
685
|
+
### Detail Object
|
|
694
686
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
});
|
|
704
|
-
```
|
|
687
|
+
| Property | Type | Description |
|
|
688
|
+
|----------|------|-------------|
|
|
689
|
+
| `expirationMonth` | `number` | Card expiration month (1-12) |
|
|
690
|
+
| `expirationYear` | `number` | Card expiration year (2 digits) |
|
|
691
|
+
| `number` | `string` | Card number |
|
|
692
|
+
| `securityCode` | `string` | CVV/CVC |
|
|
693
|
+
| `holderName` | `string` | Cardholder name |
|
|
694
|
+
| `type` | `CardType` | `CREDIT` or `DEBIT` |
|
|
705
695
|
|
|
706
696
|
---
|
|
707
697
|
|
|
708
|
-
|
|
698
|
+
# Headless SDK (Enrollment React Native)
|
|
709
699
|
|
|
710
|
-
|
|
700
|
+
The Headless Enrollment SDK allows you to save payment methods with complete UI control.
|
|
711
701
|
|
|
712
|
-
|
|
702
|
+
## Continue Enrollment
|
|
713
703
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
| `params.checkoutSession` | `string` | Yes | Checkout session token |
|
|
717
|
-
| `params.countryCode` | `string` | Yes | Country code |
|
|
718
|
-
| `params.methodSelected` | `object` | Yes | Payment method details |
|
|
719
|
-
| `params.showPaymentStatus` | `boolean` | No | Show status screen (default: false) |
|
|
720
|
-
|
|
721
|
-
**Returns:** `Promise<YunoStatus>` - The payment status
|
|
704
|
+
```typescript
|
|
705
|
+
import { YunoSdk, CardType } from '@yuno-payments/yuno-sdk-react-native';
|
|
722
706
|
|
|
723
|
-
|
|
707
|
+
const handleHeadlessEnrollment = async () => {
|
|
708
|
+
try {
|
|
709
|
+
const result = await YunoSdk.continueEnrollment(
|
|
710
|
+
{
|
|
711
|
+
customerSession: 'customer_session_id',
|
|
712
|
+
paymentMethod: {
|
|
713
|
+
type: 'CARD',
|
|
714
|
+
card: {
|
|
715
|
+
save: true,
|
|
716
|
+
detail: {
|
|
717
|
+
expirationMonth: 11,
|
|
718
|
+
expirationYear: 25,
|
|
719
|
+
number: '4000000000001091',
|
|
720
|
+
securityCode: '123',
|
|
721
|
+
holderName: 'John Doe',
|
|
722
|
+
type: CardType.CREDIT,
|
|
723
|
+
},
|
|
724
|
+
},
|
|
725
|
+
},
|
|
726
|
+
},
|
|
727
|
+
'customer_session_id',
|
|
728
|
+
'BR'
|
|
729
|
+
);
|
|
724
730
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
vaultedToken: 'payment_token',
|
|
731
|
-
paymentMethodType: 'CARD',
|
|
732
|
-
},
|
|
733
|
-
showPaymentStatus: false,
|
|
734
|
-
});
|
|
731
|
+
console.log('Vaulted Token:', result.vaultedToken);
|
|
732
|
+
} catch (error) {
|
|
733
|
+
console.error('Enrollment failed:', error);
|
|
734
|
+
}
|
|
735
|
+
};
|
|
735
736
|
```
|
|
736
737
|
|
|
737
|
-
|
|
738
|
+
## EnrollmentCollectedData Structure
|
|
738
739
|
|
|
739
|
-
|
|
740
|
+
| Property | Type | Required | Description |
|
|
741
|
+
|----------|------|----------|-------------|
|
|
742
|
+
| `customerSession` | `string` | ✓ | Customer session ID |
|
|
743
|
+
| `paymentMethod` | `EnrollmentMethod` | ✓ | Payment method details |
|
|
740
744
|
|
|
741
|
-
|
|
745
|
+
---
|
|
742
746
|
|
|
743
|
-
|
|
747
|
+
# YunoPaymentMethods Component
|
|
744
748
|
|
|
745
|
-
|
|
746
|
-
|-----------|------|----------|-------------|
|
|
747
|
-
| `params.customerSession` | `string` | Yes | Customer session token from your backend |
|
|
748
|
-
| `params.countryCode` | `string` | Yes | Country code |
|
|
749
|
-
| `params.showEnrollmentStatus` | `boolean` | No | Show enrollment status (default: true) |
|
|
749
|
+
A native component that displays available payment methods using the Yuno SDK.
|
|
750
750
|
|
|
751
|
-
|
|
751
|
+
## Usage
|
|
752
752
|
|
|
753
|
-
```
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
753
|
+
```tsx
|
|
754
|
+
import { YunoPaymentMethods } from '@yuno-payments/yuno-sdk-react-native';
|
|
755
|
+
|
|
756
|
+
<YunoPaymentMethods
|
|
757
|
+
checkoutSession="your_checkout_session_id"
|
|
758
|
+
countryCode="BR"
|
|
759
|
+
onPaymentMethodSelected={(event) => {
|
|
760
|
+
console.log('Method selected:', event.isSelected);
|
|
761
|
+
}}
|
|
762
|
+
onPaymentMethodError={(event) => {
|
|
763
|
+
console.error('Error:', event.message);
|
|
764
|
+
}}
|
|
765
|
+
style={{ height: 400 }}
|
|
766
|
+
testID="payment-methods"
|
|
767
|
+
/>
|
|
759
768
|
```
|
|
760
769
|
|
|
761
|
-
|
|
770
|
+
## Props
|
|
762
771
|
|
|
763
|
-
|
|
772
|
+
| Prop | Type | Required | Description |
|
|
773
|
+
|------|------|----------|-------------|
|
|
774
|
+
| `checkoutSession` | `string` | ✓ | Checkout session ID from Yuno API |
|
|
775
|
+
| `countryCode` | `string` | ✓ | ISO country code (e.g., 'US', 'BR', 'CO') |
|
|
776
|
+
| `onPaymentMethodSelected` | `(event) => void` | | Callback when payment method is selected/deselected |
|
|
777
|
+
| `onPaymentMethodError` | `(event) => void` | | Callback when an error occurs |
|
|
778
|
+
| `style` | `ViewStyle` | | Custom styles for the container |
|
|
779
|
+
| `testID` | `string` | | Test ID for automation tools |
|
|
764
780
|
|
|
765
|
-
|
|
781
|
+
## Events
|
|
766
782
|
|
|
767
|
-
|
|
783
|
+
### PaymentMethodSelectedEvent
|
|
768
784
|
|
|
769
785
|
```typescript
|
|
770
|
-
|
|
786
|
+
interface PaymentMethodSelectedEvent {
|
|
787
|
+
isSelected: boolean; // Whether a payment method is currently selected
|
|
788
|
+
}
|
|
771
789
|
```
|
|
772
790
|
|
|
773
|
-
|
|
791
|
+
### PaymentMethodErrorEvent
|
|
774
792
|
|
|
775
|
-
|
|
793
|
+
```typescript
|
|
794
|
+
interface PaymentMethodErrorEvent {
|
|
795
|
+
message: string; // Error message
|
|
796
|
+
}
|
|
797
|
+
```
|
|
776
798
|
|
|
777
|
-
|
|
799
|
+
---
|
|
800
|
+
|
|
801
|
+
# Continue Payment
|
|
778
802
|
|
|
779
|
-
|
|
803
|
+
Resume a previously started payment that was interrupted:
|
|
780
804
|
|
|
781
805
|
```typescript
|
|
782
|
-
await YunoSdk.
|
|
806
|
+
await YunoSdk.continuePayment(
|
|
807
|
+
'checkout_session_token',
|
|
808
|
+
'US', // Country code
|
|
809
|
+
true // Show payment status
|
|
810
|
+
);
|
|
783
811
|
```
|
|
784
812
|
|
|
785
813
|
---
|
|
786
814
|
|
|
787
|
-
|
|
815
|
+
# Handle Deep Links
|
|
788
816
|
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
**Example:**
|
|
817
|
+
For payment methods that redirect to external apps or browsers (iOS only):
|
|
792
818
|
|
|
793
819
|
```typescript
|
|
794
|
-
|
|
820
|
+
import { YunoSdk } from '@yuno-payments/yuno-sdk-react-native';
|
|
821
|
+
import { Linking } from 'react-native';
|
|
822
|
+
import { useEffect } from 'react';
|
|
823
|
+
|
|
824
|
+
function App() {
|
|
825
|
+
useEffect(() => {
|
|
826
|
+
// Handle initial URL (app was opened from a closed state)
|
|
827
|
+
Linking.getInitialURL().then((url) => {
|
|
828
|
+
if (url) {
|
|
829
|
+
handleDeepLink(url);
|
|
830
|
+
}
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
// Handle URL changes (app is running)
|
|
834
|
+
const subscription = Linking.addEventListener('url', (event) => {
|
|
835
|
+
handleDeepLink(event.url);
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
return () => {
|
|
839
|
+
subscription.remove();
|
|
840
|
+
};
|
|
841
|
+
}, []);
|
|
842
|
+
|
|
843
|
+
const handleDeepLink = async (url: string) => {
|
|
844
|
+
console.log('Received deep link:', url);
|
|
845
|
+
|
|
846
|
+
try {
|
|
847
|
+
await YunoSdk.receiveDeeplink(url);
|
|
848
|
+
console.log('Deep link processed');
|
|
849
|
+
} catch (error) {
|
|
850
|
+
console.error('Error processing deep link:', error);
|
|
851
|
+
}
|
|
852
|
+
};
|
|
853
|
+
|
|
854
|
+
return (
|
|
855
|
+
// Your app
|
|
856
|
+
);
|
|
857
|
+
}
|
|
795
858
|
```
|
|
796
859
|
|
|
797
860
|
---
|
|
798
861
|
|
|
799
|
-
|
|
862
|
+
# Event Subscriptions
|
|
800
863
|
|
|
801
|
-
|
|
864
|
+
The SDK provides several event subscriptions for real-time status updates.
|
|
802
865
|
|
|
803
|
-
|
|
866
|
+
## onPaymentStatus
|
|
804
867
|
|
|
805
|
-
|
|
868
|
+
Listen to payment status changes:
|
|
806
869
|
|
|
807
870
|
```typescript
|
|
808
871
|
const subscription = YunoSdk.onPaymentStatus((state) => {
|
|
809
|
-
console.log('
|
|
872
|
+
console.log('Status:', state.status);
|
|
873
|
+
console.log('Token:', state.token);
|
|
810
874
|
});
|
|
811
875
|
|
|
812
|
-
// Later,
|
|
876
|
+
// Later, remove the listener
|
|
813
877
|
subscription.remove();
|
|
814
878
|
```
|
|
815
879
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
##### `onEnrollmentStatus(callback: (state: EnrollmentState) => void): Subscription`
|
|
880
|
+
### YunoPaymentState
|
|
819
881
|
|
|
820
|
-
|
|
882
|
+
```typescript
|
|
883
|
+
interface YunoPaymentState {
|
|
884
|
+
token?: string; // One-time token (if available)
|
|
885
|
+
status: YunoStatus; // Payment status
|
|
886
|
+
}
|
|
887
|
+
```
|
|
821
888
|
|
|
822
|
-
|
|
889
|
+
## onEnrollmentStatus
|
|
823
890
|
|
|
824
|
-
|
|
891
|
+
Listen to enrollment status changes:
|
|
825
892
|
|
|
826
893
|
```typescript
|
|
827
894
|
const subscription = YunoSdk.onEnrollmentStatus((state) => {
|
|
@@ -829,72 +896,111 @@ const subscription = YunoSdk.onEnrollmentStatus((state) => {
|
|
|
829
896
|
});
|
|
830
897
|
```
|
|
831
898
|
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
##### `onOneTimeToken(callback: (token: string) => void): Subscription`
|
|
899
|
+
### YunoEnrollmentState
|
|
835
900
|
|
|
836
|
-
|
|
901
|
+
```typescript
|
|
902
|
+
interface YunoEnrollmentState {
|
|
903
|
+
status: YunoStatus; // Enrollment status
|
|
904
|
+
}
|
|
905
|
+
```
|
|
837
906
|
|
|
838
|
-
|
|
907
|
+
## onOneTimeToken
|
|
839
908
|
|
|
840
|
-
|
|
909
|
+
Listen to one-time token generation:
|
|
841
910
|
|
|
842
911
|
```typescript
|
|
843
912
|
const subscription = YunoSdk.onOneTimeToken((token) => {
|
|
844
|
-
console.log('
|
|
845
|
-
// Send to your backend
|
|
913
|
+
console.log('Token:', token);
|
|
846
914
|
});
|
|
847
915
|
```
|
|
848
916
|
|
|
849
|
-
|
|
917
|
+
## onOneTimeTokenInfo
|
|
850
918
|
|
|
851
|
-
|
|
919
|
+
Listen to extended token information:
|
|
852
920
|
|
|
853
|
-
|
|
921
|
+
```typescript
|
|
922
|
+
const subscription = YunoSdk.onOneTimeTokenInfo((tokenInfo) => {
|
|
923
|
+
console.log('Token:', tokenInfo.token);
|
|
924
|
+
console.log('Card Brand:', tokenInfo.cardData?.brand);
|
|
925
|
+
console.log('Customer Email:', tokenInfo.customer?.email);
|
|
926
|
+
});
|
|
927
|
+
```
|
|
854
928
|
|
|
855
|
-
|
|
929
|
+
### OneTimeTokenInfo
|
|
856
930
|
|
|
857
931
|
```typescript
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
PL = 'PL', // Polish
|
|
866
|
-
IT = 'IT', // Italian
|
|
867
|
-
DE = 'DE', // German
|
|
868
|
-
RU = 'RU', // Russian
|
|
869
|
-
TR = 'TR', // Turkish
|
|
870
|
-
NL = 'NL', // Dutch
|
|
871
|
-
SV = 'SV', // Swedish
|
|
872
|
-
TH = 'TH', // Thai
|
|
873
|
-
FIL = 'FIL', // Filipino
|
|
874
|
-
VI = 'VI', // Vietnamese
|
|
875
|
-
ZH_CN = 'ZH-CN', // Chinese (Simplified)
|
|
876
|
-
ZH_TW = 'ZH-TW', // Chinese (Traditional)
|
|
932
|
+
interface OneTimeTokenInfo {
|
|
933
|
+
token?: string;
|
|
934
|
+
vaultedToken?: string;
|
|
935
|
+
vaultOnSuccess?: boolean;
|
|
936
|
+
type?: string;
|
|
937
|
+
cardData?: CardInformation;
|
|
938
|
+
customer?: CustomerPayerInformation;
|
|
877
939
|
}
|
|
878
940
|
```
|
|
879
941
|
|
|
880
|
-
|
|
942
|
+
---
|
|
943
|
+
|
|
944
|
+
# Utility Methods
|
|
945
|
+
|
|
946
|
+
## hideLoader
|
|
881
947
|
|
|
882
|
-
|
|
948
|
+
Manually hide the SDK loader:
|
|
949
|
+
|
|
950
|
+
```typescript
|
|
951
|
+
await YunoSdk.hideLoader();
|
|
952
|
+
```
|
|
953
|
+
|
|
954
|
+
## getLastOneTimeToken
|
|
955
|
+
|
|
956
|
+
Get the last generated OTT:
|
|
957
|
+
|
|
958
|
+
```typescript
|
|
959
|
+
const lastOtt = await YunoSdk.getLastOneTimeToken();
|
|
960
|
+
```
|
|
961
|
+
|
|
962
|
+
## getLastOneTimeTokenInfo
|
|
963
|
+
|
|
964
|
+
Get extended information about the last OTT:
|
|
965
|
+
|
|
966
|
+
```typescript
|
|
967
|
+
const tokenInfo = await YunoSdk.getLastOneTimeTokenInfo();
|
|
968
|
+
```
|
|
969
|
+
|
|
970
|
+
## clearLastOneTimeToken
|
|
971
|
+
|
|
972
|
+
Clear stored OTT data:
|
|
973
|
+
|
|
974
|
+
```typescript
|
|
975
|
+
await YunoSdk.clearLastOneTimeToken();
|
|
976
|
+
```
|
|
977
|
+
|
|
978
|
+
## clearLastPaymentStatus
|
|
979
|
+
|
|
980
|
+
Clear stored payment status:
|
|
981
|
+
|
|
982
|
+
```typescript
|
|
983
|
+
await YunoSdk.clearLastPaymentStatus();
|
|
984
|
+
```
|
|
985
|
+
|
|
986
|
+
---
|
|
987
|
+
|
|
988
|
+
# Enums
|
|
989
|
+
|
|
990
|
+
## YunoStatus
|
|
883
991
|
|
|
884
992
|
```typescript
|
|
885
993
|
enum YunoStatus {
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
PROCESSING = 'PROCESSING', // Payment is processing
|
|
994
|
+
REJECTED = 'REJECTED', // Payment/operation was rejected
|
|
995
|
+
SUCCEEDED = 'SUCCEEDED', // Payment/operation succeeded
|
|
996
|
+
FAILED = 'FAILED', // Payment/operation failed
|
|
997
|
+
PROCESSING = 'PROCESSING', // Payment is being processed
|
|
891
998
|
INTERNAL_ERROR = 'INTERNAL_ERROR', // Internal error occurred
|
|
999
|
+
CANCELLED_BY_USER = 'CANCELLED_BY_USER', // Cancelled by user
|
|
892
1000
|
}
|
|
893
1001
|
```
|
|
894
1002
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
Card input flow types.
|
|
1003
|
+
## CardFlow
|
|
898
1004
|
|
|
899
1005
|
```typescript
|
|
900
1006
|
enum CardFlow {
|
|
@@ -903,75 +1009,166 @@ enum CardFlow {
|
|
|
903
1009
|
}
|
|
904
1010
|
```
|
|
905
1011
|
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
### Types
|
|
909
|
-
|
|
910
|
-
#### PaymentState
|
|
1012
|
+
## CardType
|
|
911
1013
|
|
|
912
1014
|
```typescript
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
1015
|
+
enum CardType {
|
|
1016
|
+
CREDIT = 'CREDIT',
|
|
1017
|
+
DEBIT = 'DEBIT',
|
|
916
1018
|
}
|
|
917
1019
|
```
|
|
918
1020
|
|
|
919
|
-
|
|
1021
|
+
## YunoLanguage
|
|
920
1022
|
|
|
921
1023
|
```typescript
|
|
922
|
-
|
|
923
|
-
|
|
1024
|
+
enum YunoLanguage {
|
|
1025
|
+
EN = 'EN', // English
|
|
1026
|
+
ES = 'ES', // Spanish
|
|
1027
|
+
PT = 'PT', // Portuguese
|
|
1028
|
+
ID = 'ID', // Indonesian
|
|
1029
|
+
MY = 'MY', // Malay
|
|
1030
|
+
MS = 'MS', // Malaysian
|
|
1031
|
+
FR = 'FR', // French
|
|
1032
|
+
PL = 'PL', // Polish
|
|
1033
|
+
IT = 'IT', // Italian
|
|
1034
|
+
DE = 'DE', // German
|
|
1035
|
+
RU = 'RU', // Russian
|
|
1036
|
+
TR = 'TR', // Turkish
|
|
1037
|
+
NL = 'NL', // Dutch
|
|
1038
|
+
SV = 'SV', // Swedish
|
|
1039
|
+
TH = 'TH', // Thai
|
|
1040
|
+
FIL = 'FIL', // Filipino
|
|
1041
|
+
VI = 'VI', // Vietnamese
|
|
1042
|
+
ZH_CN = 'ZH-CN', // Chinese (Simplified)
|
|
1043
|
+
ZH_TW = 'ZH-TW', // Chinese (Traditional)
|
|
924
1044
|
}
|
|
925
1045
|
```
|
|
926
1046
|
|
|
927
|
-
|
|
1047
|
+
---
|
|
928
1048
|
|
|
929
|
-
|
|
1049
|
+
# Complete Example
|
|
930
1050
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
1051
|
+
Here's a complete implementation example:
|
|
1052
|
+
|
|
1053
|
+
```tsx
|
|
1054
|
+
import React, { useEffect, useState } from 'react';
|
|
1055
|
+
import { View, Button, Alert, StyleSheet } from 'react-native';
|
|
1056
|
+
import {
|
|
1057
|
+
YunoSdk,
|
|
1058
|
+
YunoPaymentMethods,
|
|
934
1059
|
YunoStatus,
|
|
935
1060
|
CardFlow,
|
|
936
|
-
|
|
937
|
-
StartPayment,
|
|
938
|
-
SeamlessArguments,
|
|
939
|
-
EnrollmentArguments,
|
|
940
|
-
} from '@yuno/yuno-sdk-react-native';
|
|
941
|
-
```
|
|
1061
|
+
} from '@yuno-payments/yuno-sdk-react-native';
|
|
942
1062
|
|
|
943
|
-
|
|
1063
|
+
function PaymentScreen() {
|
|
1064
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
1065
|
+
const [checkoutSession, setCheckoutSession] = useState('');
|
|
1066
|
+
const [isMethodSelected, setIsMethodSelected] = useState(false);
|
|
944
1067
|
|
|
945
|
-
|
|
1068
|
+
useEffect(() => {
|
|
1069
|
+
initializeYuno();
|
|
1070
|
+
|
|
1071
|
+
// Set up event listeners
|
|
1072
|
+
const paymentSubscription = YunoSdk.onPaymentStatus((state) => {
|
|
1073
|
+
if (state.status === YunoStatus.SUCCEEDED) {
|
|
1074
|
+
Alert.alert('Success', 'Payment completed successfully!');
|
|
1075
|
+
} else if (state.status === YunoStatus.FAILED) {
|
|
1076
|
+
Alert.alert('Error', 'Payment failed. Please try again.');
|
|
1077
|
+
}
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
const tokenSubscription = YunoSdk.onOneTimeToken((token) => {
|
|
1081
|
+
console.log('OTT received:', token);
|
|
1082
|
+
// Send to backend
|
|
1083
|
+
});
|
|
1084
|
+
|
|
1085
|
+
return () => {
|
|
1086
|
+
paymentSubscription.remove();
|
|
1087
|
+
tokenSubscription.remove();
|
|
1088
|
+
};
|
|
1089
|
+
}, []);
|
|
946
1090
|
|
|
947
|
-
|
|
1091
|
+
const initializeYuno = async () => {
|
|
1092
|
+
try {
|
|
1093
|
+
await YunoSdk.initialize({
|
|
1094
|
+
apiKey: 'YOUR_API_KEY',
|
|
1095
|
+
countryCode: 'US',
|
|
1096
|
+
yunoConfig: {
|
|
1097
|
+
language: 'en',
|
|
1098
|
+
cardFlow: CardFlow.ONE_STEP,
|
|
1099
|
+
saveCardEnabled: true,
|
|
1100
|
+
},
|
|
1101
|
+
});
|
|
1102
|
+
setIsInitialized(true);
|
|
1103
|
+
|
|
1104
|
+
// Fetch checkout session from your backend
|
|
1105
|
+
const session = await fetchCheckoutSession();
|
|
1106
|
+
setCheckoutSession(session);
|
|
1107
|
+
} catch (error) {
|
|
1108
|
+
console.error('Initialization error:', error);
|
|
1109
|
+
}
|
|
1110
|
+
};
|
|
948
1111
|
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
1112
|
+
const handlePayment = async () => {
|
|
1113
|
+
try {
|
|
1114
|
+
await YunoSdk.startPayment(true);
|
|
1115
|
+
} catch (error) {
|
|
1116
|
+
console.error('Payment error:', error);
|
|
1117
|
+
}
|
|
1118
|
+
};
|
|
954
1119
|
|
|
955
|
-
|
|
1120
|
+
if (!isInitialized || !checkoutSession) {
|
|
1121
|
+
return null; // Or loading indicator
|
|
1122
|
+
}
|
|
956
1123
|
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1124
|
+
return (
|
|
1125
|
+
<View style={styles.container}>
|
|
1126
|
+
<YunoPaymentMethods
|
|
1127
|
+
checkoutSession={checkoutSession}
|
|
1128
|
+
countryCode="US"
|
|
1129
|
+
onPaymentMethodSelected={(event) => {
|
|
1130
|
+
setIsMethodSelected(event.isSelected);
|
|
1131
|
+
}}
|
|
1132
|
+
onPaymentMethodError={(event) => {
|
|
1133
|
+
Alert.alert('Error', event.message);
|
|
1134
|
+
}}
|
|
1135
|
+
style={styles.paymentMethods}
|
|
1136
|
+
/>
|
|
1137
|
+
|
|
1138
|
+
<Button
|
|
1139
|
+
title="Pay Now"
|
|
1140
|
+
disabled={!isMethodSelected}
|
|
1141
|
+
onPress={handlePayment}
|
|
1142
|
+
/>
|
|
1143
|
+
</View>
|
|
1144
|
+
);
|
|
1145
|
+
}
|
|
961
1146
|
|
|
962
|
-
|
|
963
|
-
|
|
1147
|
+
const styles = StyleSheet.create({
|
|
1148
|
+
container: {
|
|
1149
|
+
flex: 1,
|
|
1150
|
+
padding: 16,
|
|
1151
|
+
},
|
|
1152
|
+
paymentMethods: {
|
|
1153
|
+
flex: 1,
|
|
1154
|
+
marginBottom: 16,
|
|
1155
|
+
},
|
|
1156
|
+
});
|
|
964
1157
|
|
|
965
|
-
|
|
966
|
-
cd ios && pod install && cd ..
|
|
967
|
-
npm run ios
|
|
1158
|
+
export default PaymentScreen;
|
|
968
1159
|
```
|
|
969
1160
|
|
|
970
|
-
|
|
1161
|
+
---
|
|
1162
|
+
|
|
1163
|
+
# Troubleshooting
|
|
1164
|
+
|
|
1165
|
+
## Common Issues
|
|
971
1166
|
|
|
972
|
-
###
|
|
1167
|
+
### "Yuno SDK is not initialized" Error
|
|
1168
|
+
|
|
1169
|
+
**Solution:** Ensure you call `YunoSdk.initialize()` before any other SDK methods. For Android, also verify that `YunoSdkModule.initialize()` is called in your `MainApplication.onCreate()`.
|
|
973
1170
|
|
|
974
|
-
|
|
1171
|
+
### Android: Build Fails with "Could not resolve dependency"
|
|
975
1172
|
|
|
976
1173
|
**Solution:** Ensure you've added the Yuno Maven repository to your `android/build.gradle`:
|
|
977
1174
|
|
|
@@ -979,7 +1176,7 @@ npm run ios
|
|
|
979
1176
|
maven { url "https://yunopayments.jfrog.io/artifactory/snapshots-libs-release" }
|
|
980
1177
|
```
|
|
981
1178
|
|
|
982
|
-
|
|
1179
|
+
### iOS: Pod Install Fails
|
|
983
1180
|
|
|
984
1181
|
**Solution:**
|
|
985
1182
|
|
|
@@ -991,11 +1188,7 @@ pod install
|
|
|
991
1188
|
cd ..
|
|
992
1189
|
```
|
|
993
1190
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
**Solution:** Ensure you call `YunoSdk.initialize()` before any other SDK methods. For Android, also verify that `YunoSdkModule.initialize()` is called in your `MainApplication.onCreate()`.
|
|
997
|
-
|
|
998
|
-
#### Payment Events Not Received
|
|
1191
|
+
### Payment Events Not Received
|
|
999
1192
|
|
|
1000
1193
|
**Solution:** Make sure you subscribe to events before starting the payment flow:
|
|
1001
1194
|
|
|
@@ -1009,146 +1202,45 @@ useEffect(() => {
|
|
|
1009
1202
|
}, []);
|
|
1010
1203
|
```
|
|
1011
1204
|
|
|
1012
|
-
|
|
1205
|
+
### Deep Links Not Working (iOS)
|
|
1013
1206
|
|
|
1014
1207
|
**Solution:** Verify your `Info.plist` has the correct URL scheme configuration and that you're listening to the `Linking` events.
|
|
1015
1208
|
|
|
1016
|
-
|
|
1209
|
+
## Debug Mode
|
|
1017
1210
|
|
|
1018
1211
|
Enable debug logging:
|
|
1019
1212
|
|
|
1020
|
-
```typescript
|
|
1021
|
-
// Android: Check logcat
|
|
1022
|
-
adb logcat | grep -i yuno
|
|
1023
|
-
|
|
1024
|
-
// iOS: Check Xcode console
|
|
1025
|
-
```
|
|
1026
|
-
|
|
1027
|
-
### Getting Help
|
|
1028
|
-
|
|
1029
|
-
1. Check the [Example App](https://github.com/yuno-payments/yuno-sdk-react-native-example)
|
|
1030
|
-
2. Review the [API Reference](#-api-reference)
|
|
1031
|
-
3. Search existing [GitHub Issues](https://github.com/yuno-payments/yuno-sdk-react-native/issues)
|
|
1032
|
-
4. Open a new [GitHub Issue](https://github.com/yuno-payments/yuno-sdk-react-native/issues/new)
|
|
1033
|
-
|
|
1034
|
-
## 🏗️ Project Structure
|
|
1035
|
-
|
|
1036
|
-
```
|
|
1037
|
-
yuno-sdk-react-native/
|
|
1038
|
-
├── src/
|
|
1039
|
-
│ ├── core/
|
|
1040
|
-
│ │ ├── enums/
|
|
1041
|
-
│ │ │ ├── CardFlow.ts
|
|
1042
|
-
│ │ │ ├── YunoLanguage.ts
|
|
1043
|
-
│ │ │ └── YunoStatus.ts
|
|
1044
|
-
│ │ └── types/
|
|
1045
|
-
│ │ ├── YunoConfig.ts
|
|
1046
|
-
│ │ ├── StartPayment.ts
|
|
1047
|
-
│ │ ├── SeamlessArguments.ts
|
|
1048
|
-
│ │ └── EnrollmentArguments.ts
|
|
1049
|
-
│ ├── YunoSdk.ts # Main SDK class
|
|
1050
|
-
│ ├── YunoPaymentMethods.tsx # Payment methods component
|
|
1051
|
-
│ └── index.ts # Public API exports
|
|
1052
|
-
├── android/ # Android native implementation
|
|
1053
|
-
│ ├── build.gradle
|
|
1054
|
-
│ └── src/main/java/com/yunosdkreactnative/
|
|
1055
|
-
│ ├── YunoSdkModule.kt
|
|
1056
|
-
│ └── YunoSdkPackage.kt
|
|
1057
|
-
├── ios/ # iOS native implementation
|
|
1058
|
-
│ ├── YunoSdk.swift
|
|
1059
|
-
│ ├── YunoSdk.m
|
|
1060
|
-
│ └── YunoSdk.podspec
|
|
1061
|
-
├── package.json
|
|
1062
|
-
└── README.md
|
|
1063
|
-
```
|
|
1064
|
-
|
|
1065
|
-
## 🤝 Contributing
|
|
1066
|
-
|
|
1067
|
-
We welcome contributions from the community! Here's how you can help:
|
|
1068
|
-
|
|
1069
|
-
### Development Setup
|
|
1070
|
-
|
|
1071
|
-
1. **Fork and clone the repository:**
|
|
1072
|
-
|
|
1073
|
-
```bash
|
|
1074
|
-
git clone https://github.com/yuno-payments/yuno-sdk-react-native.git
|
|
1075
|
-
cd yuno-sdk-react-native
|
|
1076
|
-
```
|
|
1077
|
-
|
|
1078
|
-
2. **Install dependencies:**
|
|
1079
|
-
|
|
1080
1213
|
```bash
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
3. **Run type checking:**
|
|
1085
|
-
|
|
1086
|
-
```bash
|
|
1087
|
-
npm run typecheck
|
|
1088
|
-
```
|
|
1089
|
-
|
|
1090
|
-
4. **Run linting:**
|
|
1214
|
+
# Android: Check logcat
|
|
1215
|
+
adb logcat | grep -i yuno
|
|
1091
1216
|
|
|
1092
|
-
|
|
1093
|
-
npm run lint
|
|
1217
|
+
# iOS: Check Xcode console
|
|
1094
1218
|
```
|
|
1095
1219
|
|
|
1096
|
-
### Contribution Guidelines
|
|
1097
|
-
|
|
1098
|
-
- Write clear, descriptive commit messages
|
|
1099
|
-
- Add tests for new features
|
|
1100
|
-
- Update documentation for API changes
|
|
1101
|
-
- Follow the existing code style
|
|
1102
|
-
- Open an issue before starting work on major changes
|
|
1103
|
-
|
|
1104
|
-
### Submitting Changes
|
|
1105
|
-
|
|
1106
|
-
1. Create a feature branch: `git checkout -b feature/my-feature`
|
|
1107
|
-
2. Make your changes and commit: `git commit -am 'Add new feature'`
|
|
1108
|
-
3. Push to your fork: `git push origin feature/my-feature`
|
|
1109
|
-
4. Open a Pull Request
|
|
1110
|
-
|
|
1111
|
-
## 🔄 Versioning
|
|
1112
|
-
|
|
1113
|
-
This project follows [Semantic Versioning](https://semver.org/):
|
|
1114
|
-
|
|
1115
|
-
- **MAJOR**: Breaking changes
|
|
1116
|
-
- **MINOR**: New features (backwards compatible)
|
|
1117
|
-
- **PATCH**: Bug fixes (backwards compatible)
|
|
1118
|
-
|
|
1119
|
-
## 📄 License
|
|
1120
|
-
|
|
1121
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
1122
|
-
|
|
1123
|
-
## 🔗 Links
|
|
1124
|
-
|
|
1125
|
-
- **Website:** [https://www.y.uno/](https://www.y.uno/)
|
|
1126
|
-
- **Documentation:** [https://docs.y.uno/](https://docs.y.uno/)
|
|
1127
|
-
- **GitHub:** [https://github.com/yuno-payments/yuno-sdk-react-native](https://github.com/yuno-payments/yuno-sdk-react-native)
|
|
1128
|
-
- **Example App:** [https://github.com/yuno-payments/yuno-sdk-react-native-example](https://github.com/yuno-payments/yuno-sdk-react-native-example)
|
|
1129
|
-
- **npm Package:** [https://www.npmjs.com/package/@yuno/yuno-sdk-react-native](https://www.npmjs.com/package/@yuno/yuno-sdk-react-native)
|
|
1130
|
-
|
|
1131
|
-
## 💬 Support
|
|
1132
|
-
|
|
1133
|
-
### Community Support
|
|
1134
|
-
|
|
1135
|
-
For issues, questions, or feature requests:
|
|
1136
|
-
- 🐛 [Report a Bug](https://github.com/yuno-payments/yuno-sdk-react-native/issues/new?labels=bug)
|
|
1137
|
-
- 💡 [Request a Feature](https://github.com/yuno-payments/yuno-sdk-react-native/issues/new?labels=enhancement)
|
|
1138
|
-
- ❓ [Ask a Question](https://github.com/yuno-payments/yuno-sdk-react-native/discussions)
|
|
1139
|
-
|
|
1140
|
-
### Enterprise Support
|
|
1141
|
-
|
|
1142
|
-
For enterprise customers with support agreements:
|
|
1143
|
-
- 📧 Email: support@y.uno
|
|
1144
|
-
- 🌐 Visit: [https://www.y.uno/contact](https://www.y.uno/contact)
|
|
1145
|
-
|
|
1146
1220
|
---
|
|
1147
1221
|
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1222
|
+
# API Reference Summary
|
|
1223
|
+
|
|
1224
|
+
## YunoSdk Methods
|
|
1225
|
+
|
|
1226
|
+
| Method | Description |
|
|
1227
|
+
|--------|-------------|
|
|
1228
|
+
| `initialize(params)` | Initialize the SDK |
|
|
1229
|
+
| `startPayment(showStatus)` | Start full payment flow |
|
|
1230
|
+
| `startPaymentLite(params, countryCode?)` | Start lite payment flow |
|
|
1231
|
+
| `startPaymentSeamlessLite(params)` | Start seamless payment flow |
|
|
1232
|
+
| `enrollmentPayment(params)` | Start enrollment flow |
|
|
1233
|
+
| `continuePayment(session, country?, showStatus?)` | Continue interrupted payment |
|
|
1234
|
+
| `generateToken(data, session, country?)` | Generate token (headless) |
|
|
1235
|
+
| `getThreeDSecureChallenge(session, country?)` | Get 3DS challenge URL |
|
|
1236
|
+
| `continueEnrollment(data, session, country?)` | Continue enrollment (headless) |
|
|
1237
|
+
| `hideLoader()` | Hide SDK loader |
|
|
1238
|
+
| `receiveDeeplink(url)` | Handle deep link (iOS) |
|
|
1239
|
+
| `getLastOneTimeToken()` | Get last OTT |
|
|
1240
|
+
| `getLastOneTimeTokenInfo()` | Get last OTT info |
|
|
1241
|
+
| `clearLastOneTimeToken()` | Clear stored OTT |
|
|
1242
|
+
| `clearLastPaymentStatus()` | Clear payment status |
|
|
1243
|
+
| `onPaymentStatus(listener)` | Subscribe to payment events |
|
|
1244
|
+
| `onEnrollmentStatus(listener)` | Subscribe to enrollment events |
|
|
1245
|
+
| `onOneTimeToken(listener)` | Subscribe to OTT events |
|
|
1246
|
+
| `onOneTimeTokenInfo(listener)` | Subscribe to OTT info events |
|