---
title: "Bulk \"import into pipeline\": upsert contacts and create one deal per row. Throttled generously so a chunked multi-batch import can complete."
method: POST
path: "/crm/deals/bulk-import"
tags: ["CRM Deals"]
---

# Bulk "import into pipeline": upsert contacts and create one deal per row. Throttled generously so a chunked multi-batch import can complete.

`POST /crm/deals/bulk-import`

## Request

- Base URL: `https://developer.meetergo.com` (the document declares no server; this is the origin it was published from)
- URL: `https://developer.meetergo.com/crm/deals/bulk-import`
- Auth: one of:
  - HTTP bearer
  - HTTP bearer
  - API key in header `x-meetergo-api-user-id`

## Request body

- BulkImportDealsDto
  - `rows` BulkImportDealRowDto[], required
    - `firstName` string
    - `lastName` string
    - `email` string, email
    - `phoneNumber` string
    - `tags` string[]
    - `notes` string
    - `accountOwnerEmail` string, email: Email of a user in the same company who should be set as account owner.
    - `meetingTypeRef` string: Meeting type UUID or name within the same company.
    - `crmCompanyRef` string: CrmCompany UUID or display name. Unknown names are auto-created so spreadsheet rows that introduce new companies don't fail the row.
    - `additionalData` object: Arbitrary custom fields (UTM params, source data, ...) stored as additionalData.
    - `dealName` string: Deal title. Falls back to the contact's name when absent.
    - `dealValue` number: Deal value in `dealCurrency`. The client parses the CSV cell to a number.
    - `dealCurrency` string: ISO-4217 code. Defaults to EUR, matching a manually created deal.
    - `dealExpectedCloseDate` string: Expected close date as `YYYY-MM-DD`; the client normalizes CSV formats.
    - `dealOwnerEmail` string, email: Email of a user in the same company who owns the deal. Unresolvable emails fall back to the importing user and are reported as an `owner_not_found` issue rather than failing the row.
    - `dealNotes` string: Deal notes. Distinct from the contact's own `notes` column. Imported as a note on the deal's notes timeline, which is the only notes surface the deal detail shows.
  - `pipelineId` string, required
  - `stageId` string, required
  - `updateExisting` boolean: When true, contacts whose email already exists are updated in place. A deal is created for every row regardless, matching how Pipedrive/HubSpot import deals (contacts dedupe by email, deals are never deduplicated).

## Response `201`

- BulkImportDealsResult
  - `contactsCreated` number, required: Newly inserted contacts.
  - `contactsUpdated` number, required: Existing contacts updated in place (only when updateExisting is true).
  - `contactsSkipped` number, required: Existing contacts left untouched (a deal is still created for them).
  - `dealsCreated` number, required: Deals created in the target pipeline stage.
  - `dealsSkipped` number, required: Deals not created because the plan deal limit was reached.
  - `failed` number, required: Rows that hit a technical error (contact or deal).
  - `issues` object[]

## Other responses

- `400`: The request did not validate. `message` lists the constraints that failed.
- `401`: Missing, malformed, or expired credentials.
- `403`: Authenticated, but not allowed: the plan does not include this feature, or the token is scoped away from it.
- `429`: Rate limited. Back off and retry.

---

[API](https://skmtc.dev/meetergo/apis/meetergo-platform-api.md) · [All operations](https://skmtc.dev/meetergo/apis/meetergo-platform-api/llms.txt) · [OpenAPI document](https://skmtc.dev/meetergo/apis/meetergo-platform-api/revisions/b5d66cd8be67?raw)
