# POST /companies/merge

**Resource:** [Companies](./companies.md)  
**MCP tool:** `merge_companies`  
**Scopes:** `companies:delete`  
**Write operation:** yes

Merge duplicate companys into one. Every child record on the duplicates is re-parented onto the winner before the duplicates are deleted, across the complete foreign-key graph, so nothing is orphaned or destroyed. Pass preview: true to see what would move without writing. This is the only safe way to dedupe: deleting a duplicate directly destroys its linked records.

## Parameters

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `winner_id` | body | string | yes | The company that survives. Every duplicate is folded into this one, and it keeps its own values wherever both records have something. |
| `loser_ids` | body | array | yes | The duplicate companys to absorb, up to 100. Each is emptied onto the winner and then deleted. Ids that are not in this workspace are rejected before anything is written. |
| `preview` | body | boolean | no | Set true to get the per-table summary of what WOULD move, without writing anything. Use it to review a large dedupe before committing. |
| `fill_empty_fields` | body | boolean | no | Fill blank fields on the winner from the duplicates. Defaults to true. The winner never loses a value it already had. |
| `transfer` | body | object | no | Per-category opt-outs, e.g. { "activities": false } leaves activities behind. Anything not named is carried. A category cannot switch off a relationship the database deletes on its own (work orders, stage history, stakeholder links and the like): those are always carried, because skipping them would destroy the rows rather than leave them alone, and the response lists them under forced_categories. |
| `field_overrides` | body | object | no | Explicit keep-this-value picks from a choose-what-survives review, as field name to value. Applied before the blank-fill pass, which never talks over one. |
| `append_notes` | body | boolean | no | Append notes from each duplicate onto the winner, separated by a merged marker, instead of letting them die with the row. Defaults to false. |
| `require_approval` | body | boolean | no | Optional. Set true to route this write into the approval queue for human review instead of executing it immediately (returns 202 + an approval_id). Works even when your key/token has permission to execute directly. |

## Request example

```bash
curl -X POST   "https://api.trustpager.com/functions/v1/api/v1/companies/merge"   -H "Authorization: Bearer YOUR_API_KEY"   -H "Content-Type: application/json"   -d '{"winner_id":"...","loser_ids":"...","preview":"..."}'
```

---
Base URL: `https://api.trustpager.com/functions/v1/api/v1` — Auth: `Authorization: Bearer YOUR_API_KEY`