ima-claude 2.15.0 → 2.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -1
- package/dist/cli.js +18 -1
- package/package.json +1 -1
- package/plugins/ima-claude/.claude-plugin/plugin.json +2 -2
- package/plugins/ima-claude/agents/wp-developer.md +2 -1
- package/plugins/ima-claude/hooks/prompt_coach_digest.md +1 -1
- package/plugins/ima-claude/skills/espocrm/SKILL.md +79 -0
- package/plugins/ima-claude/skills/espocrm-api/SKILL.md +360 -0
- package/plugins/ima-claude/skills/espocrm-api/references/where-operators.md +84 -0
- package/plugins/ima-claude/skills/functional-programmer/SKILL.md +15 -0
- package/plugins/ima-claude/skills/ima-copywriting/SKILL.md +232 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/format-blog-post.md +51 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/format-fundraising-email.md +54 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/format-newsletter.md +54 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/format-op-ed.md +41 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/format-press-release.md +45 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/format-social-media.md +141 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/format-webinar-email.md +37 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/ima-copy-frameworks.md +299 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/ima-transitions.md +199 -0
- package/plugins/ima-claude/skills/ima-editorial-scorecard/SKILL.md +159 -0
- package/plugins/ima-claude/skills/ima-editorial-scorecard/references/format-expectations.md +66 -0
- package/plugins/ima-claude/skills/ima-editorial-scorecard/references/scoring-rubrics.md +73 -0
- package/plugins/ima-claude/skills/ima-editorial-workflow/SKILL.md +171 -0
- package/plugins/ima-claude/skills/ima-email-creator/SKILL.md +104 -0
- package/plugins/ima-claude/skills/ima-email-creator/assets/base-template.html +256 -0
- package/plugins/ima-claude/skills/ima-email-creator/references/drip-sequence.md +66 -0
- package/plugins/ima-claude/skills/ima-email-creator/references/email-css-safe.md +104 -0
- package/plugins/ima-claude/skills/ima-email-creator/references/espocrm-compat.md +58 -0
- package/plugins/ima-claude/skills/ima-email-creator/references/newsletter-layout.md +127 -0
- package/plugins/ima-claude/skills/ima-email-creator/references/wp-transactional.md +77 -0
- package/plugins/ima-claude/skills/ima-email-creator/scripts/css-inliner.py +47 -0
- package/plugins/ima-claude/skills/ima-email-creator/scripts/espocrm-prep.py +52 -0
- package/plugins/ima-claude/skills/ima-email-creator/scripts/requirements.txt +2 -0
- package/plugins/ima-claude/skills/wp-ddev/SKILL.md +264 -0
- package/plugins/ima-claude/skills/wp-ddev/references/ddev-commands.md +232 -0
- package/plugins/ima-claude/skills/wp-ddev/references/wp-cli-reference.md +406 -0
package/README.md
CHANGED
|
@@ -255,7 +255,7 @@ Named subagents with hard constraints — model, tools, and permissions enforced
|
|
|
255
255
|
| `ima-claude:implementer` | sonnet | full access | `functional-programmer` | Feature dev, bug fixes, refactoring, tests |
|
|
256
256
|
| `ima-claude:reviewer` | sonnet | read-only | `functional-programmer` | Code review, security audit, FP compliance |
|
|
257
257
|
| `ima-claude:tester` | sonnet | full access | `unit-testing`, `functional-programmer` | Test creation, TDD, test running, debugging failures |
|
|
258
|
-
| `ima-claude:wp-developer` | sonnet | full access | `php-fp`, `php-fp-wordpress`, `wp-local`, `ima-forms-expert`, `ima-bootstrap`, `jquery` | WordPress plugins, themes, WP-CLI, forms |
|
|
258
|
+
| `ima-claude:wp-developer` | sonnet | full access | `php-fp`, `php-fp-wordpress`, `wp-ddev`, `wp-local`, `ima-forms-expert`, `ima-bootstrap`, `jquery` | WordPress plugins, themes, WP-CLI, forms |
|
|
259
259
|
| `ima-claude:memory` | sonnet | full access | `mcp-vestige`, `mcp-qdrant`, `mcp-serena` | Memory search, storage, consolidation across Vestige/Qdrant/Serena |
|
|
260
260
|
|
|
261
261
|
Agents are auto-discovered from `plugins/ima-claude/agents/`. No manifest changes needed to add new ones.
|
|
@@ -286,6 +286,13 @@ Agents are auto-discovered from `plugins/ima-claude/agents/`. No manifest change
|
|
|
286
286
|
| `py-fp` | Python FP core - comprehensions, generators, frozen dataclasses |
|
|
287
287
|
| `quasar-fp` | Quasar Framework with utility-first CSS |
|
|
288
288
|
|
|
289
|
+
### CRM Skills
|
|
290
|
+
|
|
291
|
+
| Skill | Description |
|
|
292
|
+
|-------|-------------|
|
|
293
|
+
| `espocrm` | EspoCRM skill family router (intent detection, Salesforce mapping, child skill routing) |
|
|
294
|
+
| `espocrm-api` | EspoCRM v9.x REST API (auth, CRUD, WHERE filtering, relationships, webhooks, mass ops) |
|
|
295
|
+
|
|
289
296
|
### Domain Expert Skills
|
|
290
297
|
|
|
291
298
|
| Skill | Description |
|
|
@@ -295,6 +302,7 @@ Agents are auto-discovered from `plugins/ima-claude/agents/`. No manifest change
|
|
|
295
302
|
| `ima-bootstrap` | Bootstrap 5.3 + IMA brand (utility-first CSS, SCSS) |
|
|
296
303
|
| `playwright` | E2E testing with Playwright + TypeScript |
|
|
297
304
|
| `docs-organize` | Three-tier documentation organization |
|
|
305
|
+
| `wp-ddev` | WP-CLI commands for DDEV WordPress environments |
|
|
298
306
|
| `wp-local` | WP-CLI commands for Flywheel Local WP |
|
|
299
307
|
| `jira-checkpoint` | Jira awareness checkpoints for team visibility |
|
|
300
308
|
| `phpunit-wp` | PHPUnit testing for WordPress plugins with FP principles |
|
|
@@ -302,6 +310,10 @@ Agents are auto-discovered from `plugins/ima-claude/agents/`. No manifest change
|
|
|
302
310
|
| `ima-forms-expert` | WordPress form components (IMA Forms) |
|
|
303
311
|
| `discourse-admin` | Discourse admin API (site settings, config export/import, groups) |
|
|
304
312
|
| `ima-cancer-care-guides` | Cancer care guide document pipeline (DOCX → markdown → HTML → PDF, Canva mapping) |
|
|
313
|
+
| `ima-copywriting` | IMA editorial voice across all formats (newsletters, blogs, press releases, fundraising, social) |
|
|
314
|
+
| `ima-editorial-scorecard` | Score IMA content against editorial standards (Brand Voice, Evidence, Audience, Structure, CTA) |
|
|
315
|
+
| `ima-editorial-workflow` | Orchestrates Plan → Write → Review → Approve → Learn editorial process |
|
|
316
|
+
| `ima-email-creator` | Render branded email-client-safe HTML (table layouts, inline CSS, EspoCRM compatibility) |
|
|
305
317
|
| `prompt-starter` | Zero-friction prompt templates (quick, brainstorm, plan-implement) with Jira pre-fill and editor spawn |
|
|
306
318
|
|
|
307
319
|
### Integration Skills
|
package/dist/cli.js
CHANGED
|
@@ -11,7 +11,7 @@ var HOOKS_DIR = join(CLAUDE_DIR, "hooks");
|
|
|
11
11
|
var COMMANDS_DIR = join(CLAUDE_DIR, "commands");
|
|
12
12
|
var RULES_DIR = join(CLAUDE_DIR, "rules");
|
|
13
13
|
var SETTINGS_FILE = join(CLAUDE_DIR, "settings.json");
|
|
14
|
-
var VERSION = "2.
|
|
14
|
+
var VERSION = "2.18.0";
|
|
15
15
|
var colors = {
|
|
16
16
|
reset: "\x1B[0m",
|
|
17
17
|
bright: "\x1B[1m",
|
|
@@ -84,21 +84,38 @@ var SKILLS_TO_INSTALL = [
|
|
|
84
84
|
"js-fp-wordpress",
|
|
85
85
|
"php-fp",
|
|
86
86
|
"php-fp-wordpress",
|
|
87
|
+
"py-fp",
|
|
88
|
+
"ruby-fp",
|
|
87
89
|
"quasar-fp",
|
|
88
90
|
"jquery",
|
|
89
91
|
// Payment & API skills
|
|
90
92
|
"php-authnet",
|
|
93
|
+
// CRM skills
|
|
94
|
+
"espocrm",
|
|
95
|
+
"espocrm-api",
|
|
91
96
|
// Domain expert skills
|
|
92
97
|
"architect",
|
|
93
98
|
"docs-organize",
|
|
94
99
|
"wp-local",
|
|
100
|
+
"wp-ddev",
|
|
95
101
|
"rg",
|
|
96
102
|
"ima-forms-expert",
|
|
97
103
|
"ima-brand",
|
|
98
104
|
"ima-bootstrap",
|
|
105
|
+
"ima-copywriting",
|
|
106
|
+
"ima-editorial-scorecard",
|
|
107
|
+
"ima-editorial-workflow",
|
|
108
|
+
"ima-email-creator",
|
|
109
|
+
"ima-cancer-care-guides",
|
|
110
|
+
"ima-doc2pdf",
|
|
111
|
+
"livecanvas",
|
|
99
112
|
"jira-checkpoint",
|
|
100
113
|
// Testing skills
|
|
114
|
+
"unit-testing",
|
|
115
|
+
"phpunit-wp",
|
|
101
116
|
"playwright",
|
|
117
|
+
// Rails/Ruby skills
|
|
118
|
+
"rails",
|
|
102
119
|
// Discourse skills
|
|
103
120
|
"discourse",
|
|
104
121
|
"discourse-admin",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ima-claude",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.0",
|
|
4
4
|
"description": "IMA's AI coding agent skills - FP patterns, architecture guidance, and team standards. Supports Claude Code, Junie CLI, Gemini CLI, and GitHub Copilot.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ima-claude",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "IMA's Claude Code skills for functional programming, architecture, and team standards.
|
|
3
|
+
"version": "2.18.0",
|
|
4
|
+
"description": "IMA's Claude Code skills for functional programming, architecture, and team standards. 60 skills, 24 hooks, default persona, 3-tier memory system.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "IMA",
|
|
7
7
|
"url": "https://github.com/Soabirw/ima-claude"
|
|
@@ -5,6 +5,7 @@ model: sonnet
|
|
|
5
5
|
skills:
|
|
6
6
|
- php-fp
|
|
7
7
|
- php-fp-wordpress
|
|
8
|
+
- wp-ddev
|
|
8
9
|
- wp-local
|
|
9
10
|
- ima-forms-expert
|
|
10
11
|
- ima-bootstrap
|
|
@@ -23,7 +24,7 @@ You are a WordPress development specialist with deep knowledge of the WordPress
|
|
|
23
24
|
## Capabilities
|
|
24
25
|
|
|
25
26
|
- Plugin and theme development with WordPress coding standards
|
|
26
|
-
- WP-CLI operations via Local WP
|
|
27
|
+
- WP-CLI operations via DDEV environments (preferred) or Local WP
|
|
27
28
|
- IMA Forms component library (ima_forms_* functions)
|
|
28
29
|
- Bootstrap 5.3 integration with IMA brand system
|
|
29
30
|
- jQuery patterns for WordPress DOM manipulation
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
| WordPress plugin, nonce, sanitization, capability | `php-fp-wordpress` |
|
|
14
14
|
| Architecture, new project, scaling, microservices | `architect` |
|
|
15
15
|
| Documentation structure, organize docs | `docs-organize` |
|
|
16
|
-
| WP-CLI,
|
|
16
|
+
| WP-CLI, DDEV, ddev wp, wp plugin, wp db query | `wp-ddev` (DDEV) or `wp-local` (Flywheel) |
|
|
17
17
|
| Find in files, search code, grep | `rg` |
|
|
18
18
|
| Latest, current, 2025/2026, recent updates, research | `mcp-tavily` |
|
|
19
19
|
| Library docs, React API, how to use [library] | `mcp-context7` |
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "espocrm"
|
|
3
|
+
description: >-
|
|
4
|
+
EspoCRM skill family router. Detects intent (API calls, extension development,
|
|
5
|
+
UI customization) and routes to the appropriate child skill. Provides shared
|
|
6
|
+
context: v9.x target, entity-based REST architecture, Salesforce mental model
|
|
7
|
+
mapping. Use when: any EspoCRM work, CRM integration, CRM API, EspoCRM
|
|
8
|
+
customization. Triggers on: EspoCRM, Espo, CRM API, CRM integration, CRM
|
|
9
|
+
entity, CRM webhook, CRM hook.
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# EspoCRM - Skill Family Router
|
|
13
|
+
|
|
14
|
+
Routes EspoCRM work to the right child skill based on intent.
|
|
15
|
+
|
|
16
|
+
**Target version**: v9.x (9.0+)
|
|
17
|
+
**Architecture**: Entity-based REST API, PHP backend, Backbone.js frontend
|
|
18
|
+
|
|
19
|
+
## Decision Tree
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
What are you doing with EspoCRM?
|
|
23
|
+
├── REST API calls (external integration)?
|
|
24
|
+
│ → espocrm-api (primary) + php-fp or js-fp-api
|
|
25
|
+
│ → Auth, CRUD, filtering, webhooks, mass ops
|
|
26
|
+
│
|
|
27
|
+
├── PHP extension development (hooks, services, custom entities)?
|
|
28
|
+
│ → espocrm-extensions (Phase 2) + php-fp
|
|
29
|
+
│ → ORM, hooks, services, DI, custom controllers, modules
|
|
30
|
+
│
|
|
31
|
+
├── Frontend/UI customization (views, fields, layouts)?
|
|
32
|
+
│ → espocrm-ui (Phase 3)
|
|
33
|
+
│ → Backbone views, Espo.Ajax, Handlebars templates
|
|
34
|
+
│
|
|
35
|
+
└── Not sure / mixed?
|
|
36
|
+
→ Start with espocrm-api for data access
|
|
37
|
+
→ Route to extension/UI skill once scope is clear
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Shared Context
|
|
41
|
+
|
|
42
|
+
### Entity-Based Model
|
|
43
|
+
EspoCRM organizes data as **Entity Types** (Account, Contact, Lead, Opportunity, custom types). Every entity type gets automatic REST endpoints. Custom entities created via Entity Manager are immediately API-accessible.
|
|
44
|
+
|
|
45
|
+
### Salesforce Mental Model
|
|
46
|
+
For developers familiar with Salesforce, this mapping accelerates onboarding:
|
|
47
|
+
|
|
48
|
+
| Salesforce | EspoCRM |
|
|
49
|
+
|---|---|
|
|
50
|
+
| sObject | Entity Type |
|
|
51
|
+
| Connected App + OAuth | API User + API Key |
|
|
52
|
+
| SOQL | WHERE JSON filters + select/orderBy params |
|
|
53
|
+
| SOSL | Text filter on list endpoint |
|
|
54
|
+
| Apex Trigger | PHP Hook (beforeSave, afterSave) |
|
|
55
|
+
| Apex REST endpoint | Custom API Action (Controller + routes.json) |
|
|
56
|
+
| LWC / Visualforce | Custom Views (JS, extending base views) |
|
|
57
|
+
| Platform Events / CDC | Webhooks ({Entity}.create, .update, .delete) |
|
|
58
|
+
| Bulk API 2.0 | No equivalent (loop individual calls or use Import) |
|
|
59
|
+
| Governor Limits | None (self-hosted, you manage resources) |
|
|
60
|
+
| AppExchange | EspoCRM Extensions marketplace |
|
|
61
|
+
|
|
62
|
+
### Key Differences from Salesforce
|
|
63
|
+
- **No SOQL** — queries use structured JSON WHERE filters (verbose but explicit)
|
|
64
|
+
- **No Bulk API** — mass operations exist (massUpdate, massDelete) but no batch create
|
|
65
|
+
- **No Composite API** — one request per operation
|
|
66
|
+
- **No governor limits** — self-hosted, manage at server/proxy level
|
|
67
|
+
- **Simpler auth** — API Key in one header vs. multi-step OAuth
|
|
68
|
+
- **Metadata is JSON files** — no deployment steps, changes take effect on cache clear
|
|
69
|
+
|
|
70
|
+
### Documentation Lookup
|
|
71
|
+
Use Context7 for live EspoCRM docs: `resolve-library-id("espocrm")` resolves to `/espocrm/documentation`.
|
|
72
|
+
|
|
73
|
+
## Child Skill Status
|
|
74
|
+
|
|
75
|
+
| Skill | Status | Covers |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| `espocrm-api` | Active | REST API, auth, CRUD, filtering, webhooks, mass ops |
|
|
78
|
+
| `espocrm-extensions` | Planned | PHP hooks, services, ORM, custom entities, modules |
|
|
79
|
+
| `espocrm-ui` | Planned | JS views, fields, Espo.Ajax, Backbone, Handlebars |
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "espocrm-api"
|
|
3
|
+
description: >-
|
|
4
|
+
EspoCRM v9.x REST API patterns — authentication (API Key, HMAC), CRUD operations,
|
|
5
|
+
JSON WHERE filtering, relationship management, webhooks, mass operations, error
|
|
6
|
+
handling, and performance. Official PHP client and Node.js patterns. Use when:
|
|
7
|
+
calling EspoCRM API, building CRM integrations, querying CRM data, managing
|
|
8
|
+
webhooks, bulk CRM operations. Triggers on: EspoCRM API, CRM endpoint, CRM
|
|
9
|
+
query, CRM webhook, CRM filter, espo api, api/v1, X-Api-Key, HMAC auth,
|
|
10
|
+
entity CRUD.
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# EspoCRM REST API (v9.x)
|
|
14
|
+
|
|
15
|
+
Patterns for the EspoCRM REST API. External integrations, data pipelines, and automation.
|
|
16
|
+
|
|
17
|
+
**Base URL**: `https://{your-site}/api/v1/`
|
|
18
|
+
**Content-Type**: `application/json` (all requests)
|
|
19
|
+
**Parent skill**: `espocrm` (router — Salesforce mapping, shared context)
|
|
20
|
+
**Companion skills**: `php-fp` (PHP integrations), `js-fp-api` (Node integrations)
|
|
21
|
+
**Live docs**: Context7 `/espocrm/documentation`
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Authentication
|
|
26
|
+
|
|
27
|
+
Three methods, in order of recommendation:
|
|
28
|
+
|
|
29
|
+
### 1. API Key (Simple, Recommended for Dev/Internal)
|
|
30
|
+
|
|
31
|
+
Create an API User at Administration > API Users. Authentication method: "API Key". Assign a Role for scope.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
X-Api-Key: {key_from_api_user_detail_view}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
One header. Done. Use when transport is already secured (HTTPS, internal network).
|
|
38
|
+
|
|
39
|
+
### 2. HMAC (Production, Most Secure)
|
|
40
|
+
|
|
41
|
+
Create an API User with "HMAC" auth. Both API Key and Secret Key are generated. Secret never leaves your server.
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
X-Hmac-Authorization: base64(apiKey + ':' + hmacSha256(METHOD + ' /' + uri, secretKey))
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Where `METHOD` is uppercase (GET, POST, PUT, DELETE) and `uri` is the path after `/api/v1/`.
|
|
48
|
+
|
|
49
|
+
```php
|
|
50
|
+
// PHP
|
|
51
|
+
$string = $method . ' /' . $uri;
|
|
52
|
+
$hash = hash_hmac('sha256', $string, $secretKey);
|
|
53
|
+
$header = base64_encode($apiKey . ':' . $hash);
|
|
54
|
+
// X-Hmac-Authorization: $header
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
// Node.js
|
|
59
|
+
import { createHmac } from 'node:crypto';
|
|
60
|
+
const hash = createHmac('sha256', secretKey).update(`${method} /${uri}`).digest('hex');
|
|
61
|
+
const header = Buffer.from(`${apiKey}:${hash}`).toString('base64');
|
|
62
|
+
// X-Hmac-Authorization: header
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 3. Basic / Token Auth (Session-Based Only)
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
Espo-Authorization: base64(username + ':' + token)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Obtain token via `GET App/user` with initial credentials. Only for session flows (SPA, frontend). Never for server-to-server.
|
|
72
|
+
|
|
73
|
+
### Auth Decision
|
|
74
|
+
|
|
75
|
+
| Context | Method |
|
|
76
|
+
|---|---|
|
|
77
|
+
| Dev/testing, internal scripts | API Key |
|
|
78
|
+
| Production integrations | HMAC |
|
|
79
|
+
| Frontend SPA, session flows | Token auth |
|
|
80
|
+
| Never | Basic auth with plaintext password |
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## CRUD Operations
|
|
85
|
+
|
|
86
|
+
All entity types share the same endpoint pattern. Replace `{Entity}` with the type name (Account, Contact, Lead, CMyCustomEntity, etc.).
|
|
87
|
+
|
|
88
|
+
### List Records
|
|
89
|
+
```
|
|
90
|
+
GET {Entity}
|
|
91
|
+
```
|
|
92
|
+
Returns `{"list": [...], "total": N}`. Total is `-1` if more records exist (pagination needed), `-2` if count disabled.
|
|
93
|
+
|
|
94
|
+
### Read One Record
|
|
95
|
+
```
|
|
96
|
+
GET {Entity}/{id}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Create
|
|
100
|
+
```
|
|
101
|
+
POST {Entity}
|
|
102
|
+
{"name": "Acme Corp", "assignedUserId": "someUserId"}
|
|
103
|
+
```
|
|
104
|
+
Returns the created record with generated `id`. Use `X-Skip-Duplicate-Check: true` to bypass duplicate detection.
|
|
105
|
+
|
|
106
|
+
### Update (Partial)
|
|
107
|
+
```
|
|
108
|
+
PUT {Entity}/{id}
|
|
109
|
+
{"status": "Closed Won"}
|
|
110
|
+
```
|
|
111
|
+
Only send changed fields. Returns full updated record.
|
|
112
|
+
|
|
113
|
+
### Delete
|
|
114
|
+
```
|
|
115
|
+
DELETE {Entity}/{id}
|
|
116
|
+
```
|
|
117
|
+
Returns `true`.
|
|
118
|
+
|
|
119
|
+
### Endpoint Summary
|
|
120
|
+
|
|
121
|
+
| Operation | Method | Path |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| List | GET | `{Entity}` |
|
|
124
|
+
| Read | GET | `{Entity}/{id}` |
|
|
125
|
+
| Create | POST | `{Entity}` |
|
|
126
|
+
| Update | PUT | `{Entity}/{id}` |
|
|
127
|
+
| Delete | DELETE | `{Entity}/{id}` |
|
|
128
|
+
| List related | GET | `{Entity}/{id}/{link}` |
|
|
129
|
+
| Link | POST | `{Entity}/{id}/{link}` |
|
|
130
|
+
| Unlink | DELETE | `{Entity}/{id}/{link}` |
|
|
131
|
+
| Mass update | POST | `{Entity}/action/massUpdate` |
|
|
132
|
+
| Mass delete | POST | `{Entity}/action/massDelete` |
|
|
133
|
+
| Stream/notes | GET | `{Entity}/{id}/stream` |
|
|
134
|
+
| Webhook CRUD | POST/DELETE | `Webhook` / `Webhook/{id}` |
|
|
135
|
+
| Auth token | GET | `App/user` |
|
|
136
|
+
| Attachment up | POST | `Attachment` |
|
|
137
|
+
| Attachment down | GET | `Attachment/file/{id}` |
|
|
138
|
+
| OpenAPI spec | GET | `OpenApi` |
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Filtering & Search
|
|
143
|
+
|
|
144
|
+
Parameters go as query params or as a single JSON-encoded `searchParams` param.
|
|
145
|
+
|
|
146
|
+
### Core Parameters
|
|
147
|
+
|
|
148
|
+
| Param | Type | Purpose |
|
|
149
|
+
|---|---|---|
|
|
150
|
+
| `select` | string | Comma-separated fields: `id,name,status` |
|
|
151
|
+
| `maxSize` | int | Records per page (max 200, default varies) |
|
|
152
|
+
| `offset` | int | Pagination offset |
|
|
153
|
+
| `orderBy` | string | Sort field |
|
|
154
|
+
| `order` | string | `asc` or `desc` |
|
|
155
|
+
| `where` | array | Filter conditions (see below) |
|
|
156
|
+
| `primaryFilter` | string | Named server-side filter (`open`, `onlyMy`, etc.) |
|
|
157
|
+
| `boolFilterList` | array | Boolean toggles: `["onlyMy", "followed"]` |
|
|
158
|
+
|
|
159
|
+
v9.0+ aliases (WAF-safe): `attributeSelect` for `select`, `whereGroup` for `where`.
|
|
160
|
+
|
|
161
|
+
### WHERE Operators
|
|
162
|
+
|
|
163
|
+
Each filter is `{"type": "...", "attribute": "...", "value": "..."}`. Multiple items in the `where` array are implicitly ANDed. Use `{"type": "or", "value": [...]}` for OR logic.
|
|
164
|
+
|
|
165
|
+
**Operator categories**: equality (`equals`, `notEquals`), comparison (`greaterThan`, `lessThan`, `greaterThanOrEquals`, `lessThanOrEquals`), null (`isNull`, `isNotNull`), boolean (`isTrue`, `isFalse`), string (`contains`, `notContains`, `startsWith`, `endsWith`, `like`, `notLike`), set (`in`, `notIn`), relationship (`linkedWith`, `notLinkedWith`, `isLinked`, `isNotLinked`), date helpers (`today`, `past`, `future`, `lastSevenDays`, `currentMonth`, `lastMonth`, `currentYear`, `between`, `lastXDays`, `nextXDays`), logical (`or`, `and`).
|
|
166
|
+
|
|
167
|
+
Full operator reference with examples: `references/where-operators.md`
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Relationships
|
|
172
|
+
|
|
173
|
+
Link names are visible at Administration > Entity Manager > {Entity} > Relationships (4th column).
|
|
174
|
+
|
|
175
|
+
### List Related Records
|
|
176
|
+
```
|
|
177
|
+
GET Account/{id}/contacts?select=id,name,emailAddress&maxSize=50
|
|
178
|
+
```
|
|
179
|
+
Same search params as list endpoint.
|
|
180
|
+
|
|
181
|
+
### Link Records
|
|
182
|
+
```
|
|
183
|
+
POST Account/{id}/contacts
|
|
184
|
+
{"id": "contactId"}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Multiple at once:
|
|
188
|
+
```json
|
|
189
|
+
{"ids": ["id1", "id2", "id3"]}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Mass relate by filter:
|
|
193
|
+
```json
|
|
194
|
+
{"massRelate": true, "where": [{"type": "equals", "attribute": "status", "value": "Active"}]}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Unlink Records
|
|
198
|
+
```
|
|
199
|
+
DELETE Account/{id}/contacts
|
|
200
|
+
{"id": "contactId"}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Multiple: `{"ids": ["id1", "id2"]}`.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Webhooks
|
|
208
|
+
|
|
209
|
+
### Register
|
|
210
|
+
```
|
|
211
|
+
POST Webhook
|
|
212
|
+
{"event": "Contact.create", "url": "https://your-server.com/hook"}
|
|
213
|
+
```
|
|
214
|
+
Returns `{"id": "webhookId", "secretKey": "generatedKey"}`. Save both for signature verification.
|
|
215
|
+
|
|
216
|
+
### Event Types
|
|
217
|
+
- `{Entity}.create` — record created (all attributes in payload)
|
|
218
|
+
- `{Entity}.update` — record updated (only changed attributes)
|
|
219
|
+
- `{Entity}.delete` — record removed (ID only)
|
|
220
|
+
- `{Entity}.fieldUpdate.{field}` — specific field changed
|
|
221
|
+
|
|
222
|
+
### Payload Format
|
|
223
|
+
Always an array (even for single events):
|
|
224
|
+
```json
|
|
225
|
+
[{"id": "abc123", "name": "Updated Name", "status": "Active"}]
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Signature Verification
|
|
229
|
+
The `Signature` header contains: `base64(webhookId + ':' + hmacSha256(rawBody, secretKey))`.
|
|
230
|
+
|
|
231
|
+
```php
|
|
232
|
+
$expected = base64_encode($webhookId . ':' . hash_hmac('sha256', $rawBody, $secretKey));
|
|
233
|
+
$valid = hash_equals($expected, $_SERVER['HTTP_SIGNATURE']);
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Lifecycle
|
|
237
|
+
- Processed by scheduled job "Process Webhook Queue" (default: every 5 min)
|
|
238
|
+
- Failed deliveries are retried automatically
|
|
239
|
+
- Persistent failures deactivate the webhook
|
|
240
|
+
- Config: `webhookAllowedAddressList` in `data/config.php` for internal URLs
|
|
241
|
+
|
|
242
|
+
### Delete
|
|
243
|
+
```
|
|
244
|
+
DELETE Webhook/{id}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Mass Operations
|
|
250
|
+
|
|
251
|
+
### Mass Update
|
|
252
|
+
```
|
|
253
|
+
POST Lead/action/massUpdate
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
By IDs:
|
|
257
|
+
```json
|
|
258
|
+
{"ids": ["id1", "id2"], "data": {"assignedUserId": "userId", "status": "In Process"}}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
By filter:
|
|
262
|
+
```json
|
|
263
|
+
{"where": [{"type": "equals", "attribute": "status", "value": "New"}], "data": {"status": "Assigned"}}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Mass Delete
|
|
267
|
+
```
|
|
268
|
+
POST Lead/action/massDelete
|
|
269
|
+
```
|
|
270
|
+
Same payload patterns — `ids` array or `where` filter.
|
|
271
|
+
|
|
272
|
+
### No Bulk Create
|
|
273
|
+
There is no native batch create endpoint. For bulk ingestion:
|
|
274
|
+
1. Loop individual POST requests with reasonable pacing
|
|
275
|
+
2. Use the built-in Import feature (Administration > Import) for CSV
|
|
276
|
+
3. Write a custom API action for batch processing if volume demands it
|
|
277
|
+
|
|
278
|
+
### Important
|
|
279
|
+
API Before-Save Scripts (Formula) are **not executed** during mass update operations.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Error Handling
|
|
284
|
+
|
|
285
|
+
### Status Codes
|
|
286
|
+
|
|
287
|
+
| Code | Meaning | Action |
|
|
288
|
+
|---|---|---|
|
|
289
|
+
| 200 | Success | — |
|
|
290
|
+
| 400 | Bad Request | Check required fields, validation |
|
|
291
|
+
| 401 | Unauthorized | Check auth headers/credentials |
|
|
292
|
+
| 403 | Forbidden | Check API User role/ACL |
|
|
293
|
+
| 404 | Not Found | Record doesn't exist or no read access |
|
|
294
|
+
| 409 | Conflict | Duplicate detected or record locked |
|
|
295
|
+
| 500 | Server Error | Check `data/log` on server |
|
|
296
|
+
|
|
297
|
+
### Error Details
|
|
298
|
+
Error reason is in the `X-Status-Reason` response header (not always in the body).
|
|
299
|
+
|
|
300
|
+
### Duplicate Detection (409)
|
|
301
|
+
```json
|
|
302
|
+
{"reason": "Duplicate", "data": {"idList": ["existingId1"]}}
|
|
303
|
+
```
|
|
304
|
+
Bypass with `X-Skip-Duplicate-Check: true` header.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Performance Best Practices
|
|
309
|
+
|
|
310
|
+
1. **Select only needed fields** — `?select=id,name,status` avoids loading all attributes
|
|
311
|
+
2. **Skip total count** — `X-No-Total: true` header skips the COUNT query on list requests
|
|
312
|
+
3. **Paginate** — use `offset` + `maxSize` (keep maxSize at 50-100)
|
|
313
|
+
4. **Use primary filters** — server-optimized named filters are faster than complex WHERE
|
|
314
|
+
5. **Minimal API User roles** — dedicated API users with only required scopes
|
|
315
|
+
6. **No native rate limiter** — implement at reverse proxy level (nginx, Apache) if needed
|
|
316
|
+
7. **OpenAPI spec** — `GET OpenApi` returns full schema for your instance including custom entities (v9.3+, admin only)
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Client Libraries
|
|
321
|
+
|
|
322
|
+
### PHP (Official — Preferred)
|
|
323
|
+
|
|
324
|
+
`composer require espocrm/php-espo-api-client`
|
|
325
|
+
|
|
326
|
+
Class: `Espo\ApiClient\Client`. Constructor takes base URL. Auth via `setApiKey()` or `setApiKey()` + `setSecretKey()` for HMAC. All requests through `$client->request(METHOD, path, params, payload)`.
|
|
327
|
+
|
|
328
|
+
### Node.js
|
|
329
|
+
|
|
330
|
+
No official npm package. Build a thin client around `fetch` with:
|
|
331
|
+
- Base URL + `/api/v1/` prefix
|
|
332
|
+
- `X-Api-Key` header (or compute HMAC per-request)
|
|
333
|
+
- `Content-Type: application/json`
|
|
334
|
+
- Search params as JSON-encoded `searchParams` query param
|
|
335
|
+
- Error extraction from `X-Status-Reason` header on non-2xx responses
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## Field Types & API Representation
|
|
340
|
+
|
|
341
|
+
| Field Type | JSON Type | Example |
|
|
342
|
+
|---|---|---|
|
|
343
|
+
| varchar | string | `"name": "Test"` |
|
|
344
|
+
| text | string | `"description": "Long text"` |
|
|
345
|
+
| int | number | `"quantity": 5` |
|
|
346
|
+
| float | number | `"rate": 4.5` |
|
|
347
|
+
| boolean | boolean | `"isActive": true` |
|
|
348
|
+
| enum | string | `"status": "New"` |
|
|
349
|
+
| multiEnum | string[] | `"tags": ["A", "B"]` |
|
|
350
|
+
| date | string | `"closeDate": "2025-06-15"` |
|
|
351
|
+
| datetime | string (UTC) | `"createdAt": "2025-06-15 14:30:00"` |
|
|
352
|
+
| currency | number + string | `"amount": 1000, "amountCurrency": "USD"` |
|
|
353
|
+
| link | string (ID) | `"accountId": "someId"` |
|
|
354
|
+
| linkMultiple | string[] + object | `"teamsIds": ["id1"], "teamsNames": {"id1": "Sales"}` |
|
|
355
|
+
| email | string | `"emailAddress": "test@example.com"` |
|
|
356
|
+
| phone | string | `"phoneNumber": "+1234567890"` |
|
|
357
|
+
| address | multiple fields | `"billingAddressStreet": "123 Main", "billingAddressCity": "NYC"` |
|
|
358
|
+
| file | string (ID) | `"fileId": "attachmentId"` |
|
|
359
|
+
|
|
360
|
+
All datetime values are UTC. Date format: `YYYY-MM-DD`. Datetime: `YYYY-MM-DD HH:mm:ss`.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# EspoCRM WHERE Filter Operators
|
|
2
|
+
|
|
3
|
+
Complete reference for the `where` array filter objects used in list/search requests.
|
|
4
|
+
|
|
5
|
+
Each filter: `{"type": "...", "attribute": "...", "value": "..."}`
|
|
6
|
+
|
|
7
|
+
## Equality & Comparison
|
|
8
|
+
|
|
9
|
+
| Type | Value | Example |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `equals` | any | `{"type": "equals", "attribute": "status", "value": "New"}` |
|
|
12
|
+
| `notEquals` | any | `{"type": "notEquals", "attribute": "status", "value": "Canceled"}` |
|
|
13
|
+
| `greaterThan` | number/date | `{"type": "greaterThan", "attribute": "amount", "value": 1000}` |
|
|
14
|
+
| `lessThan` | number/date | `{"type": "lessThan", "attribute": "amount", "value": 5000}` |
|
|
15
|
+
| `greaterThanOrEquals` | number/date | `{"type": "greaterThanOrEquals", "attribute": "probability", "value": 50}` |
|
|
16
|
+
| `lessThanOrEquals` | number/date | `{"type": "lessThanOrEquals", "attribute": "probability", "value": 100}` |
|
|
17
|
+
|
|
18
|
+
## Null & Boolean
|
|
19
|
+
|
|
20
|
+
| Type | Notes |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `isNull` | No `value` needed |
|
|
23
|
+
| `isNotNull` | No `value` needed |
|
|
24
|
+
| `isTrue` | Boolean field check |
|
|
25
|
+
| `isFalse` | Boolean field check |
|
|
26
|
+
|
|
27
|
+
## String Matching
|
|
28
|
+
|
|
29
|
+
| Type | Value | Behavior |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `contains` | string | `%value%` |
|
|
32
|
+
| `notContains` | string | NOT `%value%` |
|
|
33
|
+
| `startsWith` | string | `value%` |
|
|
34
|
+
| `endsWith` | string | `%value` |
|
|
35
|
+
| `like` | string | Raw LIKE pattern (use `%` wildcards) |
|
|
36
|
+
| `notLike` | string | Raw NOT LIKE pattern |
|
|
37
|
+
|
|
38
|
+
## Set Membership
|
|
39
|
+
|
|
40
|
+
| Type | Value |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `in` | array of strings/numbers: `["New", "Assigned"]` |
|
|
43
|
+
| `notIn` | array of strings/numbers: `["Canceled", "Recycled"]` |
|
|
44
|
+
|
|
45
|
+
## Relationship Filters
|
|
46
|
+
|
|
47
|
+
| Type | Value | Notes |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `linkedWith` | array of IDs | Records linked to ANY of the given IDs |
|
|
50
|
+
| `notLinkedWith` | array of IDs | Records NOT linked to any of the given IDs |
|
|
51
|
+
| `isLinked` | — | Has at least one linked record |
|
|
52
|
+
| `isNotLinked` | — | Has no linked records |
|
|
53
|
+
|
|
54
|
+
## Date/Time Helpers
|
|
55
|
+
|
|
56
|
+
No `value` needed unless noted:
|
|
57
|
+
|
|
58
|
+
| Type | Notes |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `today` | |
|
|
61
|
+
| `past` | |
|
|
62
|
+
| `future` | |
|
|
63
|
+
| `lastSevenDays` | |
|
|
64
|
+
| `currentMonth` | |
|
|
65
|
+
| `lastMonth` | |
|
|
66
|
+
| `currentQuarter` | |
|
|
67
|
+
| `currentYear` | |
|
|
68
|
+
| `lastXDays` | `value`: number of days |
|
|
69
|
+
| `nextXDays` | `value`: number of days |
|
|
70
|
+
| `between` | `value`: `["YYYY-MM-DD", "YYYY-MM-DD"]` |
|
|
71
|
+
|
|
72
|
+
## Logical Combinators
|
|
73
|
+
|
|
74
|
+
Multiple items in the `where` array are implicitly **ANDed**.
|
|
75
|
+
|
|
76
|
+
For OR logic, wrap in a combinator:
|
|
77
|
+
```json
|
|
78
|
+
{"type": "or", "value": [
|
|
79
|
+
{"type": "equals", "attribute": "status", "value": "New"},
|
|
80
|
+
{"type": "equals", "attribute": "status", "value": "Assigned"}
|
|
81
|
+
]}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Combinators nest: `and` and `or` can contain other combinators.
|
|
@@ -158,6 +158,21 @@ Every abstraction has a cost:
|
|
|
158
158
|
|
|
159
159
|
**The question to ask:** Does this abstraction pay for itself? Will I use it enough to justify the cost? Would a junior developer understand it?
|
|
160
160
|
|
|
161
|
+
### File Size as a Smell
|
|
162
|
+
|
|
163
|
+
Keep files under 500 lines. This isn't an arbitrary limit — it's a smell detector. A file approaching 500 lines almost certainly has multiple responsibilities that should be separated.
|
|
164
|
+
|
|
165
|
+
**When a file grows too large:**
|
|
166
|
+
- Split by responsibility, not by arbitrary line count
|
|
167
|
+
- A 300-line file with two unrelated concerns is worse than a 480-line file with one
|
|
168
|
+
- The goal is cohesion: each file should have a single, clear reason to exist
|
|
169
|
+
|
|
170
|
+
**Why this matters:**
|
|
171
|
+
- Readability: Developers can hold one file's purpose in their head
|
|
172
|
+
- Testability: Smaller, focused files are easier to test in isolation
|
|
173
|
+
- Navigation: Finding what you need is faster in a well-structured codebase
|
|
174
|
+
- Review: Code review quality drops sharply beyond 500 lines
|
|
175
|
+
|
|
161
176
|
### Context-Appropriate Complexity
|
|
162
177
|
|
|
163
178
|
A CLI script has different needs than a production API.
|