> ## Documentation Index
> Fetch the complete documentation index at: https://developers.pleo.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Sync Vendors

> The Vendor Sync reconciliation process: matching rules, invalid and duplicate externalId handling, and the create/update/archive decisions per vendor.

export const VendorSyncTwoConsecutiveRunsDiagram = () => {
  const [isDark, setIsDark] = useState(false);
  useEffect(() => {
    const check = () => setIsDark(document.documentElement.classList.contains("dark"));
    check();
    const observer = new MutationObserver(check);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return () => observer.disconnect();
  }, []);
  const nodeFill = isDark ? "#212222" : "#EEF4F4";
  const nodeStroke = isDark ? "#848989" : "#E1E6E6";
  const nodeTextStyle = isDark ? ",color:#EEF4F4" : ",color:#131414";
  const errorFill = isDark ? "#3A1E22" : "#FCE9EA";
  const errorStroke = isDark ? "#FF90A1" : "#F15A71";
  const errorTextStyle = isDark ? ",color:#FF90A1" : ",color:#7A1F2B";
  const linkStyle = isDark ? "" : "linkStyle default stroke:#848989,stroke-width:1px;";
  const diagram = `
%%{init: {"themeVariables": {"fontSize": "12px"}}}%%
flowchart TD
    A[Pleo Vendor unmatched<br>in this sync run] --> B{Unmatched across ≥2 consecutive<br>successful runs? count persisted<br>across run invocations}
    B -->|Yes| C[Archive Vendor]
    B -->|No: first appearance| D[Do not archive yet:<br>wait for next run]
    B -->|"No, archive anyway (avoid this)"| E["BUG (avoid this): transient fetch<br>omission causes incorrect archive"]

   style A white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style B white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style C white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style D white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style E white-space:normal,fill:${errorFill},stroke:${errorStroke}${errorTextStyle}
${linkStyle}
`;
  return <Mermaid chart={diagram} />;
};

export const VendorSyncSkippedRecordsDiagram = () => {
  const [isDark, setIsDark] = useState(false);
  useEffect(() => {
    const check = () => setIsDark(document.documentElement.classList.contains("dark"));
    check();
    const observer = new MutationObserver(check);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return () => observer.disconnect();
  }, []);
  const nodeFill = isDark ? "#212222" : "#EEF4F4";
  const nodeStroke = isDark ? "#848989" : "#E1E6E6";
  const nodeTextStyle = isDark ? ",color:#EEF4F4" : ",color:#131414";
  const errorFill = isDark ? "#3A1E22" : "#FCE9EA";
  const errorStroke = isDark ? "#FF90A1" : "#F15A71";
  const errorTextStyle = isDark ? ",color:#FF90A1" : ",color:#7A1F2B";
  const linkStyle = isDark ? "" : "linkStyle default stroke:#848989,stroke-width:1px;";
  const diagram = `
%%{init: {"themeVariables": {"fontSize": "12px"}}}%%
flowchart TD
    A[Pleo Vendor active,<br>no matching active AS vendor] --> B{Was the AS record skipped for a<br>data integrity reason in Step 1?}
    B -->|No: genuinely absent| C[Eligible for archiving]
    B -->|Yes| D[Leave as is: resolved once AS data<br>is fixed, next sync run picks it up]
    B -->|"Yes, archive anyway (avoid this)"| E["BUG (avoid this): Vendor archived for a<br>fixable data issue, not real absence"]

   style A white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style B white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style C white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style D white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style E white-space:normal,fill:${errorFill},stroke:${errorStroke}${errorTextStyle}
${linkStyle}
`;
  return <Mermaid chart={diagram} />;
};

export const VendorSyncConcurrencyWithCreationDiagram = () => {
  const [isDark, setIsDark] = useState(false);
  useEffect(() => {
    const check = () => setIsDark(document.documentElement.classList.contains("dark"));
    check();
    const observer = new MutationObserver(check);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return () => observer.disconnect();
  }, []);
  const nodeFill = isDark ? "#212222" : "#EEF4F4";
  const nodeStroke = isDark ? "#848989" : "#E1E6E6";
  const nodeTextStyle = isDark ? ",color:#EEF4F4" : ",color:#131414";
  const errorFill = isDark ? "#3A1E22" : "#FCE9EA";
  const errorStroke = isDark ? "#FF90A1" : "#F15A71";
  const errorTextStyle = isDark ? ",color:#FF90A1" : ",color:#7A1F2B";
  const linkStyle = isDark ? "" : "linkStyle default stroke:#848989,stroke-width:1px;";
  const diagram = `
%%{init: {"themeVariables": {"fontSize": "12px"}}}%%
flowchart TD
    A[Vendor Sync run] --> B{Running concurrently with Vendor<br>Creation's create-and-activate step?}
    B -->|No: per-company lock held| C[No race]
    B -->|"Yes (avoid this)"| D["BUG (avoid this): Sync creates duplicate for<br>AS record still in flight, or archives<br>a Vendor just activated"]

   style A white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style B white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style C white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style D white-space:normal,fill:${errorFill},stroke:${errorStroke}${errorTextStyle}
${linkStyle}
`;
  return <Mermaid chart={diagram} />;
};

