Skip to content

Merge two accounts

POST/v1/accounts/merge

Supports idempotency via the Idempotency-Key header. Use a new key for each intended merge and reuse it only when retrying the same merge.

Returns 403 when you may see either record by name only.

Merges two accounts into one. The primary account retains its ID; the duplicate is soft-deleted.

Required scopes: accounts:update + accounts:delete

Rate limit category: Write

Body ParametersJSONExpand Collapse
duplicateId: string

ID of the duplicate record to merge into the primary and then discard.

primaryId: string

ID of the record to keep.

fieldResolutions: optional map["primary" or "duplicate" or object { value } ]

Per-field resolution overrides keyed by attribute slug.

One of the following:
"primary" or "duplicate"
One of the following:
"primary"
"duplicate"
Value object { value }
value: string or number or boolean or 3 more
One of the following:
string
number
boolean
array of string
Address object { city, country, latitude, 5 more }
city: optional string

City name.

country: optional string

2-letter ISO 3166-1 alpha-2 country code.

latitude: optional number

Latitude coordinate.

longitude: optional number

Longitude coordinate.

postalCode: optional string

Postal or ZIP code.

state: optional string

State or province.

street: optional string

Street address line 1.

street2: optional string

Street address line 2.

FullName object { firstName, lastName }
firstName: optional string

The contact’s first name.

lastName: optional string

The contact’s last name.

options: optional object { multiSelectUnion }
multiSelectUnion: optional boolean

When true, multi-select fields are merged by union rather than primary-takes-all.

ReturnsExpand Collapse
MergeMergeAccountsResponse object { merge, primary, summary }
merge: object { id, status }
id: string

Unique identifier for the merge operation.

status: string

Current status of the merge: cleanup_pending, done, or failed.

primary: object { id, createdAt, fields, 4 more }
id: string

Unique identifier for the entity.

createdAt: string

ISO 8601 timestamp of when the entity was created.

fields: map[object { value, valueType } ]

Map of field names to their typed values. System fields are prefixed with $ (e.g. $name, $email); custom attributes use their bare slug.

value: string or number or boolean or 3 more

The field value, or null if unset.

One of the following:
string
number
boolean
array of string
Address object { city, country, latitude, 5 more }
city: optional string

City name.

country: optional string

2-letter ISO 3166-1 alpha-2 country code.

latitude: optional number

Latitude coordinate.

longitude: optional number

Longitude coordinate.

postalCode: optional string

Postal or ZIP code.

state: optional string

State or province.

street: optional string

Street address line 1.

street2: optional string

Street address line 2.

FullName object { firstName, lastName }
firstName: optional string

The contact’s first name.

lastName: optional string

The contact’s last name.

valueType: "ADDRESS" or "CHECKBOX" or "CURRENCY" or 13 more

The data type of the field.

One of the following:
"ADDRESS"
"CHECKBOX"
"CURRENCY"
"DATE"
"DATETIME"
"EMAIL"
"FULL_NAME"
"MARKDOWN"
"MULTI_SELECT"
"NUMBER"
"SINGLE_SELECT"
"SOCIAL_HANDLE"
"TELEPHONE"
"TEXT"
"URL"
"HTML"
relationships: map[object { cardinality, objectType, values, directions } ]

Map of relationship names to their associated entities. System relationships are prefixed with $ (e.g. $owner, $contact). A self-referential relationship keeps its merged values and includes optional directional values. List filters select the current record’s role with :asSource or :asDestination, for example ?parent:asSource[contains]=account_id.

cardinality: string

Whether the relationship is has_one or has_many.

objectType: string

The type of the related object (e.g. account, contact).

values: array of string

IDs of the related entities.

directions: optional object { asDestination, asSource }

Directional values for a self-referential relationship. List filters use the relationship key with :asSource or :asDestination; writes continue to use the bare key.

asDestination: object { cardinality, values }

The current record is the destination (incoming) endpoint.

cardinality: "HAS_ONE" or "HAS_MANY"

Whether this endpoint direction is HAS_ONE or HAS_MANY.

One of the following:
"HAS_ONE"
"HAS_MANY"
values: array of string

IDs of the related entities in this direction.

asSource: object { cardinality, values }

The current record is the source (outgoing) endpoint.

cardinality: "HAS_ONE" or "HAS_MANY"

Whether this endpoint direction is HAS_ONE or HAS_MANY.

One of the following:
"HAS_ONE"
"HAS_MANY"
values: array of string

IDs of the related entities in this direction.

updatedAt: string

ISO 8601 timestamp of when the entity was last updated, or null.

externalId: optional string

External identifier for the entity, or null if unset.

summary: object { fieldWriteCount, syncRepointedCount, warnings }
fieldWriteCount: number

Number of attribute fields written onto the primary record.

minimum-9007199254740991
maximum9007199254740991
syncRepointedCount: number

Number of related records re-pointed from the duplicate to the primary.

minimum-9007199254740991
maximum9007199254740991
warnings: array of string

Non-fatal warnings from the merge (e.g. skipped transfers).

Merge two accounts

curl https://api.lightfield.app/v1/accounts/merge \
    -H 'Content-Type: application/json' \
    -H 'Lightfield-Version: 2026-03-01' \
    -H "Authorization: Bearer $API_KEY" \
    -d '{
          "duplicateId": "duplicateId",
          "primaryId": "primaryId"
        }'
{
  "merge": {
    "id": "id",
    "status": "status"
  },
  "primary": {
    "id": "id",
    "createdAt": "createdAt",
    "fields": {
      "foo": {
        "value": "string",
        "valueType": "ADDRESS"
      }
    },
    "httpLink": "httpLink",
    "relationships": {
      "foo": {
        "cardinality": "cardinality",
        "objectType": "objectType",
        "values": [
          "string"
        ],
        "directions": {
          "asDestination": {
            "cardinality": "HAS_ONE",
            "values": [
              "string"
            ]
          },
          "asSource": {
            "cardinality": "HAS_ONE",
            "values": [
              "string"
            ]
          }
        }
      }
    },
    "updatedAt": "updatedAt",
    "externalId": "externalId"
  },
  "summary": {
    "fieldWriteCount": -9007199254740991,
    "syncRepointedCount": -9007199254740991,
    "warnings": [
      "string"
    ]
  }
}
Returns Examples
{
  "merge": {
    "id": "id",
    "status": "status"
  },
  "primary": {
    "id": "id",
    "createdAt": "createdAt",
    "fields": {
      "foo": {
        "value": "string",
        "valueType": "ADDRESS"
      }
    },
    "httpLink": "httpLink",
    "relationships": {
      "foo": {
        "cardinality": "cardinality",
        "objectType": "objectType",
        "values": [
          "string"
        ],
        "directions": {
          "asDestination": {
            "cardinality": "HAS_ONE",
            "values": [
              "string"
            ]
          },
          "asSource": {
            "cardinality": "HAS_ONE",
            "values": [
              "string"
            ]
          }
        }
      }
    },
    "updatedAt": "updatedAt",
    "externalId": "externalId"
  },
  "summary": {
    "fieldWriteCount": -9007199254740991,
    "syncRepointedCount": -9007199254740991,
    "warnings": [
      "string"
    ]
  }
}