mcpField
C
contacts-management

contacts-management

github.com/zavudev生产力1394 次安装2 天前更新
代码仓库

关于 contacts-management

contacts-management 是用于 Zavu 联系人 API 的技能,面向构建联系人及其沟通渠道管理功能的开发者。它涵盖多渠道联系人模型、搜索与合并,以及电话号码和电子邮件验证。

主要功能

  1. 01管理多渠道联系人信息
  2. 02按姓名、标识符和标签搜索
  3. 03添加或移除联系人渠道
  4. 04合并联系人及其渠道
  5. 05检查电话号码与运营商信息
  6. 06验证电子邮件地址

适用场景

  1. 01创建和更新联系人记录
  2. 02按渠道标识符查找联系人
  3. 03合并同一人的重复联系人
  4. 04发送前筛查电话号码和邮件地址

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/zavudev/zavu-skills --skill contacts-management

安装后在 Claude Code 中输入/contacts-management确认已加载。

详细介绍

联系人管理

适用场景

在编写用于创建、更新或管理联系人及其通信渠道的代码时,使用此技能。涵盖多渠道联系人模型、搜索、合并操作、电话号码信息查询和电子邮件地址验证。

联系人模型

联系人支持多个渠道:一个联系人可以拥有多个渠道(SMS、WhatsApp、Email、Telegram、Instagram、Messenger、Voice),每个渠道都有自己的标识符和投递指标。顶层字段会提供主要标识符,方便快速访问。

Contact (John Doe)
├── primaryPhone: +14155551234           (E.164)
├── primaryEmail: [email protected]
├── profileName: "John D."               (WhatsApp profile name, if available)
├── verified: true
├── countryCode: "US"
└── Channels:
    ├── SMS: +14155551234 (primary)
    ├── WhatsApp: +14155551234 (primary)
    ├── Email: [email protected] (primary)
    ├── Email: [email protected] (label: "work")
    ├── Telegram: @johndoe
    └── Voice: +14155551234

注意: Contact 上的旧版 phoneNumber 字段已弃用,请改用 primaryPhone。

有效的联系人渠道类型:sms、whatsapp、email、telegram、instagram、messenger、voice(注意:auto 和 sms_oneway 是消息发送路由选项,不是联系人渠道类型)。

自动创建

向新收件人发送消息时,系统会自动创建联系人。基本消息发送无需显式创建联系人。

创建联系人

const contact = await zavu.contacts.create({
  displayName: "John Doe",
  channels: [
    { channel: "sms", identifier: "+14155551234", isPrimary: true },
    { channel: "whatsapp", identifier: "+14155551234", isPrimary: true },
    { channel: "email", identifier: "[email protected]", isPrimary: true },
  ],
  metadata: { source: "import", plan: "enterprise" },
});
console.log(contact.id);

如果某个标识符已被另一联系人用于同一渠道,系统会拒绝该请求, 并返回 400(This sms identifier is already associated with another contact)。 请将该渠道添加到现有联系人,或合并联系人。

Python:

contact = zavu.contacts.create(
    display_name="John Doe",
    channels=[
        {"channel": "sms", "identifier": "+14155551234", "isPrimary": True},
        {"channel": "email", "identifier": "[email protected]", "isPrimary": True},
    ],
)

Go:

contact, err := client.Contacts.Create(context.TODO(), zavudev.ContactCreateParams{
    DisplayName: zavudev.String("John Doe"),
    Channels: []zavudev.ContactChannelParam{
        {Channel: "sms", Identifier: "+14155551234", IsPrimary: zavudev.Bool(true)},
        {Channel: "email", Identifier: "[email protected]", IsPrimary: zavudev.Bool(true)},
    },
})

Ruby:

contact = client.contacts.create(
    display_name: "John Doe",
    channels: [
        { channel: "sms", identifier: "+14155551234", is_primary: true },
        { channel: "email", identifier: "[email protected]", is_primary: true },
    ],
)

PHP:

$contact = $client->contacts->create([
    'displayName' => 'John Doe',
    'channels' => [
        ['channel' => 'sms', 'identifier' => '+14155551234', 'isPrimary' => true],
        ['channel' => 'email', 'identifier' => '[email protected]', 'isPrimary' => true],
    ],
]);

获取和列出联系人

// Get by ID
const contact = await zavu.contacts.get({ contactId: "ct_abc123" });

// Get by phone number
const contact = await zavu.contacts.getByPhone({
  phoneNumber: "+14155551234",
});