export const VendorSyncAlwaysSetExternalIdDiagram = () => {
  const [isDark, setIsDark] = useState(false);
  useEffect(() => {
    const check = () => setIsDark(document.documentElement.classList.contains("dark"));
    check();
    const observer = new MutationObserver(check);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return () => observer.disconnect();
  }, []);
  const nodeFill = isDark ? "#212222" : "#EEF4F4";
  const nodeStroke = isDark ? "#848989" : "#E1E6E6";
  const nodeTextStyle = isDark ? ",color:#EEF4F4" : ",color:#131414";
  const errorFill = isDark ? "#3A1E22" : "#FCE9EA";
  const errorStroke = isDark ? "#FF90A1" : "#F15A71";
  const errorTextStyle = isDark ? ",color:#FF90A1" : ",color:#7A1F2B";
  const linkStyle = isDark ? "" : "linkStyle default stroke:#848989,stroke-width:1px;";
  const diagram = `
%%{init: {"themeVariables": {"fontSize": "12px"}}}%%
flowchart TD
    A[Create Pleo Vendor from AS record] --> B{externalId set<br>on creation?}
    B -->|Yes| C[Vendor state: ACTIVE]
    B -->|"No (avoid this)"| D["BUG (avoid this): Vendor created as<br>DRAFT, Vendor Creation's behaviour"]

   style A white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style B white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style C white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style D white-space:normal,fill:${errorFill},stroke:${errorStroke}${errorTextStyle}
${linkStyle}
`;
  return <Mermaid chart={diagram} />;
};

export const VendorSyncNewVendorVsPendingActivationDiagram = () => {
  const [isDark, setIsDark] = useState(false);
  useEffect(() => {
    const check = () => setIsDark(document.documentElement.classList.contains("dark"));
    check();
    const observer = new MutationObserver(check);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return () => observer.disconnect();
  }, []);
  const nodeFill = isDark ? "#212222" : "#EEF4F4";
  const nodeStroke = isDark ? "#848989" : "#E1E6E6";
  const nodeTextStyle = isDark ? ",color:#EEF4F4" : ",color:#131414";
  const errorFill = isDark ? "#3A1E22" : "#FCE9EA";
  const errorStroke = isDark ? "#FF90A1" : "#F15A71";
  const errorTextStyle = isDark ? ",color:#FF90A1" : ",color:#7A1F2B";
  const linkStyle = isDark ? "" : "linkStyle default stroke:#848989,stroke-width:1px;";
  const diagram = `
%%{init: {"themeVariables": {"fontSize": "12px"}}}%%
flowchart TD
    A[AS vendor active,<br>no matching Pleo Vendor] --> B{externalId claimed by an<br>in-flight/retryable<br>Vendor Creation attempt?}
    B -->|No| C[Create new Pleo Vendor]
    B -->|Yes| D[Skip creation here: let Vendor<br>Creation's activation retry handle it]
    B -->|"Yes, create anyway (avoid this)"| E["BUG (avoid this): duplicate<br>Pleo Vendor created"]

   style A white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style B white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style C white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style D white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style E white-space:normal,fill:${errorFill},stroke:${errorStroke}${errorTextStyle}
${linkStyle}
`;
  return <Mermaid chart={diagram} />;
};

