@appboxo/web-sdk
v1.4.0
Published
Boxo Desktop Host App SDK for handling miniapp events
Readme
Appboxo Web SDK
Embed miniapps into your desktop application using iframe communication.
Quick Start
import { AppboxoWebSDK } from "@appboxo/web-sdk";
const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id"
});
// Get auth code from your backend
const authCode = await fetch('/api/auth-code').then(r => r.json());
sdk.setAuthCode(authCode);
// Mount miniapp
await sdk.mount({
container: document.getElementById("miniapp"),
url: "https://your-miniapp.com"
});
// Or let SDK fetch URL from API automatically
await sdk.mount({
container: document.getElementById("miniapp")
});Installation
npm install @appboxo/web-sdk
# or
pnpm install @appboxo/web-sdkConfiguration
const sdk = new AppboxoWebSDK({
clientId: string; // Required
appId: string; // Required
userId?: string; // Optional, user reference identifier
baseUrl?: string; // Optional, default: "https://dashboard.boxo.io/api/v1"
sandboxMode?: boolean; // Optional, default: false
debug?: boolean; // Optional, default: false. When true, enables all console logs for debugging. When false, no console logs are output.
locale?: string; // Optional, locale/language code (e.g., 'en', 'en-US', 'ru', 'zh-CN')
isDesktop?: boolean; // Optional, default: false. When true, API calls to fetch miniapp settings will include is_desktop=true parameter
onGetAuthCode?: () => Promise<string>; // Optional, for automatic auth code retrieval
onGetAuthTokens?: () => Promise<LoginResponse>; // Optional, for direct auth tokens
onPaymentRequest?: (params: PaymentRequest) => Promise<PaymentResponse>; // Optional, for handling payment requests
});Authentication
OAuth flow:
sdk.setAuthCode(authCode);Or provide a callback:
const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id",
onGetAuthCode: async () => {
const res = await fetch('/api/generate-auth-code');
return (await res.json()).auth_code;
}
});Direct auth flow:
sdk.onAuth(async () => {
const response = await fetch('/api/get-miniapp-tokens');
const tokens = await response.json();
sdk.setAuthTokens(tokens.access_token, tokens.refresh_token);
});Or use callback:
const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id",
onGetAuthTokens: async () => {
const res = await fetch('/api/get-miniapp-tokens');
const result = await res.json();
return {
token: result.access_token,
refresh_token: result.refresh_token
};
}
});Or set tokens directly:
const tokens = await getTokensFromBackend();
sdk.setAuthTokens(tokens.access_token, tokens.refresh_token);The SDK will try these in order:
- Pre-set tokens (
setAuthTokens) - Direct auth callback (
onGetAuthTokens) - OAuth auth code (
setAuthCodeoronGetAuthCodecallback)
Payment Processing
When a miniapp calls appboxo.pay(), the SDK will call your onPaymentRequest callback. Process the payment and return the result.
Payment status values: 'success', 'failed', or 'cancelled'.
const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id",
onPaymentRequest: async (paymentData) => {
// Process payment with your backend
const response = await fetch('/api/payments/process', {
method: 'POST',
body: JSON.stringify(paymentData)
});
const result = await response.json();
return {
...paymentData,
status: result.status, // 'success', 'failed', or 'cancelled'
hostappOrderId: result.orderId,
transactionId: result.transactionId, // optional
};
},
});
// Optional: listen for payment completion
sdk.onPaymentComplete((success, data) => {
if (success) {
console.log('Payment succeeded:', data);
}
});Important Notes:
- When
onPaymentRequestis set, the SDK automatically tells the miniapp it supportsAppBoxoWebAppPay, so it can callappboxo.pay(). - If
onPaymentRequestis not configured, payment requests will fail. Enabledebug: trueto see error messages. - About
debugmode:debug: false(default): No console logs are output. Suitable for production.debug: true: All SDK operations are logged to console. Useful for development and troubleshooting.- The
debugoption does not affect SDK functionality - it only controls console logging.
Locale/Language
Set the locale/language code to pass to the miniapp. The locale will be included in the InitData response.
// Set locale during initialization
const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id",
locale: "en-US" // or 'ru', 'zh-CN', etc.
});
// Or set locale dynamically
sdk.setLocale("ru");The locale is passed to the miniapp via InitData.data.locale on the next AppBoxoWebAppGetInitData request.
Important Notes:
- If you call
setLocale()after the miniapp has already loaded, the locale will be included in the next InitData request. The miniapp may need to reload or request InitData again to receive the updated locale. - To ensure the locale is available immediately, set it during SDK initialization or before calling
mount().
Desktop Mode
When isDesktop: true is set, the SDK will include is_desktop=true parameter when fetching miniapp settings from the API. This allows the backend to return desktop-specific configurations.
const sdk = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id",
isDesktop: true // Enable desktop mode
});When enabled, API calls to /miniapps/{appId}/settings/ will include the is_desktop=true query parameter:
GET /miniapps/{appId}/settings/?client_id={clientId}&is_desktop=trueLogout
The logout() method clears the host app's storage and SDK's internal authentication data.
sdk.logout();Important Notes:
- This only clears the host app's
localStorageandsessionStorage - Miniapp's storage is separate (different origin) and cannot be cleared from the host app due to browser security restrictions
- The SDK will send a logout notification to the miniapp via
postMessageusing the standardappboxo-host-responseformat - Miniapp should listen for
AppBoxoWebAppLogouthandler to clear its own storage - SDK's internal
authCodeandauthTokensare also cleared
Miniapp Integration:
To receive logout notifications in your miniapp, add a message listener:
useEffect(() => {
const handleMessage = (event: MessageEvent) => {
if (
event.data?.type === "appboxo-host-response" &&
event.data?.handler === "AppBoxoWebAppLogout" &&
event.data?.data?.action === "logout"
) {
// Clear miniapp's storage
localStorage.clear();
sessionStorage.clear();
}
};
window.addEventListener("message", handleMessage);
return () => window.removeEventListener("message", handleMessage);
}, []);Methods
| Method | Description |
|--------|-------------|
| setAuthCode(code) | Set authentication code |
| setAuthTokens(token, refreshToken?) | Set authentication tokens directly |
| setLocale(locale) | Set locale/language code (e.g., 'en', 'en-US', 'ru', 'zh-CN') |
| onAuth(callback) | Register callback for authentication events |
| mount(config) | Create iframe and initialize SDK |
| getMiniappUrl() | Fetch miniapp URL from API settings endpoint |
| setIframe(iframe) | Set iframe element manually |
| initialize() | Start listening for events |
| onEvent(type, handler) | Register custom event handler |
| onLoginComplete(callback) | Login completion callback |
| onPaymentComplete(callback) | Payment completion callback |
| logout() | Clear host app's localStorage, sessionStorage, and SDK's internal auth data |
| destroy() | Clean up resources |
Events
SDK handles these miniapp events:
AppBoxoWebAppLogin- User authenticationAppBoxoWebAppPay- Payment processingAppBoxoWebAppGetInitData- Initial data requestAppBoxoWebAppCustomEvent- Custom events
Examples
React Example
import { AppboxoWebSDK } from "@appboxo/web-sdk";
import type { PaymentRequest, PaymentResponse } from "@appboxo/web-sdk";
function App() {
const iframeRef = useRef<HTMLIFrameElement>(null);
const [sdk, setSdk] = useState<AppboxoWebSDK | null>(null);
useEffect(() => {
const s = new AppboxoWebSDK({
clientId: "your-client-id",
appId: "your-app-id",
onPaymentRequest: async (paymentData: PaymentRequest): Promise<PaymentResponse> => {
const response = await fetch('/api/payments/process', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(paymentData)
});
const result = await response.json();
return {
...paymentData,
status: result.status,
hostappOrderId: result.hostappOrderId,
};
},
});
s.setAuthCode("your-auth-code");
s.onLoginComplete((success, data) => {
console.log('Login:', success ? 'success' : 'failed', data);
});
s.onPaymentComplete((success, data) => {
console.log('Payment:', success ? 'success' : 'failed', data);
});
setSdk(s);
return () => s.destroy();
}, []);
useEffect(() => {
const fetchUrl = async () => {
if (sdk && iframeRef.current) {
const url = await sdk.getMiniappUrl();
iframeRef.current.src = url;
}
};
fetchUrl();
}, [sdk]);
const handleLoad = () => {
if (sdk && iframeRef.current) {
sdk.setIframe(iframeRef.current);
sdk.initialize();
}
};
return <iframe ref={iframeRef} onLoad={handleLoad} src="" />;
}Using mount helper
// With explicit URL
await sdk.mount({
container: '#miniapp-container',
url: 'https://miniapp.com',
className: 'miniapp-iframe'
});
// Or fetch URL from API automatically
await sdk.mount({
container: '#miniapp-container',
className: 'miniapp-iframe'
});Styling is handled via CSS:
.miniapp-container {
width: 100%;
height: 500px;
}
.miniapp-iframe {
width: 100%;
height: 100%;
border: none;
}License
Apache-2.0