// List with filters
let cursor: string | undefined;
do {
  const result = await zavu.contacts.list({
    phoneNumber: "+14155551234",
    limit: 50,
    cursor,
  });
  for (const contact of result.items) {
    console.log(contact.id, contact.displayName, contact.availableChannels);
  }
  cursor = result.nextCursor ?? undefined;
} while (cursor);

// Search by name, phone, or email
const found = await zavu.contacts.list({ search: "marta", limit: 25 });

search 不区分大小写和重音符号,并且支持匹配电话号码的末尾片段,因此 5551234 可以找到 +14155551234。它会匹配联系人的 displayName、WhatsApp 个人资料名称以及标识符。

通过收到的入站消息自动创建的联系人没有 displayName,因此在命名之前只能通过标识符查找——请参阅更新联系人。

搜索分页前请注意两点:结果按相关性排序,而非按最新顺序排序;两种模式下的 cursor 都是不透明的。请原样传回上一次响应中的值,并在搜索词发生变化时重新开始分页。

WhatsApp 用户名联系人(BSUID)

采用了用户名的 WhatsApp 联系人可以通过其企业专属用户 ID(BSUID)识别,而非电话号码,或与电话号码同时使用。如果 Zavu 有该值,联系人会包含 whatsapp: { bsuid, username? };否则该键不存在。使用精确的 bsuid 筛选条件查找联系人(请使用 REST,SDK 可能尚未提供此功能):

curl "https://api.zavu.dev/v1/contacts?bsuid=CO.13491208655302741918" \
  -H "Authorization: Bearer $ZAVUDEV_API_KEY"

此操作会返回持有该 BSUID 的联系人,或返回空列表;还可以使用 phoneNumber 和 tag 进一步缩小范围。如果与非空的 search 一起使用,或值的格式不像 BSUID,则会返回 400(空白的 bsuid 会被忽略)。之后关联电话号码时,同一联系人会保留其 id;但如果关联操作发现同一人对应另一个联系人,且两者随后被合并,则 id 会发生变化。请订阅 contact.identity_linked,其中的 mergedContactId 会标明被移除的联系人 ID。请参阅 webhook-setup 技能。

标签

联系人上的扁平标签,用于对需要重复发送消息的受众进行分组。 支持多对多关系,没有层级或颜色。

// Contacts carrying a tag
const { items } = await zavu.contacts.list({ tag: "vip" });

// Repeat the parameter for AND — carrying BOTH tags, not either
// GET /v1/contacts?tag=vip&tag=chile

标签按名称匹配,不区分大小写。未知标签会返回 400, 而不是被忽略:拼写错误却悄悄匹配到所有联系人的结果,比返回错误更糟。

按标签筛选的页面返回结果可能少于 limit,甚至为空,但 nextCursor 仍可能有值。请继续分页,直到 nextCursor 为 null。

创建、重命名和分配标签需在控制面板中完成。目前 API 尚不支持标签 CRUD——不要告诉用户可以通过代码创建标签。

渠道操作

// Add channel
const channel = await zavu.contacts.channels.add({
  contactId: "ct_abc123",
  channel: "email",
  identifier: "[email protected]",
  label: "work",       // optional
  countryCode: "US",   // optional, 2-letter ISO
});

// Update channel
await zavu.contacts.channels.update({
  contactId: "ct_abc123",
  channelId: "ch_xyz789",
  label: "personal",
  verified: true,
});

// Set as primary
await zavu.contacts.channels.setPrimary({
  contactId: "ct_abc123",
  channelId: "ch_xyz789",
});

// Remove channel (cannot remove the last channel)
await zavu.contacts.channels.remove({
  contactId: "ct_abc123",
  channelId: "ch_xyz789",
});

更新联系人

可更新的字段:displayName、defaultChannel、metadata。

await zavu.contacts.update({
  contactId: "ct_abc123",
  displayName: "John Doe",
  defaultChannel: "whatsapp",
  metadata: { plan: "premium", region: "US" },
});

// Clear a field by passing null
await zavu.contacts.update({
  contactId: "ct_abc123",
  displayName: null,      // falls back to the contact's identifier
  defaultChannel: null,
});

从入站消息自动创建的联系人没有 displayName — 在设置名称之前,他们会显示为电话号码或电子邮件地址。为联系人命名后,就可以通过 contacts.list({ search }) 按名称查找。

若要更改联系人的电话号码或电子邮件地址,请添加或移除渠道 (参见 渠道操作),而不是更新联系人。

