Contacts

A contact is a person your team corresponds with. Carom assembles contacts from mail in connected mailboxes, so most exist before anyone creates them. Use this resource to read what Carom knows about a person, correct or enrich it, merge duplicates, and delete contacts you don’t want.

Every contact is either personal, visible only to the user who owns it, or global, visible to the whole account. A personal contact can also be shared with specific users or groups. Global contacts can be edited by anyone in the account; personal contacts only by their owner. See what a key can see.

#The contact object

Returned by every contact endpoint. List responses add correspondence statistics and leave out the embedded records. Every response about a single contact adds per-mailbox interaction histories, open tasks, comments, and shares, and Retrieve a contact adds a few more fields.

Correspondence statistics, such as thread_count and interaction_histories, cover only the mailboxes whose statistics are visible to your key: mailboxes your key’s user can read, and correspondence a colleague has shared with that user through a share request.

Attributes

  • idstring · uuid

    Unique identifier for the contact.

  • namestring · nullable

    Display name. Null when Carom has only ever seen an email address for this person.

  • contact_typestring

    What kind of sender the contact is. Carom classifies each contact automatically; you can override it. connection: a person outside your organization. colleague: a person at your organization, with an address at your account’s email domain. mailing_list: a mailing list or newsletter. notification: an automated sender, such as a no-reply address.

    connectioncolleaguemailing_listnotification
  • globalboolean

    True for a global contact, visible to the whole account; false for a personal one. Change it with Make a contact global.

  • backgroundstring · nullable

    Free-form notes about the person.

  • pinnedboolean · nullable

    Whether your key’s user has pinned this contact. Null on contacts embedded in other resources’ responses.

  • has_duplicatesboolean · nullable

    True when Carom has found other contacts that look like the same person and nobody has rejected the match. See List duplicates, and resolve them with Merge contacts. Null on contacts embedded in other resources’ responses.

  • user_idstring · uuid · nullable

    The user who owns the contact. Only the owner can make it global.

  • task_countinteger · nullable

    Open tasks attached to this contact that are visible to your key. Null on contacts embedded in other resources’ responses.

  • prioritynumber

    List responses only. A relative score of how actively your team corresponds with this contact. Higher is more active; it has no fixed scale, so use it to sort. The default sort for List contacts.

  • thread_countinteger

    List responses only. Threads with this contact, summed across the mailboxes whose statistics are visible to your key.

  • file_countinteger

    List responses only. Files attached to messages with this contact, summed the same way.

  • last_contactstring · date-time · nullable

    List responses only. When a thread with this contact last had a message, in those mailboxes.

  • recent_monthly_messagesobject

    List responses only. Messages with this contact per month for the trailing 12 months, keyed by month as YYYY-MM, oldest first.

  • email_addressesarray of objects · nullable

    Every address Carom has seen for this person.

    Show 3 child attributesHide child attributes
    • idstring · uuid
    • valuestring · nullable

      The address.

    • primaryboolean · nullable

      Addresses added through the API are primary; addresses moved onto this contact by a merge are not. A contact can have more than one primary address.

  • employmentsarray of objects · nullable

    Roles this person holds, each at an organization.

    Show 3 child attributesHide child attributes
    • idstring · uuid
    • titlestring · nullable

      Job title.

    • organizationobject · nullable
      Show 2 child attributesHide child attributes
      • idstring · uuid
      • namestring · nullable
  • numbersarray of objects · nullable

    Phone numbers, each with a free-form kind.

    Show 3 child attributesHide child attributes
    • idstring · uuid
    • valuestring · nullable
    • kindstring · nullable
  • locationsarray of objects · nullable

    Postal addresses, with a time zone when one is known.

    Show 11 child attributesHide child attributes
    • idstring · uuid
    • street_numberstring · nullable
    • streetstring · nullable
    • apartmentstring · nullable
    • citystring · nullable
    • statestring · nullable
    • state_codestring · nullable
    • countrystring · nullable
    • country_codestring · nullable
    • time_zonestring · nullable

      Time zone name.

    • utc_offsetnumber · nullable

      Offset from UTC, in hours.

  • social_profilesarray of objects · nullable

    Profiles on linkedin, twitter, github, facebook, or angellist, each with an id, network, and handle.

  • websitesarray of objects · nullable

    Links associated with the person, each with an id, url, and title.

  • avatarobject · nullable

    The contact’s picture: an id, a source_url you can display directly, and a file_name.

  • tagsarray of tags · nullable

    Tags applied to this contact.

  • interaction_historiesarray of objects · nullable

    Single-contact responses only. One entry for each pair of email address and mailbox whose statistics are visible to your key, describing that mailbox’s correspondence with this contact.

    Show 12 child attributesHide child attributes
    • mailbox_idstring · uuid
    • mailboxobject · nullable

      Identifies the mailbox. An entry can be visible to your key when the mailbox itself isn’t, so this carries only the fields below; read the rest from Mailboxes.

      Show 4 child attributesHide child attributes
      • idstring · uuid
      • email_addressstring · nullable
      • namestring · nullable

        Display name for the mailbox.

      • user_idstring · uuid · nullable

        The user who owns the mailbox.

    • thread_countinteger · nullable
    • file_countinteger · nullable
    • response_ratenumber · nullable

      Share of threads with this contact in which the mailbox sent a message, between 0 and 1.

    • prioritynumber · nullable

      A relative score of how actively this mailbox corresponds with the contact. Higher is more active; it has no fixed scale, so use it to sort.

    • average_thread_laginteger · nullable

      Average time between messages in threads with this contact, in seconds.

    • average_thread_lengthnumber · nullable

      Average messages per thread.

    • average_participant_countnumber · nullable

      Average participants per thread.

    • monthly_messagesobject · nullable

      Message counts keyed by month, as YYYY-MM, from the first month with a message.

    • first_contactstring · date-time · nullable
    • last_contactstring · date-time · nullable
  • tasksarray of tasks · nullable

    Single-contact responses only. Open tasks attached to the contact that your key can see.

  • commentsarray of comments · nullable

    Single-contact responses only. Comments your team has left on the contact.

  • sharesarray of shares · nullable

    Single-contact responses only. Active shares of this contact with users or groups.

