contacts-management について
contacts-managementは、連絡先と通信チャネルの管理機能を開発する人向けの、Zavu連絡先API用スキルです。複数チャネルの連絡先モデル、検索と統合に加え、電話番号とメールアドレスの検証を扱います。
主な機能
- 01複数チャネルの連絡先情報を管理
- 02名前、識別子、タグで検索
- 03連絡先チャネルの追加・削除
- 04連絡先とチャネルの統合
- 05電話番号と通信事業者を確認
- 06メールアドレスを検証
活用シーン
- 01連絡先レコードの作成と更新
- 02チャネル識別子から連絡先を検索
- 03同一人物の重複レコードを統合
- 04送信前に電話番号とメールを確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ zavudev/ zavu-skills --skill contacts-managementインストール後、Claude Code で/contacts-managementを入力して読み込まれたか確認します。
詳細
連絡先管理
使用する場面
連絡先とその通信チャネルを作成、更新、管理するコードを作成するときに、このスキルを使用してください。複数チャネルの連絡先モデル、検索、統合操作、電話番号の詳細確認、メールアドレスの検証について説明します。
連絡先モデル
連絡先は複数チャネルに対応しています。1つの連絡先に複数のチャネル(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 がないため、名前を設定するまでは識別子でしか検索できません。詳しくは、連絡先を更新するを参照してください。
検索結果をページネーションする前に、次の2点に注意してください。結果は新しい順ではなく関連度順で返されます。また、どちらのモードでも cursor は不透明な値です。前回のレスポンスで返された値をそのまま渡し、検索語を変更したときは新しいページネーションを開始してください。
WhatsApp のユーザー名連絡先(BSUID)
ユーザー名を設定した WhatsApp の連絡先は、電話番号の代わりに、または電話番号とあわせて、ビジネスに紐づくユーザー ID(BSUID)で識別される場合があります。Zavu が BSUID を保持している場合、連絡先には 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 は維持されます。ただし、紐づけによって同一人物の別の連絡先が見つかり、2つが統合された場合を除きます。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);
統合は取り消せません。最初に、2つの連絡先が同一人物であることを確認してください。
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形式である必要があります
- 連絡先間で識別子が重複している場合は拒否されます(代わりに統合してください)