← All action domains

Contacts

71 operations. Call each with POST https://app.chirply.io/api/v1/actions/<name> and a bearer token; the response is { "data": { "action", "summary", "result" } }. A read badge means the operation changes nothing; write requires the credential’s write scope.

Add contact email address

contacts.add_email_addresswrite

Add an email address to a contact. It becomes primary automatically when it is the contact's first address; pass primary=true to make it the address campaigns, automations and merge tokens send to. Saves CRM data only — it sends nothing and costs nothing. Refused if the address already belongs to a different contact in this account, since one address identifies one person.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)requiredThe contact receiving the email address.
emailstringrequiredThe email address to save.
labelstring (or null)optionalOptional free-text label — "work", "billing", "old Gmail". Null or omitted means unlabelled.
primarybooleanoptionalMake this the primary address. The first address becomes primary regardless of this value. Default: false

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.add_email_address \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11",
    "email": "ada@example.com"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_add_email_address at https://app.chirply.io/api/mcp, same bearer token, same input.

Add a note

contacts.add_notewrite

Add a free-text note to a contact's, company's or deal's activity timeline. Attach it to at least one of them.

Parameters

FieldTypeRequiredDescription
bodystringrequiredThe note text.
contact_idstring (uuid)optionalContact to attach the note to.
company_idstring (uuid)optionalCompany to attach the note to.
deal_idstring (uuid)optionalDeal to attach the note to.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.add_note \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "example"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_add_note at https://app.chirply.io/api/mcp, same bearer token, same input.

Add phone number

contacts.add_phone_numberwrite

Add a phone number to a contact. It becomes primary automatically when it is the contact's first number; pass primary=true to make it the number used by existing calls, texts and merge tokens. This saves CRM data but sends nothing and costs nothing.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)requiredThe contact receiving the phone number.
phonestringrequiredThe phone number in a common format; stored as E.164 when unambiguous.
phone_type"mobile" | "landline" | "voip" (or null)optionalThe line type. Use null or omit when it has not been classified.
primarybooleanoptionalMake this the primary number. The first number becomes primary regardless of this value. Default: false

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.add_phone_number \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11",
    "phone": "+15551234567"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_add_phone_number at https://app.chirply.io/api/mcp, same bearer token, same input.

Tag contacts

contacts.add_tagswriteconfirm

Add one or more existing tags to one or more contacts. Idempotent — a tag a contact already has is left alone, and fires nothing. SECOND-ORDER EFFECT: every tag that is genuinely new on a contact enqueues a 'Tag added' automation event, so tagging 200 contacts can start 200 automation runs that send real email and SMS to real people, billed to the org's own Mailgun/Twilio account. Removing the tag afterwards does not unsend them. 'Tag added' is the single most common automation trigger in this product, so assume something is listening.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
contact_idsarray of (string (uuid))requiredContact ids to act on. Ids outside this org are ignored.
tag_idsarray of (string (uuid))requiredTag ids to add (create them first with contacts.create_tag).

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.add_tags \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ],
    "tag_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ]
  }'
Test with your API key

Over MCP the same operation is the tool contacts_add_tags at https://app.chirply.io/api/mcp, same bearer token, same input.

Get AI context

contacts.ai_contextread

Assemble everything this account knows about one contact into a single AI-ready bundle for generating a page, email, or reply personalized to this exact person: their profile and custom fields, tags, open deals and tasks, recent messages, their website behavior (first-touch source, page-view totals, recent pages viewed), and their call history INCLUDING past-call transcripts and AI-call summaries. Also returns `prompt` — a ready-to-paste plain-text briefing, the same caller file the AI phone agent uses — so a server can drop it straight into a model prompt. Read-only and spends NO AI credit (it only reads stored data). The response is SENSITIVE: it contains call transcripts and private notes, so treat it exactly like the contact record itself and never expose it to an unauthenticated browser. A `context_token` can also name a contact owned by a DIFFERENT account — an affiliate who sent their own contact to this account's page — and that only resolves while the owning account has contact-context sharing switched on for this one; revoking it takes effect on the next call.

Parameters

FieldTypeRequiredDescription
idstring (uuid)optionalThe contact to assemble context for. Provide this OR context_token.
context_tokenstringoptionalA short-lived handoff token minted by the tracking script's chirply.getContext() (its `contextToken` field). Redeem it here to load the visitor a page just identified, without the browser ever seeing the internal contact id. Only the account the token was minted FOR can redeem it. Provide this OR id.
include_transcriptsbooleanoptionalInclude condensed text of past-call transcripts. Turn off for a lighter, less-sensitive bundle that keeps only call summaries and outcomes. Default: true
include_webbooleanoptionalInclude the contact's website-tracking activity (first-touch attribution, page-view totals, and recent page views). Default: true

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.ai_context \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11",
    "context_token": "example"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_ai_context at https://app.chirply.io/api/mcp, same bearer token, same input.

Assign to a teammate

contacts.assignwrite

Record which teammate every listed contact belongs to, or release them by passing null. This is bookkeeping, not a permission: it does not hide the contacts from anyone else and does not change what the assignee can do. It is what the contacts list's owner column, the inbox's Mine view and owner-based reporting read, and what an employee means when they say 'my leads'. Sends nothing and notifies nobody.

Parameters

FieldTypeRequiredDescription
contact_idsarray of (string (uuid))requiredContact ids to act on. Ids outside this org are ignored.
owner_user_idstring (uuid) (or null)requiredThe teammate's user id, from team.list_members. They must already be a member of this account. Null clears the owner, which is how a departing employee's contacts are handed back.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.assign \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ],
    "owner_user_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_assign at https://app.chirply.io/api/mcp, same bearer token, same input.

Assign everyone who uses a line

contacts.assign_by_numberwrite

Record that every contact who has called, texted or been reached on one of the account's phone numbers belongs to a teammate — the bulk version of handing somebody a line along with the people who ring it. Looks at the contacts on that number's existing calls and messages, so it reflects history at the moment it runs and does NOT keep assigning new arrivals; a number's own Belongs to setting does that going forward. Passing null releases them. Bookkeeping only: it hides nothing from anyone and sends nothing.

Parameters

FieldTypeRequiredDescription
phone_number_idstring (uuid)requiredOne of the account's phone numbers, from numbers.list.
owner_user_idstring (uuid) (or null)requiredThe teammate to assign them to, from team.list_members, or null to clear the owner on all of them.
limitintegeroptionalMost contacts to assign in one call, from one to five thousand. A line with more history than this assigns the most recent and reports how many were left, so run it again to continue. Default: 2000

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.assign_by_number \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11",
    "owner_user_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_assign_by_number at https://app.chirply.io/api/mcp, same bearer token, same input.

Delete selected contacts

contacts.bulk_deletewriteconfirm

Permanently delete every listed contact, along with their tags, notes and activity timelines. This cannot be undone.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
contact_idsarray of (string (uuid))requiredContact ids to act on. Ids outside this org are ignored.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.bulk_delete \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ]
  }'
Test with your API key

Over MCP the same operation is the tool contacts_bulk_delete at https://app.chirply.io/api/mcp, same bearer token, same input.

Email many contacts at once

contacts.bulk_emailwriteconfirm