The contact object
{
  "id": "1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41",
  "name": "Priya Natarajan",
  "contact_type": "connection",
  "global": true,
  "background": "Runs operations across Wildgrove's 14 properties. Prefers a call to a long thread.",
  "pinned": false,
  "has_duplicates": false,
  "user_id": "9c41d2e8-3f6a-4b7c-8d1e-5a2f7b9c0d3e",
  "priority": 3.68,
  "thread_count": 42,
  "file_count": 7,
  "task_count": 2,
  "last_contact": "2026-09-04T21:17:09.332Z",
  "recent_monthly_messages": {
    …
    "2026-07": 11,
    "2026-08": 16,
    "2026-09": 3
  },
  "email_addresses": [
    {
      "id": "3a8d1e6f-52c4-4b9a-8e7d-1c0f9b2a4d63",
      "value": "priya@wildgrove.example",
      "primary": true
    }
  ],
  "employments": [
    {
      "id": "c2f7b4a1-9e3d-4c6b-b5a8-7d1e2f3a4b5c",
      "title": "VP Operations",
      "organization": {
        "id": "6b0e2d9a-4c31-4f8e-a7d2-90c4e1b7f5a3",
        "name": "Wildgrove Property Management"
      }
    }
  ],
  "numbers": [
    {
      "id": "8e4c2a7b-1d5f-4a3e-9b6c-0f2d8e1a7c94",
      "value": "+1 415 555 0142",
      "kind": "mobile"
    }
  ],
  "locations": [
    {
      "id": "5d9f3b2e-8a1c-4e7d-a6b5-2c4f8d0e9a17",
      "street_number": null,
      "street": null,
      "apartment": null,
      "city": "Oakland",
      "state": "California",
      "state_code": "CA",
      "country": "United States",
      "country_code": "US",
      "time_zone": "America/Los_Angeles",
      "utc_offset": -7
    }
  ],
  "social_profiles": [
    {
      "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
      "network": "linkedin",
      "handle": "priyanatarajan"
    }
  ],
  "websites": [],
  "avatar": null,
  "tags": [
    {
      "id": "0f1e2d3c-4b5a-4968-8776-655443322110",
      "name": "Customer",
      "color": "#66b185",
      …
    }
  ]
}
get/contacts Read key

