---
title: "Validate a mappings document"
method: POST
path: "/v1/sync/syncs/{sync_id}/validate"
tags: ["Mappings"]
---

# Validate a mappings document

`POST /v1/sync/syncs/{sync_id}/validate`

## Request

- Base URL: `https://api.whalesync.com`
- URL: `https://api.whalesync.com/v1/sync/syncs/{sync_id}/validate`
- Auth: HTTP bearer

The authoritative compatibility check: field type compatibility, required and orphaned fields, linked-record constraints, create-placeholder feasibility, and everything the mappings PUT would enforce — as one issue list with stable codes and document paths. Side-effect-free: `create` placeholders are checked, never executed. Send a candidate document, or an empty body to validate the stored one. Referenced tables whose fields were never fetched are fetched during the call, so a first validate can take a few seconds. Two failure channels: a structurally malformed document (wrong types, bad `direction`, a create on both sides) is a `400 invalid_mappings` naming the path — everything semantic about a well-formed document comes back as a `200` with issues.

## Path parameters

- `sync_id` string, required

## Request body

- ValidateRequest
  - `tables` MappingTable[]: A candidate mappings document to check (same shape as the mappings PUT). Omit to validate the stored one.
    - `left_table` union, required
      - string: An existing table/field: remote id, prefixed id, or exact name when unambiguous.
      - CreatePlaceholder
        - `create` object, required
          - `name` string, required
    - `right_table` union, required
      - string: An existing table/field: remote id, prefixed id, or exact name when unambiguous.
      - CreatePlaceholder
        - `create` object, required
          - `name` string, required
    - `direction` 'left_to_right' | 'right_to_left' | 'two_way', required: Writes take these three values. A read can additionally show `"invalid"` when schema drift has disabled every allowed direction for the pair — fix the mapping and PUT it back with a real direction.
    - `left` MappingSideSettings
      - `record_delete_behavior` 'sync' | 'do_nothing': What a deletion on the other side does to records in this table. Omitted = `sync`. `do_nothing` is Delete Protection for this table — records here survive the other side deleting theirs. See https://docs.whalesync.com/features/additional-features/delete-protection.
      - `view` string: The view to sync, by value from the table's `views.options`. REQUIRED whenever the table reports `views` (Airtable, Salesforce); use `"ALL_RECORDS"` for the whole table. Omitting it on a PUT clears any prior selection rather than keeping it.
    - `right` MappingSideSettings
      - `record_delete_behavior` 'sync' | 'do_nothing': What a deletion on the other side does to records in this table. Omitted = `sync`. `do_nothing` is Delete Protection for this table — records here survive the other side deleting theirs. See https://docs.whalesync.com/features/additional-features/delete-protection.
      - `view` string: The view to sync, by value from the table's `views.options`. REQUIRED whenever the table reports `views` (Airtable, Salesforce); use `"ALL_RECORDS"` for the whole table. Omitting it on a PUT clears any prior selection rather than keeping it.
    - `fields` MappingField[], required
      - `left_field` union, required
        - string: An existing table/field: remote id, prefixed id, or exact name when unambiguous.
        - CreatePlaceholder
          - `create` object, required
            - `name` string, required
      - `right_field` union, required
        - string: An existing table/field: remote id, prefixed id, or exact name when unambiguous.
        - CreatePlaceholder
          - `create` object, required
            - `name` string, required
      - `direction` 'left_to_right' | 'right_to_left' | 'two_way': Defaults to the table's direction; must be a subset of it.
    - `advanced_settings` MappingAdvancedSetting[]: Read-only. The pair's advanced settings that are off their default and cannot be set through the API — delay before syncing, row-level sync, and connector-specific per-table options. Absent when there are none, and ignored on write: these are edited on the Advanced settings tab in the app. Delete protection is not here; it is `record_delete_behavior` above.
      - `setting` 'delay_before_syncing' | 'row_level_sync' | 'connector_option', required: `delay_before_syncing` = changes wait out a quiet period before syncing; `row_level_sync` = only records whose sync-enabled field is true sync out of this table; `connector_option` = a per-table choice the connector asks for.
      - `side` 'left' | 'right', required: The table the setting is on.
      - `value` union, required: Seconds for `delay_before_syncing`, the sync-enabled field's remote id for `row_level_sync`, the chosen values otherwise.
        - number
        - string
        - string[]
      - `description` string, required: What the setting does here, in one sentence — safe to relay to a person.
      - `docs_url` string, uri: The docs page for this setting, where one exists.
    - `filter` MappingFilter
      - `match` 'all' | 'any', required: Whether every condition must pass, or just one.
      - `conditions` union[], required: Conditions, or nested groups.
        - union
          - MappingFilterCondition
            - `left_field` string, nullable, required: The tested field on the left side; null when the field mapping it referenced is gone.
            - `right_field` string, nullable, required: The same field on the right side.
            - `operator` 'equals' | 'not_equals' | 'greater_than' | 'greater_than_or_equal' | 'less_than' | 'less_than_or_equal' | 'contains' | 'not_contains' | 'is_empty' | 'is_not_empty' | 'is_any_of' | 'is_none_of', required
            - `value` string[]: Absent for `is_empty`/`is_not_empty`; several values for `is_any_of`/`is_none_of`.
            - `value_type` 'string' | 'number' | 'boolean' | 'date' | 'datetime', required: How the values are compared.
          - MappingFilterGroup
            - `match` 'all' | 'any', required: Whether every condition must pass, or just one.
            - `conditions` union[], required: Conditions, or nested groups.
              - …
      - `summary` string, required: The whole filter as one sentence — safe to relay to a person.
      - `docs_url` string, uri, required

## Response `200`

The issues found; empty means valid.

- ValidationResult
  - `issues` ValidationIssue[], required: Empty when the document is fully valid.
    - `severity` 'error' | 'warning', required: Errors block starting the sync; warnings never block.
    - `code` string, required: Stable identifier — branch on this.
    - `path` string, nullable, required: JSON pointer into the document, or null when the issue has no single home.
    - `side` 'left' | 'right' | 'null', nullable, required
    - `message` string, required
    - `doc_url` string, uri, required

## Other responses

- `400`: The candidate document is structurally malformed (`invalid_mappings`, with the path).
- `401`: The API key is missing, invalid, or revoked (`missing_api_key`, `invalid_api_key`). Carries a `required_action` linking a person to key creation, naming the smallest scope this endpoint needs.
- `403`: The key's scope does not allow this call (`insufficient_scope` on a mutation with a `read` key).
- `404`: No such sync on this account.
- `409`: A person has to act first (`requires_action`): the error carries `required_action` — relay its `instruction` and `url` to a human, then retry.
- `429`: Rate limit exceeded. Wait for `Retry-After` seconds.

---

[API](https://skmtc.dev/whalesync/apis/whalesync-api.md) · [All operations](https://skmtc.dev/whalesync/apis/whalesync-api/llms.txt) · [OpenAPI document](https://skmtc.dev/whalesync/apis/whalesync-api/revisions/5131522b325a?raw)