Immediately queues a personalized email to every listed contact that has an email address, each into their own conversation thread — real email, sent through this account's own connected provider (Mailgun/Resend) and billed to it. Subject and body support {{merge_fields}} and are rendered per contact. Send from one address, or from an email POOL to rotate across several. The send runs as a background job so it can be paced, watched, paused or stopped; pass start_at to schedule it for later instead of sending now. Through a pool, the members' warmup allowance is a HARD ceiling on today's volume whatever pace is requested — the job sends what the ramp permits and resumes after midnight UTC, so a large list cannot burn a set of new mailboxes on day one. Contacts without an email address are skipped, not failed.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
contact_idsarray of (string (uuid))requiredContact ids to act on. Ids outside this org are ignored.
subjectstringrequiredThe subject line. Supports merge fields, e.g. {{first_name}}.
bodystringrequiredThe message body. Supports merge fields, e.g. {{first_name}}.
email_identity_idstring (uuid) (or null)optionalWhich of the account's verified sending addresses to send FROM (see email_routing capabilities). Omit or null to use each contact's own sender preference, falling back to the account default address. Ignored when email_pool_id is set.
email_pool_idstring (uuid) (or null)optionalSend through an email pool instead of one address, rotating across its members least-used-first and steering every reply to the pool's reply-to. Wins over email_identity_id. The pool's warmup allowance caps how much goes out per day.
include_signaturebooleanoptionalAppend the sender's email signature to every message, exactly as a one-to-one reply would. Defaults to true. Set false for a send that already carries its own sign-off. Default: true
start_atstring (date-time) (or null)optionalWhen this should START, as an ISO 8601 timestamp with a timezone (e.g. 2026-08-20T14:00:00Z). Omit or null to start immediately. A time in the past starts immediately. The job waits in the account's Jobs list until then and can be rescheduled or canceled before it starts.
per_minuteinteger (or null)optionalCap on items sent per minute. null removes the per-minute cap.
per_hourinteger (or null)optionalCap on items sent per hour. null removes the per-hour cap.
per_dayinteger (or null)optionalCap on items sent per day. null removes the per-day cap.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.bulk_email \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ],
    "subject": "Example",
    "body": "example"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_bulk_email at https://app.chirply.io/api/mcp, same bearer token, same input.

Load contact action options

contacts.bulk_optionsread

Read the account's available bulk contact actions, message templates, sending addresses, sender pool capacity, and automation options. Does not send messages, enroll contacts, or spend money.

Parameters

No parameters — POST an empty body.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.bulk_options \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{}'
Test with your API key

Over MCP the same operation is the tool contacts_bulk_options at https://app.chirply.io/api/mcp, same bearer token, same input.

Text many contacts at once

contacts.bulk_smswriteconfirm

Immediately queues a personalized SMS to every listed contact that has a phone number, each into their own conversation thread — real texts, sent and billed through its own Twilio account. The body supports {{merge_fields}} and is rendered per contact. The send runs as a background job so it can be paced, watched, paused or stopped; pass start_at to schedule it for later instead of sending now. Contacts without a phone number are skipped, not failed.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
contact_idsarray of (string (uuid))requiredContact ids to act on. Ids outside this org are ignored.
bodystringrequiredThe message text. Supports merge fields, e.g. {{first_name}}.
from_addrstringoptionalThe E.164 number to send FROM. Must be one of this account's active numbers; anything else falls back to its default outbound number.
start_atstring (date-time) (or null)optionalWhen this should START, as an ISO 8601 timestamp with a timezone (e.g. 2026-08-20T14:00:00Z). Omit or null to start immediately. A time in the past starts immediately. The job waits in the account's Jobs list until then and can be rescheduled or canceled before it starts.
per_minuteinteger (or null)optionalCap on items sent per minute. null removes the per-minute cap.
per_hourinteger (or null)optionalCap on items sent per hour. null removes the per-hour cap.
per_dayinteger (or null)optionalCap on items sent per day. null removes the per-day cap.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.bulk_sms \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ],
    "body": "example"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_bulk_sms at https://app.chirply.io/api/mcp, same bearer token, same input.

Brief me before I call

contacts.call_previewread

Everything worth knowing about a contact in the seconds before you phone them: who they are and where they work, why they are in the CRM, their last few calls with the outcome and the note whoever made them left, any follow-up task that is now overdue, their open deals, their tags and their CRM notes. This is the same brief the power dialer shows a rep on its preview card, so an agent and the person on the phone are looking at the same facts. Read-only — it starts no call, sends nothing, and spends no money. Pass several ids to brief a whole run of calls in one request.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)optionalThe contact to brief on. Use this or contact_ids, not both.
contact_idsarray of (string (uuid))optionalSeveral contacts to brief on at once, up to 25. Contacts that do not exist are left out of the answer rather than failing the whole request.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.call_preview \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_call_preview at https://app.chirply.io/api/mcp, same bearer token, same input.

Get communication context

contacts.communication_contextread

Read a contact's lifetime communication totals by channel and direction, provider phone duration, completed AI session duration and live AI session elapsed time, optionally for one agent. Page through complete email/text bodies, website chats, call transcripts and AI transcripts without truncation. Sensitive private history is scoped to this account. Counts distinguish exchanged messages from pending/failed outbound attempts. Elapsed session time includes pauses; it is not measured speech time. Read-only; sends nothing and spends no AI credit.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)requiredContact in this account whose communication history to read.
section"summary" | "messages" | "calls" | "ai_calls" | "live_chat" | "campaigns"optionalLifetime totals or a page of complete stored communication records, including website live chat and campaign delivery ledgers. Campaigns do not retain exact delivered message bodies. Default: "summary"
agent_idstring (uuid)optionalOptional AI agent in this account; adds this agent's cumulative session duration and active sessions to the summary.
offsetintegeroptionalRow offset from next_offset; advance only after all character pages are read. Default: 0
character_offsetintegeroptionalCharacter offset from next_character_offset for the same row; reset to zero when advancing rows. Default: 0

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.communication_context \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_communication_context at https://app.chirply.io/api/mcp, same bearer token, same input.

Create a contact

contacts.createwriteconfirm

Create a contact. Requires at least a name, business name, or email. Email addresses and normalized phone numbers are unique within the organization: if another contact already holds either identity, this fails with a conflict naming that contact rather than creating a duplicate — update that one instead. SECOND-ORDER EFFECT: a successful create fires the org's 'Contact created' automations, so a 'welcome every new lead' workflow can send this person a real email or SMS on the org's own Mailgun/Twilio account, at the org's own cost, with no further step. DOUBLE OPT-IN: when the account requires email confirmation for API contacts (or for hand-added ones, when `source` is `staff`), a new contact with an email is held off marketing email and IMMEDIATELY sent a real confirmation email from the account's own sending address; the result's `double_opt_in` says what happened.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
first_namestringoptionalGiven name.
last_namestringoptionalFamily name.
business_namestringoptionalBusiness name — the display name for company-shaped leads.
facebook_idstringoptionalStable Facebook person/friend id. Unique within this organization.
emailstring (email)optionalEmail address. Unique within this organization — it identifies the person.
phonestringoptionalPhone number, in any format; normalized to E.164 before it is stored. Unique within this organization — it identifies the person.
websitestringoptionalWebsite URL.
yelp_urlstringoptionalPublic Yelp listing URL for this business, e.g. https://www.yelp.com/biz/… Kept separate from `website` because a Yelp-sourced lead often has no site of its own.
titlestringoptionalJob title.
birthdaystring (date)optionalDate of birth as YYYY-MM-DD. Birthday automations recur from its month and day.
sourcestringoptionalWhere this contact came from — a channel slug shown on their record and used by the Source filter. One of: referral, phone_call, walk_in, event, advertisement, social_media, staff (a person typed them in), other. Defaults to `api`, meaning this call created them; set it when you know better, because a contact whose origin reads 'Unknown' is one nobody trusts.
source_detailmap of string → objectoptionalThe specifics behind `source`, shown as a line under it on the record — e.g. {"note": "referred by Dana Ortiz"}. Free-form; short strings only.
lifecyclestringoptionalLifecycle stage key, e.g. 'lead', 'trial', 'active', 'customer', 'churned'. The org defines its own set — call contacts.list_lifecycles for the valid keys. Default: "lead"
company_idstring (uuid)optionalCompany this contact works at.
owner_idstring (uuid)optionalUser id of the team member who owns the relationship.
addressobjectoptionalPostal address with separate street, city, state, and ZIP / postal code fields.
address.line1stringoptionalStreet address.
address.line2stringoptionalSuite / unit.
address.citystringoptionalCity.
address.statestringoptionalState or province.
address.postal_codestringoptionalZIP / postal code.
address.countrystringoptionalCountry.
notesstringoptionalFree-text notes on the record, visible to the whole account.
custommap of string → objectoptionalCustom-field values keyed by `custom_field_defs.key` (see contacts.list_fields). Replaces the whole blob — send the merged object.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.create \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Ada",
    "last_name": "Lovelace"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_create at https://app.chirply.io/api/mcp, same bearer token, same input.

