Unified.to
All articles

How to Sync Customers or Suppliers with Unified's Accounting API


January 20, 2026

Syncing customers and suppliers sounds like a basic accounting task. It becomes a product problem the moment you support more than one accounting system.

Many platforms treat customers and vendors as separate objects. Others merge them. Some allow a single entity to be both. Identifiers aren't stable, names change, emails aren't unique, and 'vendor vs customer' is often inferred rather than explicit. When teams integrate vendor-by-vendor, this usually leads to duplicate records, broken updates, or brittle reconciliation logic.

For a PM, this raises hard questions early:

  • Is a customer and a supplier the same logical entity in our product?
  • What happens if a contact switches roles or has multiple roles?
  • How do we guarantee idempotent syncs without relying on provider-specific IDs?

Many products solve this by branching logic per accounting platform or maintaining separate customer and vendor pipelines. That increases complexity and makes long-term maintenance expensive.

Unified's Accounting API takes a different approach. It provides a single normalized contact modelAccountingContact—and uses explicit boolean flags (is_customer, is_supplier) to represent role. Identity is stable, behavior is documented, and sync semantics are consistent across accounting providers.

This guide shows how to build a production-grade customer and supplier sync on top of that model—listing contacts, filtering by role, handling incremental updates, creating and updating records.

Prerequisites

You'll need:

  • A Unified workspace
  • An API key
  • A connectionId for an authorized accounting integration
  • Node.js 18+ (or equivalent runtime)

Install the SDK:

npm install @unified-api/typescript-sdk

Initialize the client:

import { UnifiedTo } from "@unified-api/typescript-sdk";

const unified = new UnifiedTo({
  security: {
    jwt: process.env.UNIFIED_API_KEY!,
  },
});

The AccountingContact model (important)

Unified normalizes customers and suppliers into one object:

type AccountingContact = {
  id?: string;
  name?: string;
  first_name?: string;
  last_name?: string;
  emails?: { email?: string; type?: "WORK" | "HOME" | "OTHER" }[];
  telephones?: { telephone?: string; type?: "WORK" | "HOME" | "OTHER" | "FAX" | "MOBILE" }[];
  billing_address?: { ... };
  shipping_address?: { ... };
  is_customer?: boolean;
  is_supplier?: boolean;
  is_active?: boolean;
  tax_number?: string;
  payment_methods?: { ... }[];
  company_name?: string;
  identification?: string;
  updated_at?: string;
};

Key implications:

  • Customers and suppliers are not separate endpoints.
  • Filtering is done using is_customer / is_supplier.
  • The stable identifier is (connectionId, id).

Step 1: List accounting contacts

Use listAccountingContacts to fetch contacts for a connection.

const contacts = await unified.accounting.listAccountingContacts({
  connectionId,
  limit: 100,
});

Pagination rules

  • limit defaults to 100 (maximum)
  • Use offset to paginate
  • When returned results < limit, there are no more records

Example paginated fetch:

let offset = 0;
const allContacts: AccountingContact[] = [];

while (true) {
  const page = await unified.accounting.listAccountingContacts({
    connectionId,
    limit: 100,
    offset,
  });

  allContacts.push(...page);

  if (page.length < 100) break;
  offset += 100;
}

Step 2: Filter customers or suppliers

Since Unified uses a shared model, filter in your application:

const customers = allContacts.filter(c => c.is_customer);
const suppliers = allContacts.filter(c => c.is_supplier);

You can also filter out inactive records:

const activeCustomers = customers.filter(c => c.is_active !== false);

Step 3: Incremental sync using updated timestamps

To avoid full re-syncs, use updated_gte:

const updatedSince = "2025-01-01T00:00:00Z";

const updatedContacts = await unified.accounting.listAccountingContacts({
  connectionId,
  updatedGte: updatedSince,
  limit: 100,
});

Notes:

  • Dates must be ISO-8601
  • Time and timezone are optional (defaults to UTC)
  • This is the recommended polling strategy when webhooks aren't used

Step 4: Store sync keys correctly

For every contact you store locally, persist:

{
  connectionId: string;
  unifiedContactId: string; // AccountingContact.id
}

Do not rely on:

  • name
  • email
  • identification
  • raw provider IDs

Those are not guaranteed to be unique or stable.

Step 5: Create a customer or supplier

To create a new contact, use createAccountingContact.

const created = await unified.accounting.createAccountingContact({
  connectionId,
  accountingContact: {
    name: "Acme Corp",
    is_customer: true,
    emails: [{ email: "billing@acme.com", type: "WORK" }],
  },
});

Important:

  • This is a full create (POST)
  • You must supply the fields you want set
  • The response returns the created AccountingContact

Step 6: Update a contact (PUT)

Unified's update method is PUT, shown as:

updateAccountingContact

This replaces the contact resource.

const updated = await unified.accounting.updateAccountingContact({
  connectionId,
  id: existingUnifiedContactId,
  accountingContact: {
    name: "Acme Corporation",
    is_customer: true,
    is_supplier: false,
  },
});

Step 7: Delete a contact (optional)

To remove a contact:

await unified.accounting.removeAccountingContact({
  connectionId,
  id: unifiedContactId,
});

This maps to:

DELETE /accounting/{connection_id}/contact/{id}

Final notes

Customers and suppliers are one of the most failure-prone parts of accounting integrations, not because the data is complex, but because identity is often split across inconsistent models.

By treating customers and suppliers as a single normalized AccountingContact and relying on explicit role flags (is_customer, is_supplier), you avoid duplicate records, vendor-specific branching, and fragile reconciliation logic. The sync patterns in this guide are designed to be safe by default: stable identifiers, explicit pagination, timestamp-based incremental updates, and documented create/update/delete semantics.

Used this way, Unified's Accounting API gives you a predictable, maintainable foundation for customer and supplier syncs across accounting systems—without guessing, scraping, or vendor-specific code paths.

Start your 30-day free trial

Book a demo

All articles