Feature request: expose Baileys' `addOrEditContact` / `removeContact` (write a contact's name)
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 初心者へのやさしさ
- 65/100
- issue の種類
- 機能追加
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- nodejs, typescript
調査の方向性
The issue is about adding contact write endpoints to the Evolution API. Start by examining the existing chat router in src/api/routes/chat.router.ts and the Baileys service in whatsapp.baileys.service.ts. The implementation involves creating a DTO in src/api/dto/chat.dto.ts, adding new POST routes for updateContact and removeContact, and calling the underlying Baileys methods addOrEditContact and removeContact. Ensure the local database (Prisma) and webhooks are updated. Test by verifying the new endpoints work and sync names correctly.
索引モデルが issue の本文から書いたものです。
説明
🎯 Problem Statement
There is no endpoint to WRITE a contact. POST /chat/findContacts/{instance} reads them, and POST /chat/updateProfileName/{instance} changes the connected account's OWN profile name — neither can set the name of another contact.
Checked on our instance (Baileys connection): POST to /chat/updateContact/{instance}, /chat/upsertContact/{instance}, /chat/updateContactName/{instance} and /chat/saveContact/{instance} all return 404. The route list in src/api/routes/chat.router.ts on main confirms it: 23 routes, none of them a contact write. (The "Update Contact" endpoint in the docs belongs to the EvoAI CRM service, a different product that does not touch the WhatsApp instance.)
The result is that any CRM or inbox built on Evolution has a one-way name: the address book and push names flow from the device into the application (CONTACTS_UPSERT / CONTACTS_UPDATE), but a name corrected inside the application can never reach the user's own WhatsApp.
This is not a limitation of WhatsApp. WhatsApp Web renames a contact without touching the phone's address book, because WhatsApp keeps a server-side contact list per account that syncs to every linked device.
💡 Proposed Solution
Expose what Baileys already implements in src/Socket/chats.ts:
const addOrEditContact = (jid, contact) => chatModify({ contact }, jid)
const removeContact = (jid) => chatModify({ contact: null }, jid)
It is an app-state patch (contactAction), so it propagates to all linked devices. The proto message is:
message ContactAction {
optional string fullName = 1;
optional string firstName = 2;
optional string lidJid = 3;
optional bool saveOnPrimaryAddressbook = 4;
optional string pnJid = 5;
optional string username = 6;
}
Note saveOnPrimaryAddressbook: the protocol itself distinguishes "save in WhatsApp's own contact list" from "save in the device's address book".
Suggested API:
POST /chat/updateContact/{instance}
{
"number": "5546999103009",
"fullName": "Ricardo Cavalcante | Ortopedista",
"firstName": "Ricardo",
"saveOnPrimaryAddressbook": false
}
POST /chat/removeContact/{instance}
{ "number": "5546999103009" }
Implementation sketch:
- src/api/dto/chat.dto.ts — UpdateContactDto { number?, remoteJid?, fullName, firstName?, saveOnPrimaryAddressbook? }
- src/api/routes/chat.router.ts — router.post('/updateContact') (+ removeContact), with the usual routerPath / dataValidate / schema pair.
- whatsapp.baileys.service.ts:
public async updateContact(data: UpdateContactDto) {
const jid = createJid(data.number ?? data.remoteJid)
await this.client.addOrEditContact(jid, {
fullName: data.fullName,
firstName: data.firstName ?? data.fullName,
saveOnPrimaryAddressbook: data.saveOnPrimaryAddressbook ?? false,
})
// keep the local cache consistent, otherwise findContacts keeps returning the old name
await this.prismaRepository.contact.updateMany({
where: { instanceId: this.instanceId, remoteJid: jid },
data: { pushName: data.fullName },
})
this.sendDataWebhook(Events.CONTACTS_UPDATE, [{ remoteJid: jid, pushName: data.fullName }])
return { update: 'success' }
}
- whatsapp.business.service.ts (Cloud API) — throw BadRequestException: the official API has no contact list, so this is Baileys-only by nature.
Edge cases:
- Groups are out of scope: renaming a group is updateGroupSubject, which changes the subject for every participant.
- removeContact is destructive (it clears the name on the user's own devices), so it should be a separate endpoint and never an empty fullName falling through updateContact.
- Idempotent: sending the same name twice is a no-op patch.
Happy to open a PR if this shape looks right to you.
🔄 Alternatives Considered
- Probing for an undocumented route: the four plausible names return 404, and the router source confirms none exists.
- Keeping the name local only (what we ship today), with the UI stating explicitly that it does not reach the phone. It works, but it leaves the two sides permanently out of sync.
- The EvoAI CRM "Update Contact" endpoints: different product, edits CRM records, does not touch the WhatsApp instance.
- Running a patched fork of Evolution with this route: doable, but it means maintaining a custom image for one contact name.
📊 Priority
Low - Nice to have
🧩 Component
None
🎯 Use Case
We run an internal CRM/inbox on Evolution: our team answers WhatsApp from inside our own application, with the same number they use on their phones. People arrive from Click-to-WhatsApp ads with no name in the address book, and whoever answers types the real one ("Ricardo Cavalcante | Ortopedista").
Today that name lives only in our database. The same person on the operator's phone is still a bare number, so the phone and the application disagree about who the conversation belongs to — and the correction has to be made twice, by hand, in two places.
Our user put it plainly: "WhatsApp Web doesn't write to anyone's address book, and it renames contacts." She is right, and we had to tell her the bridge we use cannot do it.
📝 Additional Context
Evolution API v2.x, Baileys connection type, self-hosted (Docker).
- 主要言語
- TypeScript
- スター
- 9.6k
- フォーク
- 7.3k
- PR マージ指標
- 30日以内にマージされた PR はありません
環境構築
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
evolution-foundation/evolution-api のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
evolution-foundation/evolution-api#2723 ·
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1〜3時間 初心者へのやさしさ 88/100
evolution-foundation/evolution-api#2704 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
evolution-foundation/evolution-api#2702 ·
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 88/100
evolution-foundation/evolution-api#2700 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
evolution-foundation/evolution-api#2675 ·
メンテナーはふだん 1 日以内に返信
evolution-foundation/evolution-api の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
diegosouzapw/OmniRoute#14869 ·
メンテナーはふだん 1 日以内に返信
-
enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 94/100
メンテナーはふだん 1 日以内に返信
-
status: waiting triage
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
freeCodeCamp/freeCodeCamp#70412 ·
メンテナーはふだん 1 日以内に返信
-
Mend: dependency security vulnerability untriaged
難易度 1/5 1時間未満 初心者へのやさしさ 88/100
opensearch-project/OpenSearch-Dashboards#12816 ·
メンテナーはふだん 1 日以内に返信