Create a custom field

contacts.create_fieldwrite

Define a new custom field on contacts, companies or deals. The storage key is derived from the label and is unique per record type — a second field with the same derived key fails.

Parameters

FieldTypeRequiredDescription
entity"contact" | "company" | "deal"requiredWhich record type the field lives on.
labelstringrequiredThe field label shown in the app.
type"text" | "textarea" | "number" | "date" | "select" | "multiselect" | … 3 moreoptionalHow the value is entered and rendered. "user" (Team member) holds one account member — their user id — and is available on deals only. Default: "text"
optionsstring[]optionalChoices for select/multiselect fields. Default: []
requiredbooleanoptionalWhether the app's form requires it. Default: false

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.create_field \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "entity": "contact",
    "label": "example"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_create_field at https://app.chirply.io/api/mcp, same bearer token, same input.

Create custom fields for unmapped columns

contacts.create_fieldswrite

Create several contact custom fields in one operation, primarily for CSV headers that have nowhere to map. Existing contact fields with the same derived key are returned instead of duplicated; no contact values are changed.

Parameters

FieldTypeRequiredDescription
fieldsobject[]requiredThe contact custom fields to create.
fields[].labelstringrequiredField label, usually the CSV column header.
fields[].type"text" | "textarea" | "number" | "date" | "select" | "multiselect" | … 3 moreoptionalHow imported values should be stored and rendered. Not "user" — Team member fields are deals-only. Default: "text"

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.create_fields \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": [
      {
        "label": "example"
      }
    ]
  }'
Test with your API key

Over MCP the same operation is the tool contacts_create_fields at https://app.chirply.io/api/mcp, same bearer token, same input.

Create lifecycle stage

contacts.create_lifecyclewriteadmin only

Add a lifecycle stage this organization can assign to contacts. This changes CRM configuration only and does not move any contacts.

Parameters

FieldTypeRequiredDescription
labelstringrequiredThe stage name people will see, for example Qualified.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.create_lifecycle \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "example"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_create_lifecycle at https://app.chirply.io/api/mcp, same bearer token, same input.

Create a tag

contacts.create_tagwrite

Create a contact tag. Tag names are unique per organization — creating one that already exists fails.

Parameters

FieldTypeRequiredDescription
namestringrequiredThe tag name.
colorstringoptionalHex colour the tag renders in, e.g. '#64748b'. Default: "#64748b"

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.create_tag \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Example"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_create_tag at https://app.chirply.io/api/mcp, same bearer token, same input.

Delete a contact

contacts.deletewriteconfirm

Permanently delete a contact and everything that cascades off them — tags, notes and the whole activity timeline. This cannot be undone.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
idstring (uuid)requiredThe contact to delete.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.delete \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_delete at https://app.chirply.io/api/mcp, same bearer token, same input.

Remove contact email address

contacts.delete_email_addresswriteconfirm

Permanently remove one email address from a contact. If it is primary, the oldest remaining address is promoted automatically; if none remain, email can no longer reach this contact at all. This cannot be undone and sends nothing.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)requiredThe contact that owns the email address.
email_idstring (uuid)requiredThe saved email address to remove permanently.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.delete_email_address \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11",
    "email_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_delete_email_address at https://app.chirply.io/api/mcp, same bearer token, same input.

Delete a custom field

contacts.delete_fieldwriteconfirm

Permanently delete a custom-field definition. The app stops showing and collecting it; values already stored in each record's `custom` blob become unreachable. This cannot be undone.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
idstring (uuid)requiredThe field definition to delete.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.delete_field \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_delete_field at https://app.chirply.io/api/mcp, same bearer token, same input.

Delete lifecycle stage

contacts.delete_lifecyclewriteconfirmadmin only

Permanently remove a custom lifecycle stage, but only when no contacts still use it. System stages cannot be removed. This cannot be undone.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
keystringrequiredStable key of the custom lifecycle stage to remove.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.delete_lifecycle \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "example"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_delete_lifecycle at https://app.chirply.io/api/mcp, same bearer token, same input.

Remove phone number

contacts.delete_phone_numberwriteconfirm

Permanently remove one phone number from a contact. If it is primary, the oldest remaining number is promoted automatically; if none remain, calling and SMS flows can no longer reach this contact. This cannot be undone and sends nothing.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)requiredThe contact that owns the phone number.
phone_idstring (uuid)requiredThe saved phone number to remove permanently.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.delete_phone_number \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11",
    "phone_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_delete_phone_number at https://app.chirply.io/api/mcp, same bearer token, same input.

Delete a tag

contacts.delete_tagwriteconfirm

Permanently delete a tag and strip it from every contact that carries it. This cannot be undone; the contacts themselves are kept.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
idstring (uuid)requiredThe tag to delete.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.delete_tag \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_delete_tag at https://app.chirply.io/api/mcp, same bearer token, same input.

Draft a follow-up

contacts.draft_follow_upwriteconfirm

Draft a ready-to-send follow-up message for a contact, grounded in their history. Returns the text only — it does NOT send anything; pass it to contacts.send_sms or contacts.send_email to actually reach them. With channel 'email' it also returns a subject line. It SPENDS MONEY: the request is billed to the account's own OpenRouter key.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
idstring (uuid)requiredThe contact to write to.
instructionstringoptionalOptional steer, e.g. 'mention the demo next week'.
channel"email" | "sms"optionalWhat the draft is for. 'email' also returns a subject line and writes at email length; 'sms' (the default) returns a message body only.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.draft_follow_up \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_draft_follow_up at https://app.chirply.io/api/mcp, same bearer token, same input.

Add contacts to automation

contacts.enroll_in_automationwriteconfirm

Start a durable automation run for each listed contact. The first step begins immediately, waits resume later, and later steps may send real texts, emails, voicemails, calls, or API requests at the org's expense. Paused automations may be started manually; pausing only prevents event-triggered enrollment.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
workflow_idstring (uuid)requiredThe workflow (automation) to run.
contact_idsarray of (string (uuid))requiredContact ids to act on. Ids outside this org are ignored.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.enroll_in_automation \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "workflow_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11",
    "contact_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ]
  }'
Test with your API key

Over MCP the same operation is the tool contacts_enroll_in_automation at https://app.chirply.io/api/mcp, same bearer token, same input.

Find a contact by Facebook ID

contacts.find_by_facebook_idread

Look up the org's contact by the stable Facebook person/friend id supplied by Friender or another integration. Returns null when no contact holds that id.

Parameters

FieldTypeRequiredDescription
facebook_idstringrequiredStable Facebook person/friend id.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.find_by_facebook_id \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "facebook_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_find_by_facebook_id at https://app.chirply.io/api/mcp, same bearer token, same input.

