@settlr/sdk 0.6.0 → 0.6.2

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
@@ -97,6 +97,71 @@ const accounts = await buildPrivateReceiptAccounts({
97
97
 
98
98
  > **Private on-chain. Compliant off-chain.** Your competitors can't see your revenue, but your accountant can.
99
99
 
100
+ ## 🛡️ Wallet Security (Range)
101
+
102
+ Settlr integrates Range Security to screen wallets before processing payments:
103
+
104
+ ```typescript
105
+ import { screenWallet, isWalletBlocked, RiskLevel } from "@settlr/sdk";
106
+
107
+ // Screen a wallet for sanctions, fraud, mixers, etc.
108
+ const result = await screenWallet("SomeWalletAddress...");
109
+
110
+ if (result.riskLevel === RiskLevel.SEVERE || result.isSanctioned) {
111
+ console.log("Wallet is blocked:", result.categories);
112
+ // Don't process payment
113
+ }
114
+
115
+ // Quick check
116
+ const blocked = await isWalletBlocked("SuspiciousWallet...");
117
+ if (blocked) {
118
+ return { error: "Payment blocked for compliance" };
119
+ }
120
+ ```
121
+
122
+ **What Range screens for:**
123
+
124
+ - 🚫 **Sanctions** - OFAC, EU sanctions lists
125
+ - 🕵️ **Fraud** - Known scam wallets
126
+ - 🌀 **Mixers** - Tornado Cash, etc.
127
+ - 🌑 **Darknet** - Illicit marketplace activity
128
+ - 💀 **Ransomware** - Known attack wallets
129
+ - 🎰 **Gambling** - Unlicensed gambling (configurable)
130
+
131
+ ## 💸 Private Payouts (Privacy Cash)
132
+
133
+ Enable ZK-shielded payments for privacy-conscious merchants:
134
+
135
+ ```typescript
136
+ import {
137
+ createPrivacyCashClient,
138
+ shieldPayment,
139
+ privateTransfer,
140
+ } from "@settlr/sdk";
141
+
142
+ // Initialize Privacy Cash
143
+ const privacy = createPrivacyCashClient({
144
+ connection,
145
+ wallet,
146
+ network: "mainnet-beta",
147
+ });
148
+
149
+ // Shield funds (move to private pool)
150
+ const shieldTx = await shieldPayment(privacy, 100); // $100 USDC
151
+ console.log("Shielded:", shieldTx);
152
+
153
+ // Private transfer (ZK-shielded, amount hidden)
154
+ const transferTx = await privateTransfer(privacy, "RecipientWallet...", 50);
155
+ console.log("Private transfer:", transferTx);
156
+ ```
157
+
158
+ **Privacy Cash features:**
159
+
160
+ - 🔐 ZK-shielded transactions
161
+ - 👁️ Amount hidden from on-chain observers
162
+ - ⚡ Fast finality on Solana
163
+ - 💰 Supports USDC and SOL
164
+
100
165
  ## Installation
101
166
 
102
167
  ```bash
@@ -499,7 +564,7 @@ app.post(
499
564
  await fulfillOrder(event.payment.orderId);
500
565
  },
501
566
  },
502
- })
567
+ }),
503
568
  );
504
569
  ```
505
570
 
package/dist/index.d.mts CHANGED
@@ -270,8 +270,10 @@ declare class Settlr {
270
270
  constructor(config: SettlrConfig);
271
271
  /**
272
272
  * Validate API key with Settlr backend
273
+ * This is called automatically by SettlrProvider, but can also be called manually.
274
+ * Fetches merchant wallet address if not provided in config.
273
275
  */
274
- private validateApiKey;
276
+ validateApiKey(): Promise<void>;
275
277
  /**
276
278
  * Get the current tier
277
279
  */
@@ -455,6 +457,10 @@ interface SettlrContextValue {
455
457
  settlr: Settlr | null;
456
458
  /** Whether user is authenticated */
457
459
  authenticated: boolean;
460
+ /** Whether the SDK is ready (API key validated) */
461
+ ready: boolean;
462
+ /** Error if initialization failed */
463
+ error: Error | null;
458
464
  /** Create a payment link (redirect flow) */
459
465
  createPayment: (options: CreatePaymentOptions) => Promise<Payment>;
460
466
  /** Generate checkout URL for redirect */
@@ -1143,4 +1149,114 @@ declare class OneClickClient {
1143
1149
  */
1144
1150
  declare function createOneClickClient(baseUrl?: string): OneClickClient;
1145
1151
 
1146
- export { type ApproveOneClickOptions, BuyButton, type BuyButtonProps, type ChargeOneClickOptions, CheckoutWidget, type CheckoutWidgetProps, type CreatePaymentOptions, type CreateSubscriptionOptions, INCO_LIGHTNING_PROGRAM_ID, type IssuePrivateReceiptResult, type MerchantConfig, OneClickClient, type OneClickResult, type Payment, PaymentModal, type PaymentModalProps, type PaymentResult, type PaymentStatus, PrivacyFeatures, type PrivateReceiptConfig, SETTLR_CHECKOUT_URL, SETTLR_PROGRAM_ID, SUPPORTED_NETWORKS, SUPPORTED_TOKENS, Settlr, type SettlrConfig, SettlrProvider, type SpendingApproval, type Subscription, type SubscriptionInterval, type SubscriptionPlan, type SubscriptionStatus, type SupportedToken, type TransactionOptions, USDC_MINT_DEVNET, USDC_MINT_MAINNET, USDT_MINT_DEVNET, USDT_MINT_MAINNET, type WebhookEventType, type WebhookHandler, type WebhookHandlers, type WebhookPayload, buildAllowanceRemainingAccounts, buildPrivateReceiptAccounts, createOneClickClient, createWebhookHandler, encryptAmount, findAllowancePda, findPrivateReceiptPda, formatUSDC, getTokenDecimals, getTokenMint, parseUSDC, parseWebhookPayload, shortenAddress, simulateAndGetHandle, usePaymentLink, usePaymentModal, useSettlr, verifyWebhookSignature };
1152
+ /**
1153
+ * Mobile Game Integration Utilities
1154
+ *
1155
+ * Simple helpers for integrating Settlr payments in mobile games.
1156
+ * Works with Unity, Unreal, native iOS/Android, React Native, etc.
1157
+ *
1158
+ * The simplest integration is URL-based - just open the checkout URL
1159
+ * and listen for the callback.
1160
+ */
1161
+ interface MobileCheckoutOptions {
1162
+ /** Amount in USDC */
1163
+ amount: number;
1164
+ /** Merchant wallet address */
1165
+ merchantWallet: string;
1166
+ /** Optional: Merchant display name */
1167
+ merchantName?: string;
1168
+ /** Optional: Payment description */
1169
+ memo?: string;
1170
+ /** URL to redirect after success */
1171
+ successUrl?: string;
1172
+ /** URL to redirect on cancel */
1173
+ cancelUrl?: string;
1174
+ /** Optional: Your order/transaction ID */
1175
+ orderId?: string;
1176
+ /** Optional: Customer ID for one-click */
1177
+ customerId?: string;
1178
+ }
1179
+ interface MobileCheckoutResult {
1180
+ success: boolean;
1181
+ signature?: string;
1182
+ orderId?: string;
1183
+ error?: string;
1184
+ }
1185
+ /**
1186
+ * Generate a checkout URL for mobile games
1187
+ *
1188
+ * Usage in Unity (C#):
1189
+ * ```csharp
1190
+ * string url = $"https://settlr.dev/checkout?amount={amount}&merchant={wallet}";
1191
+ * Application.OpenURL(url);
1192
+ * ```
1193
+ *
1194
+ * Usage in Swift:
1195
+ * ```swift
1196
+ * let url = "https://settlr.dev/checkout?amount=\(amount)&merchant=\(wallet)"
1197
+ * UIApplication.shared.open(URL(string: url)!)
1198
+ * ```
1199
+ */
1200
+ declare function generateCheckoutUrl(options: MobileCheckoutOptions, baseUrl?: string): string;
1201
+ /**
1202
+ * Generate a deep link for mobile app integration
1203
+ *
1204
+ * For apps that register a custom URL scheme (e.g., mygame://)
1205
+ * the success/cancel URLs can redirect back to the app.
1206
+ *
1207
+ * Example:
1208
+ * - successUrl: "mygame://payment-success?order=123"
1209
+ * - cancelUrl: "mygame://payment-cancel?order=123"
1210
+ */
1211
+ declare function generateDeepLinkCheckout(options: MobileCheckoutOptions, appScheme: string, baseUrl?: string): string;
1212
+ /**
1213
+ * Parse the callback URL when user returns to app
1214
+ *
1215
+ * Usage in Swift:
1216
+ * ```swift
1217
+ * func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
1218
+ * if url.scheme == "mygame" && url.host == "payment-success" {
1219
+ * let signature = URLComponents(url: url, resolvingAgainstBaseURL: true)?
1220
+ * .queryItems?.first(where: { $0.name == "signature" })?.value
1221
+ * // Handle success
1222
+ * }
1223
+ * }
1224
+ * ```
1225
+ */
1226
+ declare function parseCallbackUrl(url: string): MobileCheckoutResult;
1227
+ /**
1228
+ * REST API endpoint info for server-side integration
1229
+ *
1230
+ * Mobile games can use these APIs directly without the SDK:
1231
+ *
1232
+ * 1. Create checkout session:
1233
+ * POST /api/checkout/create
1234
+ * { amount, merchantWallet, memo }
1235
+ * → { sessionId, checkoutUrl }
1236
+ *
1237
+ * 2. Check payment status:
1238
+ * GET /api/checkout/status?session={sessionId}
1239
+ * → { status: 'pending' | 'completed' | 'expired', signature? }
1240
+ *
1241
+ * 3. One-click payment (for returning players):
1242
+ * POST /api/one-click
1243
+ * { action: 'charge', customerWallet, merchantWallet, amount }
1244
+ * → { success, signature }
1245
+ */
1246
+ declare const REST_API: {
1247
+ createSession: string;
1248
+ checkStatus: string;
1249
+ oneClick: string;
1250
+ webhook: string;
1251
+ };
1252
+ /**
1253
+ * Example Unity C# integration code
1254
+ * (For documentation purposes)
1255
+ */
1256
+ declare const UNITY_EXAMPLE = "\n// SettlrPayment.cs - Drop into your Unity project\n\nusing UnityEngine;\nusing UnityEngine.Networking;\nusing System.Collections;\n\npublic class SettlrPayment : MonoBehaviour\n{\n public string merchantWallet = \"YOUR_WALLET_ADDRESS\";\n public string settlrUrl = \"https://settlr.dev\";\n \n // Call this to start a payment\n public void StartPayment(float amount, string orderId, System.Action<bool, string> callback)\n {\n string url = $\"{settlrUrl}/checkout?amount={amount}&merchant={merchantWallet}&order_id={orderId}\";\n \n // Add deep link callback (register mygame:// scheme in your app)\n url += $\"&success_url=mygame://payment-success?order={orderId}\";\n url += $\"&cancel_url=mygame://payment-cancel?order={orderId}\";\n \n Application.OpenURL(url);\n \n // Start polling for completion\n StartCoroutine(PollPaymentStatus(orderId, callback));\n }\n \n IEnumerator PollPaymentStatus(string orderId, System.Action<bool, string> callback)\n {\n string statusUrl = $\"{settlrUrl}/api/checkout/status?order_id={orderId}\";\n \n for (int i = 0; i < 60; i++) // Poll for 5 minutes\n {\n using (UnityWebRequest request = UnityWebRequest.Get(statusUrl))\n {\n yield return request.SendWebRequest();\n \n if (request.result == UnityWebRequest.Result.Success)\n {\n var response = JsonUtility.FromJson<PaymentStatusResponse>(request.downloadHandler.text);\n \n if (response.status == \"completed\")\n {\n callback(true, response.signature);\n yield break;\n }\n else if (response.status == \"expired\" || response.status == \"cancelled\")\n {\n callback(false, null);\n yield break;\n }\n }\n }\n \n yield return new WaitForSeconds(5f); // Check every 5 seconds\n }\n \n callback(false, \"Timeout\");\n }\n \n [System.Serializable]\n class PaymentStatusResponse\n {\n public string status;\n public string signature;\n }\n}\n";
1257
+ /**
1258
+ * Example React Native integration
1259
+ */
1260
+ declare const REACT_NATIVE_EXAMPLE = "\n// SettlrPayment.tsx - React Native component\n\nimport { Linking, Alert } from 'react-native';\nimport { useEffect } from 'react';\n\nconst SETTLR_URL = 'https://settlr.dev';\nconst APP_SCHEME = 'mygame';\n\nexport function useSettlrPayment(onSuccess: (sig: string) => void) {\n useEffect(() => {\n const handleDeepLink = ({ url }: { url: string }) => {\n if (url.includes('payment-success')) {\n const sig = new URL(url).searchParams.get('signature');\n if (sig) onSuccess(sig);\n }\n };\n \n Linking.addEventListener('url', handleDeepLink);\n return () => Linking.removeAllListeners('url');\n }, [onSuccess]);\n \n const startPayment = async (amount: number, merchantWallet: string) => {\n const orderId = `order_${Date.now()}`;\n const url = `${SETTLR_URL}/checkout?amount=${amount}&merchant=${merchantWallet}` +\n `&success_url=${APP_SCHEME}://payment-success?order=${orderId}` +\n `&cancel_url=${APP_SCHEME}://payment-cancel?order=${orderId}`;\n \n await Linking.openURL(url);\n };\n \n return { startPayment };\n}\n";
1261
+
1262
+ export { type ApproveOneClickOptions, BuyButton, type BuyButtonProps, type ChargeOneClickOptions, CheckoutWidget, type CheckoutWidgetProps, type CreatePaymentOptions, type CreateSubscriptionOptions, INCO_LIGHTNING_PROGRAM_ID, type IssuePrivateReceiptResult, type MerchantConfig, type MobileCheckoutOptions, type MobileCheckoutResult, OneClickClient, type OneClickResult, type Payment, PaymentModal, type PaymentModalProps, type PaymentResult, type PaymentStatus, PrivacyFeatures, type PrivateReceiptConfig, REACT_NATIVE_EXAMPLE, REST_API, SETTLR_CHECKOUT_URL, SETTLR_PROGRAM_ID, SUPPORTED_NETWORKS, SUPPORTED_TOKENS, Settlr, type SettlrConfig, SettlrProvider, type SpendingApproval, type Subscription, type SubscriptionInterval, type SubscriptionPlan, type SubscriptionStatus, type SupportedToken, type TransactionOptions, UNITY_EXAMPLE, USDC_MINT_DEVNET, USDC_MINT_MAINNET, USDT_MINT_DEVNET, USDT_MINT_MAINNET, type WebhookEventType, type WebhookHandler, type WebhookHandlers, type WebhookPayload, buildAllowanceRemainingAccounts, buildPrivateReceiptAccounts, createOneClickClient, createWebhookHandler, encryptAmount, findAllowancePda, findPrivateReceiptPda, formatUSDC, generateCheckoutUrl, generateDeepLinkCheckout, getTokenDecimals, getTokenMint, parseCallbackUrl, parseUSDC, parseWebhookPayload, shortenAddress, simulateAndGetHandle, usePaymentLink, usePaymentModal, useSettlr, verifyWebhookSignature };
package/dist/index.d.ts CHANGED
@@ -270,8 +270,10 @@ declare class Settlr {
270
270
  constructor(config: SettlrConfig);
271
271
  /**
272
272
  * Validate API key with Settlr backend
273
+ * This is called automatically by SettlrProvider, but can also be called manually.
274
+ * Fetches merchant wallet address if not provided in config.
273
275
  */
274
- private validateApiKey;
276
+ validateApiKey(): Promise<void>;
275
277
  /**
276
278
  * Get the current tier
277
279
  */
@@ -455,6 +457,10 @@ interface SettlrContextValue {
455
457
  settlr: Settlr | null;
456
458
  /** Whether user is authenticated */
457
459
  authenticated: boolean;
460
+ /** Whether the SDK is ready (API key validated) */
461
+ ready: boolean;
462
+ /** Error if initialization failed */
463
+ error: Error | null;
458
464
  /** Create a payment link (redirect flow) */
459
465
  createPayment: (options: CreatePaymentOptions) => Promise<Payment>;
460
466
  /** Generate checkout URL for redirect */
@@ -1143,4 +1149,114 @@ declare class OneClickClient {
1143
1149
  */
1144
1150
  declare function createOneClickClient(baseUrl?: string): OneClickClient;
1145
1151
 
1146
- export { type ApproveOneClickOptions, BuyButton, type BuyButtonProps, type ChargeOneClickOptions, CheckoutWidget, type CheckoutWidgetProps, type CreatePaymentOptions, type CreateSubscriptionOptions, INCO_LIGHTNING_PROGRAM_ID, type IssuePrivateReceiptResult, type MerchantConfig, OneClickClient, type OneClickResult, type Payment, PaymentModal, type PaymentModalProps, type PaymentResult, type PaymentStatus, PrivacyFeatures, type PrivateReceiptConfig, SETTLR_CHECKOUT_URL, SETTLR_PROGRAM_ID, SUPPORTED_NETWORKS, SUPPORTED_TOKENS, Settlr, type SettlrConfig, SettlrProvider, type SpendingApproval, type Subscription, type SubscriptionInterval, type SubscriptionPlan, type SubscriptionStatus, type SupportedToken, type TransactionOptions, USDC_MINT_DEVNET, USDC_MINT_MAINNET, USDT_MINT_DEVNET, USDT_MINT_MAINNET, type WebhookEventType, type WebhookHandler, type WebhookHandlers, type WebhookPayload, buildAllowanceRemainingAccounts, buildPrivateReceiptAccounts, createOneClickClient, createWebhookHandler, encryptAmount, findAllowancePda, findPrivateReceiptPda, formatUSDC, getTokenDecimals, getTokenMint, parseUSDC, parseWebhookPayload, shortenAddress, simulateAndGetHandle, usePaymentLink, usePaymentModal, useSettlr, verifyWebhookSignature };
1152
+ /**
1153
+ * Mobile Game Integration Utilities
1154
+ *
1155
+ * Simple helpers for integrating Settlr payments in mobile games.
1156
+ * Works with Unity, Unreal, native iOS/Android, React Native, etc.
1157
+ *
1158
+ * The simplest integration is URL-based - just open the checkout URL
1159
+ * and listen for the callback.
1160
+ */
1161
+ interface MobileCheckoutOptions {
1162
+ /** Amount in USDC */
1163
+ amount: number;
1164
+ /** Merchant wallet address */
1165
+ merchantWallet: string;
1166
+ /** Optional: Merchant display name */
1167
+ merchantName?: string;
1168
+ /** Optional: Payment description */
1169
+ memo?: string;
1170
+ /** URL to redirect after success */
1171
+ successUrl?: string;
1172
+ /** URL to redirect on cancel */
1173
+ cancelUrl?: string;
1174
+ /** Optional: Your order/transaction ID */
1175
+ orderId?: string;
1176
+ /** Optional: Customer ID for one-click */
1177
+ customerId?: string;
1178
+ }
1179
+ interface MobileCheckoutResult {
1180
+ success: boolean;
1181
+ signature?: string;
1182
+ orderId?: string;
1183
+ error?: string;
1184
+ }
1185
+ /**
1186
+ * Generate a checkout URL for mobile games
1187
+ *
1188
+ * Usage in Unity (C#):
1189
+ * ```csharp
1190
+ * string url = $"https://settlr.dev/checkout?amount={amount}&merchant={wallet}";
1191
+ * Application.OpenURL(url);
1192
+ * ```
1193
+ *
1194
+ * Usage in Swift:
1195
+ * ```swift
1196
+ * let url = "https://settlr.dev/checkout?amount=\(amount)&merchant=\(wallet)"
1197
+ * UIApplication.shared.open(URL(string: url)!)
1198
+ * ```
1199
+ */
1200
+ declare function generateCheckoutUrl(options: MobileCheckoutOptions, baseUrl?: string): string;
1201
+ /**
1202
+ * Generate a deep link for mobile app integration
1203
+ *
1204
+ * For apps that register a custom URL scheme (e.g., mygame://)
1205
+ * the success/cancel URLs can redirect back to the app.
1206
+ *
1207
+ * Example:
1208
+ * - successUrl: "mygame://payment-success?order=123"
1209
+ * - cancelUrl: "mygame://payment-cancel?order=123"
1210
+ */
1211
+ declare function generateDeepLinkCheckout(options: MobileCheckoutOptions, appScheme: string, baseUrl?: string): string;
1212
+ /**
1213
+ * Parse the callback URL when user returns to app
1214
+ *
1215
+ * Usage in Swift:
1216
+ * ```swift
1217
+ * func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
1218
+ * if url.scheme == "mygame" && url.host == "payment-success" {
1219
+ * let signature = URLComponents(url: url, resolvingAgainstBaseURL: true)?
1220
+ * .queryItems?.first(where: { $0.name == "signature" })?.value
1221
+ * // Handle success
1222
+ * }
1223
+ * }
1224
+ * ```
1225
+ */
1226
+ declare function parseCallbackUrl(url: string): MobileCheckoutResult;
1227
+ /**
1228
+ * REST API endpoint info for server-side integration
1229
+ *
1230
+ * Mobile games can use these APIs directly without the SDK:
1231
+ *
1232
+ * 1. Create checkout session:
1233
+ * POST /api/checkout/create
1234
+ * { amount, merchantWallet, memo }
1235
+ * → { sessionId, checkoutUrl }
1236
+ *
1237
+ * 2. Check payment status:
1238
+ * GET /api/checkout/status?session={sessionId}
1239
+ * → { status: 'pending' | 'completed' | 'expired', signature? }
1240
+ *
1241
+ * 3. One-click payment (for returning players):
1242
+ * POST /api/one-click
1243
+ * { action: 'charge', customerWallet, merchantWallet, amount }
1244
+ * → { success, signature }
1245
+ */
1246
+ declare const REST_API: {
1247
+ createSession: string;
1248
+ checkStatus: string;
1249
+ oneClick: string;
1250
+ webhook: string;
1251
+ };
1252
+ /**
1253
+ * Example Unity C# integration code
1254
+ * (For documentation purposes)
1255
+ */
1256
+ declare const UNITY_EXAMPLE = "\n// SettlrPayment.cs - Drop into your Unity project\n\nusing UnityEngine;\nusing UnityEngine.Networking;\nusing System.Collections;\n\npublic class SettlrPayment : MonoBehaviour\n{\n public string merchantWallet = \"YOUR_WALLET_ADDRESS\";\n public string settlrUrl = \"https://settlr.dev\";\n \n // Call this to start a payment\n public void StartPayment(float amount, string orderId, System.Action<bool, string> callback)\n {\n string url = $\"{settlrUrl}/checkout?amount={amount}&merchant={merchantWallet}&order_id={orderId}\";\n \n // Add deep link callback (register mygame:// scheme in your app)\n url += $\"&success_url=mygame://payment-success?order={orderId}\";\n url += $\"&cancel_url=mygame://payment-cancel?order={orderId}\";\n \n Application.OpenURL(url);\n \n // Start polling for completion\n StartCoroutine(PollPaymentStatus(orderId, callback));\n }\n \n IEnumerator PollPaymentStatus(string orderId, System.Action<bool, string> callback)\n {\n string statusUrl = $\"{settlrUrl}/api/checkout/status?order_id={orderId}\";\n \n for (int i = 0; i < 60; i++) // Poll for 5 minutes\n {\n using (UnityWebRequest request = UnityWebRequest.Get(statusUrl))\n {\n yield return request.SendWebRequest();\n \n if (request.result == UnityWebRequest.Result.Success)\n {\n var response = JsonUtility.FromJson<PaymentStatusResponse>(request.downloadHandler.text);\n \n if (response.status == \"completed\")\n {\n callback(true, response.signature);\n yield break;\n }\n else if (response.status == \"expired\" || response.status == \"cancelled\")\n {\n callback(false, null);\n yield break;\n }\n }\n }\n \n yield return new WaitForSeconds(5f); // Check every 5 seconds\n }\n \n callback(false, \"Timeout\");\n }\n \n [System.Serializable]\n class PaymentStatusResponse\n {\n public string status;\n public string signature;\n }\n}\n";
1257
+ /**
1258
+ * Example React Native integration
1259
+ */
1260
+ declare const REACT_NATIVE_EXAMPLE = "\n// SettlrPayment.tsx - React Native component\n\nimport { Linking, Alert } from 'react-native';\nimport { useEffect } from 'react';\n\nconst SETTLR_URL = 'https://settlr.dev';\nconst APP_SCHEME = 'mygame';\n\nexport function useSettlrPayment(onSuccess: (sig: string) => void) {\n useEffect(() => {\n const handleDeepLink = ({ url }: { url: string }) => {\n if (url.includes('payment-success')) {\n const sig = new URL(url).searchParams.get('signature');\n if (sig) onSuccess(sig);\n }\n };\n \n Linking.addEventListener('url', handleDeepLink);\n return () => Linking.removeAllListeners('url');\n }, [onSuccess]);\n \n const startPayment = async (amount: number, merchantWallet: string) => {\n const orderId = `order_${Date.now()}`;\n const url = `${SETTLR_URL}/checkout?amount=${amount}&merchant=${merchantWallet}` +\n `&success_url=${APP_SCHEME}://payment-success?order=${orderId}` +\n `&cancel_url=${APP_SCHEME}://payment-cancel?order=${orderId}`;\n \n await Linking.openURL(url);\n };\n \n return { startPayment };\n}\n";
1261
+
1262
+ export { type ApproveOneClickOptions, BuyButton, type BuyButtonProps, type ChargeOneClickOptions, CheckoutWidget, type CheckoutWidgetProps, type CreatePaymentOptions, type CreateSubscriptionOptions, INCO_LIGHTNING_PROGRAM_ID, type IssuePrivateReceiptResult, type MerchantConfig, type MobileCheckoutOptions, type MobileCheckoutResult, OneClickClient, type OneClickResult, type Payment, PaymentModal, type PaymentModalProps, type PaymentResult, type PaymentStatus, PrivacyFeatures, type PrivateReceiptConfig, REACT_NATIVE_EXAMPLE, REST_API, SETTLR_CHECKOUT_URL, SETTLR_PROGRAM_ID, SUPPORTED_NETWORKS, SUPPORTED_TOKENS, Settlr, type SettlrConfig, SettlrProvider, type SpendingApproval, type Subscription, type SubscriptionInterval, type SubscriptionPlan, type SubscriptionStatus, type SupportedToken, type TransactionOptions, UNITY_EXAMPLE, USDC_MINT_DEVNET, USDC_MINT_MAINNET, USDT_MINT_DEVNET, USDT_MINT_MAINNET, type WebhookEventType, type WebhookHandler, type WebhookHandlers, type WebhookPayload, buildAllowanceRemainingAccounts, buildPrivateReceiptAccounts, createOneClickClient, createWebhookHandler, encryptAmount, findAllowancePda, findPrivateReceiptPda, formatUSDC, generateCheckoutUrl, generateDeepLinkCheckout, getTokenDecimals, getTokenMint, parseCallbackUrl, parseUSDC, parseWebhookPayload, shortenAddress, simulateAndGetHandle, usePaymentLink, usePaymentModal, useSettlr, verifyWebhookSignature };
package/dist/index.js CHANGED
@@ -36,12 +36,15 @@ __export(index_exports, {
36
36
  OneClickClient: () => OneClickClient,
37
37
  PaymentModal: () => PaymentModal,
38
38
  PrivacyFeatures: () => PrivacyFeatures,
39
+ REACT_NATIVE_EXAMPLE: () => REACT_NATIVE_EXAMPLE,
40
+ REST_API: () => REST_API,
39
41
  SETTLR_CHECKOUT_URL: () => SETTLR_CHECKOUT_URL,
40
42
  SETTLR_PROGRAM_ID: () => SETTLR_PROGRAM_ID,
41
43
  SUPPORTED_NETWORKS: () => SUPPORTED_NETWORKS,
42
44
  SUPPORTED_TOKENS: () => SUPPORTED_TOKENS,
43
45
  Settlr: () => Settlr,
44
46
  SettlrProvider: () => SettlrProvider,
47
+ UNITY_EXAMPLE: () => UNITY_EXAMPLE,
45
48
  USDC_MINT_DEVNET: () => USDC_MINT_DEVNET,
46
49
  USDC_MINT_MAINNET: () => USDC_MINT_MAINNET,
47
50
  USDT_MINT_DEVNET: () => USDT_MINT_DEVNET,
@@ -54,8 +57,11 @@ __export(index_exports, {
54
57
  findAllowancePda: () => findAllowancePda,
55
58
  findPrivateReceiptPda: () => findPrivateReceiptPda,
56
59
  formatUSDC: () => formatUSDC,
60
+ generateCheckoutUrl: () => generateCheckoutUrl,
61
+ generateDeepLinkCheckout: () => generateDeepLinkCheckout,
57
62
  getTokenDecimals: () => getTokenDecimals,
58
63
  getTokenMint: () => getTokenMint,
64
+ parseCallbackUrl: () => parseCallbackUrl,
59
65
  parseUSDC: () => parseUSDC,
60
66
  parseWebhookPayload: () => parseWebhookPayload,
61
67
  shortenAddress: () => shortenAddress,
@@ -197,6 +203,8 @@ var Settlr = class {
197
203
  }
198
204
  /**
199
205
  * Validate API key with Settlr backend
206
+ * This is called automatically by SettlrProvider, but can also be called manually.
207
+ * Fetches merchant wallet address if not provided in config.
200
208
  */
201
209
  async validateApiKey() {
202
210
  if (this.validated) return;
@@ -224,6 +232,7 @@ var Settlr = class {
224
232
  this.tier = data.tier;
225
233
  if (data.merchantWallet && !this.merchantWallet) {
226
234
  this.merchantWallet = new import_web32.PublicKey(data.merchantWallet);
235
+ this.merchantWalletFromValidation = data.merchantWallet;
227
236
  this.config.merchant.walletAddress = data.merchantWallet;
228
237
  }
229
238
  if (data.merchantName && !this.config.merchant.name) {
@@ -595,27 +604,54 @@ function SettlrProvider({
595
604
  config,
596
605
  authenticated = false
597
606
  }) {
607
+ const [ready, setReady] = (0, import_react.useState)(false);
608
+ const [error, setError] = (0, import_react.useState)(null);
598
609
  const settlr = (0, import_react.useMemo)(() => {
599
610
  return new Settlr({
600
611
  ...config,
601
612
  rpcEndpoint: config.rpcEndpoint ?? "https://api.devnet.solana.com"
602
613
  });
603
614
  }, [config]);
615
+ (0, import_react.useEffect)(() => {
616
+ let cancelled = false;
617
+ settlr.validateApiKey().then(() => {
618
+ if (!cancelled) {
619
+ setReady(true);
620
+ setError(null);
621
+ }
622
+ }).catch((err) => {
623
+ if (!cancelled) {
624
+ console.error("[Settlr] API key validation failed:", err);
625
+ setError(err instanceof Error ? err : new Error(String(err)));
626
+ if (config.apiKey?.startsWith("sk_test_")) {
627
+ setReady(true);
628
+ }
629
+ }
630
+ });
631
+ return () => {
632
+ cancelled = true;
633
+ };
634
+ }, [settlr, config.apiKey]);
604
635
  const value = (0, import_react.useMemo)(
605
636
  () => ({
606
637
  settlr,
607
638
  authenticated,
639
+ ready,
640
+ error,
608
641
  createPayment: (options) => {
609
642
  return settlr.createPayment(options);
610
643
  },
611
644
  getCheckoutUrl: (options) => {
645
+ if (!ready) {
646
+ console.warn("[Settlr] SDK not ready yet. Ensure API key is valid.");
647
+ }
612
648
  return settlr.getCheckoutUrl(options);
613
649
  },
614
650
  getBalance: () => {
615
651
  return settlr.getMerchantBalance();
616
652
  }
617
653
  }),
618
- [settlr, authenticated]
654
+ [settlr, authenticated, ready, error]
619
655
  );
620
656
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SettlrContext.Provider, { value, children });
621
657
  }
@@ -695,11 +731,18 @@ function BuyButton({
695
731
  variant = "primary",
696
732
  size = "md"
697
733
  }) {
698
- const { getCheckoutUrl, createPayment } = useSettlr();
734
+ const { getCheckoutUrl, createPayment, ready, error: sdkError } = useSettlr();
699
735
  const [loading, setLoading] = (0, import_react2.useState)(false);
700
736
  const [status, setStatus] = (0, import_react2.useState)("idle");
701
737
  const handleClick = (0, import_react2.useCallback)(async () => {
702
738
  if (disabled || loading) return;
739
+ if (!ready) {
740
+ const notReadyError = new Error(
741
+ sdkError?.message || "Settlr SDK not ready. Please check your API key configuration."
742
+ );
743
+ onError?.(notReadyError);
744
+ return;
745
+ }
703
746
  setLoading(true);
704
747
  setStatus("processing");
705
748
  onProcessing?.();
@@ -723,6 +766,8 @@ function BuyButton({
723
766
  orderId,
724
767
  disabled,
725
768
  loading,
769
+ ready,
770
+ sdkError,
726
771
  successUrl,
727
772
  cancelUrl,
728
773
  getCheckoutUrl,
@@ -1426,6 +1471,167 @@ var OneClickClient = class {
1426
1471
  function createOneClickClient(baseUrl) {
1427
1472
  return new OneClickClient(baseUrl);
1428
1473
  }
1474
+
1475
+ // src/mobile.ts
1476
+ function generateCheckoutUrl(options, baseUrl = "https://settlr.dev") {
1477
+ const params = new URLSearchParams();
1478
+ params.set("amount", options.amount.toString());
1479
+ params.set("merchant", options.merchantWallet);
1480
+ if (options.merchantName) params.set("name", options.merchantName);
1481
+ if (options.memo) params.set("memo", options.memo);
1482
+ if (options.successUrl) params.set("success_url", options.successUrl);
1483
+ if (options.cancelUrl) params.set("cancel_url", options.cancelUrl);
1484
+ if (options.orderId) params.set("order_id", options.orderId);
1485
+ if (options.customerId) params.set("customer_id", options.customerId);
1486
+ return `${baseUrl}/checkout?${params.toString()}`;
1487
+ }
1488
+ function generateDeepLinkCheckout(options, appScheme, baseUrl = "https://settlr.dev") {
1489
+ const orderId = options.orderId || `order_${Date.now()}`;
1490
+ return generateCheckoutUrl({
1491
+ ...options,
1492
+ orderId,
1493
+ successUrl: `${appScheme}://payment-success?order=${orderId}`,
1494
+ cancelUrl: `${appScheme}://payment-cancel?order=${orderId}`
1495
+ }, baseUrl);
1496
+ }
1497
+ function parseCallbackUrl(url) {
1498
+ try {
1499
+ const parsed = new URL(url);
1500
+ const params = parsed.searchParams;
1501
+ if (parsed.host === "payment-success" || parsed.pathname.includes("success")) {
1502
+ return {
1503
+ success: true,
1504
+ signature: params.get("signature") || void 0,
1505
+ orderId: params.get("order") || params.get("order_id") || void 0
1506
+ };
1507
+ }
1508
+ if (parsed.host === "payment-cancel" || parsed.pathname.includes("cancel")) {
1509
+ return {
1510
+ success: false,
1511
+ orderId: params.get("order") || params.get("order_id") || void 0,
1512
+ error: "Payment cancelled by user"
1513
+ };
1514
+ }
1515
+ return {
1516
+ success: false,
1517
+ error: "Unknown callback URL format"
1518
+ };
1519
+ } catch {
1520
+ return {
1521
+ success: false,
1522
+ error: "Failed to parse callback URL"
1523
+ };
1524
+ }
1525
+ }
1526
+ var REST_API = {
1527
+ createSession: "/api/checkout/create",
1528
+ checkStatus: "/api/checkout/status",
1529
+ oneClick: "/api/one-click",
1530
+ webhook: "/api/webhooks"
1531
+ // For server-to-server notifications
1532
+ };
1533
+ var UNITY_EXAMPLE = `
1534
+ // SettlrPayment.cs - Drop into your Unity project
1535
+
1536
+ using UnityEngine;
1537
+ using UnityEngine.Networking;
1538
+ using System.Collections;
1539
+
1540
+ public class SettlrPayment : MonoBehaviour
1541
+ {
1542
+ public string merchantWallet = "YOUR_WALLET_ADDRESS";
1543
+ public string settlrUrl = "https://settlr.dev";
1544
+
1545
+ // Call this to start a payment
1546
+ public void StartPayment(float amount, string orderId, System.Action<bool, string> callback)
1547
+ {
1548
+ string url = $"{settlrUrl}/checkout?amount={amount}&merchant={merchantWallet}&order_id={orderId}";
1549
+
1550
+ // Add deep link callback (register mygame:// scheme in your app)
1551
+ url += $"&success_url=mygame://payment-success?order={orderId}";
1552
+ url += $"&cancel_url=mygame://payment-cancel?order={orderId}";
1553
+
1554
+ Application.OpenURL(url);
1555
+
1556
+ // Start polling for completion
1557
+ StartCoroutine(PollPaymentStatus(orderId, callback));
1558
+ }
1559
+
1560
+ IEnumerator PollPaymentStatus(string orderId, System.Action<bool, string> callback)
1561
+ {
1562
+ string statusUrl = $"{settlrUrl}/api/checkout/status?order_id={orderId}";
1563
+
1564
+ for (int i = 0; i < 60; i++) // Poll for 5 minutes
1565
+ {
1566
+ using (UnityWebRequest request = UnityWebRequest.Get(statusUrl))
1567
+ {
1568
+ yield return request.SendWebRequest();
1569
+
1570
+ if (request.result == UnityWebRequest.Result.Success)
1571
+ {
1572
+ var response = JsonUtility.FromJson<PaymentStatusResponse>(request.downloadHandler.text);
1573
+
1574
+ if (response.status == "completed")
1575
+ {
1576
+ callback(true, response.signature);
1577
+ yield break;
1578
+ }
1579
+ else if (response.status == "expired" || response.status == "cancelled")
1580
+ {
1581
+ callback(false, null);
1582
+ yield break;
1583
+ }
1584
+ }
1585
+ }
1586
+
1587
+ yield return new WaitForSeconds(5f); // Check every 5 seconds
1588
+ }
1589
+
1590
+ callback(false, "Timeout");
1591
+ }
1592
+
1593
+ [System.Serializable]
1594
+ class PaymentStatusResponse
1595
+ {
1596
+ public string status;
1597
+ public string signature;
1598
+ }
1599
+ }
1600
+ `;
1601
+ var REACT_NATIVE_EXAMPLE = `
1602
+ // SettlrPayment.tsx - React Native component
1603
+
1604
+ import { Linking, Alert } from 'react-native';
1605
+ import { useEffect } from 'react';
1606
+
1607
+ const SETTLR_URL = 'https://settlr.dev';
1608
+ const APP_SCHEME = 'mygame';
1609
+
1610
+ export function useSettlrPayment(onSuccess: (sig: string) => void) {
1611
+ useEffect(() => {
1612
+ const handleDeepLink = ({ url }: { url: string }) => {
1613
+ if (url.includes('payment-success')) {
1614
+ const sig = new URL(url).searchParams.get('signature');
1615
+ if (sig) onSuccess(sig);
1616
+ }
1617
+ };
1618
+
1619
+ Linking.addEventListener('url', handleDeepLink);
1620
+ return () => Linking.removeAllListeners('url');
1621
+ }, [onSuccess]);
1622
+
1623
+ const startPayment = async (amount: number, merchantWallet: string) => {
1624
+ const orderId = \`order_\${Date.now()}\`;
1625
+ const url = \`\${SETTLR_URL}/checkout?amount=\${amount}&merchant=\${merchantWallet}\` +
1626
+ \`&success_url=\${APP_SCHEME}://payment-success?order=\${orderId}\` +
1627
+ \`&cancel_url=\${APP_SCHEME}://payment-cancel?order=\${orderId}\`;
1628
+
1629
+ await Linking.openURL(url);
1630
+ };
1631
+
1632
+ return { startPayment };
1633
+ }
1634
+ `;
1429
1635
  // Annotate the CommonJS export names for ESM import in node:
1430
1636
  0 && (module.exports = {
1431
1637
  BuyButton,
@@ -1434,12 +1640,15 @@ function createOneClickClient(baseUrl) {
1434
1640
  OneClickClient,
1435
1641
  PaymentModal,
1436
1642
  PrivacyFeatures,
1643
+ REACT_NATIVE_EXAMPLE,
1644
+ REST_API,
1437
1645
  SETTLR_CHECKOUT_URL,
1438
1646
  SETTLR_PROGRAM_ID,
1439
1647
  SUPPORTED_NETWORKS,
1440
1648
  SUPPORTED_TOKENS,
1441
1649
  Settlr,
1442
1650
  SettlrProvider,
1651
+ UNITY_EXAMPLE,
1443
1652
  USDC_MINT_DEVNET,
1444
1653
  USDC_MINT_MAINNET,
1445
1654
  USDT_MINT_DEVNET,
@@ -1452,8 +1661,11 @@ function createOneClickClient(baseUrl) {
1452
1661
  findAllowancePda,
1453
1662
  findPrivateReceiptPda,
1454
1663
  formatUSDC,
1664
+ generateCheckoutUrl,
1665
+ generateDeepLinkCheckout,
1455
1666
  getTokenDecimals,
1456
1667
  getTokenMint,
1668
+ parseCallbackUrl,
1457
1669
  parseUSDC,
1458
1670
  parseWebhookPayload,
1459
1671
  shortenAddress,
package/dist/index.mjs CHANGED
@@ -139,6 +139,8 @@ var Settlr = class {
139
139
  }
140
140
  /**
141
141
  * Validate API key with Settlr backend
142
+ * This is called automatically by SettlrProvider, but can also be called manually.
143
+ * Fetches merchant wallet address if not provided in config.
142
144
  */
143
145
  async validateApiKey() {
144
146
  if (this.validated) return;
@@ -166,6 +168,7 @@ var Settlr = class {
166
168
  this.tier = data.tier;
167
169
  if (data.merchantWallet && !this.merchantWallet) {
168
170
  this.merchantWallet = new PublicKey2(data.merchantWallet);
171
+ this.merchantWalletFromValidation = data.merchantWallet;
169
172
  this.config.merchant.walletAddress = data.merchantWallet;
170
173
  }
171
174
  if (data.merchantName && !this.config.merchant.name) {
@@ -529,7 +532,13 @@ var Settlr = class {
529
532
  };
530
533
 
531
534
  // src/react.tsx
532
- import { createContext, useContext, useMemo } from "react";
535
+ import {
536
+ createContext,
537
+ useContext,
538
+ useMemo,
539
+ useEffect,
540
+ useState
541
+ } from "react";
533
542
  import { jsx } from "react/jsx-runtime";
534
543
  var SettlrContext = createContext(null);
535
544
  function SettlrProvider({
@@ -537,27 +546,54 @@ function SettlrProvider({
537
546
  config,
538
547
  authenticated = false
539
548
  }) {
549
+ const [ready, setReady] = useState(false);
550
+ const [error, setError] = useState(null);
540
551
  const settlr = useMemo(() => {
541
552
  return new Settlr({
542
553
  ...config,
543
554
  rpcEndpoint: config.rpcEndpoint ?? "https://api.devnet.solana.com"
544
555
  });
545
556
  }, [config]);
557
+ useEffect(() => {
558
+ let cancelled = false;
559
+ settlr.validateApiKey().then(() => {
560
+ if (!cancelled) {
561
+ setReady(true);
562
+ setError(null);
563
+ }
564
+ }).catch((err) => {
565
+ if (!cancelled) {
566
+ console.error("[Settlr] API key validation failed:", err);
567
+ setError(err instanceof Error ? err : new Error(String(err)));
568
+ if (config.apiKey?.startsWith("sk_test_")) {
569
+ setReady(true);
570
+ }
571
+ }
572
+ });
573
+ return () => {
574
+ cancelled = true;
575
+ };
576
+ }, [settlr, config.apiKey]);
546
577
  const value = useMemo(
547
578
  () => ({
548
579
  settlr,
549
580
  authenticated,
581
+ ready,
582
+ error,
550
583
  createPayment: (options) => {
551
584
  return settlr.createPayment(options);
552
585
  },
553
586
  getCheckoutUrl: (options) => {
587
+ if (!ready) {
588
+ console.warn("[Settlr] SDK not ready yet. Ensure API key is valid.");
589
+ }
554
590
  return settlr.getCheckoutUrl(options);
555
591
  },
556
592
  getBalance: () => {
557
593
  return settlr.getMerchantBalance();
558
594
  }
559
595
  }),
560
- [settlr, authenticated]
596
+ [settlr, authenticated, ready, error]
561
597
  );
562
598
  return /* @__PURE__ */ jsx(SettlrContext.Provider, { value, children });
563
599
  }
@@ -571,9 +607,9 @@ function useSettlr() {
571
607
 
572
608
  // src/components.tsx
573
609
  import {
574
- useState,
610
+ useState as useState2,
575
611
  useCallback,
576
- useEffect
612
+ useEffect as useEffect2
577
613
  } from "react";
578
614
  import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
579
615
  var defaultStyles = {
@@ -641,11 +677,18 @@ function BuyButton({
641
677
  variant = "primary",
642
678
  size = "md"
643
679
  }) {
644
- const { getCheckoutUrl, createPayment } = useSettlr();
645
- const [loading, setLoading] = useState(false);
646
- const [status, setStatus] = useState("idle");
680
+ const { getCheckoutUrl, createPayment, ready, error: sdkError } = useSettlr();
681
+ const [loading, setLoading] = useState2(false);
682
+ const [status, setStatus] = useState2("idle");
647
683
  const handleClick = useCallback(async () => {
648
684
  if (disabled || loading) return;
685
+ if (!ready) {
686
+ const notReadyError = new Error(
687
+ sdkError?.message || "Settlr SDK not ready. Please check your API key configuration."
688
+ );
689
+ onError?.(notReadyError);
690
+ return;
691
+ }
649
692
  setLoading(true);
650
693
  setStatus("processing");
651
694
  onProcessing?.();
@@ -669,6 +712,8 @@ function BuyButton({
669
712
  orderId,
670
713
  disabled,
671
714
  loading,
715
+ ready,
716
+ sdkError,
672
717
  successUrl,
673
718
  cancelUrl,
674
719
  getCheckoutUrl,
@@ -820,7 +865,7 @@ function CheckoutWidget({
820
865
  showBranding = true
821
866
  }) {
822
867
  const { getCheckoutUrl } = useSettlr();
823
- const [status, setStatus] = useState("idle");
868
+ const [status, setStatus] = useState2("idle");
824
869
  const containerStyle = {
825
870
  ...widgetStyles.container,
826
871
  ...theme === "dark" ? widgetStyles.containerDark : widgetStyles.containerLight,
@@ -1003,7 +1048,7 @@ function PaymentModal({
1003
1048
  onError,
1004
1049
  checkoutUrl = "https://settlr.dev/checkout"
1005
1050
  }) {
1006
- const [loading, setLoading] = useState(true);
1051
+ const [loading, setLoading] = useState2(true);
1007
1052
  const params = new URLSearchParams({
1008
1053
  amount: amount.toString(),
1009
1054
  merchant: merchantName,
@@ -1013,7 +1058,7 @@ function PaymentModal({
1013
1058
  if (memo) params.set("memo", memo);
1014
1059
  if (orderId) params.set("orderId", orderId);
1015
1060
  const iframeSrc = `${checkoutUrl}?${params.toString()}`;
1016
- useEffect(() => {
1061
+ useEffect2(() => {
1017
1062
  const handleMessage = (event) => {
1018
1063
  if (!event.origin.includes("settlr.dev") && !event.origin.includes("localhost")) {
1019
1064
  return;
@@ -1037,7 +1082,7 @@ function PaymentModal({
1037
1082
  window.addEventListener("message", handleMessage);
1038
1083
  return () => window.removeEventListener("message", handleMessage);
1039
1084
  }, [amount, onSuccess, onError, onClose]);
1040
- useEffect(() => {
1085
+ useEffect2(() => {
1041
1086
  const handleEscape = (e) => {
1042
1087
  if (e.key === "Escape") onClose?.();
1043
1088
  };
@@ -1074,7 +1119,7 @@ function PaymentModal({
1074
1119
  ] }) });
1075
1120
  }
1076
1121
  function usePaymentModal(config) {
1077
- const [modalState, setModalState] = useState({
1122
+ const [modalState, setModalState] = useState2({
1078
1123
  isOpen: false,
1079
1124
  amount: 0
1080
1125
  });
@@ -1372,6 +1417,167 @@ var OneClickClient = class {
1372
1417
  function createOneClickClient(baseUrl) {
1373
1418
  return new OneClickClient(baseUrl);
1374
1419
  }
1420
+
1421
+ // src/mobile.ts
1422
+ function generateCheckoutUrl(options, baseUrl = "https://settlr.dev") {
1423
+ const params = new URLSearchParams();
1424
+ params.set("amount", options.amount.toString());
1425
+ params.set("merchant", options.merchantWallet);
1426
+ if (options.merchantName) params.set("name", options.merchantName);
1427
+ if (options.memo) params.set("memo", options.memo);
1428
+ if (options.successUrl) params.set("success_url", options.successUrl);
1429
+ if (options.cancelUrl) params.set("cancel_url", options.cancelUrl);
1430
+ if (options.orderId) params.set("order_id", options.orderId);
1431
+ if (options.customerId) params.set("customer_id", options.customerId);
1432
+ return `${baseUrl}/checkout?${params.toString()}`;
1433
+ }
1434
+ function generateDeepLinkCheckout(options, appScheme, baseUrl = "https://settlr.dev") {
1435
+ const orderId = options.orderId || `order_${Date.now()}`;
1436
+ return generateCheckoutUrl({
1437
+ ...options,
1438
+ orderId,
1439
+ successUrl: `${appScheme}://payment-success?order=${orderId}`,
1440
+ cancelUrl: `${appScheme}://payment-cancel?order=${orderId}`
1441
+ }, baseUrl);
1442
+ }
1443
+ function parseCallbackUrl(url) {
1444
+ try {
1445
+ const parsed = new URL(url);
1446
+ const params = parsed.searchParams;
1447
+ if (parsed.host === "payment-success" || parsed.pathname.includes("success")) {
1448
+ return {
1449
+ success: true,
1450
+ signature: params.get("signature") || void 0,
1451
+ orderId: params.get("order") || params.get("order_id") || void 0
1452
+ };
1453
+ }
1454
+ if (parsed.host === "payment-cancel" || parsed.pathname.includes("cancel")) {
1455
+ return {
1456
+ success: false,
1457
+ orderId: params.get("order") || params.get("order_id") || void 0,
1458
+ error: "Payment cancelled by user"
1459
+ };
1460
+ }
1461
+ return {
1462
+ success: false,
1463
+ error: "Unknown callback URL format"
1464
+ };
1465
+ } catch {
1466
+ return {
1467
+ success: false,
1468
+ error: "Failed to parse callback URL"
1469
+ };
1470
+ }
1471
+ }
1472
+ var REST_API = {
1473
+ createSession: "/api/checkout/create",
1474
+ checkStatus: "/api/checkout/status",
1475
+ oneClick: "/api/one-click",
1476
+ webhook: "/api/webhooks"
1477
+ // For server-to-server notifications
1478
+ };
1479
+ var UNITY_EXAMPLE = `
1480
+ // SettlrPayment.cs - Drop into your Unity project
1481
+
1482
+ using UnityEngine;
1483
+ using UnityEngine.Networking;
1484
+ using System.Collections;
1485
+
1486
+ public class SettlrPayment : MonoBehaviour
1487
+ {
1488
+ public string merchantWallet = "YOUR_WALLET_ADDRESS";
1489
+ public string settlrUrl = "https://settlr.dev";
1490
+
1491
+ // Call this to start a payment
1492
+ public void StartPayment(float amount, string orderId, System.Action<bool, string> callback)
1493
+ {
1494
+ string url = $"{settlrUrl}/checkout?amount={amount}&merchant={merchantWallet}&order_id={orderId}";
1495
+
1496
+ // Add deep link callback (register mygame:// scheme in your app)
1497
+ url += $"&success_url=mygame://payment-success?order={orderId}";
1498
+ url += $"&cancel_url=mygame://payment-cancel?order={orderId}";
1499
+
1500
+ Application.OpenURL(url);
1501
+
1502
+ // Start polling for completion
1503
+ StartCoroutine(PollPaymentStatus(orderId, callback));
1504
+ }
1505
+
1506
+ IEnumerator PollPaymentStatus(string orderId, System.Action<bool, string> callback)
1507
+ {
1508
+ string statusUrl = $"{settlrUrl}/api/checkout/status?order_id={orderId}";
1509
+
1510
+ for (int i = 0; i < 60; i++) // Poll for 5 minutes
1511
+ {
1512
+ using (UnityWebRequest request = UnityWebRequest.Get(statusUrl))
1513
+ {
1514
+ yield return request.SendWebRequest();
1515
+
1516
+ if (request.result == UnityWebRequest.Result.Success)
1517
+ {
1518
+ var response = JsonUtility.FromJson<PaymentStatusResponse>(request.downloadHandler.text);
1519
+
1520
+ if (response.status == "completed")
1521
+ {
1522
+ callback(true, response.signature);
1523
+ yield break;
1524
+ }
1525
+ else if (response.status == "expired" || response.status == "cancelled")
1526
+ {
1527
+ callback(false, null);
1528
+ yield break;
1529
+ }
1530
+ }
1531
+ }
1532
+
1533
+ yield return new WaitForSeconds(5f); // Check every 5 seconds
1534
+ }
1535
+
1536
+ callback(false, "Timeout");
1537
+ }
1538
+
1539
+ [System.Serializable]
1540
+ class PaymentStatusResponse
1541
+ {
1542
+ public string status;
1543
+ public string signature;
1544
+ }
1545
+ }
1546
+ `;
1547
+ var REACT_NATIVE_EXAMPLE = `
1548
+ // SettlrPayment.tsx - React Native component
1549
+
1550
+ import { Linking, Alert } from 'react-native';
1551
+ import { useEffect } from 'react';
1552
+
1553
+ const SETTLR_URL = 'https://settlr.dev';
1554
+ const APP_SCHEME = 'mygame';
1555
+
1556
+ export function useSettlrPayment(onSuccess: (sig: string) => void) {
1557
+ useEffect(() => {
1558
+ const handleDeepLink = ({ url }: { url: string }) => {
1559
+ if (url.includes('payment-success')) {
1560
+ const sig = new URL(url).searchParams.get('signature');
1561
+ if (sig) onSuccess(sig);
1562
+ }
1563
+ };
1564
+
1565
+ Linking.addEventListener('url', handleDeepLink);
1566
+ return () => Linking.removeAllListeners('url');
1567
+ }, [onSuccess]);
1568
+
1569
+ const startPayment = async (amount: number, merchantWallet: string) => {
1570
+ const orderId = \`order_\${Date.now()}\`;
1571
+ const url = \`\${SETTLR_URL}/checkout?amount=\${amount}&merchant=\${merchantWallet}\` +
1572
+ \`&success_url=\${APP_SCHEME}://payment-success?order=\${orderId}\` +
1573
+ \`&cancel_url=\${APP_SCHEME}://payment-cancel?order=\${orderId}\`;
1574
+
1575
+ await Linking.openURL(url);
1576
+ };
1577
+
1578
+ return { startPayment };
1579
+ }
1580
+ `;
1375
1581
  export {
1376
1582
  BuyButton,
1377
1583
  CheckoutWidget,
@@ -1379,12 +1585,15 @@ export {
1379
1585
  OneClickClient,
1380
1586
  PaymentModal,
1381
1587
  PrivacyFeatures,
1588
+ REACT_NATIVE_EXAMPLE,
1589
+ REST_API,
1382
1590
  SETTLR_CHECKOUT_URL,
1383
1591
  SETTLR_PROGRAM_ID,
1384
1592
  SUPPORTED_NETWORKS,
1385
1593
  SUPPORTED_TOKENS,
1386
1594
  Settlr,
1387
1595
  SettlrProvider,
1596
+ UNITY_EXAMPLE,
1388
1597
  USDC_MINT_DEVNET,
1389
1598
  USDC_MINT_MAINNET,
1390
1599
  USDT_MINT_DEVNET,
@@ -1397,8 +1606,11 @@ export {
1397
1606
  findAllowancePda,
1398
1607
  findPrivateReceiptPda,
1399
1608
  formatUSDC,
1609
+ generateCheckoutUrl,
1610
+ generateDeepLinkCheckout,
1400
1611
  getTokenDecimals,
1401
1612
  getTokenMint,
1613
+ parseCallbackUrl,
1402
1614
  parseUSDC,
1403
1615
  parseWebhookPayload,
1404
1616
  shortenAddress,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@settlr/sdk",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Settlr SDK - Accept Solana USDC payments with privacy. Email checkout, gasless transactions, FHE-encrypted receipts. Private on-chain, compliant off-chain.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -21,6 +21,7 @@
21
21
  "build": "tsup",
22
22
  "dev": "tsup --watch",
23
23
  "lint": "eslint src/",
24
+ "test": "npx tsx node_modules/mocha/bin/mocha.js 'src/__tests__/**/*.test.ts'",
24
25
  "prepublishOnly": "npm run build"
25
26
  },
26
27
  "keywords": [
@@ -46,7 +47,17 @@
46
47
  "typescript",
47
48
  "email-checkout",
48
49
  "no-wallet",
49
- "privy"
50
+ "privy",
51
+ "inco-lightning",
52
+ "fhe",
53
+ "homomorphic-encryption",
54
+ "private-receipts",
55
+ "privacy-cash",
56
+ "zk-payments",
57
+ "range-security",
58
+ "compliance",
59
+ "sanctions-screening",
60
+ "one-click-payments"
50
61
  ],
51
62
  "author": "Settlr <hello@settlr.dev> (https://settlr.dev)",
52
63
  "license": "MIT",
@@ -68,10 +79,16 @@
68
79
  "@solana/web3.js": "^1.98.0"
69
80
  },
70
81
  "devDependencies": {
82
+ "@types/chai": "^5.2.3",
83
+ "@types/mocha": "^10.0.10",
71
84
  "@types/node": "^20.0.0",
72
85
  "@types/react": "^19.2.7",
86
+ "chai": "^6.2.2",
87
+ "mocha": "^11.7.5",
73
88
  "react": "^19.2.3",
89
+ "ts-node": "^10.9.2",
74
90
  "tsup": "^8.0.0",
91
+ "tsx": "^4.21.0",
75
92
  "typescript": "^5.0.0"
76
93
  },
77
94
  "peerDependencies": {