@kigo-dev/marketplace-sdk
v0.5.0
Published
SDK for integrating mini-apps into the Kigo marketplace ecosystem
Readme
@kigo-dev/marketplace-sdk
SDK for integrating mini-apps into the Kigo marketplace ecosystem.
The Kigo Marketplace SDK allows web developers to integrate their applications ("mini-apps") within the Kigo native ecosystem. It provides access to native capabilities such as Payments, Authentication, Navigation, Location, and UI through a secure bridge between JavaScript and the Kigo Native App.
Table of Contents
Installation
npm install @kigo-dev/marketplace-sdkQuick Start
Step 1: Initialization
The SDK must be initialized before using any module. This ensures the communication bridge with the native app is ready.
import { kigo } from '@kigo-dev/marketplace-sdk';
async function startApp() {
try {
// 1. Initialize the bridge
await kigo.init();
// 2. Get user session and context
const session = await kigo.auth.init();
console.log(`Authenticated user: ${session.userId}`);
} catch (error) {
console.error('Error initializing Kigo SDK:', error);
// Handle the case where the app is not running inside Kigo
}
}
startApp();Bridge Configuration
kigo.init() accepts optional configuration to customize the bridge behavior:
await kigo.init({
timeout: 15000, // Default timeout for bridge calls (ms). Default: 10000
enableLogging: false, // Disable bridge debug logs in production
devtools: { enabled: true }, // Enable built-in DevTools console
});Note: Specific modules like
payments.checkout()andnavigation.openExternal()use their own extended timeouts to account for user interaction, regardless of the global setting.
Step 2: Local Development (Playground)
The SDK does not work in a standard browser because it requires the native bridge.
To develop locally, use the Playground included in the repository, which simulates the native app's behavior:
# Install dependencies
npm install
# Start dev server with playground
npm run devNote: If you see the error
Bridge not available, make sure your app is running inside the Kigo container or using the appropriate test environment.
Modules Reference
Auth (Authentication)
Manages the user session. The mini-app should never ask the user to log in; it inherits the session from Kigo.
kigo.auth.init()
Performs the handshake and retrieves the session token.
Returns:
{
sessionId: string; // Ephemeral token for backend calls
userId: string; // User's ID in Kigo
expiresAt: number; // Expiration timestamp
}Payments
Opens the native payment interface. The web app never handles credit card details directly.
Timeout:
checkout()uses a 5-minute timeout (instead of the default 10 seconds) because the user interacts with the native payment UI.getStatus()uses the standard timeout.
kigo.payments.checkout(payload)
Initiates the native payment flow.
Parameters:
{
amount: number; // Amount to charge (e.g. 100.00)
currency: string; // Currency code (e.g. 'MXN')
description?: string; // Concept displayed to the user
metadata?: object; // Extra data for your backend
}Returns:
{
transactionId: string;
status: 'approved' | 'rejected' | 'pending';
amount: number;
currency: string;
createdAt: number;
}Common Errors:
| Error Code | Description |
|---|---|
| INSUFFICIENT_FUNDS | User has insufficient balance or card was declined |
| PAYMENT_CANCELLED | User closed the payment modal |
| PAYMENT_FAILED | Payment processing error |
| INVALID_AMOUNT | Invalid amount (negative or zero) |
kigo.payments.getStatus(payload)
Checks the status of an existing transaction.
Parameters:
{
transactionId: string;
}Returns:
{
transactionId: string;
status: 'approved' | 'pending' | 'rejected' | 'cancelled';
updatedAt: number;
}Navigation
Controls the mini-app lifecycle.
kigo.navigation.close()
Closes the mini-app and returns the user to the Kigo Marketplace.
// Simple close
await kigo.navigation.close();
// Close with reason (useful for analytics)
await kigo.navigation.close({ reason: 'Purchase completed' });kigo.navigation.openExternal(options)
Opens a URL in the system browser or in a controlled in-app browser.
Parameters:
{
url: string; // URL to open (must be http:// or https://)
openInBrowser?: boolean; // true = system browser, false = in-app browser (default: false)
waitForClose?: boolean; // true = promise resolves when the in-app browser is dismissed (default: false)
closeOnUrls?: string[]; // URLs that auto-close the browser when navigated to
}Returns: { matchedUrl?: string } — the URL that triggered the auto-close (from closeOnUrls), or undefined if the user closed manually.
Basic usage:
// Open in external browser (Chrome/Safari)
await kigo.navigation.openExternal({
url: 'https://example.com/terms',
openInBrowser: true,
});
// Open in in-app browser
await kigo.navigation.openExternal({
url: 'https://example.com/privacy',
openInBrowser: false,
});Wait for the user to return:
// Open a page and wait until the user closes the in-app browser
await kigo.navigation.openExternal({
url: 'https://example.com/info',
openInBrowser: false,
waitForClose: true,
});
// This line runs only after the in-app browser is dismissed
console.log('User returned to the mini-app');Third-party payment flow with closeOnUrls:
When integrating with external payment providers (e.g., Orkesta), use closeOnUrls to detect when the payment finishes. The native app intercepts the redirect before the target page loads, auto-closes the browser, and returns the matched URL to your mini-app.
const result = await kigo.navigation.openExternal({
url: 'https://payment-provider.com/pay?ref=12345',
openInBrowser: false,
waitForClose: true,
closeOnUrls: [
'https://mysite.com/payment/success',
'https://mysite.com/payment/failure',
],
});
if (result.matchedUrl?.includes('/success')) {
await kigo.ui.toast({ message: 'Payment successful!', type: 'success' });
} else if (result.matchedUrl?.includes('/failure')) {
await kigo.ui.toast({ message: 'Payment failed', type: 'error' });
} else {
// User closed the browser manually without completing
}Common Errors:
| Error Code | Description |
|---|---|
| INVALID_URL | URL is malformed or uses a non-http(s) scheme |
| NAVIGATION_BLOCKED | URL is not in the backend allowlist |
UI (User Interface)
Uses native components to maintain visual consistency with the Kigo app.
kigo.ui.toast({ message, type?, duration? })
Shows a native floating notification.
type:'success'|'error'|'info'|'warning'(default:'info')duration: Duration in milliseconds (default:3000)
await kigo.ui.toast({
message: 'Item added to cart',
type: 'success',
});kigo.ui.confirm({ title, message, confirmText?, cancelText?, type? })
Shows a native confirmation dialog (OK/Cancel).
Returns: { confirmed: boolean }
const result = await kigo.ui.confirm({
title: 'Cancel order',
message: 'This action cannot be undone.',
confirmText: 'Yes, cancel',
cancelText: 'Keep order',
type: 'destructive',
});
if (result.confirmed) {
// Proceed with cancellation
}kigo.ui.setTitle(title)
Changes the text in the app's top navigation bar.
await kigo.ui.setTitle('Product Detail');Device
Retrieves environment information to adapt your layout and behavior.
kigo.device.getContext()
Returns:
{
theme: 'light' | 'dark'; // Useful for dynamic CSS
locale: string; // e.g. 'es', 'en'
platform: 'ios' | 'android';
safeArea: {
top: number;
bottom: number;
left: number;
right: number;
};
appVersion: string;
projectRef?: string; // Current project reference
screen: {
width: number;
height: number;
};
}const context = await kigo.device.getContext();
// Apply safe area padding
document.body.style.paddingTop = `${context.safeArea.top}px`;
// Theme adaptation
if (context.theme === 'dark') {
document.body.classList.add('dark-mode');
}Location
Retrieves the user's geographic coordinates from the native app. The web service never accesses GPS hardware directly — it always goes through the native bridge.
kigo.location.getCurrent()
Requests the device's current location.
Returns:
{
latitude: number; // Decimal degrees (e.g. 19.4326)
longitude: number; // Decimal degrees (e.g. -99.1332)
accuracy?: number; // Accuracy in meters (optional)
}const loc = await kigo.location.getCurrent();
console.log(`User is at ${loc.latitude}, ${loc.longitude}`);
// Use for nearby searches
const stores = await fetchNearbyStores(loc.latitude, loc.longitude);Common Errors:
| Error Code | Description |
|---|---|
| LOCATION_UNAVAILABLE | Location services are disabled or permission was denied |
Storage
Securely stores persistent data, isolated per mini-app.
kigo.storage.set(key, value)
Saves a string value.
kigo.storage.get(key)
Reads a string value. Returns { value: string | null }.
kigo.storage.remove(key)
Deletes a stored value.
kigo.storage.setObject(key, obj)
Saves a JSON object (automatic serialization).
kigo.storage.getObject<T>(key)
Reads and parses a JSON object. Returns T | null.
// Save preferences
await kigo.storage.setObject('user_prefs', {
theme: 'dark',
notifications: true,
});
// Read preferences
const prefs = await kigo.storage.getObject('user_prefs');Analytics
Sends tracking events to the Kigo analytics pipeline.
kigo.analytics.track({ event, properties? })
await kigo.analytics.track({
event: 'purchase_completed',
properties: {
amount: 100,
currency: 'MXN',
product_id: 'prod_123',
},
});Use
snake_casefor event names. Be specific but concise.
DevTools
Built-in debug console for inspecting bridge traffic, API calls, and SDK lifecycle events in real time. Designed for development and QA — it renders inside a Shadow DOM so it never interferes with your application's styles or layout.
Enabling DevTools
// Option A: Enable programmatically (recommended)
kigo.devtools.enable();
// Option B: Enable via init()
await kigo.init({
devtools: { enabled: true },
});Enabling with fetch interception
kigo.devtools.enable({
interceptFetch: true,
fetchFilter: url => url.includes('/v1/'),
});When interceptFetch is true, DevTools hooks window.fetch to log API calls with method, path, status code, and duration. Use fetchFilter to limit which URLs are captured.
Configuration
| Option | Type | Default | Description |
|---|---|---|---|
| enabled | boolean | false | Auto-enable on kigo.init() |
| interceptFetch | boolean | false | Log fetch() calls in the console |
| fetchFilter | (url: string) => boolean | — | Only log fetch URLs that pass this filter |
| maxEntries | number | 200 | Maximum log entries to retain |
| panelHeight | string | '40vh' | Panel height (any CSS value) |
| shortcutKey | string | 'D' | Keyboard shortcut key (Ctrl+Shift+key) |
API
kigo.devtools.enable(config?) // Activate the overlay
kigo.devtools.disable() // Tear down and restore globals
kigo.devtools.toggle() // Open/close panel (or press Ctrl+Shift+D)
kigo.devtools.clear() // Remove all log entries
kigo.devtools.copyLogs() // Copy visible entries to clipboard
kigo.devtools.isEnabled() // Check if active
// Push custom entries
kigo.devtools.log('Bootstrap complete');
kigo.devtools.log('error', 'Auth failed', JSON.stringify(err));What it captures
| Entry type | Badge | Source |
|---|---|---|
| Bridge request | JS → Flutter | Every bridge.send() call with service, action, and payload |
| Bridge response | Flutter → JS | Every response, showing service.action and round-trip time |
| Bridge timeout | ERROR | Requests that exceeded the configured timeout |
| API success | API | Fetch calls returning 2xx (when interceptFetch is on) |
| API error | API ERR | Fetch calls returning non-2xx or network errors |
| SDK lifecycle | INFO | Bridge ready, initialization, internal Bridge logs |
Safety
DevTools is wrapped in error boundaries at every layer. It will never crash your application, even if its own internals fail. When disabled, window.fetch is fully restored to its original reference.
Error Handling
The SDK uses Promises. Always use try/catch. Errors follow this structure:
interface BridgeError {
code: string; // Standard error code
message: string; // Human-readable message for debugging
}Error Codes
| Code | Description | Recommended Action |
|---|---|---|
| BRIDGE_TIMEOUT | The native app took too long to respond | Retry or show a network error |
| AUTH_FAILED | Could not obtain a session | Show error screen with an "Exit" button |
| PAYMENT_CANCELLED | User closed the checkout | Do nothing, or ask if they want to retry |
| CHANNEL_NOT_AVAILABLE | App is not running inside Kigo | Only use within the Kigo environment |
| SESSION_EXPIRED | User session has expired | Re-initialize with kigo.auth.init() |
| LOCATION_UNAVAILABLE | Location services disabled or permission denied | Ask the user to enable location |
Best Practices
Environment Validation
Call kigo.init() as early as possible in your application (e.g., in App.tsx or main.ts). If it fails, show a friendly screen indicating the app must be opened from Kigo.
// main.ts
try {
await kigo.init();
} catch {
showKigoRequiredScreen();
}Safe Areas
Use kigo.device.getContext() to get safeArea.top and safeArea.bottom. Apply that padding to your main container to prevent content from being hidden behind the status bar or home indicator on iOS.
const { safeArea } = await kigo.device.getContext();
document.documentElement.style.setProperty('--safe-top', `${safeArea.top}px`);
document.documentElement.style.setProperty('--safe-bottom', `${safeArea.bottom}px`);No Tokens in URLs
Never pass tokens or user IDs via URL parameters. Always rely on kigo.auth.init() to securely obtain the user's identity.
Robust Payments
Even if the SDK returns approved, your backend should listen to Kigo Webhooks to confirm the transaction asynchronously (reconciliation).
FAQ
Q: Can I test the SDK in my Chrome/Safari browser? A: Not directly. The SDK requires the native bridge to be available. Use the Playground included in this repository for local development, which mocks the native bridge behavior.
Q: What happens if the user has no internet?
A: Bridge calls (kigo.*) will fail with an error or timeout. Handle these cases gracefully in your UI.
Q: How do I know which user is using my app?
A: Call kigo.auth.init(). It returns a userId and a sessionId that you can send to your own backend for request validation.
Q: Can I use the SDK outside the Kigo app?
A: The SDK is designed to run inside the Kigo native app container. Attempting to use it outside will result in a CHANNEL_NOT_AVAILABLE error.
Development
# Install dependencies
npm install
# Development mode with playground
npm run dev
# Production-like dev mode
npm run dev:prod
# Build the SDK
npm run build
# Type checking
npm run typecheckArchitecture
src/
├── bridge/ # Core messaging system (JS ↔ Native)
├── modules/ # Business features (auth, payments, navigation, ...)
├── devtools/ # Built-in debug console (Shadow DOM, event bus)
├── utils/ # Shared utilities
└── index.ts # Main entry pointLicense
MIT © Kigo 2026