Find a contact by phone number

contacts.find_by_phoneread

Look up the org's contact at a phone number, matched on any spelling of it ('4098930064', '+14098930064' and '(409) 893-0064' are the same person). Returns null when nobody holds that number. Use this before creating a contact from a call or a text.

Parameters

FieldTypeRequiredDescription
phonestringrequiredThe phone number, in any format.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.find_by_phone \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+15551234567"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_find_by_phone at https://app.chirply.io/api/mcp, same bearer token, same input.

Open a contact

contacts.getread

Fetch one contact by id, with every field, assigned tags, phone numbers, and a Facebook profile URL when a valid ID or username is saved. Read-only; sends no messages and spends no money.

Parameters

FieldTypeRequiredDescription
idstring (uuid)requiredThe contact's id.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.get \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_get at https://app.chirply.io/api/mcp, same bearer token, same input.

Columns

contacts.get_column_layoutread

Read which columns you see on the contacts list and in what order, plus every column this organization could show (built-ins and its custom fields). Personal to you — it does not affect what teammates see. Returns the defaults when you have never changed them.

Parameters

No parameters — POST an empty body.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.get_column_layout \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{}'
Test with your API key

Over MCP the same operation is the tool contacts_get_column_layout at https://app.chirply.io/api/mcp, same bearer token, same input.

Import contacts

contacts.importwriteconfirm

Bulk-create contacts from a list of records — the machine intake path (CSV/lead imports). Unlike contacts.create, a row whose email or phone already matches an existing contact does NOT error and does NOT duplicate: it is reported as matched. First added is replaced on matches only when created_at_overwrite is explicitly supplied. New contacts enqueue Contact created automation events. Applying tags or joining lists can also trigger active automations that send real email or SMS at the account's provider cost. Review active automations before importing. DOUBLE OPT-IN: when the account requires email confirmation for imports, every NEW contact with an email is held off marketing email and queued a real confirmation email from the account's own sending address (sent over the following minutes/hours); matched contacts are untouched.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
contactsobject[]requiredThe records to import.
contacts[].created_atstringoptionalOriginal First added for new contacts. YYYY-MM-DD means midnight UTC; timestamps must include a timezone. Blank uses import time.
contacts[].created_at_overwritestringoptionalExplicitly replace First added on matched contacts too. Same ISO date format as created_at. Map only one date field; blank preserves an existing date.
contacts[].first_namestringoptionalGiven name.
contacts[].last_namestringoptionalFamily name.
contacts[].business_namestringoptionalBusiness name.
contacts[].emailstring (email)optionalEmail address.
contacts[].phonestringoptionalPhone number, in any format.
contacts[].websitestringoptionalWebsite URL.
contacts[].yelp_urlstringoptionalPublic Yelp listing URL.
contacts[].titlestringoptionalJob title.
contacts[].sourcestringoptionalWhere this record came from; overrides the batch-level `source`.
contacts[].lifecyclestringoptionalLifecycle stage; defaults to lead.
contacts[].company_idstring (uuid)optionalCompany to attach them to.
contacts[].owner_idstring (uuid)optionalUser id who owns the relationship.
contacts[].addressobjectoptionalPostal address with separate street, city, state, and ZIP / postal code fields.
contacts[].address.line1stringoptionalStreet address.
contacts[].address.line2stringoptionalSuite / unit.
contacts[].address.citystringoptionalCity.
contacts[].address.statestringoptionalState or province.
contacts[].address.postal_codestringoptionalZIP / postal code.
contacts[].address.countrystringoptionalCountry.
contacts[].notesstringoptionalFree-text notes.
contacts[].custommap of string → objectoptionalCustom-field values keyed by `custom_field_defs.key` (see contacts.list_fields). Replaces the whole blob — send the merged object.
sourcestringoptionalChannel slug stamped on every contact created by this batch. Defaults to `bulk` (File import), which is what the in-app CSV importer uses. Default: "bulk"
source_detailmap of string → objectoptionalWhere this batch came from, shown under the source on each record — e.g. {"file": "jan-tradeshow.csv", "rows": 412}. Without it these contacts read as an unexplained pile.
tag_idsarray of (string (uuid))optionalTags applied to every contact this import touches — the new ones AND the existing ones a row matched. The usual way to find a batch again afterwards.
list_idsarray of (string (uuid))optionalStatic contact lists every new or matched contact should join.
owner_idstring (uuid)optionalFallback owner for records that don't carry one.
lifecyclestringoptionalFallback lifecycle for records that don't carry one; defaults to lead.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.import \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contacts": [
      {}
    ]
  }'
Test with your API key

Over MCP the same operation is the tool contacts_import at https://app.chirply.io/api/mcp, same bearer token, same input.

Import contacts from a file

contacts.import_csvwriteconfirm

Queue a durable background contact import from raw CSV text — the same job the Contacts screen starts. Returns immediately with a job id; the import continues if the caller disconnects and progress is available through contacts.list_import_jobs. The first row must be headers; obvious contact columns are matched automatically and explicit mapping can override them. A full_name column is split at the first word into first_name and the remaining last_name. Street, city, state, and postal-code columns populate the structured contact address. Existing contacts are matched by email or phone. Map created_at for original First added on new contacts, or created_at_overwrite to replace this date on matches too; other existing fields stay unchanged. New contacts enqueue Contact created automation events. Applying tags or joining lists can also trigger active automations that send real email or SMS at the account's provider cost. Review active automations before importing. The job continues after the caller disconnects.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
csvstringrequiredThe CSV text, header row first. Quoted fields and embedded newlines are handled.
file_namestringoptionalWhat to call this import on each contact's record, e.g. 'jan-tradeshow.csv'. Shown under their source.
mappingmap of string → stringoptionalOverride the automatic header matching: {"<header in the file>": "<contact field>"}. Fields: full_name, first_name, last_name, business_name, email, phone, website, yelp_url, title, address, street, city, state, postal_code, notes, lifecycle, created_at, created_at_overwrite, or custom.<key> for a custom field. full_name splits the first word into first_name and stores the remainder as last_name. street, city, state, and postal_code populate the structured address; address stores a one-column address as its street line. Map a header to an empty string to skip that column. Headers you don't list keep their automatic match.
tag_idsarray of (string (uuid))optionalTags applied to every contact this import touches, new and matched.
list_idsarray of (string (uuid))optionalStatic contact lists every new or matched contact should join.
owner_idstring (uuid)optionalOwner for the imported contacts.
lifecyclestringoptionalLifecycle for the imported contacts; defaults to lead.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.import_csv \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "csv": "example"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_import_csv at https://app.chirply.io/api/mcp, same bearer token, same input.

List contacts

contacts.listread

List the organization's contacts, newest first unless you pass `sort`. Filter by one or many static lists, tags, lifecycle stages, companies, owners, lead sources, city, state, and ZIP / postal code; values inside one multi-value field are ORed while different fields stack with AND. You can also filter primary phone type from saved/cached results at no lookup charge, set inclusive lifetime-value bounds in minor currency units, filter customer status and search names, business name, email, phone, city, state, and ZIP. Each contact carries its source and customer designation. Set `include_revenue` to also get each contact's lifetime value. Sort by any list column with `sort` + `direction` — `sort: "ltv"` ranks the whole organization by money received, highest first, so the first page is its most valuable contacts.

Parameters

