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

# Upsert Synced Contact

> Create or update a contact from a CRM or another external source

Use this endpoint for Salesforce, Shopify, Zapier, or another system that sends one contact change at a time. You do not need a custom Zapier integration or a separate batch endpoint.

The combination of `source.key` and `externalId` is the durable sync identity. The first request can define the source, its fields, and the contact in one operation. Later requests can omit `fields` unless the source schema changes.

## Define fields

Field keys use lowercase snake case. Supported types are `text`, `number`, `boolean`, `date`, `enum`, `url`, `email`, and `phone`.

Define the system field keys before sending their top-level values:

* `name` uses `text`
* `email` uses `email`
* `phone_number` uses `phone`

Each non-system key in `attributes` must have a field definition owned by the same source. Dates use ISO 8601 datetime strings. Enum values must match one of the field's `enumOptions`.

## Apply sparse updates

Omitted contact properties and attribute keys remain unchanged. Send an explicit `null` to clear a top-level value or attribute. The API does not treat missing contacts as deletions.

## Link another source

Use `match.email` or `match.phoneNumber` to attach a new external identity to an existing contact. Match values are lookup-only and do not update the contact.

A match succeeds only when the value identifies one contact. Ambiguous matches, or email and phone resolving to different contacts, return `409 Conflict`.

## Use with Zapier

Create a **Webhooks by Zapier** action that sends a `POST` request to:

```text theme={null}
https://api.usesimple.ai/api/v1/contacts/upsert
```

Send `Authorization: Bearer YOUR_API_KEY` and `Content-Type: application/json` headers, then map the CRM fields into the request body shown in the example.


## OpenAPI

````yaml POST /contacts/upsert
openapi: 3.1.0
info:
  title: Public API v1
  description: >-
    Public API v1 requiring API keys.


    **Timestamps:** All datetime fields in API responses are returned in UTC
    using ISO 8601 format (e.g., `2024-01-15T14:30:00Z`). When filtering by date
    parameters, provide timestamps in ISO 8601 format.
  version: 0.1.0
servers:
  - url: https://api.prod.usesimple.ai/api/v1
    description: Production API Server
security: []
paths:
  /contacts/upsert:
    post:
      tags:
        - Contacts
      summary: Upsert Synced Contact
      description: >-
        Create or update one contact from a CRM or another external source. The
        source key and external ID form the durable sync identity. Source and
        field definitions can be included in the same request.
      operationId: upsert_synced_contact_contacts_upsert_post
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertSyncedContactRequest'
            example:
              source:
                key: salesforce
                name: Salesforce
                provider: salesforce
              fields:
                name:
                  label: Name
                  type: text
                email:
                  label: Email
                  type: email
                phone_number:
                  label: Phone number
                  type: phone
                lifecycle_stage:
                  label: Lifecycle stage
                  description: Current Salesforce lifecycle stage
                  type: enum
                  enumOptions:
                    - lead
                    - customer
              externalId: lead-42
              name: Ada Lovelace
              email: ada@example.com
              phoneNumber: '+14155550100'
              attributes:
                lifecycle_stage: lead
      responses:
        '200':
          description: >-
            The existing contact was updated or linked to the supplied external
            identity.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpsertSyncedContactResponse'
        '201':
          description: A new contact was created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpsertSyncedContactResponse'
        '401':
          description: Authentication failed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
        '409':
          description: The source, field, or contact identity conflicts with existing data.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
        '422':
          description: The request or an attribute value is invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
      security:
        - APIKeyHeader: []
components:
  schemas:
    UpsertSyncedContactRequest:
      type: object
      additionalProperties: false
      required:
        - source
        - externalId
      properties:
        source:
          $ref: '#/components/schemas/ContactSyncSource'
        fields:
          type: object
          propertyNames:
            pattern: ^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$
            maxLength: 63
          additionalProperties:
            $ref: '#/components/schemas/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: '#/components/schemas/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.
      title: Upsert Synced Contact Request
    UpsertSyncedContactResponse:
      type: object
      required:
        - contact
        - created
        - linked
      properties:
        contact:
          $ref: '#/components/schemas/SyncedContact'
        created:
          type: boolean
          description: True when this request created the Simple contact.
        linked:
          type: boolean
          description: >-
            True when a new external identity was linked to an existing Simple
            contact.
      title: Upsert Synced Contact Response
    PublicApiError:
      type: object
      required:
        - status
        - success
        - error
        - errors
      properties:
        status:
          type: string
          const: error
        success:
          type: boolean
          const: false
        error:
          type: string
        errors:
          type: array
          items:
            type: string
      title: Public API Error
    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
    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
    SyncedContact:
      type: object
      required:
        - id
        - name
        - email
        - phoneNumber
        - attributes
        - derivedAttributes
        - externalIdentities
      properties:
        id:
          type: string
          format: uuid
        name:
          anyOf:
            - type: string
            - type: 'null'
        email:
          anyOf:
            - type: string
              format: email
            - type: 'null'
        phoneNumber:
          anyOf:
            - type: string
            - type: 'null'
        attributes:
          type: object
          additionalProperties:
            anyOf:
              - type: string
              - type: number
              - type: boolean
              - type: 'null'
        derivedAttributes:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/DerivedContactAttribute'
        externalIdentities:
          type: array
          items:
            $ref: '#/components/schemas/ContactExternalIdentity'
      title: Synced Contact
    DerivedContactAttribute:
      type: object
      required:
        - value
        - status
        - confidence
        - evaluatedAt
      properties:
        value:
          anyOf:
            - type: string
            - type: number
            - type: boolean
            - type: 'null'
        status:
          type: string
          enum:
            - ready
            - pending
            - stale
            - failed
        confidence:
          anyOf:
            - type: number
            - type: 'null'
        evaluatedAt:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
      title: Derived Contact Attribute
    ContactExternalIdentity:
      type: object
      required:
        - sourceKey
        - externalId
      properties:
        sourceKey:
          type: string
        externalId:
          type: string
      title: Contact External Identity
  securitySchemes:
    APIKeyHeader:
      type: apiKey
      in: header
      name: Authorization

````