@tapayadot/accept-react-native 1.3.2 → 1.14.1
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 +196 -363
- package/android/build.gradle +23 -34
- package/android/src/main/java/com/tapaya/acceptsdkreactnative/AcceptSdkReactNativeModule.kt +191 -673
- package/android/src/main/java/com/tapaya/acceptsdkreactnative/Errors.kt +81 -0
- package/android/src/main/java/com/tapaya/acceptsdkreactnative/Parsing.kt +166 -0
- package/android/src/main/java/com/tapaya/acceptsdkreactnative/Serialization.kt +216 -0
- package/app.json +2 -2
- package/app.plugin.js +1 -1
- package/build/Accept.d.ts +255 -0
- package/build/Accept.d.ts.map +1 -0
- package/build/Accept.js +387 -0
- package/build/Accept.js.map +1 -0
- package/build/Accept.types.d.ts +352 -0
- package/build/Accept.types.d.ts.map +1 -0
- package/build/Accept.types.js +9 -0
- package/build/Accept.types.js.map +1 -0
- package/build/AcceptError.d.ts +53 -0
- package/build/AcceptError.d.ts.map +1 -0
- package/build/AcceptError.js +107 -0
- package/build/AcceptError.js.map +1 -0
- package/build/AcceptSdkReactNativeModule.d.ts +67 -26
- package/build/AcceptSdkReactNativeModule.d.ts.map +1 -1
- package/build/AcceptSdkReactNativeModule.js +53 -3
- package/build/AcceptSdkReactNativeModule.js.map +1 -1
- package/build/index.d.ts +7 -237
- package/build/index.d.ts.map +1 -1
- package/build/index.js +7 -254
- package/build/index.js.map +1 -1
- package/build/utils.d.ts.map +1 -1
- package/build/utils.js +2 -2
- package/build/utils.js.map +1 -1
- package/expo-module.config.json +1 -6
- package/package.json +8 -12
- package/plugin/withAcceptSdk.js +45 -0
- package/build/AcceptSdkReactNative.types.d.ts +0 -259
- package/build/AcceptSdkReactNative.types.d.ts.map +0 -1
- package/build/AcceptSdkReactNative.types.js +0 -2
- package/build/AcceptSdkReactNative.types.js.map +0 -1
- package/ios/.xcode.env +0 -11
- package/ios/AcceptSdkReactNative.podspec +0 -33
- package/ios/AcceptSdkReactNativeAppDelegate.swift +0 -13
- package/ios/AcceptSdkReactNativeModule.swift +0 -749
- package/ios/Podfile +0 -63
- package/ios/Podfile.properties.json +0 -4
- package/ios/acceptsdkreactnative.xcodeproj/project.pbxproj +0 -540
- package/ios/acceptsdkreactnative.xcodeproj/xcshareddata/xcschemes/acceptsdkreactnative.xcscheme +0 -88
- package/plugin/withCustomRepoModule.js +0 -96
package/README.md
CHANGED
|
@@ -1,462 +1,295 @@
|
|
|
1
|
-

