List and show companies with GET /api/v1/companies and GET /api/v1/companies/:id (see Reference data API). This page covers the merge write. All endpoints sit under /api/v1/ and need an account-scoped bearer token. See API authentication, permissions and rate limits.
POST /api/v1/companies/:id/merge
Merges duplicate companies into the company :id, then soft-deletes the duplicates. Clients and suppliers can both be merged. The web merge modal and the MCP tool merge_companies run the same operation, so all three surfaces apply the same rules.
The request needs api_create (the POST verb) and api_delete, because the merged companies are deleted. The record permissions are update_companies and delete_companies. A company the token user cannot read returns 404.
Field | Meaning |
| Array of the duplicate company ids. Required. May be sent flat or nested under |
POST /api/v1/companies/812/merge
{"source_company_ids": [815, 816]}What moves
Projects and opportunities whose client, invoice-to company or referrer is a duplicate, deleted ones included
Contracts whose primary contractor is a duplicate
Invoices that are not yet approved and not synced
Costs, purchase orders, expense claim items and staff credit cards. An expense claim item and its costs move together only when none of them is synced to finance
Records already synced to Xero, MYOB or QuickBooks keep their company, because the company is sent to the accounting software and a change would be pushed there. Approved invoices keep the company they were issued to. Contacts, addresses, notes, custom fields and finance_id stay on the deleted duplicates.
The kept company becomes both when the merge brings both sides together. A kept company that becomes the client of a moved project or opportunity also gets the account's client status (and a client number or code, when the account uses them). A referrer or invoice-to link alone changes neither.
After a merge, a project cannot be newly linked to a merged (deleted) company as its client, invoice-to company or referrer. Such a write is refused with a validation error on every surface. Projects that already point at a deleted company can still be edited.
Everything runs in one transaction. A failed merge changes nothing.
Response (200)
{
"company": {"id": 812, "trading_name": "Acme Pty Ltd", "company_type": "both"},
"merged_companies": [
{"id": 815, "trading_name": "Acme", "discarded_at": "2026-09-25T04:10:00.000Z"},
{"id": 816, "trading_name": "ACME Pty Ltd", "discarded_at": "2026-09-25T04:10:00.000Z"}
],
"moved": {
"projects": 4,
"invoices": 1,
"contracts": 0,
"costs": 12,
"purchase_orders": 2,
"expense_claim_items": 0,
"staff_credit_cards": 0
}
}
company has the same fields as GET /companies/:id.
Errors
Status |
| When |
|
|
|
|
| An id is not a number, or the company is in its own |
|
| The company |
|
| A source company is already deleted |
|
| The company |
| A missing verb permission ( | |
|
| The user lacks |