FieldTypeRequiredDescription
limitintegeroptionalMax rows to return (1–100). Default: 25
offsetintegeroptionalRows to skip. Default: 0
querystringoptionalText to match in first/last name, business name, email, phone, city, state, or ZIP / postal code.
citystringoptionalFilter contacts whose city contains this text.
statestringoptionalFilter contacts whose state or province contains this text.
postal_codestringoptionalFilter contacts whose ZIP or postal code contains this text.
phone_typesarray of ("mobile" | "landline" | "voip" | "tollFree" | "other" | "unknown" | … 1 more)optionalPrimary phone types to include: mobile, landline, voip, tollFree, other, unknown (including not yet looked up), or none (no primary phone). Uses the saved type, then existing lookup cache; no paid lookup is performed.
ltv_min_centsintegeroptionalInclusive minimum lifetime value after refunds, in minor currency units. Zero includes contacts with no payments. Combined connected-account totals may mix currencies.
ltv_max_centsintegeroptionalInclusive maximum lifetime value after refunds, in minor currency units. Must be at least ltv_min_cents when both are supplied.
lifecyclestringoptionalOnly contacts at this lifecycle stage.
lifecyclesstring[]optionalContacts at any of these lifecycle stages. Combined with `lifecycle` when both are supplied.
is_customerbooleanoptionalFilter by customer status: true = only customers (they have bought from us), false = only non-customers. Omit for all. This is separate from `lifecycle` — a churned contact can still be a customer.
company_idstring (uuid)optionalOnly contacts at this company.
company_idsarray of (string (uuid))optionalContacts at any of these companies. Values are ORed.
owner_idstring (uuid)optionalOnly contacts owned by this user.
owner_idsarray of (string (uuid))optionalContacts owned by any of these users. Values are ORed.
sourcestringoptionalOnly contacts that arrived through this channel, e.g. 'website', 'Outscraper', 'Yelp', 'facebook_lead_ad', 'unknown'. Call contacts.list_sources to see which ones this org actually has.
sourcesstring[]optionalContacts that arrived through any of these source channels. Values are ORed.
tag_idsarray of (string (uuid))optionalContacts carrying any of these tags. Tag filtering stacks with every other supplied filter.
list_idsarray of (string (uuid))optionalContacts that belong to any of these static lists. List filtering stacks with every other supplied filter.
sort"name" | "contact" | "email" | "phone" | "website" | "title" | … 10 moreoptionalWhich column orders the result, matching the contact list's own column headers: 'ltv' (lifetime value), 'created_at' (when they were added, the default), 'updated_at', 'name', 'email', 'phone', 'website', 'title', 'business_name', 'facebook_id', 'city', 'state', 'source', 'lifecycle', 'customer', or 'contact' (the email/phone stack, ordered by email).
direction"asc" | "desc"optionalWhich way to order. Omit for each column's natural direction — money and dates come back highest/newest first, text A to Z.
include_revenuebooleanoptionalWhen true, add each contact's Stripe money, unified by email across EVERY connected Stripe account: `lifetime_value_cents` (net of refunds, minor units), `mrr_cents` (monthly run-rate of their active subscriptions), `stripe_currencies` (the currencies seen — more than one means the total mixes currencies and is indicative), and `stripe_accounts_count` (how many of your Stripe accounts they've paid). Contacts with no Stripe history report zeros. Off by default because it costs an extra lookup.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.list \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "limit": 25,
    "offset": 0
  }'
Test with your API key

Over MCP the same operation is the tool contacts_list at https://app.chirply.io/api/mcp, same bearer token, same input.

Open the activity timeline

contacts.list_activityread

Read the activity timeline — notes, calls, texts, emails, tasks, automation steps, website visits and pipeline stage changes, newest first. Name a contact, company or deal for that record's timeline, or omit all three for the WHOLE account's activity feed (the same stream the dashboard's Activity Log widget shows). Read-only.

Parameters

FieldTypeRequiredDescription
limitintegeroptionalMax rows to return (1–100). Default: 25
offsetintegeroptionalRows to skip. Default: 0
contact_idstring (uuid)optionalTimeline for this contact.
company_idstring (uuid)optionalTimeline for this company.
deal_idstring (uuid)optionalTimeline for this deal.
kind"note" | "call" | "sms" | "email" | "task" | "meeting" | … 2 moreoptionalOnly entries of this kind.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.list_activity \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "limit": 25,
    "offset": 0
  }'
Test with your API key

Over MCP the same operation is the tool contacts_list_activity at https://app.chirply.io/api/mcp, same bearer token, same input.

Contact automations

contacts.list_automationsread

List every automation a contact has entered, newest automation first. Returns the latest run status, the human-readable current step, when a waiting run resumes, any error, and the total number of times the contact entered each automation. Reads only; it does not start or change a run.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)requiredThe contact whose automation memberships to list.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.list_automations \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_list_automations at https://app.chirply.io/api/mcp, same bearer token, same input.

Contact broadcasts

contacts.list_broadcastsread

List the email, SMS, ringless voicemail and voice broadcasts sent or attempted for one contact, including campaign name, channel, delivery status, time and any error. Read-only; it sends nothing and costs nothing.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)requiredThe contact whose broadcast delivery history to list.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.list_broadcasts \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_list_broadcasts at https://app.chirply.io/api/mcp, same bearer token, same input.

List duplicate phone numbers

contacts.list_duplicatesread

DEPRECATED — the Duplicates tab it was built for no longer exists, and neither does the problem: the `contacts_absorb_duplicate` trigger folds a duplicate into the surviving contact the moment it is written, so this always returns empty in practice. Kept only so a machine can verify that. It lists contacts in this org that share a phone number, grouped, oldest first inside each group; read-only. A non-empty result means two contacts were created on the same number simultaneously, neither insert able to see the other — run contacts.merge_duplicates to repair that one case.

Parameters

No parameters — POST an empty body.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.list_duplicates \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{}'
Test with your API key

Over MCP the same operation is the tool contacts_list_duplicates at https://app.chirply.io/api/mcp, same bearer token, same input.

List contact email addresses

contacts.list_email_addressesread

List every email address saved for one contact, including its optional label and which one is primary. Read-only; the primary address is the one campaigns, automations, merge tokens and one-off sends all use.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)requiredThe contact whose email addresses to list.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.list_email_addresses \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_list_email_addresses at https://app.chirply.io/api/mcp, same bearer token, same input.

List custom fields

contacts.list_fieldsread

List the org's custom-field definitions — the keys, labels and types that the `custom` blob on contacts, companies and deals is made of.

Parameters

FieldTypeRequiredDescription
limitintegeroptionalMax rows to return (1–100). Default: 25
offsetintegeroptionalRows to skip. Default: 0
entity"contact" | "company" | "deal"optionalOnly fields for this record type.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.list_fields \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "limit": 25,
    "offset": 0
  }'
Test with your API key

Over MCP the same operation is the tool contacts_list_fields at https://app.chirply.io/api/mcp, same bearer token, same input.

View contact imports

contacts.list_import_jobsread

List recent CSV contact-import jobs for this account, including queued/running/completed/failed state, rows processed, contacts created, existing contacts matched, skipped rows, and any terminal error. Read-only and safe to poll.

Parameters

FieldTypeRequiredDescription
limitintegeroptionalMaximum recent import jobs to return. Default: 10

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.list_import_jobs \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "limit": 10
  }'
Test with your API key

Over MCP the same operation is the tool contacts_list_import_jobs at https://app.chirply.io/api/mcp, same bearer token, same input.

List lifecycle stages

contacts.list_lifecyclesread

List the lifecycle stages this organization can assign to contacts, in display order. Keys are stable values used by filters and automations; labels are the editable wording people see.

Parameters

No parameters — POST an empty body.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.list_lifecycles \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{}'
Test with your API key

Over MCP the same operation is the tool contacts_list_lifecycles at https://app.chirply.io/api/mcp, same bearer token, same input.

