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

# Merge the duplicate groups a completed scan found

> Merges the duplicate groups a completed scan found — every group, or just the `groupIds` subset (16-hex `groupId` values from the scan result). Async: 202 returns a `jobId`; poll `GET /business/contacts/dedupe-jobs/{jobId}` until `status` is `completed`, then read `mergeResult` for the totals. Within each group the surviving contact is chosen by the merge contract (a Fuse contact beats a custom one; among custom-only groups the most recently created wins), its empty fields are filled from the other members, all emails and phones are combined, custom-column values are carried over, and the losing contacts are archived with their list memberships repointed to the survivor — every list that held a duplicate ends up holding the surviving contact instead. Merging cannot be undone. Two Fuse contacts with conflicting identities (different PDL ids or different LinkedIn URLs) are never combined, even when the scan grouped them; such groups are split or skipped, so `mergeResult.mergedGroups` can be lower than the number of groups submitted. The scan job must be `completed` (409 SCAN_NOT_COMPLETED while it still runs) and is consumed as stored — unknown `groupIds` merge nothing. Rate limit: 120 requests per minute, 10,000 per day on the contacts bucket, which every /business/contacts endpoint shares.

Errors:
- `404` `SCAN_NOT_FOUND` — No dedupe scan job with that id (it may have expired or belong to another workspace).
- `409` `SCAN_NOT_COMPLETED` — The scan is still running — poll it until status is completed, then retry.
- `422` `SCAN_HAS_NO_GROUPS` — The scan completed but found no duplicate groups; there is nothing to merge.
- `422` `VALIDATION_FAILED` — scanJobId is not a 24-hex id, or groupIds carries something other than 1-200 unique 16-hex ids.
- `429` `RATE_LIMITED` — More than 120 requests per minute or 10,000 per day on the contacts bucket, which every /business/contacts endpoint shares; retry after Retry-After.
- `500` `UNEXPECTED_ERROR` — The request could not be completed; quote request_id to support.

Requires one of the following token scopes: contacts.



## OpenAPI

````yaml /openapi.json post /business/contacts/dedupe-merge
openapi: 3.1.0
info:
  title: Fuse Business API
  version: 1.0.0
  description: >-
    External API for lists, campaigns, prospect search and contacts.
    Authenticate with your API token as HTTP Basic. All paths are under /api/v1.
servers:
  - url: https://api.tryfuse.ai/api/v1
    description: Production
security:
  - basicAuth: []
tags:
  - name: Lists
  - name: Custom columns
  - name: Smart columns
  - name: Exports
  - name: Campaigns
  - name: Knowledge hubs
  - name: Analytics
  - name: Website intent
  - name: Account
  - name: Prospect search
  - name: Campaign steps
  - name: Scheduled sends
  - name: Campaign templates
  - name: Agents
  - name: Research
  - name: Company search
  - name: Saved searches
  - name: Folders
  - name: Contacts
paths:
  /business/contacts/dedupe-merge:
    post:
      tags:
        - Contacts
      summary: Merge the duplicate groups a completed scan found
      description: >-
        Merges the duplicate groups a completed scan found — every group, or
        just the `groupIds` subset (16-hex `groupId` values from the scan
        result). Async: 202 returns a `jobId`; poll `GET
        /business/contacts/dedupe-jobs/{jobId}` until `status` is `completed`,
        then read `mergeResult` for the totals. Within each group the surviving
        contact is chosen by the merge contract (a Fuse contact beats a custom
        one; among custom-only groups the most recently created wins), its empty
        fields are filled from the other members, all emails and phones are
        combined, custom-column values are carried over, and the losing contacts
        are archived with their list memberships repointed to the survivor —
        every list that held a duplicate ends up holding the surviving contact
        instead. Merging cannot be undone. Two Fuse contacts with conflicting
        identities (different PDL ids or different LinkedIn URLs) are never
        combined, even when the scan grouped them; such groups are split or
        skipped, so `mergeResult.mergedGroups` can be lower than the number of
        groups submitted. The scan job must be `completed` (409
        SCAN_NOT_COMPLETED while it still runs) and is consumed as stored —
        unknown `groupIds` merge nothing. Rate limit: 120 requests per minute,
        10,000 per day on the contacts bucket, which every /business/contacts
        endpoint shares.


        Errors:

        - `404` `SCAN_NOT_FOUND` — No dedupe scan job with that id (it may have
        expired or belong to another workspace).

        - `409` `SCAN_NOT_COMPLETED` — The scan is still running — poll it until
        status is completed, then retry.

        - `422` `SCAN_HAS_NO_GROUPS` — The scan completed but found no duplicate
        groups; there is nothing to merge.

        - `422` `VALIDATION_FAILED` — scanJobId is not a 24-hex id, or groupIds
        carries something other than 1-200 unique 16-hex ids.

        - `429` `RATE_LIMITED` — More than 120 requests per minute or 10,000 per
        day on the contacts bucket, which every /business/contacts endpoint
        shares; retry after Retry-After.

        - `500` `UNEXPECTED_ERROR` — The request could not be completed; quote
        request_id to support.


        Requires one of the following token scopes: contacts.
      operationId: startDedupeMerge
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                scanJobId:
                  type: string
                  description: >-
                    Id of a completed dedupe scan job — the `jobId` returned by
                    POST /business/contacts/dedupe-scan.
                groupIds:
                  type: array
                  items:
                    type: string
                  minItems: 1
                  maxItems: 200
                  description: >-
                    Optional subset of the scan's groups to merge, by `groupId`
                    (16-hex ids from the scan result's `groups`). Omit it to
                    merge every group the scan found.
              required:
                - scanJobId
      responses:
        '202':
          description: Success
          headers:
            RateLimit-Limit:
              schema:
                type: integer
              description: Requests permitted in the current window.
            RateLimit-Remaining:
              schema:
                type: integer
              description: Requests remaining in the current window.
            RateLimit-Reset:
              schema:
                type: integer
              description: Seconds until the current window resets.
          content:
            application/json:
              schema:
                type: object
                required:
                  - jobId
                properties:
                  jobId:
                    type: string
                    description: >-
                      Id of the merge job; poll GET
                      /business/contacts/dedupe-jobs/{jobId}.
              example:
                jobId: 68a1f6039c41d20014b3ec42
        '400':
          description: Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - basicAuth: []
components:
  schemas:
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
            param:
              type:
                - string
                - 'null'
            doc_url:
              type:
                - string
                - 'null'
            request_id:
              type:
                - string
                - 'null'
          required:
            - code
            - message
      required:
        - error
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
      description: >-
        Your API token (`af_…`) as the Basic-auth username, with an empty
        password.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.