---
title: "How to Push Leads and Contacts into CRMs with Unified's CRM API"
img: https://s3.us-east-2.amazonaws.com/unified-article-images/how_to_push_leads_and_contacts_into_crms_with_unified_crm_api-icon.png
date: 2026-02-02T17:04:00.000Z
tag: Product
description: "Pushing data into a CRM sounds simple. Create a contact. Create a lead. Attach them to a company. Move on."
url: "https://unified.to/blog/how_to_push_leads_and_contacts_into_crms_with_unified_crm_api"
---

# How to Push Leads and Contacts into CRMs with Unified's CRM API
------
_February 2, 2026_

Pushing data into a CRM sounds simple. Create a contact. Create a lead. Attach them to a company. Move on.


In practice, it only works if you understand what the CRM actually accepts.


CRMs differ in how they handle identity, associations, and custom fields. Some treat contacts as primary records. Others prioritize leads. Company association may require an ID in one system and a name in another. Custom fields may exist, but only if they're written in the right format. Required fields are often integration-specific and undocumented until a write fails.


If you don't design for that variability, write flows become brittle. You end up retrying failed writes blindly or hardcoding logic per CRM.


Unified's [CRM API](/crm) gives you a normalized write surface across CRMs. You work with a single set of CRM objects—contacts, leads, and companies—and use documented create, update, retrieve, and list operations to implement safe, portable write flows.


This guide shows how to push leads and contacts into CRMs using Unified's CRM API in TypeScript. It focuses on create, find-then-update patterns, associations, and custom fields, without assuming required fields, upsert behavior, or integration-specific guarantees.


### Prerequisites

- Node.js v18+
- A Unified account with a CRM integration enabled
- Your [Unified API](/technology) key
- A customer CRM `connectionId`

## Step 1: Set up your project


```bash
mkdir crm-write-demo
cd crm-write-demo
npm init -y
npm install @unified-api/typescript-sdk dotenv
```


Create a `.env` file:


```bash
UNIFIED_API_KEY=your_unified_api_key
CONNECTION_CRM=your_customer_crm_connection_id
```


## Step 2: Initialize the SDK


```typescript
import "dotenv/config";
import { UnifiedTo } from "@unified-api/typescript-sdk";

const { UNIFIED_API_KEY, CONNECTION_CRM } = process.env;

if (!UNIFIED_API_KEY) throw new Error("Missing UNIFIED_API_KEY");
if (!CONNECTION_CRM) throw new Error("Missing CONNECTION_CRM");

const sdk = new UnifiedTo({
  security: { jwt: UNIFIED_API_KEY },
});

const connectionId = CONNECTION_CRM;
```


## Step 3: Understand what you can write (and what varies)


Unified normalizes CRM objects, but write support still varies by integration. Required fields, association behavior, and custom field support can differ across CRMs.


For this article, we rely only on fields that are:

- defined in the CRM data models
- accepted by create and update endpoints
- commonly writable across CRMs

Anything integration-specific should be verified in the **Feature Support** tab for the integration you've enabled.


### Contacts (`CrmContact`)


Contacts represent people and support structured fields, associations, and metadata.


Commonly written fields include:

- identity: `name`, `first_name`, `last_name`, `title`, `department`
- company context: `company` (string), `company_ids[]` (IDs if known)
- contact methods:
    - `emails[]` with `type` (`WORK`, `HOME`, `OTHER`)
    - `telephones[]` with `type` (`WORK`, `HOME`, `OTHER`, `FAX`, `MOBILE`)
- address fields with ISO-2 `country_code`
- attribution: `user_id`
- custom fields via `metadata[]`
- `raw` passthrough when needed

### Leads (`CrmLead`)


Leads represent top-of-funnel records and can be associated to contacts and companies.


Commonly written fields include:

- identity: `name`, `first_name`, `last_name`
- associations: `contact_id`, `company_id`, or `company_name`
- state: `source`, `status`, `is_active`
- contact methods: `emails[]`, `telephones[]`
- attribution: `user_id`, `creator_user_id`
- custom fields via `metadata[]`
- `raw` passthrough

### Companies (`CrmCompany`) optional


If you want to create or update companies directly, Unified supports full CRUD for companies as well. For this article, company creation is optional. You can associate contacts and leads using names or IDs without creating companies explicitly.