List connected profiles

contacts.list_linked_profilesread

List the Facebook Messenger and Instagram profiles that resolve to one contact, with the Page each belongs to. Read-only. A contact can hold several: the same person has a different Page-scoped id on every Page they message, and another one on Instagram.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)requiredThe contact whose connected profiles to list.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.list_linked_profiles \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_list_linked_profiles at https://app.chirply.io/api/mcp, same bearer token, same input.

List phone numbers

contacts.list_phone_numbersread

List every phone number saved for one contact, including whether each is mobile, landline or VoIP and which one is primary. Read-only; the primary number is the one existing calling, SMS and merge-token flows use.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)requiredThe contact whose phone numbers to list.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.list_phone_numbers \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_list_phone_numbers at https://app.chirply.io/api/mcp, same bearer token, same input.

Lead sources

contacts.list_sourcesread

Break this organization's contacts down by where they came from — the channel each lead arrived through, with a count, commonest first. Only sources that actually occur are returned, so an empty result means the org has no contacts. Use the returned `source` values to filter contacts.list. Reads nothing outside this org and changes nothing.

Parameters

No parameters — POST an empty body.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.list_sources \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{}'
Test with your API key

Over MCP the same operation is the tool contacts_list_sources at https://app.chirply.io/api/mcp, same bearer token, same input.

List tags

contacts.list_tagsread

List the org's contact tags, with the colour each one renders in.

Parameters

FieldTypeRequiredDescription
limitintegeroptionalMax rows to return (1–100). Default: 25
offsetintegeroptionalRows to skip. Default: 0
querystringoptionalText to match in the tag name.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.list_tags \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "limit": 25,
    "offset": 0
  }'
Test with your API key

Over MCP the same operation is the tool contacts_list_tags at https://app.chirply.io/api/mcp, same bearer token, same input.

Detect line type

contacts.lookup_line_typewriteconfirm

Queue a Twilio Lookup for each listed contact's phone number to learn whether it is mobile, landline or VoIP. Twilio BILLS the org per number looked up. Results land asynchronously in the shared line-type cache, so numbers already known cost nothing and are not re-queued. Returns how many NEW paid lookups were queued.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
contact_idsarray of (string (uuid))requiredContact ids to act on. Ids outside this org are ignored.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.lookup_line_type \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ]
  }'
Test with your API key

Over MCP the same operation is the tool contacts_lookup_line_type at https://app.chirply.io/api/mcp, same bearer token, same input.

Mark as customer

contacts.mark_customerwrite

Mark every listed contact as a customer, or clear it. `is_customer` is a durable fact meaning they have bought from us — it is SEPARATE from the lifecycle stage (a churned contact can still be a customer) and it survives churn. Marking sets `customer_since` to now and records the source as 'manual'; already-marked contacts are left untouched. Clearing removes the flag and its date. Reversible, changes nothing outside the CRM. Note the Stripe sync also marks customers automatically when a real purchase is seen, and a later sync will re-mark anyone you clear if it still finds a paid charge or active subscription for them.

Parameters

FieldTypeRequiredDescription
contact_idsarray of (string (uuid))requiredContact ids to act on. Ids outside this org are ignored.
is_customerbooleanoptionaltrue to mark them as customers, false to clear the flag. Default: true

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.mark_customer \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ]
  }'
Test with your API key

Over MCP the same operation is the tool contacts_mark_customer at https://app.chirply.io/api/mcp, same bearer token, same input.

Merge into one contact

contacts.mergewriteconfirm

Fold two or more contacts into one, for when the same person exists more than once — they messaged two of your Facebook Pages (a different Page-scoped id each time), replied on Instagram, bought under a work email and were imported under a personal one. Everything moves onto the contact you keep: every phone number and email address (kept as secondary rather than discarded), every Messenger and Instagram profile, tags, list memberships, conversations, calls, notes, deals, invoices and automation history. The kept contact fills any blank field from the others, takes the earliest first-seen date and the source that came with it, joins their notes, and stays a customer if any of them was one. The other contacts are then PERMANENTLY DELETED and their contact ids stop resolving — links and integrations pointing at them will 404. This cannot be undone. Nothing is sent and there is no charge.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
keep_idstring (uuid)requiredThe contact that survives. It keeps its id, so anything already linking to it still works, and its own non-blank values win over the others'.
merge_idsarray of (string (uuid))requiredThe contacts to fold in and then delete — up to 9. Ids equal to keep_id, or already absorbed by an earlier merge in the same call, are skipped rather than treated as an error.
primary_emailstring (or null)optionalWhich address the merged contact should send from, as text. Must be one the merged contact ends up holding; anything else is ignored. Omit to keep whatever the surviving contact already used.
primary_phonestring (or null)optionalWhich number calls and texts should go to, as text. Must be one the merged contact ends up holding; anything else is ignored. Omit to keep whatever the surviving contact already used.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.merge \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "keep_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11",
    "merge_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ]
  }'
Test with your API key

Over MCP the same operation is the tool contacts_merge at https://app.chirply.io/api/mcp, same bearer token, same input.

Merge duplicate contacts

contacts.merge_duplicateswriteconfirm

DEPRECATED — the Duplicates tab it was built for no longer exists, and the database now does this on its own: `contacts_absorb_duplicate` merges a duplicate as it is written, so there is normally nothing for this to do. Kept as the repair for the one case the trigger cannot see: two simultaneous inserts of the same new number, neither transaction able to see the other's row. It permanently collapses every set of contacts in this org that share a phone number down to one. The newest record of each set survives and absorbs the others — their calls, messages, tasks, invoices, notes, tags and list memberships all move onto it, and any field it was missing is filled in from the older record. The older rows are then DELETED and their contact ids stop resolving. This cannot be undone.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

No parameters — POST an empty body.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.merge_duplicates \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{}'
Test with your API key

Over MCP the same operation is the tool contacts_merge_duplicates at https://app.chirply.io/api/mcp, same bearer token, same input.

Untag contacts

contacts.remove_tagswriteconfirm

Remove one or more tags from one or more contacts. The tags themselves are kept — use contacts.delete_tag to remove a tag entirely. SECOND-ORDER EFFECT: each removal enqueues a 'Tag removed' automation event, which can start workflows that message real people on the org's own Mailgun/Twilio account, and untagging can also drop contacts out of tag-based audiences and stop campaigns aimed at them.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
contact_idsarray of (string (uuid))requiredContact ids to act on. Ids outside this org are ignored.
tag_idsarray of (string (uuid))requiredTag ids to remove.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.remove_tags \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ],
    "tag_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ]
  }'
Test with your API key

Over MCP the same operation is the tool contacts_remove_tags at https://app.chirply.io/api/mcp, same bearer token, same input.

Rename lifecycle stage

contacts.rename_lifecyclewriteadmin only

Change the visible name of a lifecycle stage while preserving its stable key, existing contact assignments, filters, and automations.

Parameters

FieldTypeRequiredDescription
keystringrequiredStable lifecycle key returned by contacts.list_lifecycles.
labelstringrequiredNew stage name people will see.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.rename_lifecycle \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "example",
    "label": "example"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_rename_lifecycle at https://app.chirply.io/api/mcp, same bearer token, same input.

Reset columns

contacts.reset_column_layoutwrite

Forget your saved column choices for the contacts list so it goes back to the default columns (name, contact details, source, company, tags, owner, lifecycle, customer status, lifetime value, and first-added date). Personal to you, and affects only which columns are displayed — no contact data is changed or deleted.

Parameters

No parameters — POST an empty body.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.reset_column_layout \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{}'
Test with your API key

