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

# Create / Upload Lead Endpoint

> Create a single lead or upload multiple leads into a Tuco workspace

## Endpoint

* **Method**: `POST`
* **Path**: `/api/leads`

This endpoint is used both for creating a single lead and for bulk uploads (multiple leads in one request), just like the CSV import in the Tuco app.

***

## Request Body

```json theme={null}
{
  "leads": [
    {
      "firstName": "John",
      "lastName": "Doe",
      "email": "john@example.com",
      "phone": "+12025551234",
      "companyName": "Acme Corp",
      "jobTitle": "CEO",
      "notes": "Warm intro from Sarah",
      "contactOwnerEmail": "rep@yourcompany.com",
      "customFields": {
        "industry": "Technology",
        "segment": "Mid-market"
      }
    }
  ],
  "listId": "507f1f77bcf86cd799439011",
  "source": "api",
  "defaultCountryCode": "+1"
}
```

* `leads` – one or more contacts; a single contact is just a one‑element array.
* `listId` – **Optional.** Tuco list that should own these leads. Omit to use the **Quick Sends** list.
* `source` – optional origin label (for example, `"api"` or `"gohighlevel"`).
* `defaultCountryCode` – used to normalize phone numbers when no country code is present.
* `ghlLocationId` – optional; used when syncing with GoHighLevel.
* `contactOwnerEmail` – Email of the workspace user who owns this contact. If omitted or invalid, defaults to the first user in the workspace.
* You may send `body` as an alias for `leads` (same array shape).

***

## Response

**Success** – status `201 Created` when at least one lead was created, or `200 OK` when the request succeeded but no new leads were inserted. Example:

```json theme={null}
{
  "message": "Leads saved successfully",
  "savedCount": 1,
  "duplicateCount": 0,
  "totalProcessed": 1,
  "listId": "507f1f77bcf86cd799439011",
  "leadId": "674a1b2c3d4e5f678901234a",
  "leadIds": ["674a1b2c3d4e5f678901234a"],
  "leadListIds": ["507f1f77bcf86cd799439011"],
  "ghlContactId": null,
  "ghlLocationId": null,
  "hsPortalId": null,
  "hsContactId": null
}
```

Response fields:

* `savedCount` – number of new leads actually inserted.
* `duplicateCount` – leads skipped as duplicates within the same list (email/phone‑based).
* `totalProcessed` – total rows you attempted to upload.
* `listId` – list the leads were added to.
* `leadIds` – array of Tuco lead IDs for **newly created** leads only, in the same order as inserted. Use these to link created leads back to your system or to fetch/update them later.
* `leadListIds` – array of list IDs the new leads were added to (one list per request; same as `listId` when adding to a single list).
* `duplicates` – present only when some (but not all) leads were duplicates; each entry describes the submitted input and the existing lead in the list.

**All duplicates** – status **`200 OK`** (not 409). No new leads are created; the body includes `duplicateOnly: true`, `duplicateCount`, `totalProcessed`, `leadId` (first existing), `existingLeadIds`, `leadIds`, `duplicates` (each with `input` and `existingLead` including `_id`), and integration IDs (`ghlContactId`, `ghlLocationId`, etc.) so you can reconcile with existing records and continue your workflow (e.g. n8n).

**Other errors:** Validation failures return `400` with a readable error. If the requested list does not exist, you get `404`. If the workspace is temporarily read‑only (e.g. payment past due), you get `402` with `code: "READ_ONLY"`. See `/api-reference/errors` for more.
