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

# Troubleshoot ERP sync

> Find out why the ERP Sync agent is offline or why changes from your ERP are not arriving, and fix it.

Start with the quick checks, then open the entry that matches what you see. Run the PowerShell commands on the agent
computer.

## Quick checks

```powershell theme={null}
# Is the Windows service running?
Get-Service OmnilinkerErpSyncService

# What does the agent report? (state 0 = Idle, 1 = Syncing, 2 = Paused, 3 = Error)
Invoke-RestMethod -Headers @{ "X-Omnilinker-Local" = "1" } http://localhost:5555/api/sync/status |
  Select-Object state, isConnected, isErpConnected, lastError, waitingReason

# Are events waiting to be sent to Omnilinker?
Invoke-RestMethod -Headers @{ "X-Omnilinker-Local" = "1" } http://localhost:5555/api/sync/outbox/stats

# Can this computer reach Omnilinker?
Test-NetConnection omnilinker.pl -Port 443
```

In Omnilinker, open **ERP Integration** > **Connections**, open the connection and check its **Agent** tab. See
[Monitoring](/erp/monitoring#agent-tab).

* `isConnected: False`: the agent cannot talk to Omnilinker, or Omnilinker rejects it.
* `isErpConnected: False`: the agent cannot read the ERP database.
* `pending` growing in the outbox stats: changes are detected but not delivered.

The status fields are described in the [local API reference](/erp/local-api).

## Common problems

<AccordionGroup>
  <Accordion title="Where are the logs?">
    The agent has two logs.

    **Service log files.** The Windows service writes one file per day and keeps the last 30:

    ```text theme={null}
    %ProgramData%\Omnilinker\ErpSync\logs\erpsync-<yyyyMMdd>.log
    ```

    That is usually `C:\ProgramData\Omnilinker\ErpSync\logs`. Everyone signed in to the computer can read it. To
    follow today's file:

    ```powershell theme={null}
    Get-Content "$env:ProgramData\Omnilinker\ErpSync\logs\erpsync-$(Get-Date -Format yyyyMMdd).log" -Tail 50 -Wait
    ```

    In the tray app, **View Logs** > **Open Log Folder** opens the same folder.

    **Setup log.** Setup, updates and uninstalling write what they could not do to `setup.log` in the same folder.
    See **Setup finished, but there is no service**.

    **Sync log.** The agent also keeps a short log of sync events in its local database. Read it in the tray app with
    **View Logs**, or with `GET /api/sync/logs` on the [local API](/erp/local-api).

    The agent does not write its own messages to the Windows event log. Windows records service start failures in
    the System log (see the next entry).
  </Accordion>

  <Accordion title="The service does not start">
    `Get-Service OmnilinkerErpSyncService` shows `Stopped`, or the service stops shortly after it starts. The tray
    app shows **Disconnected** in its tooltip.

    The service is set to restart itself after a failure (after 5, 10 and 30 seconds), so a service that keeps
    stopping has a problem that a restart does not fix.

    1. Open **Event Viewer** > **Windows Logs** > **System** and look for errors from the source **Service Control
       Manager** that name **Omnilinker ERP Sync** (**Omnilinker ERP Sync Service** on an installation made with
       `install-service.ps1`). For a crash, also check **Windows Logs** >
       **Application** for **.NET Runtime** or **Application Error** entries.
    2. Open the newest service log file (see **Where are the logs?**). If the service started far enough to log, the
       last lines say why it stopped. A fatal start-up error ends with
       `Omnilinker ERP Sync Service terminated unexpectedly`.

    Common causes:

    * **Logon failure.** Someone changed the service to run under another account, and its password changed. The
      System log says the service did not start due to a logon failure. Open **Services**, open
      **Omnilinker ERP Sync** > **Log On**, select **Local System account** and click **OK**. The agent is designed
      to run as Local System.
    * **Port 5555 in use.** See **The local API port is already in use**.
    * **Broken `appsettings.json`.** If you edited it, check that it is still valid JSON. From the install folder:

      ```powershell theme={null}
      Get-Content .\appsettings.json -Raw | ConvertFrom-Json
      ```

      An error means the file is not valid. Fix it or restore it from the original package.

    Start the service again after a fix, in PowerShell as Administrator:

    ```powershell theme={null}
    Start-Service OmnilinkerErpSyncService
    ```
  </Accordion>

  <Accordion title="Setup finished, but there is no service">
    Setup completed, but `Get-Service OmnilinkerErpSyncService` finds no service, or the tray app does not start at
    sign-in. Setup never fails because of one step; it writes what it could not do to
    `%ProgramData%\Omnilinker\ErpSync\logs\setup.log`:

    ```powershell theme={null}
    Get-Content "$env:ProgramData\Omnilinker\ErpSync\logs\setup.log" -Tail 20
    ```

    | Line in `setup.log`                                                                                                                | What to do                                                                                                                                                                                                        |
    | ---------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `not registering the service: <path> is inside a user's profile. Install for all users.`                                           | The agent was installed into a user profile, for example by double-clicking the installer. Uninstall it, then install it again with `--installto`. See [Install the agent](/erp/install-agent#install-the-agent). |
    | `data folder:`, `operators group:`, `service:`, `tray at sign-in:` or `start service:` followed by an error, such as `exit code 5` | Setup could not do that step, most often because it did not run as an administrator. Run the same setup command again from PowerShell as Administrator.                                                           |
    | `done`                                                                                                                             | Every step succeeded.                                                                                                                                                                                             |

    If there is no `setup.log` at all, setup could not even create the folder. Run it again from PowerShell as
    Administrator.
  </Accordion>

  <Accordion title="The tray app cannot reach the service">
    The tooltip says **Disconnected**, or the setup wizard shows "Failed to connect to service".

    1. Check that the service is running: `Get-Service OmnilinkerErpSyncService`. If it is not, see **The service
       does not start**.
    2. If the tray app shows "Something other than the Omnilinker service answered. Restart the PC; if it happens
       again, contact support.", another program answered on the agent's pipe. The tray app talks only to the
       Windows service. Restart the computer.
  </Accordion>

  <Accordion title="The tray app says Only an administrator of this PC can do that.">
    You can see the agent's status, but saving settings, the setup wizard, pausing or enabling change tracking
    fails with "Only an administrator of this PC can do that."

    Your Windows account is not allowed to change the agent. Ask an administrator of the computer to add you to the
    local group **Omnilinker ERP Sync Operators**, then try again. You do not need to sign out. See
    [Who can change the agent](/erp/install-agent#who-can-change-the-agent).

    An administrator can also exit the tray app and start it again with **Run as administrator**.
  </Accordion>

  <Accordion title="The local API answers 403 Forbidden">
    A script or monitoring tool gets `403 Forbidden` with an empty body from `http://localhost:5555/api/...`.

    * Add the header `X-Omnilinker-Local: 1` to every request. See [Local API](/erp/local-api#access-and-security).
    * Call the API as `localhost`, `127.0.0.1` or `[::1]`, not by the computer's name.
    * From a web page, only Omnilinker's own pages may call the API.
  </Accordion>

  <Accordion title="The local API port is already in use">
    The service stops right after it starts. Its log file contains a line like
    `Failed to bind to address http://127.0.0.1:5555: address already in use`.

    Another program uses port 5555 on the agent computer. Find it:

    ```powershell theme={null}
    Get-NetTCPConnection -LocalPort 5555 -State Listen |
      ForEach-Object { Get-Process -Id $_.OwningProcess }
    ```

    Stop that program or move it to another port, then start the service.

    You can move the agent to another port with `LocalApiPort` in `appsettings.json`, but the web app's **Local
    Service** tab and the tray app's fallback connection keep using port 5555 and will not reach the agent. Free
    port 5555 if you can. See the [configuration reference](/erp/configuration-reference).
  </Accordion>

  <Accordion title="The Agent tab says Offline">
    **Offline** means Omnilinker has not received a heartbeat for more than 3 minutes. **Last heartbeat** shows when
    the last one arrived. A running, accepted agent sends one every 60 seconds.

    Work through these in order:

    1. **Is the service running?** See **The service does not start**.
    2. **Can the agent reach Omnilinker?** See **The agent cannot reach omnilinker.pl**.
    3. **Is the connection active?** On **ERP Integration** > **Connections**, the connection's **Status** must be
       **Active**. Omnilinker rejects heartbeats and changes for an inactive connection. To switch it on, click
       **Activate** in the row's **Actions** menu.
    4. **Is the API key still valid?** See **The API key is rejected**.
    5. **Is the agent too old?** See **Omnilinker rejects the agent version**.

    If the tab says **No agent has connected yet**, the agent has never reached Omnilinker with this connection's key.
    Complete the [setup wizard](/erp/setup-wizard) on the agent computer.
  </Accordion>

  <Accordion title="The API key is rejected">
    The agent's log shows, repeatedly:

    ```text theme={null}
    Authentication failed for connection <connection-id>. Status: Unauthorized. Please verify API key is valid and not expired.
    Heartbeat returned Unauthorized for connection <connection-id>
    ```

    In the tray app, validating the key shows "Invalid API key. Please check and try again."

    The agent's key no longer works. Most often someone clicked **Generate Agent Key** on the connection again:
    generating a new key revokes the previous one straight away.

    To fix it:

    1. In Omnilinker, open **ERP Integration** > **Connections**, open the row's **Actions** menu and click
       **Generate Agent Key**. Copy the key. It is shown only once. See
       [Create a connection](/erp/create-connection).
    2. On the agent computer, open the tray app's **Settings...**, paste the key under **Cloud Connection**, click
       **Validate**, then **Save**. See [Tray app](/erp/tray-app#settings-window).

    Generating a key again revokes the one you just made too, so do it only once and store the new key in the agent
    straight away.

    Two related messages:

    * "API key doesn't have required permissions. Grant ERP Integration permissions to this API key." The key is
      not an agent key. Use a key from **Generate Agent Key**, not one from the Administration API keys page.
    * "This agent key is not authorized for the requested ERP connection." The key belongs to a different
      connection. Select the right connection in the tray app's settings, or generate a key on this connection.

    `Status: Forbidden` in the first message above is not a key problem. See **Omnilinker rejects the agent version**
    and **Changes are not arriving**.
  </Accordion>

  <Accordion title="Omnilinker rejects the agent version">
    Omnilinker can require a minimum agent version. When your agent is older, Omnilinker rejects every request from it
    with:

    ```text theme={null}
    Agent version <version> is no longer supported (minimum supported version: <minimum>). Please update the ERP Sync agent.
    ```

    What you see:

    * In Omnilinker, the connection's **Agent** tab turns **Offline** and **Last heartbeat** stops moving.
      **Agent version** still shows your old version.
    * In the agent's log, `Heartbeat returned Forbidden`, and `Cloud API returned Forbidden for batch publish:`
      followed by the message above. The configuration check also logs `Authentication failed ... Status: Forbidden`,
      even though the key is fine.
    * The outbox `pending` count grows, and later `failed` grows too.

    The agent [updates itself](/erp/install-agent#update-the-agent) at night when a newer version is published, so
    this should clear by itself. If it does not, check that automatic updates are on (`AutoUpdateEnabled`) and that
    the agent computer can reach `releases.omnilinker.com`, or run the new installer by hand.

    Do it promptly. Each rejected send counts as a failed attempt, and changes that fail every attempt are not sent
    again (see **Changes are not arriving**).
  </Accordion>

  <Accordion title="The agent cannot reach omnilinker.pl">
    The status shows `isConnected: False`. The tray app's cloud connection test fails with `Cloud connection failed:`
    followed by the reason, or `Cloud returned status:` followed by an HTTP status.

    1. Test the connection from the agent computer:

       ```powershell theme={null}
       Test-NetConnection omnilinker.pl -Port 443
       ```

       `TcpTestSucceeded : False` means a firewall or the network blocks it. The agent needs outbound HTTPS to
       `omnilinker.pl` on port 443. See [Requirements](/erp/requirements#network).
    2. If your network requires a proxy, set it for the machine with the `HTTPS_PROXY` environment variable, then
       restart the service. The service runs as Local System, so it does not use the proxy settings of the person
       signed in:

       ```powershell theme={null}
       [Environment]::SetEnvironmentVariable("HTTPS_PROXY", "http://<proxy-host>:<port>", "Machine")
       Restart-Service OmnilinkerErpSyncService
       ```
    3. Check the **API URL** in the tray app's **Settings...**. It should be `https://omnilinker.pl`.

    While Omnilinker cannot be reached, the agent keeps working from its last downloaded configuration and keeps
    queuing changes. But every failed send counts as an attempt, so a long outage can make queued changes fail for
    good. See **Changes are not arriving**.
  </Accordion>

  <Accordion title="The agent cannot connect to the ERP database">
    The status shows `isErpConnected: False`, or the tray app's **Test Connection** shows `SQL error:` followed by
    SQL Server's message.

    Test the database settings in the tray app: **Settings...** > **Database Connection** > **Test Connection**. The
    test runs inside the Windows service, with the service's account, so it behaves the same way as the agent.

    **The server cannot be found.** SQL Server's message starts with "A network-related or instance-specific error
    occurred while establishing a connection to SQL Server".

    * Check **Server / Host**. For a named instance use `server\instance`, for example `erp-server\WAPRO`.
    * Check that the agent computer can reach the SQL Server port:

      ```powershell theme={null}
      Test-NetConnection <erp-server> -Port 1433
      ```

      Use your instance's port if it is not 1433. A named instance with a dynamic port also needs the SQL Server
      Browser service and UDP port 1434.

    **Login failed.** SQL Server's message starts with "Login failed for user".

    * **SQL Server authentication** (a **Username** is filled in): check the username and password, and that SQL
      Server allows SQL Server authentication (mixed mode).
    * **Windows authentication** (**Username** left empty): the agent logs in as **the service's account**, Local
      System, not as you. The user named in the message is that account: the agent computer's domain account
      (`DOMAIN\COMPUTER$`) on a remote SQL Server, or `NT AUTHORITY\SYSTEM` on SQL Server on the same computer. Give
      that account a login and read access to the ERP database, or use SQL Server authentication. See
      [Requirements](/erp/requirements#sql-server-login).
    * Check that the login can open the database named in **Database Name**.

    **Certificate errors.** SQL Server's message mentions the certificate, for example "The certificate chain was
    issued by an authority that is not trusted".

    The agent encrypts the connection to SQL Server by default, even when **Encrypt connection** is not ticked, and
    most SQL Server installations use a self-signed certificate. Either install a certificate on SQL Server that the
    agent computer trusts, or tick **Trust server certificate** under **Advanced Connection Options** and click
    **Save**.

    <Note>
      **Test Connection** uses the two check boxes exactly as ticked, while the service encrypts unless told
      otherwise. So the test can pass with both boxes unticked while the service still fails with a certificate
      error. If you see that, tick **Trust server certificate**.
    </Note>
  </Accordion>

  <Accordion title="Changes are not arriving (the outbox is backing up)">
    The agent detects changes but Omnilinker does not receive them. `GET /api/sync/outbox/stats` shows `pending`
    growing, or `failed` above zero. The tray menu shows **Queue: `<n>` pending | `<n>` failed**.

    **How the agent retries.** The agent keeps every change in a local outbox and sends it in batches every few
    seconds. When a send fails, for any reason, the change stays **pending** and is tried again in the next cycle.
    After 5 failed attempts (`MaxRetryAttempts` in `appsettings.json`) it is marked **failed** and the agent does not
    send it again.

    Find the reason in the agent's log file. Look for:

    | Log line                                            | Meaning                                                                                                        |
    | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
    | `Cloud API returned Unauthorized for batch publish` | The key is rejected. See **The API key is rejected**.                                                          |
    | `Cloud API returned Forbidden for batch publish:`   | The text after it says why: an agent that is too old, an inactive connection, or a key for another connection. |
    | `Failed to publish chunk`                           | The send failed, often because Omnilinker could not be reached. See **The agent cannot reach omnilinker.pl**.  |
    | `OUTBOX PARTIAL REJECTION`                          | Omnilinker accepted some changes and rejected others. The line lists the first reasons.                        |

    Also check that the connection is **Active** in Omnilinker.

    Changes that have already failed every attempt are not sent again automatically. A later change to the same
    record in the ERP is detected and sent as usual.
  </Accordion>

  <Accordion title="The agent is online but nothing syncs">
    The **Agent** tab says **Online**, but no new sync log entries appear in Omnilinker.

    Check, in order:

    1. **Is syncing paused?** The tray icon is amber and the tooltip says **Paused**, or the status shows `state: 2`.
       Select **Resume Sync** in the tray menu. See [Tray app](/erp/tray-app#sync-now-pause-and-resume).
    2. **Is the entity type configured?** On the connection's **Sync Configuration** tab, each entity type you want
       to sync needs a configuration that is **Enabled**. If the tab says "No sync configurations found. Add one to
       enable synchronization.", add one. See [Sync configuration](/erp/sync-configuration).
    3. **Is change detection on?** With hash scan change detection (the default), the agent finds changes only with
       hash checks. Open the **Product** sync configuration, expand **Advanced Timing Settings** and make sure
       **Hash-Based Change Detection** is **Enabled**. In the tray menu, **Hash Check: Disabled** means it is off.
    4. **Has the agent loaded its configuration?** If `lastError` is `Waiting for cloud configuration`, the agent has
       not yet downloaded its settings from Omnilinker. See **The API key is rejected** and **The agent cannot reach
       omnilinker.pl**.
    5. **Are the ERP credentials set?** If `lastError` is `ERP credentials not configured`, or the tray app's ERP test
       says "No ERP credentials configured. Run setup wizard to configure.", complete the
       [setup wizard](/erp/setup-wizard).
    6. **Has anything changed in the ERP?** The agent sends only changes. The first hash check after installation
       compares every record; later ones find only what changed since. To check now, select **Trigger Hash Check**
       in the tray menu.

    A hash check runs on its interval (15 minutes by default). **Sync Now** in the tray app starts one sooner.
  </Accordion>

  <Accordion title="Changes arrive as Skipped">
    Sync log entries in Omnilinker show no status badge, and their error message is a code such as
    `ErpIntegration:Skip:ProductNotMapped`. Omnilinker received the change but did not apply it on purpose.

    Most of these mean something is not mapped yet:

    * `ErpIntegration:Skip:PriceLevelNotMapped` or `ErpIntegration:Skip:WarehouseNotMapped`: map the ERP price level
      or warehouse on the connection's **Mappings** tab. See [Reference items](/erp/reference-items).
    * `ErpIntegration:Skip:ProductNotMapped`: the price, stock or bundle belongs to a product that is not linked to a
      catalog product yet. Make sure products sync first. See [Field mappings](/erp/field-mappings).

    The full list is in [Monitoring](/erp/monitoring#sync-logs).
  </Accordion>

  <Accordion title="Test Connection in the web app always fails">
    **Test Connection** in a connection's **Actions** menu always reports a failure. That is expected: Omnilinker
    does not have your ERP database credentials, which stay on the agent computer. Test the database connection in
    the tray app instead: **Settings...** > **Database Connection** > **Test Connection**.
  </Accordion>

  <Accordion title="Trigger Sync or Retry in the web app does nothing">
    **Trigger Sync** on the connection page (and the sync button on the dashboard) confirms "Synchronization has been
    triggered", but it does not reach the agent. **Retry** on a failed sync log entry only sets it back to
    **Pending**.

    To make the agent look for changes now, use **Sync Now** or **Trigger Hash Check** in the tray app, or
    `POST /api/sync/now` on the [local API](/erp/local-api). See also [Monitoring](/erp/monitoring).
  </Accordion>

  <Accordion title="The Local Service tab says Local Sync Service Not Available">
    The **Local Service** tab of a connection talks to the agent at `http://localhost:5555` from your browser. It
    works only in a browser on the agent computer, with the agent on port 5555. On any other computer this message
    is expected. Use the **Agent** tab instead. See [Monitoring](/erp/monitoring#local-service-tab).
  </Accordion>
</AccordionGroup>

## Get help

If none of this solves the problem, contact Omnilinker support.

Include:

* The connection name, and what you see on its **Agent** tab.
* The agent's version, from the **Agent** tab or the `version` field of `GET /api/sync/status`.
* The output of the quick checks at the top of this page.
* The service log files from the time the problem started.

<Warning>
  Never send `credentials.dat`, and do not paste your API key or ERP password into a message. The local API never
  returns them. Look through the log files before you send them.
</Warning>
