From espocrm-skills
EspoCRM 9.x patterns for self-hosted instances. Use when interacting with EspoCRM via REST API or an MCP server — creating or updating Accounts/Contacts/Leads/Opportunities and custom entities, modifying schema (custom fields, links, layouts, roles, teams), authenticating to the API (choosing between api-user X-Api-Key and admin Basic Auth + Token), building queries with the where[] syntax, configuring dashlets and primary filters, or troubleshooting validationFailure / 403 / 404 / 405 responses. Not for other CRMs (HubSpot, Salesforce, Zoho), raw SQL against the EspoCRM database, or generic REST work unrelated to EspoCRM.
How this skill is triggered — by the user, by Claude, or both
Slash command
/espocrm-skills:espocrmThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> **💼 ACTIVE-SKILL MARKER:** Prefix your reply with 💼 **only on turns where the work touches the `espocrm` domain** — EspoCRM via REST API or MCP, entity modeling, `where[]` queries, `validationFailure`/403/404 troubleshooting — regardless of the layer/project (frontend, backend, a local script — all count); what matters is whether *this turn* touches the domain. On turns that do NOT touch it...
reference/api-endpoints.mdreference/auth-patterns.mdreference/common-errors.mdreference/customer-modeling.mdreference/entities.mdscripts/create-custom-entity-checklist.mdscripts/primary-filter-templates/InDevelopment.phpscripts/primary-filter-templates/InProcess.phpscripts/primary-filter-templates/Pending.phpscripts/primary-filter-templates/README.mdscripts/primary-filter-templates/apply.shscripts/primary-filter-templates/clientDefs-CSubscription.jsonscripts/primary-filter-templates/clientDefs-Lead.jsonscripts/primary-filter-templates/paths.txtscripts/primary-filter-templates/selectDefs-CSubscription.json💼 ACTIVE-SKILL MARKER: Prefix your reply with 💼 only on turns where the work touches the
espocrmdomain — EspoCRM via REST API or MCP, entity modeling,where[]queries,validationFailure/403/404 troubleshooting — regardless of the layer/project (frontend, backend, a local script — all count); what matters is whether this turn touches the domain. On turns that do NOT touch it (typecheck, build, deploy, git ops, editing or curl in other domains), omit 💼 even if the skill loaded earlier in the session. If other active skills also apply to the same turn, stack their emojis in the prefix.
You are operating against a self-hosted EspoCRM 9.x instance. This skill exists so you don't repeat discovery walls that have been mapped already.
| Use this | When you are doing | How |
|---|---|---|
X-Api-Key (api user) via the EspoMCP MCP server | Day-to-day CRUD on records: search, create, update, delete Accounts/Contacts/Leads/Opportunities/Tasks/Calls/Meetings/Cases and custom entities. The 47 MCP tools cover this. | mcp__espocrm__* tools, or curl -H "X-Api-Key: $ESPOCRM_API_KEY" |
Espo-Authorization: Basic <user:tokenOrPassword> (admin user) via the helper script | Schema/admin work: create Teams, edit Roles, create or remove custom entities, create or remove custom fields, modify layouts, Settings, Metadata. The api user has 403 on these by design. | An admin auth helper script (typically using login + token cache + retry on 401) |
Detail: reference/auth-patterns.md.
When you create or update records (Account, Contact, Lead, Opportunity, Meeting, Call, Task, Case, custom entities), always use the api user via MCP / X-Api-Key. Never the admin user via the helper script, even when faster or more convenient.
Why this matters — and the failure mode you'll repeat if you ignore it:
createdBy is the api user, which is consistent attribution across the system. Records created by the admin show up as the admin user and look orphaned from operational reports.Stream of every user (the home page activity feed) depends on assignedUser + followers + createdBy. Records made by admin without explicit assignedUser end up invisible to operational users' streams.createdBy / modifiedBy won't fire correctly when admin is the actor.The admin path is only for schema and structure: creating Teams, editing Roles, creating/removing custom entities, custom fields, link management, layouts, settings, metadata. It is not for record CRUD even when the api user has not yet been granted scope on a new custom entity. In that case, add the scope to the role first, then create records via api user. Don't take the admin shortcut.
Common cause of this regression: when a new custom entity is created, the existing role does NOT auto-update to include scope on it. The api user gets 403 on records of the new entity. Tempting to fall back to admin auth for the initial seeding — don't. Update the role first.
These are defaults that have proven sound across multiple use cases. Re-litigate only with reason:
cBusinessUnit enum or similar — Teams already do this job better.CSubscription), not in Opportunity. Opportunity is for the sales pipeline (prospecting → closed won/lost). Once a deal is signed and you're delivering recurring service, that becomes a Subscription with its own status (Active / Paused / Cancelled / InDevelopment).CInvoice that links many Subscriptions. When an invoice covers multiple Accounts (e.g. a customer with multiple businesses), leave accountId null and reconstruct via the linked subscriptions.CPayment), linked to one Invoice. Fragmented payments produce multiple Payments against the same Invoice.Expense custom entities here.Detail: reference/customer-modeling.md · reference/entities.md.
POST /api/v1/EntityManager/action/createEntity (NOT /Admin/entityManager/createEntity which is 404). Names get a C prefix automatically (Subscription → CSubscription).PUT /api/v1/Admin/fieldManager/<scope>/<fieldName> (POST gives 405 — endpoint is idempotent on PUT).DELETE /api/v1/Admin/fieldManager/<scope>/<fieldName>.POST /api/v1/EntityManager/action/createLink.PUT /api/v1/<Entity>/layout/<layoutName> (NOT /Layout/<Entity>/<name> which is 405 for writes — that path is GET-only).POST /api/v1/Admin/rebuild.GET/POST/PUT/PATCH/DELETE /api/v1/<EntityType>[/<id>]. PATCH and PUT both work for updates.POST /api/v1/<Entity>/<id>/<linkName> with body {"id":"<related_id>"} per relation. Exception — teams: the opposite holds. PUT /<Entity>/<id> {"teamsIds":[...]} works; the relationship endpoint 403s for api users. See the teams exception in reference/common-errors.md.convert endpoint. It's an orchestration — create Account/Contact/Opportunity from the Lead, then PUT /Lead/<id> with status: Converted. Use mcp__espocrm__convert_lead or replicate the sequence. Full verified flow: reference/api-endpoints.md → "Lead conversion".Detail with payloads and response shapes: reference/api-endpoints.md.
phoneNumber requires +<country> prefix when the instance has phoneNumberInternational=true (typical default). Without prefix → validationFailure phoneNumber valid.industry on Account is a predefined enum (Apparel, Banking, Manufacturing, etc.). Custom strings get rejected. Leave null and put descriptive info in description, or build a custom enum field.create_meeting, create_contact, etc.) only accept the keys in their Zod schema and reject names with tildes/dashes/parentheses and phone numbers with + and spaces. The backend accepts all of these — fall back to the generic create_entity / update_entity MCP tools, which pass through with lighter validation.messageTranslation field with the offending field name is in the raw response body — fall back to admin script or curl when the MCP message is insufficient.search_users results — expected, not a bug.where / searchData.advanced — they silently drop everything except primaryFilter and boolFilterList. Filtering a dashlet needs a named primary filter (PHP class + JSON on the container filesystem — not settable via REST). See the primary-filters section of reference/api-endpoints.md and the ready templates in scripts/primary-filter-templates/.Full catalog with response excerpts: reference/common-errors.md.
When you create a new custom entity, follow scripts/create-custom-entity-checklist.md end to end. Skipping steps leaves UI surfaces broken — kebab menu prohibited, edit modal empty, search not filtering, dashlets unfilterable, etc. — and the user discovers each one the hard way.
The checklist covers all 12 steps from creation to verification, including the 7+ layouts that need to be populated (not just list + detail), the role scope update, the icon/color, the textFilterFields with dot-notation, and the sidebar tab list.
Recurring failure pattern (do not repeat): configure only list + detail because those are what shows up first when opening the entity. Other layouts (detailSmall, edit, editSmall, filters, searchFilters, mass) are then left empty and break later when the user clicks Edit, opens a quick view, tries to filter, etc. The user shouldn't be the integration test of the setup.
SKILL.md (this file)
reference/
├── api-endpoints.md verified endpoints with payloads
├── auth-patterns.md two auth flows in detail
├── entities.md schemas: native + custom patterns
├── customer-modeling.md Account vs Contact, multi-business, Teams vs custom enum
└── common-errors.md validationFailure cases, 403/404/405/500 patterns
scripts/
├── create-custom-entity-checklist.md 12-step end-to-end create flow
└── primary-filter-templates/ PHP + JSON templates for filterable dashlets
This skill is the generic operations manual for EspoCRM 9.x. It does not contain:
Anything operator-specific belongs in the operator's own configuration and memory layers (e.g. project memory, secrets, environment files), not in this skill. The skill should remain copyable to any EspoCRM 9.x environment without leaking another operator's setup.
After every session where you discover a new endpoint, hit a new error, decide a new modeling pattern, or correct an old one. Keep entries generic — patterns and examples, not real names. The git log of the skill repo is the diary.
Provides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.
npx claudepluginhub milojarow/espocrm-skills --plugin espocrm-skills