CRM
Reference
Every crm.* and data.crm.* workflow with who may run it, error codes, limits and troubleshooting
Workflows
Each workflow acts on your current organization and on the Identity app you pass as identity_app_uuid. Read exact inputs and outputs with get_workflow_schema or in the reference catalog.
| Workflow | Who | Does |
|---|---|---|
crm.lead.capture | members | Find or create the contact, open a lead if none is open, log a timeline entry. Idempotent on ref |
crm.contact.upsert | members | Create a contact or update the one with the same phone or email |
crm.contact.update | members | Edit one contact: name, phone, email, owner, tags, attributes, opt-out |
crm.contact.erase | owner or admin | Anonymize a contact and its timeline, close its open leads |
crm.lead.update-stage | members | Move a lead to another stage |
crm.lead.assign | members | Give a lead an owner, or clear it |
crm.lead.convert | owner or admin | Turn an open lead into an end user of the app |
crm.activity.add | members | Add a note or message to a contact's timeline. Idempotent on ref |
data.crm.contact.list | members | Page contacts |
data.crm.contact.get | members | One contact with its leads and timeline size |
data.crm.lead.list | members | Page leads |
data.crm.activity.list | members | Page one contact's timeline |
"Members" means members of your organization. Your app's end users cannot run any of them.
Errors
| Code | Means |
|---|---|
CRM_ACCESS_DENIED | The run was made for an end user, or the organization_uuid passed does not match your token |
CRM_ADMIN_REQUIRED | Converting and erasing need an organization owner or admin |
Input problems fail the run with a readable failure_reason, listed under Troubleshooting.
Limits
| Limit | Value |
|---|---|
| Tags per contact | 16, each up to 64 characters |
attributes, source_detail, timeline data | JSON object, up to 8 KB per call |
Timeline body | 20,000 characters |
| Name | 256 characters |
ref | 255 characters |
| Stage, source, channel, kind | Lowercase slug: starts with a letter, then a-z, 0-9, _, ., -, up to 32 characters |
pipeline_key | Same rule, up to 64 characters |
data.crm.lead.list, data.crm.activity.list | 50 rows by default, at most 100 |
data.crm.contact.list | 25 rows by default, at most 50 |
data.crm.contact.get | The contact's 50 most recent leads |
| Timeline body in lists | First 2,000 characters |
Contact search | 120 characters |
Troubleshooting
| You see | Do this |
|---|---|
phone_e164, wa_id or email is required | Send at least one way to reach the person |
phone_e164 must be an E.164 number | Use the country code, for example +5511999998888 |
identity_app_uuid is not an identity app of this organization | Check the app id with identity.app.query |
owner_user_uuid is not a member of this organization | Pick an owner from identity.membership.query |
the contact already has an open lead in this pipeline | Close or move the other lead first, or use another pipeline_key |
use crm.lead.convert to convert a lead | converted cannot be set with crm.lead.update-stage |
a converted lead is final | Open a new lead for the contact with crm.lead.capture |
lead is lost; reopen it (crm.lead.update-stage) first | Only open leads convert |
the contact has no phone; pass end_user_uuid ... | Create the end user with identity.end-user.create, then convert with its id |
another contact already has this phone (or email) | Two contacts cannot share a phone or email. Edit the other contact first |
a contact keeps a phone or an email | Do not clear both |
contact was erased | Erased contacts cannot be edited. Capture the person again to start a new contact |
ref is already recorded on another contact's timeline | Each ref belongs to one contact. Use a different id |
A capture returns deduplicated: true and changed nothing | That ref was already recorded. This is the retry protection working |
A value you stored in attributes is missing from a list | Lists leave out attributes. Read the contact with data.crm.contact.get |