export const VendorSyncPartialFetchFailuresDiagram = () => {
  const [isDark, setIsDark] = useState(false);
  useEffect(() => {
    const check = () => setIsDark(document.documentElement.classList.contains("dark"));
    check();
    const observer = new MutationObserver(check);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return () => observer.disconnect();
  }, []);
  const nodeFill = isDark ? "#212222" : "#EEF4F4";
  const nodeStroke = isDark ? "#848989" : "#E1E6E6";
  const nodeTextStyle = isDark ? ",color:#EEF4F4" : ",color:#131414";
  const errorFill = isDark ? "#3A1E22" : "#FCE9EA";
  const errorStroke = isDark ? "#FF90A1" : "#F15A71";
  const errorTextStyle = isDark ? ",color:#FF90A1" : ",color:#7A1F2B";
  const linkStyle = isDark ? "" : "linkStyle default stroke:#848989,stroke-width:1px;";
  const diagram = `
%%{init: {"themeVariables": {"fontSize": "12px"}}}%%
flowchart TD
    A[Fetch AS vendors + Pleo vendors] --> B{All pages fetched<br>successfully?}
    B -->|Yes| C[Proceed to reconciliation]
    B -->|No, any page fails| D[Abort sync run:<br>no create/update/unarchive/archive]
    D --> E[Retry full fetch<br>next sync cycle]
    B -->|"No, reconcile with<br>partial results (avoid this)"| F["BUG (avoid this): vendors never<br>fetched get incorrectly archived"]

   style A white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style B white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style C white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style D white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style E white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style F white-space:normal,fill:${errorFill},stroke:${errorStroke}${errorTextStyle}
${linkStyle}
`;
  return <Mermaid chart={diagram} />;
};

export const VendorSyncInvalidDuplicateExternalIdDiagram = () => {
  const [isDark, setIsDark] = useState(false);
  useEffect(() => {
    const check = () => setIsDark(document.documentElement.classList.contains("dark"));
    check();
    const observer = new MutationObserver(check);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return () => observer.disconnect();
  }, []);
  const nodeFill = isDark ? "#212222" : "#EEF4F4";
  const nodeStroke = isDark ? "#848989" : "#E1E6E6";
  const nodeTextStyle = isDark ? ",color:#EEF4F4" : ",color:#131414";
  const errorFill = isDark ? "#3A1E22" : "#FCE9EA";
  const errorStroke = isDark ? "#FF90A1" : "#F15A71";
  const errorTextStyle = isDark ? ",color:#FF90A1" : ",color:#7A1F2B";
  const linkStyle = isDark ? "" : "linkStyle default stroke:#848989,stroke-width:1px;";
  const diagram = `
%%{init: {"themeVariables": {"fontSize": "12px"}}}%%
flowchart TD
    A[AS or Pleo vendor record] --> B{externalId empty or null?}
    B -->|Yes| C[Skip vendor, log error:<br>no create/update]
    B -->|No| D{Duplicate externalId<br>within AS or within Pleo?}
    D -->|Yes| E[Skip matching for that externalId,<br>log error, leave untouched]
    D -->|No| F[Proceed with matching]
    D -->|"Yes, arbitrarily match<br>one instead (avoid this)"| G["BUG (avoid this): wrong vendor<br>matched, or duplicate created"]

   style A white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style B white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style C white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style D white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style E white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style F white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
   style G white-space:normal,fill:${errorFill},stroke:${errorStroke}${errorTextStyle}
${linkStyle}
`;
  return <Mermaid chart={diagram} />;
};

export const IntegrationDesignVendorSyncDiagram = () => {
  const [isDark, setIsDark] = useState(false);
  useEffect(() => {
    const check = () => setIsDark(document.documentElement.classList.contains("dark"));
    check();
    const observer = new MutationObserver(check);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return () => observer.disconnect();
  }, []);
  const nodeFill = isDark ? "#212222" : "#EEF4F4";
  const nodeStroke = isDark ? "#848989" : "#212222";
  const nodeTextStyle = isDark ? ",color:#EEF4F4" : ",color:#131414";
  const linkStyle = isDark ? "" : "linkStyle default stroke:#848989,stroke-width:1px;";
  const themeVariables = {
    fontSize: "12px",
    ...isDark ? {} : {
      edgeLabelBackground: "#FAFCFC"
    }
  };
  const diagram = `
%%{init: {"themeVariables": ${JSON.stringify(themeVariables)}}}%%
flowchart TD
    A[1. Fetch active Vendors from AS] --> B[2. Fetch active and archived Vendors from Pleo]
    B --> C[3. Match each AS Vendor to Pleo Vendor by externalId]
    C -->|Found, Pleo<br> active, <br>details match| D[Preserve Vendor as-is]
    C -->|Found, Pleo<br> active, <br>details differ| E[Update code, country, currency,<br>name, registration and tax numbers]
    C -->|Found, Pleo<br> archived| F[Unarchive Vendor and update if needed]
    C -->|Not found| G[Create new Vendor]
    D --> H[Continue to next AS Vendor]
    E --> H
    F --> H
    G --> H
    H --> J{All AS Vendors processed?}
    J -->|No| C
    J -->|Yes| I[4. Archive unmatched Vendors]

    style A white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
    style B white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
    style C white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
    style D white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
    style E white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
    style F white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
    style G white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
    style H white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
    style I white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
    style J white-space:normal,fill:${nodeFill},stroke:${nodeStroke}${nodeTextStyle}
${linkStyle}
`;
  return <Mermaid chart={diagram} />;
};

