---
title: "Create or update a contact"
method: POST
path: "/api/contacts"
tags: ["Contacts"]
---

# Create or update a contact

`POST /api/contacts`

## Request

- Base URL: `https://core-api.getaptly.com`
- URL: `https://core-api.getaptly.com/api/contacts`
- Auth: one of:
  - API key in header `x-token`
  - API key in header `Authorization`
- TypeScript: <https://skmtc.dev/getaptly/apis/aptly-api/docs/api/contacts/post.ts> (a function with typed inputs; its response is checked against the schema)

Creates a new contact or updates an existing one (upsert).

**Lookup order:**
1. If `_id` is provided, finds by ID.
2. Otherwise finds by first email address.
3. If no match is found, creates a new contact.

**Body formats** — either native or legacy (capitalized keys) are accepted:

*Native:* `firstname`, `lastname`, `email` (string or array), `phone` (array of `{number, type}`),
`typeId`, `contactType`, `isCompany`, `title`, `company`, `imageUrl`, `customFields`

*Legacy:* `"First Name"`, `"Last Name"`, `Email`, `"Mobile Phone"`, `"Work Phone"`,
`"Home Phone"`, `"Contact Type"`, `Title`, `Company`

Returns the enriched contact with custom fields populated by their type definitions.

## Request body

- object
  - `_id` string: Existing contact ID — when provided, updates that contact.
  - `firstname` string
  - `lastname` string
  - `email` union: One or more email addresses.
    - string
    - string[]
  - `phone` object[]
    - `number` string
    - `type` 'mobile' | 'work' | 'home'
  - `typeId` string: Contact type ID.
  - `contactType` string: Contact type name (alternative to `typeId` — resolved to an ID automatically).
  - `isCompany` boolean
  - `title` string
  - `company` string
  - `imageUrl` string: Absolute URL to a JPG or PNG photo.
  - `customFields` object: Map of custom field ID to value. Unknown field IDs are rejected.

## Response `200`

Contact created or updated.

- Contact
  - `_id` string: MongoDB ObjectId of the contact.
  - `uuid` string
  - `firstname` string
  - `lastname` string
  - `fullName` string: Computed display name (first + last, or company name for org records).
  - `duogram` string: Two-letter initials derived from first and last name.
  - `photoId` string, nullable
  - `imageUrl` string, nullable: CDN thumbnail URL for the contact's photo, or null if none.
  - `email` string
  - `phone` string
  - `typeId` string
  - `companyId` string
  - `address` object
  - `title` string
  - `alerts` object[]
  - `company` string: Company name — populated when isCompany is true.
  - `isCompany` boolean

## Other responses

- `400`: Invalid input (bad URL, unknown custom field, invalid date, etc.).
- `401`: Invalid or missing API key.

---

[API](https://skmtc.dev/getaptly/apis/aptly-api.md) - [All operations](https://skmtc.dev/getaptly/apis/aptly-api/llms.txt) - [OpenAPI document](https://skmtc.dev/getaptly/apis/aptly-api/revisions/75c367e0b8e5?raw)
