skills/crm/SKILL.md
Twenty CRM integration. List, create, and update contacts (people), opportunities, and tasks via the MyPA backend API. All CRM data lives in Twenty — never look for local files.
npx skillsauth add rplogic-inc/mypa crmInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill gives you access to the Twenty CRM system through the MyPA backend API. Twenty runs as a separate service — you interact with it via HTTP API calls, never by looking for local files or folders.
All CRM endpoints require a JWT Bearer token from the MyPA backend.
Login (do this first if you don't have a token):
TOKEN=$(curl -s -X POST "$MYPA_API_URL/api/auth/login" \
-H "Content-Type: application/json" \
-d "{\"email\": \"$MYPA_EMAIL\", \"password\": \"$MYPA_PASSWORD\"}" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['data']['tokens']['accessToken'])")
Then include on every request:
-H "Authorization: Bearer $TOKEN"
Before any CRM operation, verify the CRM is connected:
curl -s "$MYPA_API_URL/api/crm/status" \
-H "Authorization: Bearer $TOKEN"
Expected response:
{
"data": {
"configured": true,
"reachable": true,
"baseUrl": "http://127.0.0.1:3004"
}
}
configured: false → Tell user: "Twenty CRM is not configured. An admin needs to set TWENTY_API_URL and TWENTY_API_KEY in the backend .env."reachable: false → Tell user: "Twenty CRM is configured but not reachable. The Twenty service may be down."true → Proceed with CRM operations.curl -s "$MYPA_API_URL/api/crm/people?limit=20" \
-H "Authorization: Bearer $TOKEN"
Optional query params: ?q=search+term&limit=20&offset=0
Response: { "data": { "items": [...], "total": N } }
Each person has fields like:
{
"id": "uuid",
"name": { "firstName": "John", "lastName": "Doe" },
"emails": { "primaryEmail": "[email protected]" },
"phones": { "primaryPhoneNumber": "+1234567890" },
"company": { "name": "Acme Corp" },
"city": "New York",
"jobTitle": "CEO"
}
Important: Twenty uses structured name fields (firstName/lastName), not a flat string.
curl -s -X POST "$MYPA_API_URL/api/crm/people" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"payload": {
"name": { "firstName": "Jane", "lastName": "Smith" },
"emails": { "primaryEmail": "[email protected]" },
"phones": { "primaryPhoneNumber": "+1555123456" },
"city": "San Francisco",
"jobTitle": "CTO"
}
}'
curl -s -X PATCH "$MYPA_API_URL/api/crm/people/<person-id>" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"payload": {
"jobTitle": "VP Engineering",
"company": { "name": "NewCo" }
}
}'
curl -s "$MYPA_API_URL/api/crm/opportunities?limit=20" \
-H "Authorization: Bearer $TOKEN"
curl -s -X POST "$MYPA_API_URL/api/crm/opportunities" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"payload": {
"name": "Acme Corp Renewal Q2",
"stage": "NEGOTIATION",
"amount": { "amountMicros": 50000000000, "currencyCode": "USD" },
"closeDate": "2026-06-30"
}
}'
curl -s -X PATCH "$MYPA_API_URL/api/crm/opportunities/<opportunity-id>" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"payload": {
"stage": "WON",
"amount": { "amountMicros": 55000000000, "currencyCode": "USD" }
}
}'
curl -s "$MYPA_API_URL/api/crm/tasks?limit=20" \
-H "Authorization: Bearer $TOKEN"
curl -s -X POST "$MYPA_API_URL/api/crm/tasks" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"payload": {
"title": "Follow up with client",
"body": "Discuss renewal terms",
"status": "TODO",
"dueAt": "2026-03-01T09:00:00Z"
}
}'
curl -s -X PATCH "$MYPA_API_URL/api/crm/tasks/<task-id>" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"payload": {
"status": "DONE"
}
}'
curl -s "$MYPA_API_URL/api/crm/person/<entity-id>" \
-H "Authorization: Bearer $TOKEN"
curl -s "$MYPA_API_URL/api/crm/opportunity/<entity-id>" \
-H "Authorization: Bearer $TOKEN"
curl -s "$MYPA_API_URL/api/crm/task/<entity-id>" \
-H "Authorization: Bearer $TOKEN"
Use the q parameter on any list endpoint:
# Find contacts named "Williams"
curl -s "$MYPA_API_URL/api/crm/people?q=Williams&limit=10" \
-H "Authorization: Bearer $TOKEN"
# Find deals mentioning "renewal"
curl -s "$MYPA_API_URL/api/crm/opportunities?q=renewal&limit=10" \
-H "Authorization: Bearer $TOKEN"
GET /api/crm/statusGET /api/crm/people?limit=50POST /api/crm/people with structured payloadGET /api/crm/opportunities?limit=20POST /api/crm/tasks with title, body, due datepayload must be a non-empty object./api/crm/*)development
Personal communication hub. Send tezits to family/team members, manage messages, get briefings, interrogate context, and share mirrors. Voice-first with Library of Context preservation and Tezit Protocol support.
development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
development
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.