This page describes the Vendor Sync reconciliation process: synchronising active vendors from the Accounting System with Vendors in Pleo.

This step runs on every Vendor Sync cycle.

## Implementation

* [Vendor Sync Workflow Guide](/docs/current/guides/accounting-integrations/imports/vendor-sync-workflow-guide): workflow context and sequencing
* [How to Fetch and Match Vendors](/docs/current/how-tos/accounting-integrations/imports/vendors/how-to-fetch-and-match-vendors): API usage and step-by-step instructions

For a conceptual overview of how AS vendors map to Pleo Vendors, see [Platform Capabilities: Vendor Sync](/docs/current/platform/accounting-integrations/imports/vendors/vendor-sync-overview).

## Matching Rules

* Matching is performed using the **`externalId`** field on both ends.
* The `externalId` is the unique, long-lasting identifier assigned to the vendor by the Accounting System.
* `code` and `name` are not used for matching, only `externalId` is used.

### Invalid or Duplicate externalId

Since matching relies entirely on `externalId`, treat it as a hard requirement. If the AS returns a vendor with an empty or null `externalId`, skip that vendor and log an error: do not create or update a Pleo Vendor for it.

Duplicates are a data integrity error, not a matching decision. If the AS returns two or more vendors with the same `externalId`, skip all of them and log an error rather than arbitrarily matching one; the AS may not enforce uniqueness on `externalId`, so this can happen on any sync run. Pleo enforces `externalId` uniqueness per company at the database level, so Pleo-side duplicates shouldn't normally occur, but the integration should still defend against one when matching (see [How to Fetch and Match Vendors](/docs/current/how-tos/accounting-integrations/imports/vendors/how-to-fetch-and-match-vendors#3-match-as-vendors-to-pleo-vendors-by-externalid)), in case of legacy data or any other data-quality issue.

<VendorSyncInvalidDuplicateExternalIdDiagram />

### Partial Fetch Failures

Fetches must be complete before reconciliation begins. If any page fetch fails, whether from the Accounting System or from Pleo, abort the entire sync run without performing any create, update, unarchive, or archive operation. Do not reconcile using a partial result set: this can incorrectly archive vendors that were never fetched due to the error. Retry the full fetch on the next sync cycle.

<VendorSyncPartialFetchFailuresDiagram />

## Sync Process

<IntegrationDesignVendorSyncDiagram />

### 1. Fetch Active Vendors from the AS

Retrieve all active vendors from the Accounting System.

Only active vendors are used for reconciliation. Inactive, blocked, or deleted vendors in the AS are not synced into Pleo.

### 2. Fetch Vendors from Pleo

Retrieve both **active and archived** Vendors from Pleo for the connected company.

Including archived Vendors allows unarchiving rather than creating duplicates if a vendor becomes active in the AS again.

### 3. Match Vendors by externalId

For every active AS vendor, attempt to find a matching Vendor in Pleo using the `externalId` field on both ends.

#### externalId found, Vendor is active in Pleo, details match

The AS vendor is active and the matching Pleo Vendor is also active with the same `code`, `country`, `defaultCurrency`, `name`, `registrationNumber`, and `taxRegistrationNumber`. No action required.

#### externalId found, Vendor is active in Pleo, details differ

The AS vendor is active and the matching Pleo Vendor is also active, but one or more details differ. **Update** the Vendor's `code`, `country`, `defaultCurrency`, `name`, `registrationNumber`, and `taxRegistrationNumber` to match the AS.

#### externalId found, Vendor is archived in Pleo

The AS vendor is active but the matching Pleo Vendor is archived. **Unarchive** the Vendor and update its details if they differ from the AS.

#### externalId not found

The AS vendor is active but no matching Pleo Vendor exists. **Create a new Vendor** with the vendor's `externalId`, `code`, `country`, `defaultCurrency`, `name`, `registrationNumber`, and `taxRegistrationNumber`.

##### Distinguishing a New Vendor from a Pending Activation

