> For the complete documentation index, see [llms.txt](https://protectedseas.gitbook.io/navigator-api-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://protectedseas.gitbook.io/navigator-api-docs/conventions/data-synchronization.md).

# Data Synchronization

To keep a local copy of Navigator data in sync, use the Search endpoint's **Updated Sites Since Date** mode. It returns all sites across every region whose `last_update` is on or after a date you provide.

```http
GET /api/search/?type=sites_updated&changed_since=2025-01-01&lang=en_EN
```

The response returns only sites — no regions and no summary block:

```json
{
  "regions": [],
  "sites": [ ... ]
}
```

## Parameters

<table><thead><tr><th width="167.7999267578125">Parameter</th><th>Required?</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>Required</td><td>string</td><td>Must be <code>sites_updated</code>.</td></tr><tr><td><code>changed_since</code></td><td>Required</td><td>string (date)</td><td>Date in <code>YYYY-MM-DD</code> format. Returns sites with <code>last_update</code> on or after this date. Must be a valid calendar date.</td></tr><tr><td><code>include_inactive</code></td><td>Optional</td><td>boolean</td><td>If <code>true</code>, also returns removed sites, each carrying a <code>status</code> field, so consumers can delete them locally. Default: <code>false</code>. Only valid with <code>type=sites_updated</code>.</td></tr><tr><td><code>lang</code></td><td>Optional</td><td>string</td><td>Language ISO ID. Default: English. Example: <code>en_EN</code>.</td></tr><tr><td><code>sort</code></td><td>Optional</td><td>string</td><td>Sort order. See <a href="/navigator-api-docs/api-reference/search/text-and-filter-queries.md">Text &#x26; filter queries</a> for accepted values.</td></tr><tr><td><code>limit</code></td><td>Optional</td><td>integer</td><td>Maximum number of results per page.</td></tr><tr><td><code>page</code></td><td>Optional</td><td>integer</td><td>Page number (requires <code>limit</code>).</td></tr><tr><td><code>export_bounds</code></td><td>Optional</td><td>boolean</td><td>If <code>true</code>, includes bounding-box geometry.</td></tr></tbody></table>

## Pagination

When you page through results with `limit` and `page`, sites are returned in a stable, deterministic order. A full paginated sweep returns every matching site exactly once — none skipped or repeated between pages — as long as the data does not change mid-sweep. A single pass is enough to capture the complete set; you don't need to confirm a site's absence across two sweeps to rule out a paging artifact.

## Recommended workflow

1. **Initial load** — Pull all regions and sites via the standard [Search](/navigator-api-docs/api-reference/search.md) endpoints.
2. **Periodic sync** — Call `type=sites_updated` with `changed_since` set to your last sync date. Pass `include_inactive=true` to also receive removed sites; without it, removals can only be found by reconciling against a full catalog sweep.
3. **Apply changes** — For each site in the response, branch on `status`:

   * `active` — upsert into your local copy, keyed on `ps_id`, keeping the newest version (highest `site_major_version` / `site_minor_version`). If you maintain more than the sync response delivers, refresh the rest for every updated site — a correction can change the boundary or the Site Details-only fields (e.g. regulation summaries) without advancing the version, so there is no safe way to skip refreshes. If you only need geometry on top of the sync record, the Boundary endpoint is the lighter call; if you also store Site Details fields, fetch Site Details with `export_boundaries=true` and get both in one request.
   * `removed` — delete all local records for that `ps_id`.

   The `status` field is present only when you pass `include_inactive=true`; without it, every returned site is active.
4. **Record the sync date** — Store the date your sync *started* (not finished) for your next `changed_since` call. Because `changed_since` is inclusive and date-granular, the next sync will re-deliver some changes you have already applied — this is intentional and harmless: step 3's operations are idempotent (re-upserting an unchanged site and re-deleting an absent `ps_id` are both no-ops). Never advance the stored date past a sync that failed partway.
5. **Reconcile periodically** — Schedule an occasional full catalog sweep (e.g. monthly) via `type=sites` and diff it against your local copy. The incremental stream is the lightweight day-to-day path; the full sweep is a self-healing backstop that corrects drift from missed windows or consumer-side bugs, and is the only mechanism that can restore a site your local processing wrongly dropped.

{% hint style="warning" %}
**Detect changes with `last_update`, not version numbers.** A site's attributes, activity codings, or boundary geometry can be corrected without advancing `site_major_version` / `site_minor_version` — but any such change still updates `last_update`. Always drive your sync from `changed_since` (which filters on `last_update`); diffing version numbers to decide what changed will miss same-version corrections. Use the version fields for record identity, not as a change signal.
{% endhint %}

{% hint style="warning" %}
**Sanity-check deltas before applying them** — especially if you republish Navigator data downstream. Refuse to act on a sweep that returns implausibly few sites or a delta that would remove a large fraction of your local copy (the full catalog exceeds 30,000 sites). A transient error surfacing as an empty or truncated response should halt your pipeline, not propagate as mass deletions to your users.
{% endhint %}

{% hint style="info" %}
**Expect fewer boundaries than sites.** Some catalog sites have their boundary geometry withheld for redistribution reasons (see [Search](/navigator-api-docs/api-reference/search.md)). They still return full attributes, so don't treat a missing boundary as a deletion or a sync error — reconcile on the attribute record, not on boundary presence. When syncing, track these sites attribute-only and don't re-request their boundaries — requests for withheld boundaries never succeed and only waste your rate-limit budget. If a site's boundary ever becomes servable (e.g. its source changes), that is a correction and will surface through `changed_since` like any other.
{% endhint %}

## Errors

| Status | Condition                                             | Example                                                                                                                     |
| ------ | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `400`  | `changed_since` missing or not in `YYYY-MM-DD` format | `{"error": "The \"changed_since\" parameter is required and must be a valid date in YYYY-MM-DD format (e.g. 2025-01-15)."}` |
| `400`  | `changed_since` is not a valid calendar date          | `{"error": "The \"changed_since\" date \"2025-02-30\" is not a valid calendar date."}`                                      |
