Error Handling
Patterns for handling bridge timeouts, typed API errors, user-facing error states, billing failures, and webhook processing errors.
Robust error handling prevents a single failure from breaking the entire merchant experience.
1. Handle bridge timeouts gracefully
All bridge actions have a 5-second timeout. A timeout does not necessarily mean the action failed — it means the response was not received in time.
const result = await bridge.toast.show("Saved!");
if (!result.success) {
// Log for debugging but do not crash the UI
console.warn("Toast action timed out:", result.error);
}2. Handle API errors by type
The SDK exports typed error classes so you can respond appropriately to each failure mode:
import { NotFoundError, RateLimitError, ValidationError } from "@whatalo/plugin-sdk";
try {
await client.products.update(id, data);
} catch (error) {
if (error instanceof NotFoundError) {
showMessage("Product not found");
} else if (error instanceof RateLimitError) {
showMessage(`Too many requests. Try again in ${error.retryAfter}s`);
} else if (error instanceof ValidationError) {
showFieldErrors(error.fieldErrors);
} else {
// Unexpected error — surface a generic message
showMessage("An unexpected error occurred");
}
}3. Show user-friendly error states
Use the Banner component to display errors inline rather than crashing the page:
import { Banner } from "./components/whatalo-ui";
{error && (
<Banner status="error" title="Error">
{error.message}
</Banner>
)}4. Always check isReady before rendering
The bridge handshake is asynchronous. Rendering your main UI before isReady is true means the bridge context is not yet available.
import { Spinner } from "./components/whatalo-ui";
import { useAppBridge } from "@whatalo/plugin-sdk/bridge";
function App() {
const { isReady } = useAppBridge();
// Show spinner until the bridge is initialized
if (!isReady) return <Spinner />;
return <DashboardPage />;
}5. Handle billing errors
Billing methods throw on failure. Wrap them in try/catch and inform the merchant:
try {
await bridge.billing.requestSubscription("pro");
} catch (error) {
bridge.toast.show("Could not start subscription. Please try again.", {
variant: "error",
});
}6. Log errors in webhook handlers
Always log failures in your webhook handlers so you can diagnose delivery issues:
export async function POST(request: Request) {
try {
const payload = await request.json();
await processOrder(payload);
return new Response("OK", { status: 200 });
} catch (error) {
console.error("[webhook] order.created failed:", error);
return new Response("Processing failed", { status: 500 });
}
}Use whatalo logs to review webhook delivery history and retry failed events:
# Follow failed webhook deliveries in real time
whatalo logs --status failed --followPerformance Best Practices
Guidelines for keeping your plugin fast — bundle size, initial load time, API usage patterns, resize rate limits, and lazy loading.
Plugin Design Guidelines
Ten guidelines for building plugins that feel native to the admin — component usage, dark mode support, loading states, empty states, and navigation patterns.