#List contacts

Returns the contacts visible to your key, 50 per page, highest priority first. Filter by a search query, by scope, by tags, or by a slice, and page forward through the result with a cursor.

The list holds people: contacts whose contact_type is connection. The automated slice lists mailing_list and notification contacts instead. colleague contacts are not listed.

Query parameters

  • querystring

    Match part of the contact’s name, background, or any of its email addresses. Up to 500 characters.

  • scopestring

    Restrict to global or personal contacts. Omit, or send any other value, to include both.

    globalpersonal
  • slicestring

    A preset filter. automated: mailing lists and notifications instead of people. latest: last contact within the past 30 days in at least one mailbox. lapsed: last contact more than 90 days ago in at least one mailbox. shared: contacts shared with your key’s user or their groups. tasked: contacts with an open task owned by your key’s user. pinned: contacts your key’s user has pinned. duplicated: contacts with possible duplicates.

    automatedlatestlapsedsharedtaskedpinnedduplicated
  • sortstringdefault priority

    Field to sort by. Any other value sorts by priority.

    prioritylast_contactthread_countname
  • orderstring

    Defaults to desc for priority, last_contact, and thread_count, and to asc for name. Any other value uses the default.

    ascdesc
  • tagsstring

    Comma-separated tag ids, at most 50.

  • tag_operatorstringdefault any

    Whether a contact must carry any of the given tags, or all of them.

    anyall
  • next_cursorstring

    Opaque token from the previous page’s page_info.next_cursor. Omit to start from the beginning. Send the same sort and order as on the first page. See Cursor pagination.

Returns

  • collectionobject

    A page of contacts and the cursor to the next one.

    Show 3 child attributesHide child attributes
    • recordsarray of contacts

      Up to 50 contacts in the requested order, with the list-only statistics and without the single-contact embeds.

    • page_infopage info

      Where this page sits in the full list. Pass next_cursor back to fetch the next page while has_more_after is true.

    • sort, order, slice_key, filtersnullable

      The sort, order, and slice you sent, and your query, scope, tags, and tag_operator as filters, echoed back. Null when you sent none. See the cursor collection.

Errors

  • 400invalid_requestA parameter is malformed, for example more than 50 tag ids or a query over 500 characters.
  • 400invalid_cursorThe cursor is unreadable, or came from another list or sort.
  • 400unsupported_cursor_directionA prev_cursor was sent. This list pages forward only.
get/contacts
curl "https://api.carom.io/contacts?sort=last_contact&tags=0f1e2d3c-4b5a-4968-8776-655443322110" \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response200
{
  "collection": {
    "filters": {
      "tags": "0f1e2d3c-4b5a-4968-8776-655443322110"
    },
    "sort": "last_contact",
    "page_info": {
      "limit": 50,
      "next_cursor": "Wd8Hs2Kq5Tn9Rz3Lb7Xv1Cp4Jm6Fy0Ea8Gu2Qe",
      "prev_cursor": null,
      "has_more_after": true,
      "has_more_before": false
    },
    "records": [
      {
        "id": "1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41",
        "name": "Priya Natarajan",
        "contact_type": "connection",
        "global": true,
        "priority": 3.68,
        "last_contact": "2026-09-04T21:17:09.332Z",
        …
      },
      {
        "id": "b7e1d4c9-2a6f-4e8b-9c3d-5f0a7b2e1d84",
        "name": "Tomás Ferreira",
        "contact_type": "connection",
        "global": true,
        "priority": 2.91,
        "last_contact": "2026-08-29T14:03:52.118Z",
        …
      }
    ]
  }
}
post/contacts Write key