|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# Tapaya Accept SDK for React Native
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Accept card payments on Android terminals from a React Native or Expo app.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
```
|
|
7
|
+
This package is a thin wrapper over the [Accept SDK for Android](https://docs.tapaya.com)
|
|
8
|
+
(`com.tapaya:accept`), which in turn drives the **Accept plugin app** — the companion
|
|
9
|
+
installed on the terminal that owns the card reader and the payment UI. Every surface here
|
|
10
|
+
mirrors the Android SDK 1:1, so its reference documentation applies unchanged.
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
Full documentation: [docs.tapaya.com](https://docs.tapaya.com)
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
## Requirements
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
- **Android only.** There is no iOS implementation. The package is safe to import on
|
|
17
|
+
iOS, but every call throws, so guard them with `Platform.OS === 'android'`.
|
|
18
|
+
- **`minSdkVersion` 30** (Android 11). The config plugin raises the host app to match.
|
|
19
|
+
- **Expo SDK 54+**, or a bare React Native app using `expo-modules-core`. Verified against
|
|
20
|
+
SDK 57 / React Native 0.86 on an Android 16 terminal.
|
|
21
|
+
- A **custom development build** — this package contains native code and does not run in
|
|
22
|
+
Expo Go.
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
## Installation
|
|
26
25
|
|
|
27
26
|
```sh
|
|
28
|
-
npx expo
|
|
27
|
+
npx expo install @tapayadot/accept-react-native
|
|
29
28
|
```
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
The plugin accepts options to toggle optional native features. Pass them as the second element of the plugin entry in `app.json`:
|
|
34
|
-
|
|
35
|
-
| Option | Type | Default | Description |
|
|
36
|
-
|---|---|---|---|
|
|
37
|
-
| `enableStripe` | `boolean` | `false` | Android only. Bundle the optional `com.tapaya:accept-stripe` dependency. Enable this only if your merchant account uses Stripe-backed payment processing. |
|
|
30
|
+
Add the config plugin to `app.json`:
|
|
38
31
|
|
|
39
32
|
```json
|
|
40
33
|
{
|
|
41
34
|
"expo": {
|
|
42
|
-
"plugins": [
|
|
43
|
-
[
|
|
44
|
-
"@tapayadot/accept-react-native",
|
|
45
|
-
{ "enableStripe": true }
|
|
46
|
-
]
|
|
47
|
-
]
|
|
35
|
+
"plugins": ["@tapayadot/accept-react-native"]
|
|
48
36
|
}
|
|
49
37
|
}
|
|
50
38
|
```
|
|
51
39
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
Re-run prebuild after changing plugin options so the native projects pick up the change:
|
|
40
|
+
Then rebuild the native project:
|
|
55
41
|
|
|
56
42
|
```sh
|
|
57
43
|
npx expo prebuild --clean
|
|
44
|
+
npx expo run:android
|
|
58
45
|
```
|
|
59
46
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
The iOS SDK is resolved via Swift Package Manager during `prebuild` / `pod install`. No additional configuration is required.
|
|
67
|
-
|
|
68
|
-
## Requirements
|
|
69
|
-
|
|
70
|
-
- React Native 0.74+ / Expo SDK 51+
|
|
71
|
-
- iOS 26+
|
|
72
|
-
- Android API 30+
|
|
73
|
-
|
|
74
|
-
## Usage
|
|
47
|
+
The plugin only raises `minSdkVersion` to 30. Everything else the SDK needs — the
|
|
48
|
+
`INTERNET`, `ACCESS_NETWORK_STATE`, and location permissions, the `<queries>` entries that
|
|
49
|
+
make the plugin app visible on API 30+, and the activities that run a payment on a
|
|
50
|
+
customer-facing display — ships in the Android SDK's own manifest and merges in
|
|
51
|
+
automatically.
|
|
75
52
|
|
|
76
|
-
|
|
53
|
+
## Quick start
|
|
77
54
|
|
|
78
55
|
```ts
|
|
79
56
|
import Accept from '@tapayadot/accept-react-native';
|
|
80
57
|
|
|
81
|
-
// Initialize once at app
|
|
82
|
-
|
|
58
|
+
// 1. Initialize once, at app startup.
|
|
59
|
+
Accept.initialize({ isProduction: false }); // false = sandbox
|
|
83
60
|
|
|
84
|
-
// Authenticate
|
|
85
|
-
await Accept.authenticate(
|
|
86
|
-
```
|
|
61
|
+
// 2. Authenticate the merchant.
|
|
62
|
+
await Accept.auth.authenticate(merchantToken);
|
|
87
63
|
|
|
88
|
-
|
|
64
|
+
// 3. Make sure the plugin app is installed and its terminal is activated.
|
|
65
|
+
if (!Accept.plugin.isInstalled()) {
|
|
66
|
+
await Accept.plugin.install(); // opens the store listing
|
|
67
|
+
}
|
|
68
|
+
if ((await Accept.plugin.status()) !== 'readyForPayments') {
|
|
69
|
+
await Accept.plugin.activateTerminal();
|
|
70
|
+
}
|
|
89
71
|
|
|
90
|
-
|
|
72
|
+
// 4. Take a payment. Amounts are in the currency's minor unit.
|
|
73
|
+
const result = await Accept.payments.payAsync({ amount: 1000, currency: 'USD' });
|
|
74
|
+
if (result.type === 'success') {
|
|
75
|
+
console.log(result.paymentToken, result.receiptUrl);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
91
78
|
|
|
92
|
-
|
|
93
|
-
import Accept, { type AcceptThemeConfiguration } from '@tapayadot/accept-react-native';
|
|
94
|
-
import { assetToBase64 } from '@tapayadot/accept-react-native/utils';
|
|
79
|
+
### Location permission
|
|
95
80
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
error: '#E6282B',
|
|
100
|
-
warning: '#FF8000',
|
|
101
|
-
success: '#228800',
|
|
102
|
-
brandGradientColors: { start: '#FF8400', end: '#9A94E9' },
|
|
103
|
-
},
|
|
104
|
-
images: {
|
|
105
|
-
brandLogo: await assetToBase64(require('./assets/brand-logo.png')),
|
|
106
|
-
toolbarLogo: await assetToBase64(require('./assets/toolbar-logo.png')),
|
|
107
|
-
solidLogo: await assetToBase64(require('./assets/solid-logo.png')),
|
|
108
|
-
},
|
|
109
|
-
};
|
|
81
|
+
A payment requires a device location fix, and the **host app** must request the permission —
|
|
82
|
+
the SDK does not. Request it before the first payment, or it fails with
|
|
83
|
+
`LocationPermissionRequired`:
|
|
110
84
|
|
|
111
|
-
|
|
112
|
-
|
|
85
|
+
```ts
|
|
86
|
+
import { PermissionsAndroid } from 'react-native';
|
|
113
87
|
|
|
114
|
-
|
|
115
|
-
await Accept.setTheme(theme);
|
|
88
|
+
await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION);
|
|
116
89
|
```
|
|
117
90
|
|
|
118
|
-
|
|
91
|
+
## API
|
|
119
92
|
|
|
120
|
-
|
|
93
|
+
Everything hangs off the default export.
|
|
121
94
|
|
|
122
|
-
|
|
95
|
+
| Surface | Access | Purpose |
|
|
96
|
+
| -------- | ------------------ | ------------------------------------------------------------------------------ |
|
|
97
|
+
| State | `Accept.state` | `'idle' \| 'initialized' \| 'authenticated'`, plus `addStateListener()` |
|
|
98
|
+
| Auth | `Accept.auth` | `authenticate(merchantToken)` |
|
|
99
|
+
| SDK | `Accept.sdk` | `version`, `isProduction`, `deviceId()`, `minimumAmounts()` |
|
|
100
|
+
| Merchant | `Accept.merchant` | `info()`, `config()`, `onboardingStatus()`, `availableCurrencies()` |
|
|
101
|
+
| Payments | `Accept.payments` | `pay()`, `payAsync()`, `status()`, `cancel()`, `refund()`, `setOptions()` |
|
|
102
|
+
| Plugin | `Accept.plugin` | `isInstalled()`, `install()`, `activateTerminal()`, `status()`, `updateInfo()`, `logout()` |
|
|
103
|
+
| Displays | `Accept.displays` | `all()`, `customerFacing()`, `isDualScreen` |
|
|
123
104
|
|
|
124
|
-
|
|
105
|
+
Top-level: `initialize()`, `clear()`, `setTheme()`, `getTheme()`,
|
|
106
|
+
`createLocalThemeImageUri()`, `setLogLevel()`, `setDebugLoggingEnabled()`, `setLogger()`.
|
|
125
107
|
|
|
126
|
-
|
|
127
|
-
await Accept.requestLocationPermission();
|
|
128
|
-
```
|
|
108
|
+
### Lifecycle
|
|
129
109
|
|
|
130
|
-
|
|
110
|
+
`Accept.state` moves `idle → initialized → authenticated`:
|
|
131
111
|
|
|
132
112
|
```ts
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
settlementCurrency: 'EUR',
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
const result = await Accept.payments.startCardPayment(
|
|
143
|
-
intent,
|
|
144
|
-
(status) => console.log('Status update:', status),
|
|
145
|
-
(message, exception) => console.error('Error:', message, exception),
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
switch (result.status) {
|
|
149
|
-
case 'approved':
|
|
150
|
-
console.log('Approved:', result.authorizationCode);
|
|
151
|
-
break;
|
|
152
|
-
case 'declined':
|
|
153
|
-
console.log('Declined:', result.reason);
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
113
|
+
const subscription = Accept.addStateListener((state) => {
|
|
114
|
+
if (state === 'authenticated') loadMerchant();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// later
|
|
118
|
+
subscription.remove();
|
|
156
119
|
```
|
|
157
120
|
|
|
158
|
-
###
|
|
121
|
+
### Payments as a stream
|
|
122
|
+
|
|
123
|
+
`payAsync()` is a convenience over `pay()`, which reports the whole lifecycle. Use it when
|
|
124
|
+
the UI reflects the intermediate states:
|
|
159
125
|
|
|
160
126
|
```ts
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
127
|
+
const subscription = Accept.payments.pay({ amount: 1000, currency: 'USD' }, (event) => {
|
|
128
|
+
switch (event.type) {
|
|
129
|
+
case 'creating':
|
|
130
|
+
setStatus('Creating payment…');
|
|
131
|
+
break;
|
|
132
|
+
case 'created':
|
|
133
|
+
// The payment token and receipt URL exist before the plugin is launched.
|
|
134
|
+
setReceiptUrl(event.receiptUrl);
|
|
135
|
+
break;
|
|
136
|
+
case 'launched':
|
|
137
|
+
setStatus('Waiting for the card…');
|
|
138
|
+
break;
|
|
139
|
+
case 'result':
|
|
140
|
+
setResult(event.payResult); // success | declined | canceled | failed
|
|
141
|
+
break;
|
|
142
|
+
case 'creationFailed':
|
|
143
|
+
setError(event.error); // an AcceptError payload; the payment never started
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
164
146
|
});
|
|
165
|
-
|
|
166
|
-
console.log(refund.status); // 'success' | 'pending' | 'cancelled' | 'refunded' | 'failed' | 'actionNeeded'
|
|
167
147
|
```
|
|
168
148
|
|
|
169
|
-
|
|
149
|
+
`pay()` never throws — a failure to create the payment arrives as `creationFailed`. The
|
|
150
|
+
stream ends after `result` or `creationFailed` and the subscription removes itself; call
|
|
151
|
+
`subscription.remove()` to stop listening early (the plugin's UI stays on screen).
|
|
170
152
|
|
|
171
|
-
|
|
172
|
-
// Dismisses any payment UI and cancels the in-flight transaction.
|
|
173
|
-
await Accept.payments.cancelActivePayment();
|
|
174
|
-
```
|
|
153
|
+
### Payment options
|
|
175
154
|
|
|
176
|
-
|
|
155
|
+
Per payment, or session-wide via `Accept.payments.setOptions()`:
|
|
177
156
|
|
|
178
157
|
```ts
|
|
179
|
-
|
|
180
|
-
{
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
158
|
+
Accept.payments.setOptions({
|
|
159
|
+
receiptConfig: {
|
|
160
|
+
type: 'show',
|
|
161
|
+
showQrCodeReceipt: true,
|
|
162
|
+
dismissBehavior: { type: 'delayed', delayMs: 5000 },
|
|
163
|
+
printBehavior: 'onDemand',
|
|
185
164
|
},
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
);
|
|
165
|
+
nfcPosition: { type: 'onDevice', surface: 'back', xFraction: 0.5, yFraction: 0.25 },
|
|
166
|
+
transactionTimeoutMs: 60_000, // 0…120000
|
|
167
|
+
});
|
|
189
168
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
169
|
+
await Accept.payments.payAsync({
|
|
170
|
+
amount: 2500,
|
|
171
|
+
currency: 'EUR',
|
|
172
|
+
tip: 250, // skips the plugin's own tip screen
|
|
173
|
+
metadata: { orderId: 'A-1024' }, // echoed back on the result
|
|
174
|
+
});
|
|
193
175
|
```
|
|
194
176
|
|
|
195
|
-
|
|
177
|
+
Only the keys you pass are changed, so one default can be set without disturbing the others.
|
|
196
178
|
|
|
197
|
-
|
|
198
|
-
const result = await Accept.payments.startCertisPayment(
|
|
199
|
-
{
|
|
200
|
-
paymentIntentId: 'pi_xxx',
|
|
201
|
-
amount: 10000,
|
|
202
|
-
requestedCurrency: 'CZK',
|
|
203
|
-
settlementCurrency: 'CZK',
|
|
204
|
-
},
|
|
205
|
-
(status) => console.log('Status update:', status),
|
|
206
|
-
(message, exception) => console.error('Error:', message, exception),
|
|
207
|
-
);
|
|
208
|
-
```
|
|
179
|
+
### Dual-screen terminals
|
|
209
180
|
|
|
210
|
-
|
|
181
|
+
On dual-sided hardware, run the payment UI on the customer-facing panel while your app keeps
|
|
182
|
+
the merchant panel:
|
|
211
183
|
|
|
212
184
|
```ts
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
onboarding.paymentMethods.forEach((m) =>
|
|
217
|
-
console.log(m.method, m.status), // e.g. 'CARD', 'ACTIVE'
|
|
218
|
-
);
|
|
219
|
-
|
|
220
|
-
// Single-method status
|
|
221
|
-
const cardStatus = await Accept.identity.getPaymentMethodStatus('CARD');
|
|
222
|
-
// 'NOT_STARTED' | 'PENDING' | 'ACTIVE' | 'ATTENTION_NEEDED' | 'ACTION_REQUIRED' | 'BLOCKED'
|
|
185
|
+
if (Accept.displays.isDualScreen) {
|
|
186
|
+
Accept.payments.setOptions({ display: { type: 'customerFacing' } });
|
|
187
|
+
}
|
|
223
188
|
```
|
|
224
189
|
|
|
225
|
-
|
|
190
|
+
Set this **before** `authenticate()` — the terminal warm-up it fires follows the same target,
|
|
191
|
+
and you don't want the warm-up flashing on the merchant's screen.
|
|
226
192
|
|
|
227
|
-
|
|
228
|
-
// Check if onboarding is needed before launching the KYB flow
|
|
229
|
-
await Accept.identity.presentKyb({
|
|
230
|
-
businessType: 'company',
|
|
231
|
-
legalName: 'Acme s.r.o.',
|
|
232
|
-
businessEmail: 'billing@acme.com',
|
|
233
|
-
countryCode: 'CZ',
|
|
234
|
-
registrationNumber: '12345678',
|
|
235
|
-
vatNumber: 'CZ12345678',
|
|
236
|
-
addressLine1: 'Václavské náměstí 1',
|
|
237
|
-
city: 'Praha',
|
|
238
|
-
postalCode: '11000',
|
|
239
|
-
bankAccountIban: 'CZ...',
|
|
240
|
-
businessUrl: 'https://acme.com',
|
|
241
|
-
productDescription: 'SaaS platform',
|
|
242
|
-
supportPhone: '+420123456789',
|
|
243
|
-
});
|
|
244
|
-
```
|
|
193
|
+
### Errors
|
|
245
194
|
|
|
246
|
-
|
|
195
|
+
Every rejection is an `AcceptError` whose `code` names the failure, carrying that case's
|
|
196
|
+
fields:
|
|
247
197
|
|
|
248
198
|
```ts
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
199
|
+
import Accept, { AcceptError } from '@tapayadot/accept-react-native';
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
await Accept.payments.payAsync({ amount: 10, currency: 'USD' });
|
|
203
|
+
} catch (error) {
|
|
204
|
+
if (!AcceptError.is(error)) throw error;
|
|
205
|
+
|
|
206
|
+
switch (error.code) {
|
|
207
|
+
case 'AmountBelowMinimum':
|
|
208
|
+
alert(`Minimum is ${error.minimum} ${error.currency}`);
|
|
209
|
+
break;
|
|
210
|
+
case 'PluginNotReadyForPayments':
|
|
211
|
+
await Accept.plugin.activateTerminal();
|
|
212
|
+
break;
|
|
213
|
+
case 'LocationPermissionRequired':
|
|
214
|
+
await requestLocationPermission();
|
|
215
|
+
break;
|
|
216
|
+
case 'NoInternetConnection':
|
|
217
|
+
alert('No connection.');
|
|
218
|
+
break;
|
|
219
|
+
default:
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
257
223
|
```
|
|
258
224
|
|
|
259
|
-
###
|
|
260
|
-
|
|
261
|
-
```ts
|
|
262
|
-
await Accept.demo.enable(); // simulate payments without real terminals
|
|
263
|
-
const isDemo = await Accept.demo.isEnabled();
|
|
264
|
-
await Accept.demo.disable();
|
|
265
|
-
```
|
|
225
|
+
### Theming
|
|
266
226
|
|
|
267
|
-
|
|
227
|
+
Branding for the plugin's activation, status, and payment screens. Session-wide, and pushed
|
|
228
|
+
to the plugin the next time it is bound or launched:
|
|
268
229
|
|
|
269
230
|
```ts
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
231
|
+
Accept.setTheme({
|
|
232
|
+
light: {
|
|
233
|
+
colors: { primary: '#0B5FFF', onPrimary: '#FFFFFF', surface: '#FFFFFF' },
|
|
234
|
+
images: { logoSymbol: 'https://example.com/logo.png' },
|
|
235
|
+
},
|
|
236
|
+
dark: {
|
|
237
|
+
colors: { primary: '#6E9BFF', onPrimary: '#001B3D', surface: '#101418' },
|
|
276
238
|
},
|
|
277
239
|
});
|
|
278
240
|
```
|
|
279
241
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
The Tapaya companion app is required for card payments. Supported on both iOS and Android:
|
|
242
|
+
For a logo bundled with the app rather than hosted, convert it and hand the plugin a
|
|
243
|
+
`content://` URL:
|
|
283
244
|
|
|
284
245
|
```ts
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
if (!installed) {
|
|
288
|
-
// Prompt user to install via the store product sheet (App Store on iOS, Play Store on Android)
|
|
289
|
-
await Accept.presentCompanionAppSheet();
|
|
290
|
-
} else {
|
|
291
|
-
// Pair with the companion app (rejects if it is not installed or not ready)
|
|
292
|
-
await Accept.pairWithCompanionApp();
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
## API Reference
|
|
297
|
-
|
|
298
|
-
### Top-level
|
|
299
|
-
|
|
300
|
-
| Method | Description |
|
|
301
|
-
|---|---|
|
|
302
|
-
| `initialize(demo?, theme?)` | Initialize the SDK. Pass `true` for sandbox mode. Optionally provide a UI theme. |
|
|
303
|
-
| `setTheme(theme)` | Apply a UI theme after initialization. |
|
|
304
|
-
| `setUiBehavior(behavior)` | Android only. Configure result screen + NFC zone. |
|
|
305
|
-
| `authenticate(token)` | Authenticate with a merchant JWT token. |
|
|
306
|
-
| `getStatus()` | Returns `'IDLE' \| 'INITIALIZED' \| 'LOGGED_IN'`. |
|
|
307
|
-
| `getPaymentStatus(paymentIntentId)` | Retrieve the result of a previous payment. |
|
|
308
|
-
| `logOut()` | End the current merchant session. |
|
|
309
|
-
| `requestLocationPermission()` | Request location permission (required for card payments). |
|
|
310
|
-
| `isCompanionAppInstalled()` | Check if the Tapaya companion app is installed. |
|
|
311
|
-
| `presentCompanionAppSheet()` | Show the store product sheet for the companion app (App Store on iOS, Play Store on Android). |
|
|
312
|
-
| `pairWithCompanionApp()` | Pair with the installed companion app. |
|
|
313
|
-
|
|
314
|
-
### `Accept.payments`
|
|
315
|
-
|
|
316
|
-
| Method | Description |
|
|
317
|
-
|---|---|
|
|
318
|
-
| `startCardPayment(intent, onStatus, onError)` | Start a card/Tap-to-Pay payment. |
|
|
319
|
-
| `startSepaPayment(intent, onStatus, onError)` | Start a SEPA Instant payment. |
|
|
320
|
-
| `startCertisPayment(intent, onStatus, onError)` | Start a Certis Instant payment. |
|
|
321
|
-
| `refund(intent)` | Refund a previously completed card payment (headless, no UI). |
|
|
322
|
-
| `cancelActivePayment()` | Dismiss in-flight payment UI and cancel the transaction. |
|
|
323
|
-
|
|
324
|
-
### `Accept.identity`
|
|
325
|
-
|
|
326
|
-
| Method | Description |
|
|
327
|
-
|---|---|
|
|
328
|
-
| `presentKyb(prefilling?)` | Launch the KYB onboarding UI with optional prefill data. |
|
|
329
|
-
| `getOnboardingStatus()` | Returns aggregate merchant onboarding status across payment methods. |
|
|
330
|
-
| `getPaymentMethodStatus(method)` | Returns onboarding status for a single payment method. |
|
|
246
|
+
import { assetToBase64 } from '@tapayadot/accept-react-native/utils';
|
|
331
247
|
|
|
332
|
-
|
|
248
|
+
const base64 = await assetToBase64(require('./assets/logo.png'));
|
|
249
|
+
const uri = Accept.createLocalThemeImageUri(base64, 'png');
|
|
333
250
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
| `enable()` | Enable demo mode — payments are simulated, no real terminal required. |
|
|
337
|
-
| `disable()` | Return to real terminal flows. |
|
|
338
|
-
| `isEnabled()` | Whether demo mode is currently enabled. |
|
|
251
|
+
Accept.setTheme({ light: { images: { logoSymbol: uri } } });
|
|
252
|
+
```
|
|
339
253
|
|
|
340
|
-
|
|
254
|
+
`assetToBase64` needs `expo-asset` and `expo-file-system`, both present in managed Expo
|
|
255
|
+
projects. Bare React Native consumers must install them.
|
|
341
256
|
|
|
342
|
-
|
|
343
|
-
- Currency — ISO 4217 alpha-3 (`'CZK'`, `'EUR'`, `'GBP'`, …)
|
|
344
|
-
- Country — ISO 3166-1 alpha-2 (`'CZ'`, `'GB'`, …)
|
|
257
|
+
### Logging
|
|
345
258
|
|
|
346
259
|
```ts
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
requestedCurrency: string // ISO 4217 alpha-3
|
|
351
|
-
settlementCurrency?: string // defaults to requestedCurrency
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
type CardPaymentResult = {
|
|
355
|
-
status: 'pending' | 'approved' | 'declined' | 'refunded' | 'aborted'
|
|
356
|
-
last4?: string
|
|
357
|
-
brand?: string
|
|
358
|
-
authorizationCode?: string
|
|
359
|
-
terminalId?: string
|
|
360
|
-
companyName?: string
|
|
361
|
-
companyAddress1?: string
|
|
362
|
-
companyAddress2?: string
|
|
363
|
-
companyCity?: string
|
|
364
|
-
companyCountry?: string // ISO 3166-1 alpha-2
|
|
365
|
-
reason?: string
|
|
366
|
-
receiptUrl?: string
|
|
367
|
-
refundToken?: string // present when this card payment was refunded
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
type SepaPaymentIntent = { paymentIntentId: string; amount: number; requestedCurrency: string; settlementCurrency?: string }
|
|
371
|
-
type SepaPaymentResult = { status: 'pending' | 'verified' | 'aborted' | 'refunded' | 'declined'; postponed: boolean; receivedAt: string; receivedFromIban: string; receiptUrl?: string }
|
|
372
|
-
|
|
373
|
-
type CertisPaymentIntent = { paymentIntentId: string; amount: number; requestedCurrency: string; settlementCurrency?: string }
|
|
374
|
-
type CertisPaymentResult = { status: 'pending' | 'verified' | 'aborted' | 'refunded' | 'declined'; postponed: boolean; receivedAt: string; receivedFromIban: string; receiptUrl?: string }
|
|
375
|
-
|
|
376
|
-
type RefundReason = 'customerRequest' | 'duplicate' | 'fraudulent' | 'expiredCharge'
|
|
377
|
-
type TransactionStatus = 'pending' | 'success' | 'cancelled' | 'refunded' | 'failed' | 'actionNeeded'
|
|
378
|
-
|
|
379
|
-
type RefundIntent = {
|
|
380
|
-
paymentToken: string // source payment UUID or original paymentIntentId
|
|
381
|
-
refundToken?: string // idempotency token, pass same value on retry
|
|
382
|
-
reason: RefundReason
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
type RefundResult = {
|
|
386
|
-
refundToken?: string
|
|
387
|
-
status: TransactionStatus
|
|
388
|
-
refundReason: RefundReason
|
|
389
|
-
paymentMethod?: PaymentMethod
|
|
390
|
-
requestedAmount?: number
|
|
391
|
-
requestedCurrency?: string
|
|
392
|
-
settlementAmount?: number
|
|
393
|
-
settlementCurrency?: string
|
|
394
|
-
fxRate?: number
|
|
395
|
-
createdAt?: string // ISO 8601 UTC
|
|
396
|
-
processedAt?: string // ISO 8601 UTC
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
type PaymentMethod = 'CARD' | 'SEPA' | 'CERTIS' | 'CRYPTO'
|
|
400
|
-
type PaymentMethodStatus = 'NOT_STARTED' | 'PENDING' | 'ACTIVE' | 'ATTENTION_NEEDED' | 'ACTION_REQUIRED' | 'BLOCKED'
|
|
401
|
-
|
|
402
|
-
type AcceptPaymentMethodStatus = { method: PaymentMethod; status: PaymentMethodStatus }
|
|
403
|
-
type AcceptOnboardingStatus = { isOnboarded: boolean; paymentMethods: AcceptPaymentMethodStatus[] }
|
|
260
|
+
Accept.setLogLevel('DEBUG'); // NONE | ERROR | WARN | INFO | DEBUG | VERBOSE
|
|
261
|
+
Accept.setLogger((entry) => Sentry.addBreadcrumb({ message: entry.message }));
|
|
262
|
+
```
|
|
404
263
|
|
|
405
|
-
|
|
264
|
+
Logging defaults to `DEBUG` against sandbox and `NONE` against production. Pass `null` to
|
|
265
|
+
`setLogger` to restore the default Logcat sink.
|
|
406
266
|
|
|
407
|
-
|
|
408
|
-
accent: string // #RRGGBB or #AARRGGBB
|
|
409
|
-
error: string
|
|
410
|
-
warning: string
|
|
411
|
-
success: string
|
|
412
|
-
brandGradientColors?: GradientColors
|
|
413
|
-
brandSubtleGradientColors?: GradientColors
|
|
414
|
-
}
|
|
267
|
+
### Logout
|
|
415
268
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
}
|
|
269
|
+
```ts
|
|
270
|
+
await Accept.plugin.logout(); // sign the merchant out of the plugin app
|
|
271
|
+
await Accept.clear(); // clear the local token, device id, cached config, and theme
|
|
272
|
+
```
|
|
421
273
|
|
|
422
|
-
|
|
423
|
-
colors?: AcceptColorTheme
|
|
424
|
-
images?: AcceptImageTheme
|
|
425
|
-
}
|
|
274
|
+
## Running the example app
|
|
426
275
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
type NfcPosition = { xBias: number; yBias: number } // 0..1 normalized; omit position for terminal default
|
|
430
|
-
type NfcZone = { indicator: NfcIndicator; position?: NfcPosition }
|
|
431
|
-
type AcceptUiBehavior = {
|
|
432
|
-
resultScreenDurationSeconds?: number
|
|
433
|
-
showResultScreen?: boolean
|
|
434
|
-
nfcZone?: NfcZone
|
|
435
|
-
}
|
|
276
|
+
`example/` is a demo harness mirroring the Accept SDK for Android's own `example` module: one
|
|
277
|
+
control per public API call, and a log pane showing what each one returned.
|
|
436
278
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
vatNumber?: string
|
|
442
|
-
legalName?: string
|
|
443
|
-
addressLine1?: string
|
|
444
|
-
addressLine2?: string
|
|
445
|
-
city?: string
|
|
446
|
-
postalCode?: string
|
|
447
|
-
merchantCategoryCode?: number
|
|
448
|
-
businessEmail?: string
|
|
449
|
-
bankAccountIban?: string
|
|
450
|
-
businessUrl?: string
|
|
451
|
-
productDescription?: string
|
|
452
|
-
supportPhone?: string
|
|
453
|
-
}
|
|
279
|
+
```sh
|
|
280
|
+
npm install # installs the root package and the example workspace
|
|
281
|
+
cp example/.env.example example/.env.local # optional: prefill credentials
|
|
282
|
+
npm run android # prebuilds and runs on a connected device
|
|
454
283
|
```
|
|
455
284
|
|
|
456
|
-
|
|
285
|
+
`.env.local` is gitignored. Leave it out and type the API key and merchant token into the app's
|
|
286
|
+
Credentials fields instead — nothing is persisted either way. Never put a production key in it:
|
|
287
|
+
Expo inlines `EXPO_PUBLIC_*` variables into the bundle at build time.
|
|
457
288
|
|
|
458
|
-
|
|
289
|
+
The example needs a real device with the Accept plugin app installed; an emulator has no card
|
|
290
|
+
reader. Tap **Login** to mint a merchant token and authenticate, then **activateTerminal()** once
|
|
291
|
+
before the first payment.
|
|
459
292
|
|
|
460
293
|
## License
|
|
461
294
|
|
|
462
|
-
|
|
295
|
+
Apache-2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
|