## Step 4: Create a contact


Creating a contact uses `POST /crm/{connection_id}/contact` via the SDK.


Start with a minimal payload. Required fields are integration-dependent, so avoid assuming email or name requirements unless you've verified them for your CRM.


```typescript
const contact = await sdk.crm.createCrmContact({
  connectionId,
  crmContact: {
    first_name: "Alex",
    last_name: "Morgan",
    title: "VP Engineering",
    emails: [
      { email: "alex@example.com", type: "WORK" },
    ],
    company: "Example Corp",
  },
});
```


The call returns a `CrmContact` object, including the generated `id`. Store this ID if you plan to update or associate the contact later.


## Step 5: Find an existing contact safely


Unified does not provide a true upsert endpoint. To avoid duplicates, implement a find-then-update pattern.


The list endpoint supports a `query` parameter that searches by name or email, depending on the CRM.


```typescript
const matches = await sdk.crm.listCrmContacts({
  connectionId,
  limit: 1,
  offset: 0,
  query: "alex@example.com",
});
```


If `matches.length > 0`, treat the first result as the existing contact. If no results are returned, create a new contact.


## Step 6: Update an existing contact


Updates use `PUT /crm/{connection_id}/contact/{id}`.


Send only the fields you want to change. Fields not included in the payload are left unchanged.


```typescript
const updated = await sdk.crm.updateCrmContact({
  connectionId,
  id: contact.id,
  crmContact: {
    title: "Chief Architect",
    department: "Platform",
  },
});
```


The response returns the updated `CrmContact`.


## Step 7: Create a lead


Creating a lead uses `POST /crm/{connection_id}/lead`.


You can associate a lead to a company by ID or by name. Use IDs when you already have them; otherwise, pass a name and let the CRM handle matching.


```typescript
const lead = await sdk.crm.createCrmLead({
  connectionId,
  crmLead: {
    first_name: "Jordan",
    last_name: "Lee",
    company_name: "Example Corp",
    source: "Website",
    status: "New",
    emails: [
      { email: "jordan@example.com", type: "WORK" },
    ],
  },
});
```


As with contacts, the response includes the lead `id`.


## Step 8: Find or update a lead


Use the same find-then-update pattern for leads.


```typescript
const leads = await sdk.crm.listCrmLeads({
  connectionId,
  limit: 1,
  offset: 0,
  query: "jordan@example.com",
});

if (leads.length > 0) {
  await sdk.crm.updateCrmLead({
    connectionId,
    id: leads[0].id,
    crmLead: {
      status: "Qualified",
    },
  });
}
```


## Step 9: Write custom fields with metadata


Both contacts and leads support `metadata[]` for custom fields.


Each metadata entry includes:

- `slug` to identify the field
- `value`
- `format` to describe the data type

```typescript
await sdk.crm.updateCrmContact({
  connectionId,
  id: contact.id,
  crmContact: {
    metadata: [
      {
        slug: "account_tier",
        value: "enterprise",
        format: "SINGLE_SELECT",
      },
      {
        slug: "employee_count",
        value: 1200,
        format: "NUMBER",
      },
    ],
  },
});
```


Custom field support varies by CRM. Always verify field availability and write support in the Feature Support tab.


## Step 10: Verify writes with retrieve


After creating or updating records, retrieve them by ID to confirm the write succeeded.


```typescript
const verified = await sdk.crm.getCrmContact({
  connectionId,
  id: contact.id,
});
```


This is especially useful when debugging integration-specific constraints or required fields.


## Step 11: Optional cleanup


Unified supports record deletion if your workflow requires it.


```typescript
await sdk.crm.removeCrmLead({
  connectionId,
  id: lead.id,
});
```


Deletion support varies by CRM and should be used cautiously.


## Summary


Using Unified's CRM API, you can push leads and contacts into CRMs with a single, consistent write surface:

- Create and update contacts and leads using normalized schemas
- Associate records using IDs or names
- Write custom fields through `metadata[]`
- Implement safe find-then-update flows without assuming upsert
- Verify writes using retrieve endpoints
- Handle [pagination](/docs/reference/pagination), filtering, and integration variance explicitly

→ [Start your 30-day free trial](https://app.unified.to/login)


→ [Book a demo](https://calendly.com/d/cph9-g8n-jzg/connect-with-unified)