insert-affiliate-js-sdk 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -37,7 +37,25 @@ declare class InsertAffiliate {
37
37
  */
38
38
  static getAffiliateDetails(affiliateCode: string): Promise<AffiliateDetails | null>;
39
39
  static returnCompanyId(): Promise<string | null>;
40
- static getOfferCode(): Promise<string | null>;
40
+ /**
41
+ * Get the offer code for the current affiliate
42
+ * @param platformType Optional platform type: 'stripe' (default for web), 'ios', or 'android'
43
+ * @returns The offer code for the specified platform, or null if not found
44
+ */
45
+ static getOfferCode(platformType?: 'ios' | 'android' | 'stripe'): Promise<string | null>;
46
+ /**
47
+ * Get the Stripe coupon/promo code for the current affiliate
48
+ * Convenience method that calls getOfferCode with platformType='stripe'
49
+ * @returns The Stripe coupon/promo code, or null if not found
50
+ */
51
+ static getStripeCouponCode(): Promise<string | null>;
52
+ /**
53
+ * Fetch offer code for a specific platform
54
+ * @param shortCode The affiliate short code
55
+ * @param platformType The platform type: 'ios', 'android', or 'stripe'
56
+ * @returns The offer code for the specified platform, or null if not found
57
+ */
58
+ private static fetchOfferCodeForPlatform;
41
59
  private static fetchAndStoreOfferCode;
42
60
  static trackEvent(eventName: string): Promise<void>;
43
61
  static returnUserAccountTokenAndStoreExpectedTransaction(): Promise<string | null>;
package/dist/index.js CHANGED
@@ -295,21 +295,90 @@ var InsertAffiliate = class {
295
295
  this.verboseLog(`Company ID: ${companyCode || "none"}`);
296
296
  return companyCode;
297
297
  }
298
- static async getOfferCode() {
299
- this.verboseLog("Getting offer code...");
300
- if (this.offerCode) {
298
+ /**
299
+ * Get the offer code for the current affiliate
300
+ * @param platformType Optional platform type: 'stripe' (default for web), 'ios', or 'android'
301
+ * @returns The offer code for the specified platform, or null if not found
302
+ */
303
+ static async getOfferCode(platformType = "stripe") {
304
+ this.verboseLog(`Getting offer code for platform: ${platformType}...`);
305
+ const storageKey = platformType === "stripe" ? "offerCode" : `offerCode_${platformType}`;
306
+ if (platformType === "stripe" && this.offerCode) {
301
307
  this.verboseLog(`Returning cached offer code: ${this.offerCode}`);
302
308
  return this.offerCode;
303
309
  }
304
- const storedOfferCode = await getValue("offerCode");
310
+ const storedOfferCode = await getValue(storageKey);
305
311
  if (storedOfferCode) {
306
312
  this.verboseLog(`Returning stored offer code: ${storedOfferCode}`);
307
- this.offerCode = storedOfferCode;
313
+ if (platformType === "stripe") {
314
+ this.offerCode = storedOfferCode;
315
+ }
308
316
  return storedOfferCode;
309
317
  }
318
+ const shortCode = await getValue("referrerLink");
319
+ if (shortCode) {
320
+ this.verboseLog(`No stored offer code, fetching for short code: ${shortCode}`);
321
+ const fetchedCode = await this.fetchOfferCodeForPlatform(shortCode, platformType);
322
+ return fetchedCode;
323
+ }
310
324
  this.verboseLog("No offer code found");
311
325
  return null;
312
326
  }
327
+ /**
328
+ * Get the Stripe coupon/promo code for the current affiliate
329
+ * Convenience method that calls getOfferCode with platformType='stripe'
330
+ * @returns The Stripe coupon/promo code, or null if not found
331
+ */
332
+ static async getStripeCouponCode() {
333
+ return this.getOfferCode("stripe");
334
+ }
335
+ /**
336
+ * Fetch offer code for a specific platform
337
+ * @param shortCode The affiliate short code
338
+ * @param platformType The platform type: 'ios', 'android', or 'stripe'
339
+ * @returns The offer code for the specified platform, or null if not found
340
+ */
341
+ static async fetchOfferCodeForPlatform(shortCode, platformType) {
342
+ this.verboseLog(`Fetching offer code for platform: ${platformType}, short code: ${shortCode}`);
343
+ try {
344
+ const companyCode = this.companyCode || await getValue("companyCode");
345
+ if (!companyCode) {
346
+ this.verboseLog("Cannot fetch offer code: no company code available");
347
+ return null;
348
+ }
349
+ const encoded = encodeURIComponent(shortCode);
350
+ const url = `https://api.insertaffiliate.com/v1/affiliateReturnOfferCode/${companyCode}/${encoded}?platformType=${platformType}`;
351
+ this.verboseLog(`Making API call to: ${url}`);
352
+ const response = await fetch(url);
353
+ this.verboseLog(`API response status: ${response.status}`);
354
+ if (!response.ok) {
355
+ this.verboseLog(`Failed to fetch offer code, status: ${response.status}`);
356
+ return null;
357
+ }
358
+ const offerCode = (await response.text()).replace(/[^a-zA-Z0-9]/g, "");
359
+ this.verboseLog(`Received offer code: ${offerCode}`);
360
+ const errorCodes = [
361
+ "errorofferCodeNotFound",
362
+ "errorAffiliateoffercodenotfoundinanycompany",
363
+ "errorAffiliateoffercodenotfoundinanycompanyAffiliatelinkwas",
364
+ "Routenotfound"
365
+ ];
366
+ if (errorCodes.includes(offerCode)) {
367
+ this.verboseLog("Offer code not found or invalid");
368
+ return null;
369
+ }
370
+ const storageKey = platformType === "stripe" ? "offerCode" : `offerCode_${platformType}`;
371
+ await saveValue(storageKey, offerCode);
372
+ if (platformType === "stripe") {
373
+ this.offerCode = offerCode;
374
+ }
375
+ this.verboseLog(`Offer code stored successfully with key ${storageKey}: ${offerCode}`);
376
+ return offerCode;
377
+ } catch (error) {
378
+ this.verboseLog(`Error fetching offer code: ${error}`);
379
+ return null;
380
+ }
381
+ }
313
382
  static async fetchAndStoreOfferCode(shortCode) {
314
383
  this.verboseLog(`Fetching offer code for short code: ${shortCode}`);
315
384
  try {
@@ -0,0 +1,199 @@
1
+ # Deep Linking for Web Payments
2
+
3
+ This guide covers how to configure deep links from Branch.io, AppsFlyer, or Insert Links to correctly pass affiliate parameters to your web checkout.
4
+
5
+ ## Overview
6
+
7
+ When using web-based payments (Stripe), your deep linking provider needs to redirect users to your web checkout page with the `insertAffiliate` parameter. The Insert Affiliate SDK will automatically detect this parameter and attribute the payment to the correct affiliate.
8
+
9
+ ## Insert Links (Automatic)
10
+
11
+ If you're using [Insert Links](https://docs.insertaffiliate.com/insert-links) (Insert Affiliate's built-in deep linking solution), no additional configuration is needed for web payments.
12
+
13
+ Insert Links automatically:
14
+ 1. Adds the `insertAffiliate` parameter to URLs
15
+ 2. Detects and processes attribution in your web app
16
+ 3. Tracks the payment to the correct affiliate
17
+
18
+ Just initialize the SDK and you're done:
19
+
20
+ ```javascript
21
+ import { InsertAffiliate } from 'insert-affiliate-js-sdk';
22
+
23
+ await InsertAffiliate.initialize('your_company_code');
24
+ // Affiliate parameters are automatically detected from the URL
25
+ ```
26
+
27
+ Learn more: [Insert Links Documentation](https://docs.insertaffiliate.com/insert-links)
28
+
29
+ ## Branch.io Web Redirect Setup
30
+
31
+ Use these steps if you're using [Branch.io](https://docs.insertaffiliate.com/branch) Quick Links to send users to your web-hosted payment page.
32
+
33
+ ### Creating a Branch.io Quick Link for Web Checkout
34
+
35
+ 1. **Create a new Quick Link** in your Branch.io dashboard
36
+ 2. Go to the **Redirects** section
37
+ 3. **Select "Web URL"** as the redirect destination
38
+ 4. **Configure the URL** to point to your web app:
39
+ - Enter your web app's URL
40
+ - Append the parameter: `?insertAffiliate={affiliateShortCode}`
41
+ - Replace `{affiliateShortCode}` with the actual short code of the affiliate
42
+
43
+ **Example URL:**
44
+ ```
45
+ https://yourwebsite.com/checkout?insertAffiliate=ABC123
46
+ ```
47
+
48
+ Once the user arrives on your site, the Insert Affiliate SDK automatically detects `insertAffiliate` and attributes the payment.
49
+
50
+ ### Branch.io with Capacitor (Hybrid Apps)
51
+
52
+ For Capacitor apps using the Branch.io plugin:
53
+
54
+ ```javascript
55
+ import { BranchDeepLinks, BranchInitEvent } from 'capacitor-branch-deep-links';
56
+ import { InsertAffiliate } from 'insert-affiliate-js-sdk';
57
+
58
+ // Set up callback to capture affiliate identifier
59
+ InsertAffiliate.setInsertAffiliateIdentifierChangeCallback((identifier) => {
60
+ if (identifier) {
61
+ console.log('Affiliate identifier captured:', identifier);
62
+ }
63
+ });
64
+
65
+ let branchInitialised = false;
66
+
67
+ async function setUpBranchListener() {
68
+ if (branchInitialised) return;
69
+ branchInitialised = true;
70
+
71
+ try {
72
+ await BranchDeepLinks.addListener('init', async (event: BranchInitEvent) => {
73
+ const clicked = event?.referringParams?.['+clicked_branch_link'];
74
+ const referringLink = event?.referringParams?.['~referring_link'];
75
+
76
+ if (clicked && referringLink) {
77
+ // This will automatically trigger the callback
78
+ await InsertAffiliate.setInsertAffiliateIdentifier(referringLink);
79
+ }
80
+ });
81
+
82
+ BranchDeepLinks.addListener('initError', (error: any) => {
83
+ console.error('Branch init error:', error);
84
+ });
85
+ } catch (err) {
86
+ console.error('Error setting up Branch listener:', err);
87
+ }
88
+ }
89
+ ```
90
+
91
+ ## AppsFlyer Web Redirect Setup
92
+
93
+ Use these steps if you're using [AppsFlyer](https://docs.insertaffiliate.com/appsflyer) OneLinks to send users to your web checkout.
94
+
95
+ ### Creating an AppsFlyer OneLink for Web Checkout
96
+
97
+ 1. **Create a new OneLink** in your AppsFlyer dashboard
98
+ 2. Open the link configuration settings
99
+ 3. Under **"When link is clicked on desktop web page"**, set the redirect URL
100
+ 4. Enter your web app's checkout URL
101
+ 5. Append the parameter: `?insertAffiliate={affiliateShortCode}`
102
+ - Replace `{affiliateShortCode}` with the actual short code of the affiliate
103
+
104
+ **Example URL:**
105
+ ```
106
+ https://yourwebsite.com/checkout?insertAffiliate=ABC123
107
+ ```
108
+
109
+ The Insert Affiliate SDK will automatically detect the parameter and attribute the resulting payment.
110
+
111
+ ## How the SDK Detects Parameters
112
+
113
+ When your web app loads, the Insert Affiliate SDK automatically:
114
+
115
+ 1. Checks the URL for `insertAffiliate` parameter
116
+ 2. Validates the affiliate code with the Insert Affiliate API
117
+ 3. Stores the affiliate identifier for later use
118
+ 4. Triggers any registered callbacks
119
+
120
+ **Automatic URL Detection:**
121
+
122
+ ```javascript
123
+ import { InsertAffiliate } from 'insert-affiliate-js-sdk';
124
+
125
+ // Initialize the SDK - it automatically checks URL parameters
126
+ await InsertAffiliate.initialize('your_company_code');
127
+
128
+ // The affiliate identifier is now available
129
+ const affiliateId = await InsertAffiliate.returnInsertAffiliateIdentifier();
130
+ console.log('Detected affiliate:', affiliateId);
131
+ ```
132
+
133
+ ## Using the Change Callback
134
+
135
+ For dynamic updates when an affiliate link is clicked:
136
+
137
+ ```javascript
138
+ import { InsertAffiliate } from 'insert-affiliate-js-sdk';
139
+
140
+ // Set up callback before initialization
141
+ InsertAffiliate.setInsertAffiliateIdentifierChangeCallback((identifier) => {
142
+ if (identifier) {
143
+ console.log('Affiliate identifier changed:', identifier);
144
+
145
+ // Update UI
146
+ const banner = document.getElementById('affiliate-banner');
147
+ if (banner) {
148
+ banner.textContent = 'You used a special affiliate link!';
149
+ banner.style.display = 'block';
150
+ }
151
+
152
+ // Track in analytics
153
+ analytics.track('affiliate_link_clicked', { identifier });
154
+ }
155
+ });
156
+
157
+ await InsertAffiliate.initialize('your_company_code');
158
+ ```
159
+
160
+ ## URL Parameter Reference
161
+
162
+ | Parameter | Description | Example |
163
+ |-----------|-------------|---------|
164
+ | `insertAffiliate` | The affiliate's short code | `?insertAffiliate=ABC123` |
165
+
166
+ ## Testing
167
+
168
+ Test your deep link setup by visiting your web app with the affiliate parameter:
169
+
170
+ ```
171
+ https://yourwebsite.com/checkout?insertAffiliate=TEST123
172
+ ```
173
+
174
+ Then check the console for:
175
+ ```
176
+ [Insert Affiliate] Affiliate identifier set: TEST123
177
+ ```
178
+
179
+ ## Troubleshooting
180
+
181
+ **Problem:** Affiliate parameter not detected
182
+ - **Solution:** Ensure the SDK is initialized before the URL parameters are processed
183
+ - Check that the parameter name is exactly `insertAffiliate` (case-sensitive)
184
+
185
+ **Problem:** Deep link opens app instead of web checkout
186
+ - **Solution:** Configure your deep linking provider to redirect to web URL for web-only flows
187
+ - Check the "Desktop redirect" settings in Branch.io or AppsFlyer
188
+
189
+ **Problem:** Parameter lost after page navigation
190
+ - **Solution:** The SDK stores the affiliate identifier in local storage, so it persists across pages
191
+ - Verify local storage is not being cleared
192
+
193
+ ## Next Steps
194
+
195
+ - Configure your deep linking provider to pass `insertAffiliate` parameter
196
+ - Test with a sample affiliate short code
197
+ - Integrate with your payment flow (see [Stripe Integration Guide](./stripe-integration.md))
198
+
199
+ [Back to Main README](../README.md)
@@ -0,0 +1,237 @@
1
+ # Stripe Integration Guide
2
+
3
+ This guide covers all Stripe-based payment integrations for affiliate tracking with Insert Affiliate.
4
+
5
+ ## Prerequisites
6
+
7
+ - Insert Affiliate SDK initialized in your web application
8
+ - Stripe account connected to Insert Affiliate (see [Connect Stripe Account](#1-connect-your-stripe-account) below)
9
+
10
+ ## 1. Connect Your Stripe Account
11
+
12
+ Before integrating the SDK code, you must connect your Stripe account to Insert Affiliate:
13
+
14
+ 1. Go to your [Insert Affiliate dashboard settings](https://app.insertaffiliate.com/settings)
15
+ 2. Navigate to the payment verification settings
16
+ 3. Select **Stripe** as your verification method
17
+ 4. Click **Connect with Stripe** to authorize the connection via Stripe Connect
18
+ 5. Once connected, Insert Affiliate will automatically receive your Stripe events
19
+
20
+ ## 2. Direct Stripe Checkout Integration
21
+
22
+ For web-based subscriptions and payments using Stripe Checkout directly.
23
+
24
+ ### Frontend Code
25
+
26
+ Retrieve the affiliate identifier and company ID before creating a checkout session:
27
+
28
+ ```javascript
29
+ import { InsertAffiliate } from 'insert-affiliate-js-sdk';
30
+
31
+ const affiliateId = await InsertAffiliate.returnInsertAffiliateIdentifier();
32
+ const companyId = await InsertAffiliate.returnCompanyId();
33
+
34
+ const response = await fetch('https://your-backend.com/create-checkout-session', {
35
+ method: 'POST',
36
+ headers: {
37
+ 'Content-Type': 'application/json',
38
+ },
39
+ body: JSON.stringify({
40
+ priceId: 'price_xxxxx',
41
+ insertAffiliate: affiliateId,
42
+ insertAffiliateCompanyId: companyId,
43
+ successUrl: window.location.origin + '/success',
44
+ cancelUrl: window.location.origin + '/canceled',
45
+ }),
46
+ });
47
+
48
+ const { sessionId } = await response.json();
49
+ // Redirect to Stripe Checkout
50
+ ```
51
+
52
+ ### Backend Code (Node.js)
53
+
54
+ Store both the affiliate identifier and company ID in Stripe metadata:
55
+
56
+ ```javascript
57
+ const stripe = require('stripe')('sk_test_xxxxx');
58
+
59
+ app.post('/create-checkout-session', async (req, res) => {
60
+ const { priceId, insertAffiliate, insertAffiliateCompanyId, successUrl, cancelUrl } = req.body;
61
+
62
+ const session = await stripe.checkout.sessions.create({
63
+ mode: 'subscription',
64
+ line_items: [{
65
+ price: priceId,
66
+ quantity: 1,
67
+ }],
68
+ metadata: {
69
+ insertAffiliate: insertAffiliate || '',
70
+ insertAffiliateCompanyId: insertAffiliateCompanyId || '',
71
+ },
72
+ subscription_data: {
73
+ metadata: {
74
+ insertAffiliate: insertAffiliate || '',
75
+ insertAffiliateCompanyId: insertAffiliateCompanyId || '',
76
+ },
77
+ },
78
+ success_url: successUrl,
79
+ cancel_url: cancelUrl,
80
+ });
81
+
82
+ res.json({ sessionId: session.id });
83
+ });
84
+ ```
85
+
86
+ **Required Metadata Fields:**
87
+ - `insertAffiliate`: The affiliate's short code
88
+ - `insertAffiliateCompanyId`: Your Insert Affiliate company ID
89
+
90
+ Both fields are required for proper affiliate attribution and commission tracking.
91
+
92
+ ## 3. Stripe Billing with RevenueCat
93
+
94
+ If you're using RevenueCat's [Stripe Billing](https://www.revenuecat.com/docs/web/integrations/stripe), you can track affiliate conversions through Insert Affiliate while using RevenueCat for subscription management.
95
+
96
+ **Prerequisites:**
97
+ - You must host your own web checkout page where Stripe Checkout is embedded
98
+ - Follow RevenueCat's [Stripe integration guide](https://www.revenuecat.com/docs/web/integrations/stripe)
99
+
100
+ **Integration:**
101
+
102
+ Follow the same steps as [Direct Stripe Checkout Integration](#2-direct-stripe-checkout-integration) above. Since you've connected your Stripe account via Stripe Connect, Insert Affiliate will automatically receive all Stripe events. RevenueCat handles subscription management, while Insert Affiliate handles affiliate attribution through the Stripe metadata.
103
+
104
+ ## 4. RevenueCat Web Billing Integration
105
+
106
+ If you're using [RevenueCat's Web SDK with Web Billing](https://www.revenuecat.com/docs/web/web-billing/overview), pass UTM parameters as purchase metadata.
107
+
108
+ **Prerequisites:**
109
+ - RevenueCat Web SDK installed and configured
110
+ - RevenueCat Web Billing set up with Stripe
111
+ - Insert Affiliate SDK initialized on your page
112
+ - Stripe account connected via Stripe Connect
113
+
114
+ ### Implementation
115
+
116
+ ```javascript
117
+ import { InsertAffiliate } from 'insert-affiliate-js-sdk';
118
+ import { Purchases } from '@revenuecat/purchases-js';
119
+
120
+ // Initialize both SDKs
121
+ await InsertAffiliate.initialize('your_company_code');
122
+ const purchases = Purchases.configure('your_revenuecat_web_api_key');
123
+
124
+ // Get affiliate information
125
+ const affiliateId = await InsertAffiliate.returnInsertAffiliateIdentifier(true);
126
+ const companyId = await InsertAffiliate.returnCompanyId();
127
+
128
+ // Prepare metadata with UTM parameters
129
+ const metadata: Record<string, string> = {};
130
+
131
+ if (affiliateId && affiliateId !== 'none') {
132
+ metadata.utm_source = 'insertAffiliate';
133
+ metadata.utm_medium = companyId || 'none';
134
+ metadata.utm_campaign = affiliateId;
135
+ }
136
+
137
+ // Get offerings and make purchase
138
+ const offerings = await purchases.getOfferings();
139
+ const selectedPackage = offerings.current?.availablePackages[0];
140
+
141
+ if (selectedPackage) {
142
+ const { customerInfo } = await purchases.purchase({
143
+ rcPackage: selectedPackage,
144
+ metadata: metadata,
145
+ });
146
+ console.log('Purchase successful!');
147
+ }
148
+ ```
149
+
150
+ **UTM Parameter Mapping:**
151
+ | Parameter | Value | Purpose |
152
+ |-----------|-------|---------|
153
+ | `utm_source` | `'insertAffiliate'` | Identifies Insert Affiliate conversions |
154
+ | `utm_medium` | Your company ID | Links to your Insert Affiliate account |
155
+ | `utm_campaign` | Affiliate identifier | Credits the specific affiliate |
156
+
157
+ ## 5. RevenueCat Web Purchase Links
158
+
159
+ If you're using [RevenueCat Web Purchase Links](https://www.revenuecat.com/docs/web/web-billing/web-purchase-links) for online campaigns, append UTM parameters to the links.
160
+
161
+ ### URL Format
162
+
163
+ Base URL:
164
+ ```
165
+ https://pay.rev.cat/sandbox/viqxbcoudyfaeaae/
166
+ ```
167
+
168
+ With affiliate parameters:
169
+ ```
170
+ https://pay.rev.cat/sandbox/viqxbcoudyfaeaae/?utm_source=insertAffiliate&utm_medium={companyId}&utm_campaign={affiliateShortCode}
171
+ ```
172
+
173
+ ### Full Example
174
+
175
+ ```
176
+ https://pay.rev.cat/sandbox/viqxbcoudyfaeaxa/?utm_source=insertAffiliate&utm_medium=12345&utm_campaign=AFF123
177
+ ```
178
+
179
+ Where:
180
+ - `utm_source=insertAffiliate` - Identifies this as an Insert Affiliate conversion
181
+ - `utm_medium=12345` - Your Insert Affiliate company ID
182
+ - `utm_campaign=AFF123` - The affiliate's short code
183
+
184
+ The Insert Affiliate SDK automatically processes the UTM parameters when users open these URLs and attributes the resulting purchase to the correct affiliate.
185
+
186
+ ## Using the Callback for Automatic Integration
187
+
188
+ The SDK provides a callback that fires whenever the affiliate identifier changes, making it easy to automatically update your checkout flow:
189
+
190
+ ```javascript
191
+ import { InsertAffiliate } from 'insert-affiliate-js-sdk';
192
+
193
+ let currentAffiliateId = null;
194
+
195
+ InsertAffiliate.setInsertAffiliateIdentifierChangeCallback((identifier) => {
196
+ if (identifier) {
197
+ console.log('Affiliate identifier changed:', identifier);
198
+ currentAffiliateId = identifier;
199
+ }
200
+ });
201
+
202
+ // Later, when creating a Stripe checkout session
203
+ const companyId = await InsertAffiliate.returnCompanyId();
204
+
205
+ const response = await fetch('/create-checkout-session', {
206
+ method: 'POST',
207
+ headers: { 'Content-Type': 'application/json' },
208
+ body: JSON.stringify({
209
+ priceId: 'price_xxxxx',
210
+ insertAffiliate: currentAffiliateId,
211
+ insertAffiliateCompanyId: companyId,
212
+ successUrl: window.location.origin + '/success',
213
+ cancelUrl: window.location.origin + '/canceled',
214
+ }),
215
+ });
216
+ ```
217
+
218
+ ## Troubleshooting
219
+
220
+ **Problem:** Affiliate not credited for purchase
221
+ - **Solution:** Verify both `insertAffiliate` and `insertAffiliateCompanyId` are included in Stripe metadata
222
+ - Check that your Stripe account is connected via Stripe Connect in the Insert Affiliate dashboard
223
+
224
+ **Problem:** Metadata not appearing in Stripe
225
+ - **Solution:** Ensure metadata is passed to both `metadata` and `subscription_data.metadata` in the checkout session
226
+
227
+ **Problem:** UTM parameters not being captured
228
+ - **Solution:** Initialize the Insert Affiliate SDK before users interact with purchase flows
229
+ - Verify the SDK is processing URL parameters on page load
230
+
231
+ ## Next Steps
232
+
233
+ - Test with a test affiliate link to verify attribution
234
+ - Make a test purchase to confirm tracking works end-to-end
235
+ - Monitor conversions in your Insert Affiliate dashboard
236
+
237
+ [Back to Main README](../README.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "insert-affiliate-js-sdk",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -326,27 +326,111 @@ export class InsertAffiliate {
326
326
  return companyCode;
327
327
  }
328
328
 
329
- static async getOfferCode(): Promise<string | null> {
330
- this.verboseLog('Getting offer code...');
329
+ /**
330
+ * Get the offer code for the current affiliate
331
+ * @param platformType Optional platform type: 'stripe' (default for web), 'ios', or 'android'
332
+ * @returns The offer code for the specified platform, or null if not found
333
+ */
334
+ static async getOfferCode(platformType: 'ios' | 'android' | 'stripe' = 'stripe'): Promise<string | null> {
335
+ this.verboseLog(`Getting offer code for platform: ${platformType}...`);
331
336
 
332
- // Return cached offer code if available
333
- if (this.offerCode) {
337
+ const storageKey = platformType === 'stripe' ? 'offerCode' : `offerCode_${platformType}`;
338
+
339
+ // Return cached offer code if available (only for default Stripe)
340
+ if (platformType === 'stripe' && this.offerCode) {
334
341
  this.verboseLog(`Returning cached offer code: ${this.offerCode}`);
335
342
  return this.offerCode;
336
343
  }
337
344
 
338
345
  // Try to get from storage
339
- const storedOfferCode = await getValue('offerCode');
346
+ const storedOfferCode = await getValue(storageKey);
340
347
  if (storedOfferCode) {
341
348
  this.verboseLog(`Returning stored offer code: ${storedOfferCode}`);
342
- this.offerCode = storedOfferCode;
349
+ if (platformType === 'stripe') {
350
+ this.offerCode = storedOfferCode;
351
+ }
343
352
  return storedOfferCode;
344
353
  }
345
354
 
355
+ // If not in storage, try to fetch it
356
+ const shortCode = await getValue('referrerLink');
357
+ if (shortCode) {
358
+ this.verboseLog(`No stored offer code, fetching for short code: ${shortCode}`);
359
+ const fetchedCode = await this.fetchOfferCodeForPlatform(shortCode, platformType);
360
+ return fetchedCode;
361
+ }
362
+
346
363
  this.verboseLog('No offer code found');
347
364
  return null;
348
365
  }
349
366
 
367
+ /**
368
+ * Get the Stripe coupon/promo code for the current affiliate
369
+ * Convenience method that calls getOfferCode with platformType='stripe'
370
+ * @returns The Stripe coupon/promo code, or null if not found
371
+ */
372
+ static async getStripeCouponCode(): Promise<string | null> {
373
+ return this.getOfferCode('stripe');
374
+ }
375
+
376
+ /**
377
+ * Fetch offer code for a specific platform
378
+ * @param shortCode The affiliate short code
379
+ * @param platformType The platform type: 'ios', 'android', or 'stripe'
380
+ * @returns The offer code for the specified platform, or null if not found
381
+ */
382
+ private static async fetchOfferCodeForPlatform(shortCode: string, platformType: 'ios' | 'android' | 'stripe'): Promise<string | null> {
383
+ this.verboseLog(`Fetching offer code for platform: ${platformType}, short code: ${shortCode}`);
384
+
385
+ try {
386
+ const companyCode = this.companyCode || await getValue('companyCode');
387
+ if (!companyCode) {
388
+ this.verboseLog('Cannot fetch offer code: no company code available');
389
+ return null;
390
+ }
391
+
392
+ const encoded = encodeURIComponent(shortCode);
393
+ const url = `https://api.insertaffiliate.com/v1/affiliateReturnOfferCode/${companyCode}/${encoded}?platformType=${platformType}`;
394
+ this.verboseLog(`Making API call to: ${url}`);
395
+
396
+ const response = await fetch(url);
397
+ this.verboseLog(`API response status: ${response.status}`);
398
+
399
+ if (!response.ok) {
400
+ this.verboseLog(`Failed to fetch offer code, status: ${response.status}`);
401
+ return null;
402
+ }
403
+
404
+ const offerCode = (await response.text()).replace(/[^a-zA-Z0-9]/g, '');
405
+ this.verboseLog(`Received offer code: ${offerCode}`);
406
+
407
+ const errorCodes = [
408
+ 'errorofferCodeNotFound',
409
+ 'errorAffiliateoffercodenotfoundinanycompany',
410
+ 'errorAffiliateoffercodenotfoundinanycompanyAffiliatelinkwas',
411
+ 'Routenotfound'
412
+ ];
413
+
414
+ if (errorCodes.includes(offerCode)) {
415
+ this.verboseLog('Offer code not found or invalid');
416
+ return null;
417
+ }
418
+
419
+ // Store offer code with platform-specific key
420
+ const storageKey = platformType === 'stripe' ? 'offerCode' : `offerCode_${platformType}`;
421
+ await saveValue(storageKey, offerCode);
422
+ if (platformType === 'stripe') {
423
+ this.offerCode = offerCode;
424
+ }
425
+ this.verboseLog(`Offer code stored successfully with key ${storageKey}: ${offerCode}`);
426
+
427
+ return offerCode;
428
+ } catch (error) {
429
+ this.verboseLog(`Error fetching offer code: ${error}`);
430
+ return null;
431
+ }
432
+ }
433
+
350
434
  private static async fetchAndStoreOfferCode(shortCode: string): Promise<void> {
351
435
  this.verboseLog(`Fetching offer code for short code: ${shortCode}`);
352
436