syntro-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,205 @@
1
+ # syntro-sdk
2
+
3
+ Official JavaScript/TypeScript SDK for [Syntro](https://syntro.run) BaaS.
4
+
5
+ ```bash
6
+ npm install syntro-sdk
7
+ ```
8
+
9
+ ---
10
+
11
+ ## Setup
12
+
13
+ ```typescript
14
+ import { Syntro } from 'syntro-sdk';
15
+
16
+ const syntro = new Syntro('sk_your_api_key', {
17
+ baseUrl: 'https://api.syntro.run' // optional, this is the default
18
+ });
19
+ ```
20
+
21
+ ---
22
+
23
+ ## Events & Analytics
24
+
25
+ ```typescript
26
+ // Track a custom business event
27
+ await syntro.event('CUSTOM', 'cart_add', 'User added product to cart', {
28
+ productId: 'prod_123'
29
+ });
30
+
31
+ // Track an error
32
+ await syntro.sendError('checkout_failed', 'Error loading checkout', {
33
+ page: '/checkout',
34
+ statusCode: 500
35
+ });
36
+
37
+ // Get event stats (for analytics dashboard)
38
+ const stats = await syntro.getStats();
39
+ // { summary: { custom: 12, error: 3, auth: 8, total: 23 }, events: [...] }
40
+
41
+ // Get stats for a specific type
42
+ const errorStats = await syntro.getStats('ERROR');
43
+
44
+ // List raw events
45
+ const { events, total } = await syntro.listEvents({ type: 'ERROR', limit: 20 });
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Auth (ProjectUsers)
51
+
52
+ ### Register & Login
53
+
54
+ ```typescript
55
+ // Register a new user
56
+ const { user, token, error } = await syntro.register(
57
+ 'johndoe', // username
58
+ 'john@example.com', // email
59
+ 'password123' // password (min 6 chars)
60
+ );
61
+
62
+ // Login with username
63
+ const { user, token, error } = await syntro.login('johndoe', 'password123');
64
+
65
+ // Login with email
66
+ const { user, token, error } = await syntro.loginWithEmail('john@example.com', 'password123');
67
+ ```
68
+
69
+ ### Token Verification
70
+
71
+ ```typescript
72
+ // Verify a JWT token (e.g. sent in a request header)
73
+ const { valid, user, error } = await syntro.verifyToken(token);
74
+
75
+ if (valid) {
76
+ console.log('Authenticated user:', user.username);
77
+ }
78
+ ```
79
+
80
+ ### User Info
81
+
82
+ ```typescript
83
+ // Get full user object
84
+ const { user } = await syntro.getUser(userId);
85
+
86
+ // Quick accessors
87
+ const username = await syntro.getUsername(userId); // e.g. "johndoe"
88
+ const email = await syntro.getUserEmail(userId); // e.g. "john@example.com"
89
+ const meta = await syntro.getMetadata(userId); // e.g. { plan: "pro", role: "admin" }
90
+ ```
91
+
92
+ ### User Management
93
+
94
+ ```typescript
95
+ // Update a user's username or metadata (replaces metadata)
96
+ await syntro.updateUser(userId, { username: 'new_username' });
97
+ await syntro.updateUser(userId, { metadata: { plan: 'pro' } });
98
+
99
+ // Merge-update metadata (preserves existing keys)
100
+ await syntro.updateMetadata(userId, { onboardingDone: true });
101
+
102
+ // Delete a user
103
+ const { success } = await syntro.deleteUser(userId);
104
+
105
+ // List all users
106
+ const { users, total } = await syntro.listUsers({ limit: 50 });
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Billing (Stripe Payments)
112
+
113
+ ### Accepting Payments in 3 Steps
114
+
115
+ #### Step 1: Configure Stripe in Syntro Dashboard
116
+ Go to **Settings → Stripe** in your Syntro project and add:
117
+ - **Stripe Secret Key** (`sk_live_...`)
118
+ - **Stripe Webhook Secret** (`whsec_...`)
119
+
120
+ #### Step 2: Add the Webhook in Stripe Dashboard
121
+ In **Stripe → Developers → Webhooks**, create a new endpoint:
122
+
123
+ ```
124
+ URL: https://api.syntro.run/v1/billing/webhook/<YOUR_PROJECT_ID>
125
+ Events to listen for: checkout.session.completed
126
+ ```
127
+
128
+ #### Step 3: Create a Checkout Session in Your App
129
+
130
+ ```typescript
131
+ const { url, error } = await syntro.createPayment('Premium Plan', 999, {
132
+ currency: 'usd', // optional, default: usd
133
+ successUrl: 'https://yourapp.com/payment/success', // optional
134
+ cancelUrl: 'https://yourapp.com/payment/cancel', // optional
135
+ customerEmail: 'customer@email.com', // optional, pre-fills Stripe form
136
+ });
137
+
138
+ if (error) {
139
+ console.error('Payment error:', error);
140
+ return;
141
+ }
142
+
143
+ // Redirect customer to Stripe Checkout
144
+ window.location.href = url!;
145
+ ```
146
+
147
+ Syntro will automatically:
148
+ 1. ✅ Verify the Stripe webhook signature
149
+ 2. ✅ Record the transaction in the database
150
+ 3. ✅ Log a `payment_completed` CUSTOM event
151
+ 4. ✅ Show it in your Transactions dashboard
152
+
153
+ ### List Transactions
154
+
155
+ ```typescript
156
+ const { transactions, total } = await syntro.listTransactions({
157
+ limit: 50,
158
+ skip: 0,
159
+ status: 'paid' // optional filter
160
+ });
161
+ ```
162
+
163
+ ### Verify Payment
164
+ Check if a specific customer has already paid for a product. Great for unlocking digital features after payment.
165
+
166
+ ```typescript
167
+ const { paid, transaction, error } = await syntro.verifyPayment('customer@email.com', {
168
+ name: 'Premium Plan' // optional: filter by product name
169
+ });
170
+
171
+ if (paid) {
172
+ console.log(`Verified! Customer paid on ${transaction.createdAt}`);
173
+ // Unlock premium features...
174
+ }
175
+ ```
176
+
177
+ ---
178
+
179
+ ## API Reference
180
+
181
+ Full interactive documentation: [api.syntro.run/docs](https://api.syntro.run/docs)
182
+
183
+ ### All Methods
184
+
185
+ | Method | Description |
186
+ |--------|-------------|
187
+ | `event(type, name, message?, meta?, userId?)` | Track any event |
188
+ | `sendError(name, message?, meta?)` | Shorthand for ERROR events |
189
+ | `getStats(type?)` | Get analytics stats |
190
+ | `listEvents(options?)` | List raw events |
191
+ | `register(username, email, password)` | Register a new user |
192
+ | `login(username, password)` | Login with username |
193
+ | `loginWithEmail(email, password)` | Login with email |
194
+ | `verifyToken(token)` | Verify JWT and get user |
195
+ | `getUser(userId)` | Get full user object |
196
+ | `getUsername(userId)` | Get just the username |
197
+ | `getUserEmail(userId)` | Get just the email |
198
+ | `getMetadata(userId)` | Get user metadata object |
199
+ | `updateMetadata(userId, patch)` | Merge-update metadata |
200
+ | `updateUser(userId, data)` | Update username/metadata |
201
+ | `deleteUser(userId)` | Delete a user |
202
+ | `listUsers(options?)` | List project users |
203
+ | `createPayment(name, amount, options?)` | Create Stripe Checkout → URL |
204
+ | `listTransactions(options?)` | List payment transactions |
205
+ | `verifyPayment(email, options?)` | Verify if a customer has paid |
@@ -0,0 +1,231 @@
1
+ interface SyntroConfig {
2
+ baseUrl?: string;
3
+ }
4
+ type EventType = 'CUSTOM' | 'ERROR' | 'AUTH';
5
+ interface SyntroEvent {
6
+ type: EventType;
7
+ name: string;
8
+ message?: string;
9
+ metadata?: Record<string, unknown>;
10
+ userId?: string;
11
+ }
12
+ interface SyntroUser {
13
+ id: string;
14
+ username: string;
15
+ email: string;
16
+ createdAt?: string;
17
+ updatedAt?: string;
18
+ metadata?: unknown;
19
+ provider?: string;
20
+ }
21
+ interface AuthResult {
22
+ success: boolean;
23
+ user?: SyntroUser;
24
+ token?: string;
25
+ error?: string;
26
+ }
27
+ interface UserResult {
28
+ user?: SyntroUser;
29
+ success?: boolean;
30
+ error?: string;
31
+ }
32
+ interface MetadataResult {
33
+ success: boolean;
34
+ metadata?: Record<string, unknown>;
35
+ error?: string;
36
+ }
37
+ interface VerifyResult {
38
+ valid: boolean;
39
+ user?: SyntroUser;
40
+ error?: string;
41
+ }
42
+ interface PaymentResult {
43
+ url?: string | null;
44
+ sessionId?: string;
45
+ error?: string;
46
+ }
47
+ interface EventResult {
48
+ success: boolean;
49
+ eventId?: string;
50
+ error?: string;
51
+ }
52
+ interface VerifyPaymentResult {
53
+ paid: boolean;
54
+ transaction?: {
55
+ id: string;
56
+ amount: number;
57
+ currency: string;
58
+ createdAt: string;
59
+ } | null;
60
+ error?: string;
61
+ }
62
+ interface VerifyPaymentOptions {
63
+ name?: string;
64
+ }
65
+
66
+ /**
67
+ * Syntro SDK — Official JavaScript/TypeScript client for api.syntro.run
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * import { Syntro } from 'syntro-sdk';
72
+ * const syntro = new Syntro('sk_your_api_key');
73
+ *
74
+ * // Events
75
+ * await syntro.event('CUSTOM', 'cart_add', 'User added to cart');
76
+ * await syntro.sendError('checkout_failed', 'Checkout error', { page: '/checkout' });
77
+ *
78
+ * // Auth
79
+ * const { token } = await syntro.login('username', 'password');
80
+ * const username = await syntro.getUsername(userId);
81
+ * const email = await syntro.getUserEmail(userId);
82
+ * const meta = await syntro.getMetadata(userId);
83
+ *
84
+ * // Billing
85
+ * const { url } = await syntro.createPayment('Pro Plan', 999);
86
+ * ```
87
+ */
88
+ declare class Syntro {
89
+ private readonly apiKey;
90
+ private readonly baseUrl;
91
+ constructor(apiKey: string, config?: SyntroConfig);
92
+ private get headers();
93
+ private post;
94
+ private put;
95
+ private patch;
96
+ private del;
97
+ private get;
98
+ /**
99
+ * Track an event.
100
+ * @param type - 'CUSTOM' | 'ERROR' | 'AUTH'
101
+ * @param name - Short event key, e.g. 'cart_add'
102
+ * @param message - Optional description
103
+ * @param metadata - Optional arbitrary JSON
104
+ * @param userId - Optional ProjectUser ID
105
+ */
106
+ event(type: EventType, name: string, message?: string, metadata?: Record<string, unknown>, userId?: string): Promise<EventResult>;
107
+ /**
108
+ * Track an ERROR event.
109
+ * @example
110
+ * await syntro.sendError('checkout_failed', 'Error loading page', { code: 500 });
111
+ */
112
+ sendError(name: string, message?: string, metadata?: Record<string, unknown>): Promise<EventResult>;
113
+ /** Get event statistics grouped by name (for analytics dashboard). */
114
+ getStats(type?: EventType): Promise<unknown>;
115
+ /** List raw events with pagination. */
116
+ listEvents(options?: {
117
+ type?: EventType;
118
+ limit?: number;
119
+ skip?: number;
120
+ }): Promise<unknown>;
121
+ /**
122
+ * Register a new end-user.
123
+ * @example
124
+ * const { user, token, error } = await syntro.register('john', 'john@email.com', 'pass123');
125
+ */
126
+ register(username: string, email: string, password: string): Promise<AuthResult>;
127
+ /**
128
+ * Login with username + password.
129
+ * @example
130
+ * const { token, user, error } = await syntro.login('john', 'pass123');
131
+ */
132
+ login(username: string, password: string): Promise<AuthResult>;
133
+ /**
134
+ * Login with email + password.
135
+ */
136
+ loginWithEmail(email: string, password: string): Promise<AuthResult>;
137
+ /**
138
+ * Verify a JWT token and get the associated user.
139
+ * @example
140
+ * const { valid, user } = await syntro.verifyToken(token);
141
+ */
142
+ verifyToken(token: string): Promise<VerifyResult>;
143
+ /**
144
+ * Get a ProjectUser by ID.
145
+ * @example
146
+ * const { user } = await syntro.getUser(userId);
147
+ */
148
+ getUser(userId: string): Promise<UserResult>;
149
+ /**
150
+ * Get a user's username by ID.
151
+ * @example
152
+ * const username = await syntro.getUsername(userId);
153
+ */
154
+ getUsername(userId: string): Promise<string | null>;
155
+ /**
156
+ * Get a user's email by ID.
157
+ * @example
158
+ * const email = await syntro.getUserEmail(userId);
159
+ */
160
+ getUserEmail(userId: string): Promise<string | null>;
161
+ /**
162
+ * Get a user's metadata by ID.
163
+ * @example
164
+ * const meta = await syntro.getMetadata(userId);
165
+ * console.log(meta?.plan, meta?.role);
166
+ */
167
+ getMetadata(userId: string): Promise<Record<string, unknown> | null>;
168
+ /**
169
+ * Merge-update a user's metadata. Existing keys are preserved.
170
+ * @example
171
+ * await syntro.updateMetadata(userId, { plan: 'pro', role: 'admin' });
172
+ */
173
+ updateMetadata(userId: string, metadata: Record<string, unknown>): Promise<MetadataResult>;
174
+ /**
175
+ * Update a user's username or fully replace their metadata.
176
+ * @example
177
+ * await syntro.updateUser(userId, { username: 'new_name' });
178
+ */
179
+ updateUser(userId: string, data: {
180
+ username?: string;
181
+ metadata?: Record<string, unknown>;
182
+ }): Promise<UserResult>;
183
+ /**
184
+ * Delete a ProjectUser permanently.
185
+ * @example
186
+ * const { success } = await syntro.deleteUser(userId);
187
+ */
188
+ deleteUser(userId: string): Promise<{
189
+ success: boolean;
190
+ error?: string;
191
+ }>;
192
+ /** List users with pagination. */
193
+ listUsers(options?: {
194
+ limit?: number;
195
+ skip?: number;
196
+ }): Promise<unknown>;
197
+ /**
198
+ * Create a Stripe Checkout payment session.
199
+ * Returns a `url` to redirect the customer to.
200
+ *
201
+ * @param name - Product/payment name
202
+ * @param amount - Amount in cents (e.g. 999 = $9.99)
203
+ * @param options - currency, successUrl, cancelUrl, customerEmail
204
+ *
205
+ * @example
206
+ * const { url, error } = await syntro.createPayment('Pro Plan', 999);
207
+ * if (url) window.location.href = url;
208
+ */
209
+ createPayment(name: string, amount: number, options?: {
210
+ currency?: string;
211
+ successUrl?: string;
212
+ cancelUrl?: string;
213
+ customerEmail?: string;
214
+ }): Promise<PaymentResult>;
215
+ /** List payment transactions. */
216
+ listTransactions(options?: {
217
+ limit?: number;
218
+ skip?: number;
219
+ status?: string;
220
+ }): Promise<unknown>;
221
+ /**
222
+ * Verify if a customer has paid for a specific product or any product.
223
+ *
224
+ * @example
225
+ * const { paid, transaction } = await syntro.verifyPayment('customer@email.com');
226
+ * if (paid) console.log('Customer paid!', transaction.amount);
227
+ */
228
+ verifyPayment(customerEmail: string, options?: VerifyPaymentOptions): Promise<VerifyPaymentResult>;
229
+ }
230
+
231
+ export { type AuthResult, type EventResult, type EventType, type MetadataResult, type PaymentResult, Syntro, type SyntroConfig, type SyntroEvent, type UserResult, type VerifyPaymentOptions, type VerifyPaymentResult, type VerifyResult };
@@ -0,0 +1,231 @@
1
+ interface SyntroConfig {
2
+ baseUrl?: string;
3
+ }
4
+ type EventType = 'CUSTOM' | 'ERROR' | 'AUTH';
5
+ interface SyntroEvent {
6
+ type: EventType;
7
+ name: string;
8
+ message?: string;
9
+ metadata?: Record<string, unknown>;
10
+ userId?: string;
11
+ }
12
+ interface SyntroUser {
13
+ id: string;
14
+ username: string;
15
+ email: string;
16
+ createdAt?: string;
17
+ updatedAt?: string;
18
+ metadata?: unknown;
19
+ provider?: string;
20
+ }
21
+ interface AuthResult {
22
+ success: boolean;
23
+ user?: SyntroUser;
24
+ token?: string;
25
+ error?: string;
26
+ }
27
+ interface UserResult {
28
+ user?: SyntroUser;
29
+ success?: boolean;
30
+ error?: string;
31
+ }
32
+ interface MetadataResult {
33
+ success: boolean;
34
+ metadata?: Record<string, unknown>;
35
+ error?: string;
36
+ }
37
+ interface VerifyResult {
38
+ valid: boolean;
39
+ user?: SyntroUser;
40
+ error?: string;
41
+ }
42
+ interface PaymentResult {
43
+ url?: string | null;
44
+ sessionId?: string;
45
+ error?: string;
46
+ }
47
+ interface EventResult {
48
+ success: boolean;
49
+ eventId?: string;
50
+ error?: string;
51
+ }
52
+ interface VerifyPaymentResult {
53
+ paid: boolean;
54
+ transaction?: {
55
+ id: string;
56
+ amount: number;
57
+ currency: string;
58
+ createdAt: string;
59
+ } | null;
60
+ error?: string;
61
+ }
62
+ interface VerifyPaymentOptions {
63
+ name?: string;
64
+ }
65
+
66
+ /**
67
+ * Syntro SDK — Official JavaScript/TypeScript client for api.syntro.run
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * import { Syntro } from 'syntro-sdk';
72
+ * const syntro = new Syntro('sk_your_api_key');
73
+ *
74
+ * // Events
75
+ * await syntro.event('CUSTOM', 'cart_add', 'User added to cart');
76
+ * await syntro.sendError('checkout_failed', 'Checkout error', { page: '/checkout' });
77
+ *
78
+ * // Auth
79
+ * const { token } = await syntro.login('username', 'password');
80
+ * const username = await syntro.getUsername(userId);
81
+ * const email = await syntro.getUserEmail(userId);
82
+ * const meta = await syntro.getMetadata(userId);
83
+ *
84
+ * // Billing
85
+ * const { url } = await syntro.createPayment('Pro Plan', 999);
86
+ * ```
87
+ */
88
+ declare class Syntro {
89
+ private readonly apiKey;
90
+ private readonly baseUrl;
91
+ constructor(apiKey: string, config?: SyntroConfig);
92
+ private get headers();
93
+ private post;
94
+ private put;
95
+ private patch;
96
+ private del;
97
+ private get;
98
+ /**
99
+ * Track an event.
100
+ * @param type - 'CUSTOM' | 'ERROR' | 'AUTH'
101
+ * @param name - Short event key, e.g. 'cart_add'
102
+ * @param message - Optional description
103
+ * @param metadata - Optional arbitrary JSON
104
+ * @param userId - Optional ProjectUser ID
105
+ */
106
+ event(type: EventType, name: string, message?: string, metadata?: Record<string, unknown>, userId?: string): Promise<EventResult>;
107
+ /**
108
+ * Track an ERROR event.
109
+ * @example
110
+ * await syntro.sendError('checkout_failed', 'Error loading page', { code: 500 });
111
+ */
112
+ sendError(name: string, message?: string, metadata?: Record<string, unknown>): Promise<EventResult>;
113
+ /** Get event statistics grouped by name (for analytics dashboard). */
114
+ getStats(type?: EventType): Promise<unknown>;
115
+ /** List raw events with pagination. */
116
+ listEvents(options?: {
117
+ type?: EventType;
118
+ limit?: number;
119
+ skip?: number;
120
+ }): Promise<unknown>;
121
+ /**
122
+ * Register a new end-user.
123
+ * @example
124
+ * const { user, token, error } = await syntro.register('john', 'john@email.com', 'pass123');
125
+ */
126
+ register(username: string, email: string, password: string): Promise<AuthResult>;
127
+ /**
128
+ * Login with username + password.
129
+ * @example
130
+ * const { token, user, error } = await syntro.login('john', 'pass123');
131
+ */
132
+ login(username: string, password: string): Promise<AuthResult>;
133
+ /**
134
+ * Login with email + password.
135
+ */
136
+ loginWithEmail(email: string, password: string): Promise<AuthResult>;
137
+ /**
138
+ * Verify a JWT token and get the associated user.
139
+ * @example
140
+ * const { valid, user } = await syntro.verifyToken(token);
141
+ */
142
+ verifyToken(token: string): Promise<VerifyResult>;
143
+ /**
144
+ * Get a ProjectUser by ID.
145
+ * @example
146
+ * const { user } = await syntro.getUser(userId);
147
+ */
148
+ getUser(userId: string): Promise<UserResult>;
149
+ /**
150
+ * Get a user's username by ID.
151
+ * @example
152
+ * const username = await syntro.getUsername(userId);
153
+ */
154
+ getUsername(userId: string): Promise<string | null>;
155
+ /**
156
+ * Get a user's email by ID.
157
+ * @example
158
+ * const email = await syntro.getUserEmail(userId);
159
+ */
160
+ getUserEmail(userId: string): Promise<string | null>;
161
+ /**
162
+ * Get a user's metadata by ID.
163
+ * @example
164
+ * const meta = await syntro.getMetadata(userId);
165
+ * console.log(meta?.plan, meta?.role);
166
+ */
167
+ getMetadata(userId: string): Promise<Record<string, unknown> | null>;
168
+ /**
169
+ * Merge-update a user's metadata. Existing keys are preserved.
170
+ * @example
171
+ * await syntro.updateMetadata(userId, { plan: 'pro', role: 'admin' });
172
+ */
173
+ updateMetadata(userId: string, metadata: Record<string, unknown>): Promise<MetadataResult>;
174
+ /**
175
+ * Update a user's username or fully replace their metadata.
176
+ * @example
177
+ * await syntro.updateUser(userId, { username: 'new_name' });
178
+ */
179
+ updateUser(userId: string, data: {
180
+ username?: string;
181
+ metadata?: Record<string, unknown>;
182
+ }): Promise<UserResult>;
183
+ /**
184
+ * Delete a ProjectUser permanently.
185
+ * @example
186
+ * const { success } = await syntro.deleteUser(userId);
187
+ */
188
+ deleteUser(userId: string): Promise<{
189
+ success: boolean;
190
+ error?: string;
191
+ }>;
192
+ /** List users with pagination. */
193
+ listUsers(options?: {
194
+ limit?: number;
195
+ skip?: number;
196
+ }): Promise<unknown>;
197
+ /**
198
+ * Create a Stripe Checkout payment session.
199
+ * Returns a `url` to redirect the customer to.
200
+ *
201
+ * @param name - Product/payment name
202
+ * @param amount - Amount in cents (e.g. 999 = $9.99)
203
+ * @param options - currency, successUrl, cancelUrl, customerEmail
204
+ *
205
+ * @example
206
+ * const { url, error } = await syntro.createPayment('Pro Plan', 999);
207
+ * if (url) window.location.href = url;
208
+ */
209
+ createPayment(name: string, amount: number, options?: {
210
+ currency?: string;
211
+ successUrl?: string;
212
+ cancelUrl?: string;
213
+ customerEmail?: string;
214
+ }): Promise<PaymentResult>;
215
+ /** List payment transactions. */
216
+ listTransactions(options?: {
217
+ limit?: number;
218
+ skip?: number;
219
+ status?: string;
220
+ }): Promise<unknown>;
221
+ /**
222
+ * Verify if a customer has paid for a specific product or any product.
223
+ *
224
+ * @example
225
+ * const { paid, transaction } = await syntro.verifyPayment('customer@email.com');
226
+ * if (paid) console.log('Customer paid!', transaction.amount);
227
+ */
228
+ verifyPayment(customerEmail: string, options?: VerifyPaymentOptions): Promise<VerifyPaymentResult>;
229
+ }
230
+
231
+ export { type AuthResult, type EventResult, type EventType, type MetadataResult, type PaymentResult, Syntro, type SyntroConfig, type SyntroEvent, type UserResult, type VerifyPaymentOptions, type VerifyPaymentResult, type VerifyResult };