Best Practices

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 --follow

On this page