#Create a contact

Creates a contact from whatever you know about a person. Provide a name, an email address, or both. The contact is personal to your key’s user until you make it global.

If one of the email addresses is already on another contact owned by your key’s user, the request fails with duplicate_association_record and nothing is created. Retrieve the existing contact and update it instead.

Request body application/json

  • contactobjectrequired
    Show 10 child attributesHide child attributes
    • namestring

      Required unless you supply at least one email address.

    • email_addressesarray of objects

      Each with a value. Carom stores addresses in lowercase.

    • contact_typestring

      Omit to have Carom classify the contact from its first email address. Without an email address, the contact is a connection.

      connectioncolleaguemailing_listnotification
    • backgroundstring

      Free-form notes about the person.

    • employmentsarray of objects

      A title and an organization. Link an existing organization by its id, or give a name without an id to create a new organization.

      Show 2 child attributesHide child attributes
      • titlestring
      • organizationobject
        Show 2 child attributesHide child attributes
        • idstring · uuid

          Id of an existing organization in your account, to link it. Other fields sent with id are ignored; to change the organization, use Update an organization.

        • namestring

          Name for a new organization. Required when id is omitted.

    • numbersarray of objects

      Each with a value (required) and an optional kind.

    • social_profilesarray of objects

      Each with a network and handle.

      linkedintwittergithubfacebookangellist
    • locationsarray of objects

      Each with any of street_number, street, apartment, city, state, and country_code.

    • websitesarray of objects

      Each with a url (required).

    • avatar_upload_idstring · uuid

      Id of an image you uploaded to use as the picture. On update, send null to remove the picture.

Returns

The new contact object, wrapped in contact, with status 201.

Errors

  • 400missing_name_or_emailNeither a name nor an email address was given.
  • 400missing_emailcontact_type was omitted and the first email address is blank.
  • 400duplicate_association_recordAn email address is already on another contact owned by your key’s user.
  • 400invalid_requestA field failed validation. error.fields says which. An organization id that isn’t a UUID or doesn’t name an organization in your account is reported on its employment’s index, such as employments.0.organization.id; an organization with neither id nor name, on employments.0.organization.name.
post/contacts
curl https://api.carom.io/contacts \
  -H "Authorization: Bearer $CAROM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contact": {
      "name": "Priya Natarajan",
      "contact_type": "connection",
      "email_addresses": [
        { "value": "priya@wildgrove.example" }
      ],
      "employments": [
        {
          "title": "VP Operations",
          "organization": {
            "id": "6b0e2d9a-4c31-4f8e-a7d2-90c4e1b7f5a3"
          }
        }
      ]
    }
  }'
Response201
{
  "contact": {
    "id": "1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41",
    "name": "Priya Natarajan",
    "contact_type": "connection",
    "global": false,
    "user_id": "9c41d2e8-3f6a-4b7c-8d1e-5a2f7b9c0d3e",
    "email_addresses": [
      {
        "id": "3a8d1e6f-52c4-4b9a-8e7d-1c0f9b2a4d63",
        "value": "priya@wildgrove.example",
        "primary": true
      }
    ],
    "employments": [
      {
        "id": "c2f7b4a1-9e3d-4c6b-b5a8-7d1e2f3a4b5c",
        "title": "VP Operations",
        "organization": {
          "id": "6b0e2d9a-4c31-4f8e-a7d2-90c4e1b7f5a3",
          "name": "Wildgrove Property Management"
        }
      }
    ],
    …
  }
}
get/contacts/{id} Read key

#Retrieve a contact

Returns a single contact with everything Carom knows about the person that is visible to your key: an interaction_histories entry for each mailbox that has corresponded with the person, comments, shares, up to five open tasks, up to three upcoming calendar events, and a timeline of recent activity.

Path parameters

  • idstring · uuidrequired

    The contact’s id.

Returns

