Insites CRM module. Use for looking up contacts and companies, searching the CRM, adding/updating records, and logging emails as activities. Trigger on any mention of CRM contacts, companies, client records, or logging emails to the CRM.
The CRM module manages contacts and companies. For tasks and activities, see .claude/skills/insites/globals/SKILL.md.
Requires: INSITES_INSTANCE_URL and INSITES_API_KEY. Use the combinate skill to resolve these for Combinate projects.
Base path: $INSITES_INSTANCE_URL/crm/api/v2/
Auth: See .claude/skills/insites/SKILL.md for the base request pattern and .env setup.
Always use ?search_by=[field]&keyword=[value] for filtering. Replace spaces with +.
Supported search_by fields:
first_name, last_name, emailcompany_nameDo not use ?search=, ?name&keyword=, or - these do not filter correctly.
?company_name&keyword=source .env && curl -s \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
"$INSITES_INSTANCE_URL/crm/api/v2/contacts?page=1&size=25" | python3 -c "
import sys, json
data = json.load(sys.stdin)
print(f\"Total: {data.get('total_entries', '?')} contacts\")
for c in data.get('results', []):
name = c.get('name', f\"{c.get('first_name','')} {c.get('last_name','')}\".strip())
email = c.get('email', '')
company = (c.get('company') or {}).get('company_name', '')
print(f\"[{c['id']}] {name} {email} {company}\")
"
source .env && curl -s \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
"$INSITES_INSTANCE_URL/crm/api/v2/contacts?page=1&size=25&search_by=email&keyword=SEARCH+TERM" | python3 -c "
import sys, json
data = json.load(sys.stdin)
results = data.get('results', [])
print(f\"Total: {data.get('total_entries', '?')}\")
if not results:
print('No matches found.')
for c in results:
name = c.get('name', '')
email = c.get('email', '')
company = (c.get('company') or {}).get('company_name', '')
print(f\"[{c['id']}] [{c['uuid']}] {name} {email} {company}\")
"
source .env && curl -s \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
"$INSITES_INSTANCE_URL/crm/api/v2/contacts/CONTACT_UUID" | python3 -c "
import sys, json
c = json.load(sys.stdin)
print(f\"Name: {c.get('name', '')}\")
print(f\"Email: {c.get('email', '')}\")
print(f\"Phone: {c.get('work_phone_number', '')}\")
print(f\"Job Title: {c.get('job_title', '')}\")
print(f\"Company: {(c.get('company') or {}).get('company_name', '')}\")
print(f\"UUID: {c.get('uuid', '')}\")
print(f\"Archived: {c.get('is_archived', False)}\")
print(f\"Notes: {c.get('notes', '')}\")
"
source .env && curl -s -X POST \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"first_name": "FIRST NAME",
"last_name": "LAST NAME",
"email": "EMAIL",
"work_phone_number": "PHONE",
"job_title": "JOB TITLE"
}' \
"$INSITES_INSTANCE_URL/crm/api/v2/contacts" | python3 -c "
import sys, json
c = json.load(sys.stdin)
print(f\"Created: {c.get('name', '')} UUID: {c.get('uuid', '')}\")
"
Note: The contact PATCH endpoint requires email to be included in the request body even when you are not changing it. Omitting it causes a GraphQL validation error.
source .env && curl -s -X PATCH \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"email": "EXISTING_EMAIL", "first_name": "UPDATED NAME"}' \
"$INSITES_INSTANCE_URL/crm/api/v2/contacts/CONTACT_UUID"
# Archive
source .env && curl -s -X PATCH \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
"$INSITES_INSTANCE_URL/crm/api/v2/contacts/CONTACT_UUID/archive"
# Restore
source .env && curl -s -X PATCH \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
"$INSITES_INSTANCE_URL/crm/api/v2/contacts/CONTACT_UUID/restore"
source .env && curl -s \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
"$INSITES_INSTANCE_URL/crm/api/v2/companies?page=1&size=25" | python3 -c "
import sys, json
data = json.load(sys.stdin)
print(f\"Total: {data.get('total_entries', '?')} companies\")
for c in data.get('results', []):
print(f\"[{c['id']}] [{c.get('uuid','')}] {c.get('company_name', '')} {c.get('email_1', '')} {c.get('website', '')}\")
"
source .env && curl -s \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
"$INSITES_INSTANCE_URL/crm/api/v2/companies?page=1&size=25&search_by=company_name&keyword=SEARCH+TERM" | python3 -c "
import sys, json
data = json.load(sys.stdin)
results = data.get('results', [])
print(f\"Total: {data.get('total_entries', '?')}\")
if not results:
print('No matches found.')
for c in results:
cf = c.get('custom_field') or {}
print(f\"[{c['id']}] [{c.get('uuid','')}] {c.get('company_name','')} {c.get('email_1','')} {c.get('website','')}\")
"
source .env && curl -s \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
"$INSITES_INSTANCE_URL/crm/api/v2/companies/COMPANY_UUID" | python3 -c "
import sys, json
c = json.load(sys.stdin)
print(f\"Name: {c.get('company_name', '')}\")
print(f\"Email: {c.get('email_1', '')}\")
print(f\"Phone: {c.get('phone_1_number', '')}\")
print(f\"Website: {c.get('website', '')}\")
print(f\"UUID: {c.get('uuid', '')}\")
print(f\"Custom: {c.get('custom_field', {})}\")
"
source .env && curl -s -X POST \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"company_name": "COMPANY NAME",
"email_1": "EMAIL",
"website": "WEBSITE"
}' \
"$INSITES_INSTANCE_URL/crm/api/v2/companies" | python3 -c "
import sys, json
c = json.load(sys.stdin)
print(f\"Created: {c.get('company_name', '')} UUID: {c.get('uuid', '')}\")
"
source .env && curl -s -X PATCH \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"company_name": "UPDATED NAME"}' \
"$INSITES_INSTANCE_URL/crm/api/v2/companies/COMPANY_UUID"
# Archive
source .env && curl -s -X PATCH \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
"$INSITES_INSTANCE_URL/crm/api/v2/companies/COMPANY_UUID/archive"
# Restore
source .env && curl -s -X PATCH \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
"$INSITES_INSTANCE_URL/crm/api/v2/companies/COMPANY_UUID/restore"
Use this workflow to record a sent email as an activity on a contact or company record.
Search by email to find the contact:
source .env && curl -s \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
"$INSITES_INSTANCE_URL/crm/api/v2/contacts?page=1&size=25&search_by=email&keyword=SEARCH+TERM" | python3 -c "
import sys, json
data = json.load(sys.stdin)
results = data.get('results', [])
if not results:
print('No matches. Try search_by=first_name or search_by=last_name')
for c in results:
company = (c.get('company') or {}).get('company_name', '')
print(f\"[{c['uuid']}] {c.get('name','')} {c.get('email','')} {company}\")
"
Log against a contact record:
source .env && curl -s -X POST \
-H "Authorization: $INSITES_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"type": "email",
"subject": "EMAIL SUBJECT",
"message": "EMAIL BODY (plain text)",
"feature_type": "contact",
"contact_uuid": "CONTACT_UUID",
"related_uuid": "CONTACT_UUID",
"last_updated_by_administrator_uuid": "'"$INSITES_CRM_ADMIN_UUID"'",
"start_date_time": "YYYY-MM-DDTHH:MM:SS.000Z"
}' \
"$INSITES_INSTANCE_URL/crm/api/v2/activities" | python3 -c "
import sys, json
a = json.load(sys.stdin)
if 'errors' in a:
print('ERROR:', a['errors'])