@growthub/cli 0.3.54 → 0.3.55
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/assets/worker-kits/growthub-ai-website-cloner-v1/.env.example +7 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/QUICKSTART.md +116 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/brands/NEW-CLIENT.md +22 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/brands/_template/brand-kit.md +27 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/brands/growthub/brand-kit.md +26 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/bundles/growthub-ai-website-cloner-v1.json +53 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/docs/ai-website-cloner-fork-integration.md +118 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/docs/design-token-system.md +135 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/docs/multi-phase-pipeline.md +129 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/docs/parallel-builder-dispatch.md +103 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/examples/clone-brief-sample.md +54 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/examples/component-spec-sample.md +123 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/examples/platform-handoff-sample.md +102 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/examples/visual-qa-sample.md +119 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/growthub-meta/README.md +71 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/growthub-meta/kit-standard.md +47 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/kit.json +105 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/output/README.md +26 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/output-standards.md +75 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/runtime-assumptions.md +70 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/setup/check-deps.sh +50 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/setup/clone-fork.sh +66 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/setup/verify-env.mjs +78 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/skills.md +186 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/asset-manifest.md +57 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/builder-dispatch-plan.md +92 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/clone-brief.md +59 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/component-spec.md +124 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/design-token-extraction.md +89 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/platform-handoff.md +114 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/reconnaissance-report.md +77 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/visual-qa-checklist.md +107 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/validation-checklist.md +76 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/workers/ai-website-cloner-operator/CLAUDE.md +256 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/.env.example +40 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/QUICKSTART.md +114 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/brands/NEW-CLIENT.md +42 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/brands/_template/brand-kit.md +49 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/brands/growthub/brand-kit.md +50 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/bundles/growthub-open-montage-studio-v1.json +55 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/docs/cms-node-bridge.md +152 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/docs/open-montage-fork-integration.md +120 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/docs/pipeline-reference.md +147 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/docs/provider-adapter-layer.md +105 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/examples/cms-node-video-gen-sample.md +109 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/examples/pipeline-selection-sample.md +67 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/examples/platform-ready-handoff-sample.md +101 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/examples/video-production-brief-sample.md +68 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/growthub-meta/README.md +7 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/growthub-meta/kit-standard.md +45 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/kit.json +107 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/output/README.md +34 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/output-standards.md +79 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/runtime-assumptions.md +86 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/setup/check-deps.sh +43 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/setup/clone-fork.sh +53 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/setup/verify-env.mjs +102 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/skills.md +254 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/asset-tracking.md +46 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/cms-node-pipeline-mapping.md +64 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/generation-batch-plan.md +70 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/pipeline-selection-brief.md +67 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/platform-ready-execution-handoff.md +103 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/prompt-matrix.md +48 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/provider-selection-brief.md +86 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/review-qa-checklist.md +59 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/scene-plan.md +65 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/video-production-brief.md +58 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/validation-checklist.md +46 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/workers/open-montage-studio-operator/CLAUDE.md +304 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/.env.example +15 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/QUICKSTART.md +90 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/brands/NEW-CLIENT.md +57 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/brands/_template/brand-kit.md +88 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/brands/growthub/brand-kit.md +92 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/bundles/growthub-twenty-crm-v1.json +56 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/docs/api-and-webhooks.md +296 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/docs/data-model-layer.md +172 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/docs/twenty-fork-integration.md +213 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/examples/crm-playbook-sample.md +172 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/examples/crm-setup-sample.md +100 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/examples/lead-enrichment-sample.md +117 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/examples/pipeline-automation-sample.md +132 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/growthub-meta/README.md +114 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/growthub-meta/kit-standard.md +61 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/kit.json +108 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/output/README.md +46 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/output-standards.md +175 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/runtime-assumptions.md +150 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/setup/check-deps.sh +56 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/setup/clone-fork.sh +77 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/setup/verify-env.mjs +105 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/skills.md +401 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/api-query-plan.md +179 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/crm-playbook.md +155 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/crm-setup-brief.md +94 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/custom-object-design.md +115 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/data-model-design.md +112 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/enrichment-field-map.md +100 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/import-mapping.md +139 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/integration-handoff.md +190 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/lead-enrichment-pipeline.md +128 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/pipeline-automation-brief.md +88 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/webhook-integration-spec.md +129 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/workspace-config-checklist.md +129 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/validation-checklist.md +115 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/workers/twenty-crm-operator/CLAUDE.md +310 -0
- package/package.json +1 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 2,
|
|
3
|
+
"bundle": {
|
|
4
|
+
"id": "growthub-twenty-crm-v1",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"kitId": "growthub-twenty-crm-v1",
|
|
7
|
+
"workerId": "twenty-crm-operator"
|
|
8
|
+
},
|
|
9
|
+
"briefType": "twenty-crm-growth-stack",
|
|
10
|
+
"publicExampleBrandPaths": [
|
|
11
|
+
"brands/growthub/brand-kit.md"
|
|
12
|
+
],
|
|
13
|
+
"requiredFrozenAssets": [
|
|
14
|
+
"QUICKSTART.md",
|
|
15
|
+
".env.example",
|
|
16
|
+
"skills.md",
|
|
17
|
+
"output-standards.md",
|
|
18
|
+
"runtime-assumptions.md",
|
|
19
|
+
"validation-checklist.md",
|
|
20
|
+
"workers/twenty-crm-operator/CLAUDE.md",
|
|
21
|
+
"brands/_template/brand-kit.md",
|
|
22
|
+
"brands/growthub/brand-kit.md",
|
|
23
|
+
"brands/NEW-CLIENT.md",
|
|
24
|
+
"setup/clone-fork.sh",
|
|
25
|
+
"setup/verify-env.mjs",
|
|
26
|
+
"setup/check-deps.sh",
|
|
27
|
+
"output/README.md",
|
|
28
|
+
"templates/crm-setup-brief.md",
|
|
29
|
+
"templates/data-model-design.md",
|
|
30
|
+
"templates/lead-enrichment-pipeline.md",
|
|
31
|
+
"templates/pipeline-automation-brief.md",
|
|
32
|
+
"templates/webhook-integration-spec.md",
|
|
33
|
+
"templates/api-query-plan.md",
|
|
34
|
+
"templates/crm-playbook.md",
|
|
35
|
+
"templates/custom-object-design.md",
|
|
36
|
+
"templates/import-mapping.md",
|
|
37
|
+
"templates/workspace-config-checklist.md",
|
|
38
|
+
"templates/integration-handoff.md",
|
|
39
|
+
"templates/enrichment-field-map.md",
|
|
40
|
+
"examples/crm-setup-sample.md",
|
|
41
|
+
"examples/lead-enrichment-sample.md",
|
|
42
|
+
"examples/pipeline-automation-sample.md",
|
|
43
|
+
"examples/crm-playbook-sample.md",
|
|
44
|
+
"docs/twenty-fork-integration.md",
|
|
45
|
+
"docs/api-and-webhooks.md",
|
|
46
|
+
"docs/data-model-layer.md",
|
|
47
|
+
"growthub-meta/README.md",
|
|
48
|
+
"growthub-meta/kit-standard.md"
|
|
49
|
+
],
|
|
50
|
+
"optionalPresets": [],
|
|
51
|
+
"export": {
|
|
52
|
+
"folderName": "growthub-agent-worker-kit-twenty-crm-v1",
|
|
53
|
+
"zipFileName": "growthub-agent-worker-kit-twenty-crm-v1.zip"
|
|
54
|
+
},
|
|
55
|
+
"activationModes": ["export"]
|
|
56
|
+
}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# API and Webhooks — Twenty CRM
|
|
2
|
+
|
|
3
|
+
**Kit:** `growthub-twenty-crm-v1`
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## OVERVIEW
|
|
8
|
+
|
|
9
|
+
Twenty CRM exposes two API surfaces:
|
|
10
|
+
|
|
11
|
+
1. **GraphQL API** at `<TWENTY_API_URL>/graphql` — the primary data access surface for queries and mutations
|
|
12
|
+
2. **REST API** at `<TWENTY_API_URL>/api/objects/<object-name>` — simpler CRUD operations
|
|
13
|
+
|
|
14
|
+
Both require a Bearer token authentication header.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## AUTHENTICATION
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
Authorization: Bearer <TWENTY_API_TOKEN>
|
|
22
|
+
Content-Type: application/json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Tokens are workspace-scoped and generated in:
|
|
26
|
+
**Settings > API > Tokens > Generate API Token**
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## GRAPHQL API
|
|
31
|
+
|
|
32
|
+
### Endpoint
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
POST <TWENTY_API_URL>/graphql
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Common query patterns
|
|
39
|
+
|
|
40
|
+
#### List all People
|
|
41
|
+
|
|
42
|
+
```graphql
|
|
43
|
+
query {
|
|
44
|
+
people {
|
|
45
|
+
edges {
|
|
46
|
+
node {
|
|
47
|
+
id
|
|
48
|
+
name { firstName lastName }
|
|
49
|
+
emails { primaryEmail }
|
|
50
|
+
position
|
|
51
|
+
company { name domain }
|
|
52
|
+
createdAt
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
totalCount
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
#### Filter People by email domain
|
|
61
|
+
|
|
62
|
+
```graphql
|
|
63
|
+
query {
|
|
64
|
+
people(filter: {
|
|
65
|
+
emails: { primaryEmail: { like: "%@acme.com" } }
|
|
66
|
+
}) {
|
|
67
|
+
edges {
|
|
68
|
+
node {
|
|
69
|
+
id
|
|
70
|
+
name { firstName lastName }
|
|
71
|
+
emails { primaryEmail }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### Get open Opportunities by stage
|
|
79
|
+
|
|
80
|
+
```graphql
|
|
81
|
+
query {
|
|
82
|
+
opportunities(filter: {
|
|
83
|
+
stage: { in: ["LEAD", "QUALIFIED", "DEMO", "PROPOSAL"] }
|
|
84
|
+
}, orderBy: { closeDate: AscNullsLast }) {
|
|
85
|
+
edges {
|
|
86
|
+
node {
|
|
87
|
+
id
|
|
88
|
+
name
|
|
89
|
+
stage
|
|
90
|
+
amount { amountMicros currencyCode }
|
|
91
|
+
closeDate
|
|
92
|
+
assignee { name { firstName lastName } }
|
|
93
|
+
pointOfContact { name { firstName lastName } emails { primaryEmail } }
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
totalCount
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### Create a Person
|
|
102
|
+
|
|
103
|
+
```graphql
|
|
104
|
+
mutation {
|
|
105
|
+
createPerson(data: {
|
|
106
|
+
name: { firstName: "Jane", lastName: "Doe" }
|
|
107
|
+
emails: { primaryEmail: "jane@example.com" }
|
|
108
|
+
position: "Head of Growth"
|
|
109
|
+
linkedInLink: { url: "https://linkedin.com/in/janedoe", label: "LinkedIn" }
|
|
110
|
+
companyId: "<company-uuid>"
|
|
111
|
+
}) {
|
|
112
|
+
id
|
|
113
|
+
name { firstName lastName }
|
|
114
|
+
createdAt
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### Update an Opportunity stage
|
|
120
|
+
|
|
121
|
+
```graphql
|
|
122
|
+
mutation {
|
|
123
|
+
updateOpportunity(
|
|
124
|
+
id: "<opportunity-uuid>"
|
|
125
|
+
data: { stage: "CLOSED_WON" }
|
|
126
|
+
) {
|
|
127
|
+
id
|
|
128
|
+
stage
|
|
129
|
+
updatedAt
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### Create a Note linked to a Person
|
|
135
|
+
|
|
136
|
+
```graphql
|
|
137
|
+
mutation {
|
|
138
|
+
createNote(data: {
|
|
139
|
+
body: "Spoke on 2026-04-15 — interested in Growthub platform for their outbound motion."
|
|
140
|
+
noteTargets: {
|
|
141
|
+
createMany: {
|
|
142
|
+
data: [{ personId: "<person-uuid>" }]
|
|
143
|
+
skipDuplicates: true
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}) {
|
|
147
|
+
id
|
|
148
|
+
body
|
|
149
|
+
createdAt
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## REST API
|
|
157
|
+
|
|
158
|
+
### Endpoint
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
GET/POST/PATCH/DELETE <TWENTY_API_URL>/api/objects/<object-name>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Object name is the plural lowercase form (e.g. `people`, `companies`, `opportunities`).
|
|
165
|
+
|
|
166
|
+
### Examples
|
|
167
|
+
|
|
168
|
+
#### List companies
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
curl -X GET "<TWENTY_API_URL>/api/objects/companies" \
|
|
172
|
+
-H "Authorization: Bearer $TWENTY_API_TOKEN"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
#### Create a company via REST
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
curl -X POST "<TWENTY_API_URL>/api/objects/companies" \
|
|
179
|
+
-H "Authorization: Bearer $TWENTY_API_TOKEN" \
|
|
180
|
+
-H "Content-Type: application/json" \
|
|
181
|
+
-d '{"name": "Acme Corp", "domainName": {"primaryLinkUrl": "acme.com"}}'
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### Update an opportunity
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
curl -X PATCH "<TWENTY_API_URL>/api/objects/opportunities/<id>" \
|
|
188
|
+
-H "Authorization: Bearer $TWENTY_API_TOKEN" \
|
|
189
|
+
-H "Content-Type: application/json" \
|
|
190
|
+
-d '{"stage": "PROPOSAL"}'
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## WEBHOOKS
|
|
196
|
+
|
|
197
|
+
### Outbound webhooks (Twenty → external)
|
|
198
|
+
|
|
199
|
+
Twenty can fire outbound webhooks on object lifecycle events. Configure in:
|
|
200
|
+
**Settings > API > Webhooks > Add Webhook**
|
|
201
|
+
|
|
202
|
+
Or create via the workflow engine using the `SEND_HTTP_REQUEST` action type.
|
|
203
|
+
|
|
204
|
+
**Event naming convention:** `<object>.<event>` (e.g. `opportunity.created`, `person.updated`)
|
|
205
|
+
|
|
206
|
+
**Outbound webhook payload schema:**
|
|
207
|
+
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"targetUrl": "https://your-endpoint.com/webhook",
|
|
211
|
+
"eventName": "opportunity.created",
|
|
212
|
+
"workspaceId": "<workspace-uuid>",
|
|
213
|
+
"webhookId": "<webhook-uuid>",
|
|
214
|
+
"eventDate": "2026-04-15T10:00:00.000Z",
|
|
215
|
+
"objectMetadata": {
|
|
216
|
+
"id": "<object-uuid>",
|
|
217
|
+
"nameSingular": "opportunity"
|
|
218
|
+
},
|
|
219
|
+
"record": {
|
|
220
|
+
"id": "<record-uuid>",
|
|
221
|
+
"name": "Acme Corp — Deal",
|
|
222
|
+
"stage": "LEAD",
|
|
223
|
+
"createdAt": "2026-04-15T10:00:00.000Z"
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Note:** The exact `record` payload structure depends on the object and Twenty version. Inspect the actual webhook in the Twenty UI or via a test event before finalizing payload parsing.
|
|
229
|
+
|
|
230
|
+
### Inbound webhooks (external → Twenty)
|
|
231
|
+
|
|
232
|
+
Twenty does not natively receive inbound webhooks — you must build a webhook receiver that:
|
|
233
|
+
1. validates the incoming event signature (from the source system)
|
|
234
|
+
2. transforms the payload to the Twenty GraphQL mutation format
|
|
235
|
+
3. calls the Twenty API to create or update the relevant record
|
|
236
|
+
|
|
237
|
+
See `docs/twenty-fork-integration.md` for the workflow engine's inbound webhook trigger, which can be used to trigger automations from external systems.
|
|
238
|
+
|
|
239
|
+
### Retry policy
|
|
240
|
+
|
|
241
|
+
Twenty's outbound webhooks retry on failure with exponential backoff. The default retry count and backoff schedule depend on the Twenty version. Check the workflow logs in Settings > Workflows for retry status.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## METADATA API
|
|
246
|
+
|
|
247
|
+
Used to create and manage custom objects and fields programmatically.
|
|
248
|
+
|
|
249
|
+
### Endpoint
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
POST <TWENTY_API_URL>/metadata
|
|
253
|
+
Authorization: Bearer <TWENTY_API_TOKEN>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Introspect existing metadata
|
|
257
|
+
|
|
258
|
+
```graphql
|
|
259
|
+
query {
|
|
260
|
+
objects {
|
|
261
|
+
edges {
|
|
262
|
+
node {
|
|
263
|
+
id
|
|
264
|
+
nameSingular
|
|
265
|
+
labelSingular
|
|
266
|
+
isActive
|
|
267
|
+
fields {
|
|
268
|
+
edges {
|
|
269
|
+
node {
|
|
270
|
+
id
|
|
271
|
+
name
|
|
272
|
+
type
|
|
273
|
+
isNullable
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## ERROR HANDLING
|
|
286
|
+
|
|
287
|
+
| HTTP Status | Meaning | Action |
|
|
288
|
+
|---|---|---|
|
|
289
|
+
| 200 | Success | Check `errors` array in GraphQL response body |
|
|
290
|
+
| 401 | Unauthorized | Token is missing, expired, or wrong workspace |
|
|
291
|
+
| 403 | Forbidden | Token valid but lacks access to the resource |
|
|
292
|
+
| 404 | Not found | Object ID does not exist |
|
|
293
|
+
| 429 | Rate limited | Back off and retry after the period indicated in headers |
|
|
294
|
+
| 500 | Server error | Log and retry; contact workspace admin if persistent |
|
|
295
|
+
|
|
296
|
+
**GraphQL errors** are returned with HTTP 200 but include an `errors` array. Always check `body.errors` after parsing the response.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Data Model Layer — Twenty CRM
|
|
2
|
+
|
|
3
|
+
**Kit:** `growthub-twenty-crm-v1`
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## OVERVIEW
|
|
8
|
+
|
|
9
|
+
Twenty CRM's data model layer controls how objects, fields, and relations are defined, stored, and exposed via the API. Understanding this layer is essential for designing accurate CRM schemas and writing reliable migration or enrichment scripts.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## STANDARD VS. CUSTOM OBJECTS
|
|
14
|
+
|
|
15
|
+
### Standard objects
|
|
16
|
+
|
|
17
|
+
Standard objects ship with Twenty and cannot be deleted. Their core fields are fixed, but additional custom fields can be added.
|
|
18
|
+
|
|
19
|
+
| Object | Purpose | Key standard fields |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `Person` | Individual contact | `name`, `emails`, `phones`, `company` (relation), `position`, `linkedInLink`, `city` |
|
|
22
|
+
| `Company` | Organization | `name`, `domainName`, `employees`, `annualRecurringRevenue`, `address`, `linkedInLink` |
|
|
23
|
+
| `Opportunity` | Sales pipeline item | `name`, `stage`, `amount`, `closeDate`, `pointOfContact` (relation), `company` (relation) |
|
|
24
|
+
| `Note` | Freeform text | `body`, `noteTargets` (polymorphic relation to any object) |
|
|
25
|
+
| `Task` | Action item | `title`, `body`, `dueAt`, `assignee` (relation to WorkspaceMember), `taskTargets` |
|
|
26
|
+
| `Workspace Member` | CRM user | `name`, `email`, `role` |
|
|
27
|
+
|
|
28
|
+
### Custom objects
|
|
29
|
+
|
|
30
|
+
Custom objects are created via:
|
|
31
|
+
- **UI:** Settings > Objects > `+ New custom object`
|
|
32
|
+
- **Metadata API:** `createOneObject` mutation at `/metadata`
|
|
33
|
+
|
|
34
|
+
Once created and activated, custom objects are immediately queryable and mutable via the GraphQL API using automatically generated resolvers.
|
|
35
|
+
|
|
36
|
+
**Custom object naming:**
|
|
37
|
+
- `nameSingular`: camelCase (e.g. `partnerAccount`)
|
|
38
|
+
- `namePlural`: camelCase plural (e.g. `partnerAccounts`)
|
|
39
|
+
- `labelSingular`: Display name singular (e.g. `Partner Account`)
|
|
40
|
+
- `labelPlural`: Display name plural (e.g. `Partner Accounts`)
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## FIELD TYPES
|
|
45
|
+
|
|
46
|
+
| Type | Description | Example values |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `TEXT` | Single-line string | `"Jane Doe"`, `"San Francisco"` |
|
|
49
|
+
| `RICH_TEXT` | Multi-line rich text | Note body, description |
|
|
50
|
+
| `NUMBER` | Integer or decimal | `250`, `4.5` |
|
|
51
|
+
| `BOOLEAN` | True/false | `true`, `false` |
|
|
52
|
+
| `DATE` | Date only (ISO 8601) | `"2026-04-15"` |
|
|
53
|
+
| `DATE_TIME` | Date and time (ISO 8601) | `"2026-04-15T10:00:00.000Z"` |
|
|
54
|
+
| `SELECT` | Single choice from options | `"QUALIFIED"`, `"CLOSED_WON"` |
|
|
55
|
+
| `MULTI_SELECT` | Multiple choices | `["INBOUND", "REFERRAL"]` |
|
|
56
|
+
| `RELATION` | Link to another object | `{ id: "<uuid>" }` |
|
|
57
|
+
| `LINK` | URL with optional label | `{ url: "https://...", label: "LinkedIn" }` |
|
|
58
|
+
| `EMAILS` | Multi-email with primary | `{ primaryEmail: "jane@example.com" }` |
|
|
59
|
+
| `PHONES` | Multi-phone with primary | `{ primaryPhoneNumber: "+14155550100" }` |
|
|
60
|
+
| `CURRENCY` | Amount + currency code | `{ amountMicros: 10000000, currencyCode: "USD" }` |
|
|
61
|
+
| `ADDRESS` | Structured address | `{ addressStreet1: "...", addressCity: "...", addressCountryCode: "US" }` |
|
|
62
|
+
| `RATING` | Star rating (1–5) | `"RATING_4"` |
|
|
63
|
+
| `FULL_NAME` | First + last name pair | `{ firstName: "Jane", lastName: "Doe" }` |
|
|
64
|
+
| `UUID` | Universally unique identifier | `"a3d9f2..."` |
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## RELATIONS
|
|
69
|
+
|
|
70
|
+
Twenty uses three types of relations between objects:
|
|
71
|
+
|
|
72
|
+
| Relation type | Description |
|
|
73
|
+
|---|---|
|
|
74
|
+
| One-to-one | One record on each side (rare) |
|
|
75
|
+
| One-to-many | One parent record links to many child records (e.g. Company → many Persons) |
|
|
76
|
+
| Many-to-many | Records on both sides can link to multiple records on the other side |
|
|
77
|
+
|
|
78
|
+
### Relation field definition
|
|
79
|
+
|
|
80
|
+
When you add a RELATION field to an object, you define:
|
|
81
|
+
- **Source object** (where the field appears)
|
|
82
|
+
- **Target object** (what it links to)
|
|
83
|
+
- **Cardinality** (one-to-one, one-to-many, many-to-many)
|
|
84
|
+
- **Field name** on both the source and target sides
|
|
85
|
+
|
|
86
|
+
### Standard relation examples
|
|
87
|
+
|
|
88
|
+
```text
|
|
89
|
+
Person ─── company (manyToOne) ──> Company
|
|
90
|
+
Company ─── people (oneToMany) ──> [Person]
|
|
91
|
+
|
|
92
|
+
Opportunity ─── pointOfContact (manyToOne) ──> Person
|
|
93
|
+
Opportunity ─── company (manyToOne) ──> Company
|
|
94
|
+
|
|
95
|
+
Note ─── noteTargets (polymorphic) ──> [Person | Company | Opportunity | ...]
|
|
96
|
+
Task ─── taskTargets (polymorphic) ──> [Person | Company | Opportunity | ...]
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## SELECT FIELD OPTIONS
|
|
102
|
+
|
|
103
|
+
SELECT fields require predefined options. Each option has:
|
|
104
|
+
- `value`: internal identifier, `SCREAMING_SNAKE_CASE` (e.g. `CLOSED_WON`)
|
|
105
|
+
- `label`: display name (e.g. `Closed Won`)
|
|
106
|
+
- `color`: optional UI color for the badge
|
|
107
|
+
- `position`: display order
|
|
108
|
+
|
|
109
|
+
**Opportunity stage options (default):**
|
|
110
|
+
|
|
111
|
+
| Value | Label | Typical position |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| `LEAD` | Lead | 1 |
|
|
114
|
+
| `QUALIFIED` | Qualified | 2 |
|
|
115
|
+
| `MEETING` | Meeting | 3 |
|
|
116
|
+
| `PROPOSAL` | Proposal | 4 |
|
|
117
|
+
| `CUSTOMER` | Customer | 5 |
|
|
118
|
+
| `CLOSED` | Closed | 6 |
|
|
119
|
+
|
|
120
|
+
**Note:** The exact default stage values depend on the Twenty version and workspace seed. Inspect the actual Opportunity object in your workspace before mapping stage values in automation or import scripts.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## CURRENCY FIELD: MICROS FORMAT
|
|
125
|
+
|
|
126
|
+
Twenty stores currency amounts in **micros** (millionths of the base unit) to avoid floating-point precision issues.
|
|
127
|
+
|
|
128
|
+
**Conversion:**
|
|
129
|
+
- `$10,000` → `amountMicros: 10000000000` (multiply by 1,000,000)
|
|
130
|
+
- `amountMicros: 5000000` → `$5` (divide by 1,000,000)
|
|
131
|
+
|
|
132
|
+
Always convert amounts to micros before writing to the API. Always divide by 1,000,000 when reading amounts for display.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## ID FORMAT
|
|
137
|
+
|
|
138
|
+
All Twenty record IDs are UUIDs (version 4). Example:
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
a3d9f2c1-4b5e-4a8b-9c7d-0e1f2a3b4c5d
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Never assume sequential IDs. Use the UUID when referencing related records in mutations.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## SYSTEM FIELDS
|
|
149
|
+
|
|
150
|
+
Every object (standard or custom) automatically includes these system fields:
|
|
151
|
+
|
|
152
|
+
| Field | Type | Notes |
|
|
153
|
+
|---|---|---|
|
|
154
|
+
| `id` | UUID | Primary key — auto-generated |
|
|
155
|
+
| `createdAt` | DATE_TIME | Set at creation — do not override |
|
|
156
|
+
| `updatedAt` | DATE_TIME | Set on every update — do not override |
|
|
157
|
+
| `deletedAt` | DATE_TIME | Set on soft delete — null if record is active |
|
|
158
|
+
|
|
159
|
+
Do not create custom fields with these names.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## DATABASE LAYER
|
|
164
|
+
|
|
165
|
+
Twenty uses PostgreSQL. Each workspace has its own schema (multi-tenant by schema). Custom objects create new tables within the workspace schema.
|
|
166
|
+
|
|
167
|
+
For local-fork development:
|
|
168
|
+
- PostgreSQL runs on `localhost:5432` (Docker)
|
|
169
|
+
- Default credentials are in `.env` (from `.env.example`)
|
|
170
|
+
- Use `npx nx run twenty-server:database:migrate` to run migrations after code changes
|
|
171
|
+
|
|
172
|
+
**Do not query the database directly in production.** Always use the GraphQL or REST API. Direct database access is only appropriate during local-fork development for schema inspection.
|