The contact object, wrapped in contact, with these additional attributes. Here tasks holds at most five open tasks, soonest due first.

  • countsobject
    Show 2 child attributesHide child attributes
    • open_tasksinteger

      All open tasks attached to the contact that are visible to your key.

    • upcoming_eventsinteger

      Calendar events with the contact from today on.

  • eventsarray of calendar events

    Up to three upcoming calendar events with the contact.

  • timelineobject · nullable

    The contact’s recent activity, as an object with an items array of timeline items.

  • known_byarray of strings · uuid

    Ids of other users whose mailboxes have corresponded with this contact and share that knowledge with the account (interaction_sharing is knowledge), but whose statistics aren’t visible to your key. Ask them for access with a share request. Empty when there are none.

Errors

  • 404record_not_foundNo contact with that id is visible to your key.
get/contacts/{id}
curl https://api.carom.io/contacts/1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41 \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response200
{
  "contact": {
    "id": "1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41",
    "name": "Priya Natarajan",
    …
    "interaction_histories": [
      {
        "mailbox": { "id": "d4e5f6a7-b8c9-4d0e-9f1a-2b3c4d5e6f70", "email_address": "dana@harborline.example", "name": "Dana Whitfield", "user_id": "9c41d2e8-3f6a-4b7c-8d1e-5a2f7b9c0d3e" },
        "mailbox_id": "d4e5f6a7-b8c9-4d0e-9f1a-2b3c4d5e6f70",
        "thread_count": 42,
        "file_count": 7,
        "response_rate": 0.93,
        "priority": 3.68,
        "average_thread_lag": 5820,
        "average_thread_length": 3.4,
        "monthly_messages": {
          …
          "2026-08": 16,
          "2026-09": 3
        },
        "first_contact": "2025-11-18T16:02:41.207Z",
        "last_contact": "2026-09-04T21:17:09.332Z",
        …
      }
    ],
    "tasks": [
      {
        "id": "e7f8a9b0-c1d2-4e3f-8a4b-5c6d7e8f9a01",
        "assignment": "Send the Q4 renewal proposal",
        "due": "2026-09-12",
        …
      }
    ],
    "comments": […],
    "shares": [],
    "counts": {
      "open_tasks": 2,
      "upcoming_events": 1
    },
    "events": [
      { "id": "9b310b6a-d686-4b27-9af4-16f9734aec81", "name": "Wildgrove renewal review", … }
    ],
    "timeline": { "items": […] },
    "known_by": []
  }
}
patch/contacts/{id} Write key

#Update a contact

Changes the fields you send and leaves the rest alone. Nested collections such as email_addresses and employments are merged by id: include an id to change an existing entry, omit it to add a new one, and send "deleted": true to remove one.

Only the owner can edit a personal contact; anyone in the account can edit a global one. A request that sends name or email_addresses must leave the contact with at least one of them.

Path parameters

  • idstring · uuidrequired

Request body application/json

  • contactobjectrequired

    Any of the attributes accepted by Create a contact. Entries in nested collections take two more fields.

    Show 2 child attributesHide child attributes
    • idstring · uuid

      On a nested entry: the entry to change. Omit to add one.

    • deletedboolean

      On a nested entry: remove it.

Returns

The updated contact object, wrapped in contact.

Errors

  • 400missing_name_or_emailThe request sends name or email_addresses, but neither has a value.
  • 400duplicate_association_recordAn email address is already on another contact owned by your key’s user.
  • 400invalid_requestA field failed validation, as on Create a contact, or a nested entry’s id isn’t a UUID. error.fields says which.
  • 403permission_deniedThe contact is visible to your key but not editable by it, for example a personal contact another user shared with your key’s user.
  • 404record_not_foundNo contact with that id is visible to your key.
patch/contacts/{id}
curl -X PATCH https://api.carom.io/contacts/1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41 \
  -H "Authorization: Bearer $CAROM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contact": {
      "background": "Runs operations across Wildgrove's 14 properties. Prefers a call to a long thread.",
      "numbers": [
        { "value": "+1 415 555 0142", "kind": "mobile" },
        { "id": "8e4c2a7b-1d5f-4a3e-9b6c-0f2d8e1a7c94", "deleted": true }
      ]
    }
  }'