An AS vendor with no matching Pleo Vendor is not always a genuinely new vendor: it can also be an AS record that Vendor Creation already created in Step 1 of its create-and-activate flow, whose Pleo `:activate` call (Step 2) then failed, timed out, or is still pending, non-concurrently with this Sync run. Before creating, check whether the AS vendor's identifier is already claimed by an in-flight or retryable Vendor Creation attempt (see [Interaction with Vendor Sync](/docs/current/integration-design/exports/vendors/integration-design-vendor-creation-create-and-activate#interaction-with-vendor-sync) on that flow), and skip creation for it if so, leaving it to be picked up by Vendor Creation's own activation retry instead.

<VendorSyncNewVendorVsPendingActivationDiagram />

##### Always Set externalId on Creation

Always set `externalId` when creating a Vendor from an AS record. Pleo automatically sets a Vendor's `state` to `ACTIVE` when it is created with an `externalId`. Without one, the Vendor is created in `DRAFT` state instead, which is the behaviour used by [Vendor Creation](/docs/current/integration-design/exports/vendors/integration-design-vendor-creation-overview), not Vendor Sync.

<VendorSyncAlwaysSetExternalIdDiagram />

##### Concurrency with Vendor Creation

Vendor Sync and [Vendor Creation's create-and-activate step](/docs/current/integration-design/exports/vendors/integration-design-vendor-creation-create-and-activate) must not run concurrently for the same company. If they do, races can occur: Sync may create a duplicate Vendor for an AS record that Vendor Creation already has in flight (still `DRAFT` in Pleo, and so invisible to Sync's matching), or Sync may archive a Vendor that Vendor Creation just activated if the AS fetch has not yet caught up. Use the same per-company concurrency lock for both workflows to prevent this.

<VendorSyncConcurrencyWithCreationDiagram />

### 4. Archive Unmatched Vendors

Pleo Vendors that are active but have no matching active AS vendor must be **archived**. This covers vendors that were previously present in the AS but have since been deactivated, blocked, or removed. Vendors are never permanently deleted: archiving preserves historical data and allows unarchiving if the vendor becomes active in the AS again.

##### Skipped Records Are Not Absent Records

"No matching active AS vendor" must be computed only from the AS vendors that passed the skip checks in [Invalid or Duplicate externalId](#invalid-or-duplicate-externalid) above. A Pleo Vendor whose only corresponding AS record was skipped for a data integrity reason is not the same as a Pleo Vendor with no AS record at all, and must not be archived on that basis. Leave it as is, and let it be picked up correctly once the AS-side data integrity issue is fixed and a later sync run resolves it.

<VendorSyncSkippedRecordsDiagram />

##### Require Two Consecutive Unmatched Runs

A successful fetch is not the same as a complete one: pagination against a live AS can miss a vendor that is concurrently created, updated, or paged past due to replica lag or list-ordering drift, even when every page request itself succeeds (this is distinct from the [Partial Fetch Failures](#partial-fetch-failures) rule above, which covers requests that fail outright).

Do not archive a Pleo Vendor on its first appearance as unmatched; require it to be unmatched across at least two consecutive successful sync runs before archiving, so a single run's transient omission cannot cause an incorrect archive. This requires persisting the unmatched-run count or set across separate run invocations, not just within a single run's memory: otherwise the safeguard is never actually enforced.

<VendorSyncTwoConsecutiveRunsDiagram />

## Performance and Scalability

Vendor lists can be large. The integration must be able to sync vendor lists at production scale, potentially thousands to tens of thousands of vendors per company (see [Pleo API Rate Limit](/docs/current/integration-design/accounting-integrations/imports/vendors/integration-design-vendor-sync-periodicity#pleo-api-rate-limit)), without delays or degradation, while staying within that rate limit.

***

## What Comes Next?

* [Vendor Sync Data Mapping](/docs/current/integration-design/accounting-integrations/imports/vendors/integration-design-vendor-sync-data-mapping)

***

## Related Reading

* [How to Fetch and Match Vendors](/docs/current/how-tos/accounting-integrations/imports/vendors/how-to-fetch-and-match-vendors)
* [How to Create Vendors](/docs/current/how-tos/accounting-integrations/imports/vendors/how-to-create-vendors)
* [How to Unarchive Vendors](/docs/current/how-tos/accounting-integrations/imports/vendors/how-to-unarchive-vendors)
* [How to Update Vendors](/docs/current/how-tos/accounting-integrations/imports/vendors/how-to-update-vendors)
* [How to Archive Vendors](/docs/current/how-tos/accounting-integrations/imports/vendors/how-to-archive-vendors)
* [Vendor Sync Workflow Guide](/docs/current/guides/accounting-integrations/imports/vendor-sync-workflow-guide)
* [Platform Capabilities: Vendor Sync](/docs/current/platform/accounting-integrations/imports/vendors/vendor-sync-overview)

***
