Vatly
JavaScript Fluent

Customers and bindings

Find or create a Vatly customer for your signed-in user.

Find or create a Vatly customer for your signed-in user. Wire binding storage first.

Create and bind

import type { Vatly } from '@getvatly/fluent';

export async function customerFor(vatly: Vatly, hostId: string, email: string) {
  const existing = await vatly.customers.findByHostCustomerId(hostId);
  if (existing) return existing;
  return vatly.customers.createFor(
    hostId,
    { email, name: 'Example Customer' },
    { metadata: { accountId: hostId } },
    { idempotencyKey: `customer-for:${hostId}` },
  );
}

createFor rejects an already-bound host. The API may return an existing customer for the email; Fluent checks the binding before attaching it. A binding failure cannot undo remote creation. Reconcile the customer before retrying.

To link a verified existing customer, use vatly.customers.attribute(vatlyId, hostId). To create without a host owner, use createUnattributed(profile, extra?, requestOptions?); it still needs bindings to record the ID.

Read and update identity

import type { Vatly } from '@getvatly/fluent';

export async function updateIdentity(vatly: Vatly, customerId: string) {
  const customer = vatly.customer(customerId);
  await customer.update({ name: null }); // Explicitly clear the display name.
  await customer.sync();                // Refresh the cached API resource.
  return customer.identity();          // { name, email }
}

export async function matchingCustomers(vatly: Vatly, email: string) {
  const ids: string[] = [];
  for await (const customer of vatly.customers.findByEmail(email)) ids.push(customer.id);
  return ids;
}

Handles fetch lazily and cache per handle. model(), name(), and email() read that cache; sync() refreshes it. Email lookup searches all cursor pages on the server. findOneByEmail returns the first match or null, not proof of ownership. Identity updates do not change invoice addresses; use the billing-update flow.

Returning from checkout

customerIdFromCheckout(checkoutId) returns an ID or null for a missing customer or 404; other API errors propagate. claimCustomerFromCheckout(checkoutId, hostId) binds that customer. Verify checkout ownership before calling it: an ID in a return URL is not proof. See payment confirmation.

See customer portal for portal links and the Customers API reference for field details.

Copyright © 2026