{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/simple-ai/json-schema/simple-ai-upsert-synced-contact-request-schema.json",
  "title": "Upsert Synced Contact Request",
  "x-generated": "2026-10-29",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/simple-ai-openapi.json#/components/schemas/UpsertSyncedContactRequest",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "source",
    "externalId"
  ],
  "properties": {
    "source": {
      "oneOf": [
        {
          "type": "string",
          "minLength": 1,
          "maxLength": 63,
          "pattern": "^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$",
          "description": "Stable lowercase snake_case identifier for the source."
        },
        {
          "$ref": "#/$defs/ContactSyncSource"
        }
      ],
      "description": "A source key reuses or creates a custom source. The object form supplies its display name and provider. Existing metadata is preserved when using a string."
    },
    "fields": {
      "type": "object",
      "propertyNames": {
        "pattern": "^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$",
        "maxLength": 63
      },
      "additionalProperties": {
        "$ref": "#/$defs/ContactSyncFieldDefinition"
      },
      "default": {},
      "description": "Field definitions owned by this source. Include them when first used or when labels, descriptions, or enum options change. Define name, email, and phone_number before sending their corresponding top-level values."
    },
    "externalId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 1000,
      "description": "Stable contact identifier from the external source."
    },
    "name": {
      "anyOf": [
        {
          "type": "string",
          "minLength": 1,
          "maxLength": 255
        },
        {
          "type": "null"
        }
      ],
      "description": "Contact name. Omit to leave unchanged or send null to clear it."
    },
    "email": {
      "anyOf": [
        {
          "type": "string",
          "format": "email"
        },
        {
          "type": "null"
        }
      ],
      "description": "Contact email. Omit to leave unchanged or send null to clear it."
    },
    "phoneNumber": {
      "anyOf": [
        {
          "type": "string",
          "minLength": 1,
          "maxLength": 255
        },
        {
          "type": "null"
        }
      ],
      "description": "Contact phone number. Omit to leave unchanged or send null to clear it."
    },
    "match": {
      "$ref": "#/$defs/ContactSyncMatch"
    },
    "attributes": {
      "type": "object",
      "propertyNames": {
        "pattern": "^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$",
        "maxLength": 63
      },
      "additionalProperties": true,
      "default": {},
      "description": "Values for non-system fields defined by this source. Values must match their field type. Omit a key to leave it unchanged or send null to clear it."
    },
    "eventId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255,
      "description": "Unique event ID within this source. Supply with sourceUpdatedAt; required for nonempty consents. Retry with the same request body."
    },
    "sourceUpdatedAt": {
      "type": "string",
      "format": "date-time",
      "description": "Timestamp of the source change, including timezone. Older events for the external identity are skipped. Supply with eventId."
    },
    "consents": {
      "type": "array",
      "maxItems": 6,
      "default": [],
      "items": {
        "$ref": "#/$defs/ContactConsentInput"
      },
      "description": "Preferences for the supplied primary phoneNumber. Omitted or empty leaves consent unchanged. Duplicate medium/category entries are rejected."
    }
  },
  "dependentRequired": {
    "eventId": [
      "sourceUpdatedAt"
    ],
    "sourceUpdatedAt": [
      "eventId"
    ]
  },
  "allOf": [
    {
      "if": {
        "required": [
          "consents"
        ],
        "properties": {
          "consents": {
            "minItems": 1
          }
        }
      },
      "then": {
        "required": [
          "phoneNumber",
          "eventId",
          "sourceUpdatedAt"
        ],
        "properties": {
          "phoneNumber": {
            "type": "string",
            "pattern": "^\\+[1-9]\\d{1,14}$"
          }
        }
      }
    }
  ],
  "$defs": {
    "ContactConsentInput": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "medium",
        "category",
        "optOut"
      ],
      "properties": {
        "medium": {
          "type": "string",
          "enum": [
            "voice",
            "text"
          ]
        },
        "category": {
          "type": "string",
          "enum": [
            "all",
            "transactional",
            "marketing"
          ]
        },
        "optOut": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "description": "True reports an opt-out, false reports no opt-out from this source, and null reports unknown. False is not affirmative consent."
        }
      }
    },
    "ContactSyncFieldDefinition": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "label",
        "type"
      ],
      "properties": {
        "label": {
          "type": "string",
          "minLength": 1,
          "maxLength": 255,
          "description": "Display label for the field."
        },
        "description": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 2000
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Optional explanation of the field."
        },
        "type": {
          "type": "string",
          "enum": [
            "text",
            "number",
            "boolean",
            "date",
            "enum",
            "url",
            "email",
            "phone"
          ],
          "description": "Value type enforced for this field. A field's type cannot be changed after creation."
        },
        "enumOptions": {
          "type": "array",
          "maxItems": 100,
          "uniqueItems": true,
          "items": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          },
          "default": [],
          "description": "Allowed values for an enum field. Required for enum fields and omitted for other types. Existing options cannot be removed."
        }
      },
      "title": "Contact Sync Field Definition"
    },
    "ContactSyncMatch": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "email": {
          "type": "string",
          "format": "email",
          "description": "Lookup-only email used to link this identity to one existing contact."
        },
        "phoneNumber": {
          "type": "string",
          "minLength": 1,
          "maxLength": 255,
          "description": "Lookup-only phone number used to link this identity to one existing contact."
        }
      },
      "default": {},
      "title": "Contact Sync Match"
    },
    "ContactSyncSource": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "key",
        "name",
        "provider"
      ],
      "properties": {
        "key": {
          "type": "string",
          "minLength": 1,
          "maxLength": 63,
          "pattern": "^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$",
          "description": "Stable lowercase snake_case identifier for the source."
        },
        "name": {
          "type": "string",
          "minLength": 1,
          "maxLength": 255,
          "description": "Display name for the source."
        },
        "provider": {
          "type": "string",
          "enum": [
            "salesforce",
            "shopify",
            "custom"
          ],
          "description": "The system that owns the synced contact data."
        }
      },
      "title": "Contact Sync Source"
    }
  }
}