合并联系人

将一个联系人合并到另一个联系人。源联系人的所有渠道都会转移到目标联系人, 目标联系人的主要电话和电子邮件地址会重新计算,源联系人会标记为已合并,并不再出现在列表中。

const merged = await zavu.contacts.merge({
  contactId: "ct_target123",        // survives
  sourceContactId: "ct_source456",  // absorbed
});
console.log("Merged channels:", merged.channels.length);

合并无法撤销 — 请先确认这两个联系人属于同一个人。

Zavu 不会为你检测重复项。 不会提供合并建议:请根据自己的数据决定要合并哪些联系人。一个实用的候选查找方法是 列出联系人,并按共同标识符或规范化后的名称分组。

电话信息查询

验证电话号码并查看运营商信息:

const result = await zavu.introspect.phone({
  phoneNumber: "+14155551234",
});
console.log(result.validNumber);      // true
console.log(result.countryCode);       // "US"
console.log(result.nationalFormat);    // "(415) 555-1234"
console.log(result.lineType);         // "mobile" | "landline" | "voip" | "toll_free"
console.log(result.carrier?.name);    // "Verizon Wireless"
console.log(result.availableChannels); // ["sms", "whatsapp", "voice"]

Python:

result = zavu.introspect.phone(phone_number="+14155551234")
print(result.valid_number)
print(result.line_type)
print(result.carrier.name if result.carrier else "Unknown")

Go:

result, err := client.Introspect.Phone(context.TODO(), zavudev.PhoneIntrospectionParams{
    PhoneNumber: zavudev.String("+14155551234"),
})
fmt.Println(result.ValidNumber, result.LineType, result.Carrier.Name)

Ruby:

result = client.introspect.phone(phone_number: "+14155551234")
puts result.valid_number, result.line_type, result.carrier&.name

PHP:

$result = $client->introspect->phone(['phoneNumber' => '+14155551234']);
echo $result->validNumber, $result->lineType, $result->carrier?->name;

电子邮件验证

发送前验证电子邮件地址,以降低退信率。此功能会检测无效语法、无法使用的域名(没有 MX/A 记录)、一次性收件箱、基于角色的地址(info@、contacto@、sales@),以及已列入项目抑制列表的地址。不会探测 SMTP 邮箱:deliverable 表示未发现负面信号,并不保证邮件一定送达。

SDK 中尚未生成相关功能 — 请直接使用 REST 端点:

# Single address
curl -X POST https://api.zavu.dev/v1/introspect/email \
  -H "Authorization: Bearer $ZAVU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]"}'

# Batch (max 100 per request)
curl -X POST https://api.zavu.dev/v1/introspect/email \
  -H "Authorization: Bearer $ZAVU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"emails": ["[email protected]", "[email protected]", "not-an-email"]}'

响应:

{
  "results": [
    {
      "email": "[email protected]",
      "normalized": "[email protected]",
      "domain": "example.com",
      "verdict": "deliverable",
      "reasons": []
    },
    {
      "email": "[email protected]",
      "normalized": "[email protected]",
      "domain": "deaddomain.example",
      "verdict": "undeliverable",
      "reasons": ["domain_not_found", "role_address"]
    },
    {
      "email": "not-an-email",
      "normalized": null,
      "domain": null,
      "verdict": "undeliverable",
      "reasons": ["invalid_syntax"]
    }
  ],
  "summary": { "total": 3, "deliverable": 1, "risky": 0, "undeliverable": 2 }
}

判定结果:

  • deliverable — 未发现负面信号。
  • risky — 可以发送,但某个信号表明退信或投诉概率较高:role_address、disposable_domain、domain_no_mx(域名可解析,但没有 MX 记录)或 suppressed_soft_bounce。
  • undeliverable — 应丢弃这些地址:invalid_syntax、domain_not_found,或因硬退信/投诉而被抑制的地址(suppressed_hard_bounce、suppressed_complaint、suppressed_manual、suppressed_unsubscribe)。

群发前的典型流程:验证列表,丢弃 undeliverable,检查 risky,然后仅添加无问题的收件人。

限制

  • 每个联系人最多 20 个渠道
  • 渠道标签:最多 50 个字符
  • 显示名称:最多 200 个字符
  • 不能移除联系人的最后一个渠道
  • 不能将联系人与自身合并
  • 电话号码必须采用 E.164 格式
  • 拒绝跨联系人的重复标识符(请改用合并)

评论

支持 Markdown