Over MCP the same operation is the tool contacts_reset_column_layout at https://app.chirply.io/api/mcp, same bearer token, same input.

Run actions on contacts

contacts.run_actionswriteconfirm

Run a list of shared-registry actions against each listed contact — the same actions the contacts bulk bar and a single contact's 'Reach out' panel offer. Actions can text, email, drop a ringless voicemail, place an outbound IVR, AI-agent or sales-bridge call, enroll in a campaign, send an invoice, move a deal, create a task, call a webhook, or delete the contact — so this can spend money, reach real people, and destroy data depending on what you pass. Runs immediately by default; pass start_at to schedule it for later, or a per_minute/per_hour/per_day cap to pace it — either turns the run into a background job you watch with bulk_jobs.get.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
contact_idsarray of (string (uuid))requiredContact ids to act on. Ids outside this org are ignored.
actionsobject[]requiredThe actions to run, in order, against every contact.
actions[].type"send_sms" | "send_email" | "send_review_request" | "add_tag" | "remove_tag" | "add_to_list" | … 29 morerequiredWhich registry action to run.
actions[].configmap of string → objectoptionalThe action's own settings, as the app's action builder stores them. Default: {}
start_atstring (date-time) (or null)optionalWhen this should START, as an ISO 8601 timestamp with a timezone (e.g. 2026-08-20T14:00:00Z). Omit or null to start immediately. A time in the past starts immediately. The job waits in the account's Jobs list until then and can be rescheduled or canceled before it starts.
per_minuteinteger (or null)optionalCap on items sent per minute. null removes the per-minute cap.
per_hourinteger (or null)optionalCap on items sent per hour. null removes the per-hour cap.
per_dayinteger (or null)optionalCap on items sent per day. null removes the per-day cap.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.run_actions \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ],
    "actions": [
      {
        "type": "send_sms"
      }
    ]
  }'
Test with your API key

Over MCP the same operation is the tool contacts_run_actions at https://app.chirply.io/api/mcp, same bearer token, same input.

Search contact filter options

contacts.search_filter_optionsread

Search this account's tags, lists, lead sources, owners or companies before pagination. Returns up to 20 matches and whether another page is available; selected values can be resolved separately. Read-only; sends no messages and spends no money.

Parameters

FieldTypeRequiredDescription
field"listIds" | "tagIds" | "sources" | "ownerIds" | "companyIds"requiredFilter directory to search: listIds, tagIds, sources, ownerIds or companyIds.
querystringoptionalCase-insensitive text within an option name. Empty text returns the first page. Default: ""
offsetintegeroptionalRows to skip, in steps of 20 for subsequent pages. Default: 0
selectedstring[]optionalOptional selected option values to resolve to labels; searches and offset are ignored when this is supplied. Default: []

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.search_filter_options \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "field": "listIds"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_search_filter_options at https://app.chirply.io/api/mcp, same bearer token, same input.

Email contacts

contacts.send_emailwriteconfirm

SEND A REAL EMAIL to each listed contact through the org's own Mailgun account. Reaches real inboxes immediately and cannot be recalled. Subject and body both render `{{token}}` merge fields per contact, and each email lands in that contact's own conversation. Contacts with no email address are skipped.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
contact_idsarray of (string (uuid))requiredContact ids to act on. Ids outside this org are ignored.
subjectstringrequiredSubject line. May use merge tokens.
bodystringrequiredMessage body, as PLAIN TEXT — raw HTML is escaped and arrives as visible tags. Blank lines start new paragraphs, and `[the words you see](https://where-they-go)` becomes an inline hyperlink. May use merge tokens.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.send_email \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ],
    "subject": "Example",
    "body": "example"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_send_email at https://app.chirply.io/api/mcp, same bearer token, same input.

Text contacts

contacts.send_smswriteconfirm

SEND A REAL TEXT MESSAGE to each listed contact from one of the org's active Twilio numbers. Costs money per message and reaches real people immediately; there is no undo. `{{token}}` merge fields are rendered per contact and each text lands in that contact's own conversation. Contacts with no phone number are skipped.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
contact_idsarray of (string (uuid))requiredContact ids to act on. Ids outside this org are ignored.
bodystringrequiredMessage text. May use merge tokens like {{first_name}}.
from_numberstringoptionalE.164 of the number to send from. Must be one of the org's active numbers; defaults to the org's default outbound number.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.send_sms \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ],
    "body": "example"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_send_sms at https://app.chirply.io/api/mcp, same bearer token, same input.

Block contact

contacts.set_blockedwrite

Block or unblock a contact. Blocked contacts and their communications are hidden from normal CRM and inbox views; no data is deleted and unblocking restores visibility.

Parameters

FieldTypeRequiredDescription
idstring (uuid)requiredThe contact to block or unblock.
blockedbooleanoptionalTrue blocks and hides the contact; false restores them. Default: true

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.set_blocked \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_set_blocked at https://app.chirply.io/api/mcp, same bearer token, same input.

Save columns

contacts.set_column_layoutwrite

Choose which columns you see on the contacts list and in what order — the array order IS the left-to-right order, and any column you leave out is hidden. Personal to you; teammates' lists are unaffected. Unknown keys are dropped and 'name' is always kept (it is the link into each record), so the list can never be left unusable. Call contacts.get_column_layout for the valid keys.

Parameters

FieldTypeRequiredDescription
columnsstring[]requiredOrdered column keys, e.g. ['name','contact','source','lifecycle']. Custom fields use the 'custom:<field key>' form.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.set_column_layout \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "columns": [
      "example"
    ]
  }'
Test with your API key

Over MCP the same operation is the tool contacts_set_column_layout at https://app.chirply.io/api/mcp, same bearer token, same input.

Hide from Activity Log

contacts.set_feed_visibilitywrite

Mute or unmute contacts in the dashboard's org-wide Activity Log — the same switch on a contact's Activity tab. Hidden contacts' events (calls, texts, website visits, and the rest) stop appearing in that shared feed for everyone, while their own timeline and every other screen are untouched. Deal stage changes are the one exception: they stay in the feed whoever the deal belongs to, because the pipeline's audit trail is not something a mute is allowed to erase. Fully reversible; set `hidden` false to show them again.

Parameters

FieldTypeRequiredDescription
contact_idsarray of (string (uuid))requiredContact ids to act on. Ids outside this org are ignored.
hiddenbooleanrequiredTrue to hide these contacts from the Activity Log feed; false to show them again.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.set_feed_visibility \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ],
    "hidden": true
  }'
Test with your API key

Over MCP the same operation is the tool contacts_set_feed_visibility at https://app.chirply.io/api/mcp, same bearer token, same input.

Set lifecycle stage

contacts.set_lifecyclewriteconfirm

Move every listed contact to a lifecycle stage (lead, trial, active, customer, churned). The stage change itself is reversible — set it back to change your mind — but its SECOND-ORDER EFFECT is not: a database trigger enqueues a 'Lifecycle changed' automation event for EVERY contact in the list, so moving 200 contacts can start 200 automation runs that send real email and SMS to real people, billed to the org's own Mailgun/Twilio account. Setting the stage back does not unsend those.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
contact_idsarray of (string (uuid))requiredContact ids to act on. Ids outside this org are ignored.
lifecyclestringrequiredThe stage to move them to.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.set_lifecycle \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_ids": [
      "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
    ],
    "lifecycle": "example"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_set_lifecycle at https://app.chirply.io/api/mcp, same bearer token, same input.

Make contact email primary

contacts.set_primary_emailwrite

