Easy Labs
Frontend SDKsJavaScriptExamples

Customer Management

Customer Management pattern for JavaScript.

This recipe shows how to use the typed EasyApiClient surface from @easylabs/browser to build a small "manage customers" UI — list, create, look up, paginate. It assumes you've already constructed a client per the Quickstart.

A note on environments: @easylabs/browser is designed so the same client can run on the server (it's a thin fetch wrapper). For data-mutation flows like creating customers, decide deliberately whether the call belongs in the browser (with a key scoped accordingly) or behind your own backend endpoint. The examples below assume server-side execution unless noted.

Goal

Build the four common customer-management touch points:

  1. List customers with pagination.
  2. Look up a single customer by id.
  3. Create a new customer.
  4. Surface their payment instruments and active subscriptions.

Implementation

Setup

import { createEasyClient, EasyApiError } from "@easylabs/browser";

const easy = await createEasyClient({ apiKey: process.env.EASY_API_KEY! });

List customers

getCustomers takes optional pagination params:

const { data: customers } = await easy.getCustomers({
  limit: 25,
  offset: 0,
});

For a "load more" UI, increment offset by limit. To fetch a specific subset by id:

const { data } = await easy.getCustomers({ ids: ["cus_abc", "cus_def"] });

Look up one customer

async function loadCustomer(id: string) {
  try {
    const { data } = await easy.getCustomer(id);
    return data;
  } catch (err) {
    if (err instanceof EasyApiError && err.status === 404) {
      return null;
    }
    throw err;
  }
}

Create a customer

CreateCustomer requires first_name and last_name; everything else is optional.

const { data: customer } = await easy.createCustomer({
  first_name: "Ada",
  last_name: "Lovelace",
  email: "ada@example.com",
  phone: "+15555550123",
  personal_address: {
    line1: "10 Downing St",
    city: "London",
    region: "GB",
    postal_code: "SW1A 2AA",
    country: "GB",
  },
  tags: { source: "signup_v2" },
});

console.log(customer.id);

A few convenience endpoints sit alongside the core CRUD methods:

const { data: instruments } = await easy.getCustomerPaymentInstruments(
  customer.id,
);

const { data: subscriptions } = await easy.getCustomerSubscriptions(
  customer.id,
  { status: "active" },
);

const { data: orders } = await easy.getCustomerOrders(customer.id, {
  limit: 10,
});

const { data: wallets } = await easy.getCustomerWallets(customer.id);

getCustomerSubscriptions returns a Paginated<SubscriptionData> so you can drive infinite scroll off data.has_more if your shape requires it.

Update a customer

updateCustomer accepts a partial:

await easy.updateCustomer(customer.id, {
  email: "ada+billing@example.com",
});

Tradeoffs

  • Browser vs. server. EasyApiClient works in both contexts, but mutations from the browser ship your API key to every user who loads the page. For anything beyond read-only utility flows, run mutations server-side and expose a thin endpoint.
  • Pagination ceilings. limit is bounded by the API (see your tier's limits). Don't request unbounded list calls in a hot loop — paginate explicitly.
  • Error shape. Always branch on EasyApiError.status / err.code rather than string-matching err.message. The message includes the JSON-stringified error body and is intended for logs, not control flow.
  • Identity coupling. A CustomerData object includes the underlying processor identity payload (entity, _links). Treat anything outside the documented top-level fields as opaque — it's there for advanced flows but not part of the stable contract.

On this page