The CRM commands work on Kenso's Accounts lane: accounts (companies), the people on them, and opportunities. They are beta: they need the accounts feature flag on your workspace (opportunities need opportunities, CRM sync needs ingestion). Help and kenso describe hide them until your workspace has the flag; --all-commands shows them.
| Command | What it does |
|---|---|
accounts import | Create accounts from a CSV or JSONL file. Research is charged per created account |
people import | Create or match people from a file, optionally onto accounts |
accounts update --each, people update --each, opportunities update --each | Edit many records from a file, one call per row |
crm-connections, crm-imports, crm-sync-issues | Read and run CRM sync. Connecting a CRM stays in the app |
Import accounts first, then people: people import never creates an account.
Import accounts
kenso accounts import --file accounts.csv
kenso accounts import --file accounts.csv --yes
name,domain,industry,employeeCount
Acme,acme.io,Software,120
Globex,globex.com,Manufacturing,"1,200"
- Columns map by name, ignoring case, spaces and dashes:
name(orcompany,companyName,accountName),domains(several, split on,or;) or onedomain(orwebsite,companyDomain),industry,employeeCount,hqLocation,linkedinUrl,stage,angle,whyNow,fitScore,fundingRound,cadenceDays,ownerMemberId,kenCompanyId,sendsFromInboxId,sendsFromLinkedInAccountIdandsource. - A domain is required. A file with no domain column is a usage error, and a row without a domain is
invalid(domain_required). - The dry run prices the research. It asks for a credit estimate per 1,000 accounts and puts the sum in the plan:
kind,accountCount,totalMillicredits,availableMillicreditsandsufficient. - Rows go 100 per call to
POST /v1/accounts/bulk-create.
Each row comes back:
| Status | Meaning |
|---|---|
created | A new account; id is the account id. Research is queued (researchQueued in the summary), or waits for credits (researchWaitingCredits) |
skipped, reason domain_taken | A company that is already an account; id is that account |
failed | Kenso refused the row (reason is the API's code, error names the field) or failed to save it. An item Kenso failed to save is sent once more before it counts as failed |
Rerunning the same file is safe: accounts that exist come back domain_taken.
Import people
kenso people import --file people.csv
kenso people import --file people.csv --find-emails --yes
kenso people import --file people.jsonl --dry-run
fullName,email,title,accountDomain,role
Ann Lee,[email protected],VP Sales,acme.io,champion
Bob Ray,,CTO,acme.io,
- Columns map by name, ignoring case, spaces and dashes:
email,fullName(orname),firstName,lastName,title,linkedinUrl(orlinkedin,profileUrl),accountDomain(ordomain,website,companyDomain),accountId,roleandpriority. Other columns are ignored with one warning. - A person needs a name:
fullName, orfirstName,lastNameor both (the CLI joins them). A row with none of them isinvalid(name_required). - To put a person on an account, give
accountDomainoraccountId. A row with both sends onlyaccountId. --find-emailsqueues an email find (charged in credits) for each person without an email.- Rows go 200 per call to
POST /v1/people/batch.
People already in the workspace are matched by email, then LinkedIn URL, so running the same file again creates nobody twice.
| Result | Row status | reason |
|---|---|---|
| A new person | created | |
| An existing person, added to the account | updated | |
| An existing person already on the account | skipped | already_on_account |
| An existing person, no account asked | skipped | matched |
| The person was removed from the account before | skipped | previously_removed |
| The account does not exist | failed | account_not_found: the person was saved without an account. Import the account, then rerun to place them |
| Kenso refused the row | failed | the API's reason |
The summary adds matched, addedToAccounts and emailFindsQueued.
Edit accounts, people and opportunities
Apart from accounts bulk-update, which sets one accountType on up to 500 accounts, there is no bulk edit route, so run the generated update command once per row with --each. Columns are the command's flags by API name or flag name, and the id column fills the route:
kenso accounts update --each accounts-edit.csv --dry-run
kenso accounts update --each accounts-edit.csv --yes
kenso people update --each people-edit.csv --yes
kenso opportunities update --each deals.csv --yes
accountId,stage,ownerMemberId,overwritePinned
501,engaged,42,true
502,customer,42,true
A row that changes a field someone pinned in the app fails as a whole (409 conflict, pinned_by_user: nothing on that record changes, the other fields of the row included), unless the row sets overwritePinned to true (or you pass --overwrite-pinned). To see every flag of an update command:
kenso describe accounts update
kenso accounts update --help
CRM sync
CRM sync has generated commands only: read connections, preview, start an import, and work through sync issues. Connect the CRM itself in the app.
kenso crm-connections list
kenso crm-connections get --connection-id 7
kenso crm-imports create --connection-id 7 --dry-run
kenso crm-sync-issues list --connection-id 7 --all
Run kenso crm-connections --help (or add --all-commands when the actions are hidden) to see every action.