Response200
{
  "contact": {
    "id": "1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41",
    "name": "Priya Natarajan",
    "background": "Runs operations across Wildgrove's 14 properties. Prefers a call to a long thread.",
    "numbers": [
      {
        "id": "2b6d9f1c-4e8a-4c3b-a7d5-9e0f1a2b3c4d",
        "value": "+1 415 555 0142",
        "kind": "mobile"
      }
    ],
    …
  }
}
delete/contacts/{id} Write key

#Delete a contact

Permanently deletes a contact. Only the owner can delete a personal contact. Only an account admin can delete a global contact, even one your key’s user created.

The contact’s email addresses, numbers, locations, employments, social profiles, websites, and picture are deleted with it, and so are the tasks attached to it, the comments on it, and its pins, shares, share requests, and duplicate pairs. It is removed from its tags and spaces. Pending proposals about the contact or its tasks expire. Threads and files are not changed.

A contact that is the counterparty of a deal can’t be deleted, including deals in pipelines your key can’t see. Delete the deal or change its counterparty first.

Path parameters

  • idstring · uuidrequired

Returns

An empty response with status 204.

Errors

  • 403permission_deniedThe contact is visible to your key but your key’s user can’t delete it: a personal contact they don’t own, or a global contact when they aren’t an account admin.
  • 404record_not_foundNo contact with that id is visible to your key.
  • 409contact_has_dealsThe contact is the counterparty of at least one deal. Nothing was deleted.
delete/contacts/{id}
curl -X DELETE https://api.carom.io/contacts/4c7a1e9d-3b5f-4d2e-8a6c-0b9d7e5f3a21 \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response204
No content
get/contacts/count Read key

#Count contacts

Counts the contacts that List contacts would return for the same filters, without fetching them. Counting stops at cap when you give one, which keeps the call fast on large accounts.

Query parameters

  • query, scope, slice, tags, tag_operator

    As on List contacts.

  • capinteger

    Stop counting at this many. When more contacts match, total equals cap and exact is false. A value of 0 or less is ignored.

Returns

  • countcount
    Show 4 child attributesHide child attributes
    • totalinteger
    • exactboolean

      False when counting stopped at cap.

    • cappedboolean

      True when counting stopped at cap.

    • capinteger · nullable

      The cap that applied. Null when you sent none, or sent zero or a negative number.

Errors

  • 400invalid_requestA parameter is malformed, as on List contacts.
get/contacts/count
curl "https://api.carom.io/contacts/count?scope=global&cap=1000" \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response200
{
  "count": {
    "total": 418,
    "exact": true,
    "capped": false,
    "cap": 1000
  }
}
patch/contacts/{id}/global Write key

#Make a contact global

Makes a personal contact global, so everyone in the account can see and edit it. Only the contact’s owner (user_id) can do this. The change is one-way: a global contact can’t be made personal again, and the API refuses with cannot_unglobalize.

Path parameters

  • idstring · uuidrequired

Request body application/json

  • globalbooleanrequired

    true to make the contact global. false is accepted only for a contact that is already personal, and changes nothing.

Returns

The contact object with its new global value, wrapped in contact.

Errors

  • 400cannot_unglobalizeglobal is false and the contact is already global.
  • 403permission_deniedYour key’s user doesn’t own the contact.
  • 404record_not_foundNo contact with that id is visible to your key.
patch/contacts/{id}/global
curl -X PATCH https://api.carom.io/contacts/1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41/global \
  -H "Authorization: Bearer $CAROM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "global": true }'
Response200
{
  "contact": {
    "id": "1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41",
    "global": true,
    "user_id": "9c41d2e8-3f6a-4b7c-8d1e-5a2f7b9c0d3e",
    …
  }
}
post/contacts/{id}/merge Write key

#Merge contacts

Merges one or more contacts into the contact at {id}. Their email addresses, numbers, profiles, employments, websites, locations, tasks, comments, shares, tags, pins, deals, and space memberships move to the target; entries the target already has are dropped, and the source’s picture moves only if the target has none. When the target has no name or background, it takes them from a source, and it becomes global if any source was global. The sources are then deleted. Their ids stop resolving, so update any you have stored.