Make one of a contact's saved addresses primary. Campaigns, automations, merge tokens and one-off emails immediately go to this address instead; the previous primary is kept as a secondary address. This changes routing data but sends nothing and costs nothing.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)requiredThe contact that owns the email address.
email_idstring (uuid)requiredThe saved email address to make primary.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.set_primary_email \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11",
    "email_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_set_primary_email at https://app.chirply.io/api/mcp, same bearer token, same input.

Make primary

contacts.set_primary_phonewrite

Make one of a contact's saved phone numbers primary. Existing calling, SMS, automations and merge tokens immediately use this number instead. This changes routing data but sends nothing and costs nothing.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)requiredThe contact that owns the phone number.
phone_idstring (uuid)requiredThe saved phone number to make primary.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.set_primary_phone \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11",
    "phone_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_set_primary_phone at https://app.chirply.io/api/mcp, same bearer token, same input.

Set contact sender defaults

contacts.set_sender_defaultswrite

Choose the account email identity and Twilio phone number normally used when contacting one CRM contact. Either value can be cleared to resume account defaults; sends nothing.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)requiredContact whose preferred account senders are changing.
email_identity_idstring (uuid) (or null)optionalPreferred account email identity, or null for the account default.
phone_number_idstring (uuid) (or null)optionalPreferred active account phone number, or null for the account default.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.set_sender_defaults \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_set_sender_defaults at https://app.chirply.io/api/mcp, same bearer token, same input.

Summarize a contact

contacts.summarizewriteconfirm

Generate a short situational summary plus two or three next-best actions for a contact, grounded in their profile, deals and recent activity. It changes no data, but it SPENDS MONEY: the request is billed to the account's own OpenRouter key, which must be connected. Same standard as contacts.validate_email, which is gated for a paid validation credit.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
idstring (uuid)requiredThe contact to summarize.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.summarize \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_summarize at https://app.chirply.io/api/mcp, same bearer token, same input.

Edit a contact

contacts.updatewrite

Update fields on an existing contact. Omitted fields are left alone; an explicit null clears one. Moving an email address or phone number onto this contact fails with a conflict when it is already someone else's in this organization.

Parameters

FieldTypeRequiredDescription
idstring (uuid)requiredThe contact to edit.
first_namestring (or null)optionalGiven name.
last_namestring (or null)optionalFamily name.
business_namestring (or null)optionalBusiness name — the display name for company-shaped leads.
facebook_idstring (or null)optionalStable Facebook person/friend id. Null clears it.
emailstring (email) (or null)optionalEmail address. Null clears it; moving one that belongs to another contact in this org fails with a conflict.
phonestring (or null)optionalPhone number, in any format. Null clears it; moving one that belongs to another contact in this org fails with a conflict.
websitestring (or null)optionalWebsite URL.
yelp_urlstring (or null)optionalPublic Yelp listing URL. Null clears it.
titlestring (or null)optionalJob title.
birthdaystring (date) (or null)optionalDate of birth as YYYY-MM-DD. Null clears it.
sourcestring (or null)optionalWhere this contact came from — the channel slug behind the Source filter (referral, phone_call, walk_in, event, advertisement, social_media, staff, other, or a machine one like website / google_maps). Only change it when the current value is wrong; it is provenance, not a note field.
source_detailmap of string → object (or null)optionalThe specifics behind `source`, shown as a line beneath it — e.g. {"note": "referred by Dana Ortiz"}. Replaces the whole object.
lifecyclestringoptionalNew lifecycle stage key. Changing it fires the org's 'Lifecycle changed' automations, which can message this person for real.
company_idstring (uuid) (or null)optionalCompany this contact works at.
owner_idstring (uuid) (or null)optionalUser id of the team member who owns the relationship, or null to leave it unowned. Changing it fires the org's 'Owner changed' automations.
addressobject (or null)optionalPostal address with separate street, city, state, and ZIP / postal code fields.
address.line1stringoptionalStreet address.
address.line2stringoptionalSuite / unit.
address.citystringoptionalCity.
address.statestringoptionalState or province.
address.postal_codestringoptionalZIP / postal code.
address.countrystringoptionalCountry.
notesstring (or null)optionalFree-text notes on the record, visible to the whole account.
custommap of string → objectoptionalCustom-field values keyed by `custom_field_defs.key` (see contacts.list_fields). Replaces the whole blob — send the merged object.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.update \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_update at https://app.chirply.io/api/mcp, same bearer token, same input.

Edit contact email address

contacts.update_email_addresswrite

Change a saved email address and/or its label. If this row is primary, changing the address immediately changes where campaigns, automations and one-off emails are delivered. Nothing is sent and there is no charge.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)requiredThe contact that owns the email address.
email_idstring (uuid)requiredThe email-address row to edit.
emailstringoptionalReplacement email address.
labelstring (or null)optionalReplacement label, or null to clear it.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.update_email_address \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11",
    "email_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_update_email_address at https://app.chirply.io/api/mcp, same bearer token, same input.

Edit a custom field

contacts.update_fieldwrite

Change a custom field's label, type, choices or required flag. The storage key never changes, so values already recorded stay attached.

Parameters

FieldTypeRequiredDescription
idstring (uuid)requiredThe field definition to edit.
labelstringoptionalNew label.
type"text" | "textarea" | "number" | "date" | "select" | "multiselect" | … 3 moreoptionalNew field type. "user" (Team member) is accepted only on a deal field.
optionsstring[]optionalNew select/multiselect choices.
requiredbooleanoptionalWhether the app's form requires it.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.update_field \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_update_field at https://app.chirply.io/api/mcp, same bearer token, same input.

Edit phone number

contacts.update_phone_numberwrite

Change a contact phone number and/or classify it as mobile, landline or VoIP. If this row is primary, changing the number immediately changes the destination used by calls, SMS and merge tokens. Nothing is sent and there is no charge.

Parameters

FieldTypeRequiredDescription
contact_idstring (uuid)requiredThe contact that owns the phone number.
phone_idstring (uuid)requiredThe phone-number row to edit.
phonestringoptionalReplacement phone number in a common format.
phone_type"mobile" | "landline" | "voip" (or null)optionalReplacement line type, or null to mark it unclassified.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.update_phone_number \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11",
    "phone_id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_update_phone_number at https://app.chirply.io/api/mcp, same bearer token, same input.

Rename a tag

contacts.update_tagwrite

Rename a tag or change its colour. Every contact carrying it is updated at once.

Parameters

FieldTypeRequiredDescription
idstring (uuid)requiredThe tag to edit.
namestringoptionalNew tag name.
colorstringoptionalNew hex colour.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.update_tag \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_update_tag at https://app.chirply.io/api/mcp, same bearer token, same input.

Validate now

contacts.validate_emailwriteconfirm

Immediately validate this contact's current email address through the account's configured Mailgun or NeverBounce account. This makes a real provider request that may consume a paid validation credit, then stores the result beside the contact's email. It does not send email or change the address.

Marked confirm: this operation is irreversible, reaches real people, or spends money. Holding a credential is itself the confirmation for API and MCP callers — call it only when you mean it. The in-app assistant refuses to run it without a human approving first.

Parameters

FieldTypeRequiredDescription
idstring (uuid)requiredThe contact whose current email address should be validated.

Example

curl -X POST https://app.chirply.io/api/v1/actions/contacts.validate_email \
  -H "Authorization: Bearer chp_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "2f6a1c1e-6c3b-4c62-9f6e-8a2d4b7c9e11"
  }'
Test with your API key

Over MCP the same operation is the tool contacts_validate_email at https://app.chirply.io/api/mcp, same bearer token, same input.

The machine-readable version of this page is GET https://app.chirply.io/api/v1/actions?domain=contacts — same operations, with full JSON Schemas. Authentication, errors and rate limits are covered in the API documentation home.