Your key’s user must be able to edit every contact involved. Carom flags likely duplicates with has_duplicates on the contact object. Merging is permanent.

Path parameters

  • idstring · uuidrequired

    The contact to keep.

Request body application/json

  • contact_idsarray of strings · uuidrequired

    The contacts to merge into the target, at most 10. Don’t include the target itself.

Returns

The merged contact object, wrapped in contact.

Errors

  • 400missing_source_contactscontact_ids is empty.
  • 400invalid_requestcontact_ids is missing, isn’t an array of UUIDs, or holds more than 10 ids.
  • 403contacts_not_editableYour key’s user can’t edit one of the contacts involved.
  • 404record_not_foundThe target or one of the contact_ids isn’t a contact visible to your key.
  • 409target_in_sourcescontact_ids includes the target contact.
post/contacts/{id}/merge
curl https://api.carom.io/contacts/1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41/merge \
  -H "Authorization: Bearer $CAROM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "contact_ids": ["4c7a1e9d-3b5f-4d2e-8a6c-0b9d7e5f3a21"] }'
Response200
{
  "contact": {
    "id": "1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41",
    "name": "Priya Natarajan",
    "has_duplicates": false,
    "email_addresses": [
      {
        "id": "3a8d1e6f-52c4-4b9a-8e7d-1c0f9b2a4d63",
        "value": "priya@wildgrove.example",
        "primary": true
      },
      {
        "id": "7e2b5c8d-9f1a-4b3e-8d6c-4a0f2e9b1c75",
        "value": "pnatarajan@gmail.example",
        "primary": false
      }
    ],
    …
  }
}
get/contacts/{id}/discussion Read key

#Retrieve a contact’s discussion

Returns the comments your team has left on this contact and on the deals where the contact is the counterparty, grouped into scopes: one for the contact itself, then one for its deals when at least one of them has comments. Comments are internal; the contact never sees them.

To post a comment on the contact, use Create a comment.

Path parameters

  • idstring · uuidrequired

Returns

  • discussionobject
    Show 1 child attributeHide child attributes
    • scopesarray of objects · nullable

      The contact’s own scope first, then its deals.

      Show 6 child attributesHide child attributes
      • keystring · nullable
        contactdeals
      • labelstring · nullable

        A display name for the scope, such as This contact.

      • unitstring · nullable

        The plural noun for the scope’s records, such as deals.

      • primaryboolean · nullable

        True for the contact’s own scope.

      • total_commentsinteger · nullable
      • recordsarray of objects · nullable

        The records in the scope that have comments, most recently discussed first. The contact’s own scope always holds the contact, even with no comments.

        Show 6 child attributesHide child attributes
        • keystring · nullable

          record_type and record_id joined with a hyphen.

        • record_typestring · nullable
          contactdeal
        • record_idstring · uuid · nullable
        • namestring · nullable
        • total_commentsinteger · nullable
        • commentsarray of comments · nullable

          Oldest first.

Errors

  • 404record_not_foundNo contact with that id is visible to your key.
get/contacts/{id}/discussion
curl https://api.carom.io/contacts/1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41/discussion \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response200
{
  "discussion": {
    "scopes": [
      {
        "key": "contact",
        "label": "This contact",
        "unit": "people",
        "primary": true,
        "total_comments": 1,
        "records": [
          {
            "key": "contact-1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41",
            "record_type": "contact",
            "record_id": "1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41",
            "name": "Priya Natarajan",
            "total_comments": 1,
            "comments": [
              {
                "id": "a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d",
                "html_content": "<p>Priya needs the renewal numbers before the 15th. She's out the week after.</p>",
                "user_id": "9c41d2e8-3f6a-4b7c-8d1e-5a2f7b9c0d3e",
                "contact_id": "1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41",
                "created_at": "2026-09-03T18:44:12.618Z",
                …
              }
            ]
          }
        ]
      }
    ]
  }
}