
Zendesk チケットコメント API の public デフォルト動作を検証
はじめに
Zendesk の Ticket Comments API を使用してチケットにコメントを追加する際、一般的には「チケット作成時の public
設定が引き継がれる」と認識されがちですが、実際の動作は異なる可能性があります。本記事では、public
パラメータを指定しない場合の実際の動作を検証し、開発者が陥りやすい誤解を解消します。
Zendesk とは
Zendesk は、カスタマーサポート業務を効率化するクラウド型のヘルプデスクソフトウェアです。チケット管理、ナレッジベース、チャットサポートなどの機能を提供し、企業の顧客対応を一元管理できます。Zendesk では、顧客からの問い合わせや要望を「チケット」として管理し、各チケットに対してエージェント(=サポート担当者)や顧客がコメントを追加することでやり取りを行います。
Zendesk API を使用してチケットにコメントを追加するには、Tickets API の PUT /api/v2/tickets/{id}.json
エンドポイントを使用します。リクエストボディに comment
オブジェクトを含めることで、新しいコメントを追加できます。
// Node.js での実装例
const response = await axios.put(`https://${domain}/api/v2/tickets/${ticketId}.json`, {
ticket: {
comment: {
body: "コメント内容",
public: true, // 顧客も閲覧可能
author_id: userId
}
}
}, {
headers: {
'Authorization': `Basic ${authToken}`,
'Content-Type': 'application/json'
}
});
この API 呼び出し時のパラメータのうち public
について挙動を確認することが本記事の目的となります。
対象読者
- Zendesk API を使用してチケット管理システムを開発している開発者
- Zendesk の自動化やインテグレーションを構築している技術者
- Zendesk API の動作仕様について詳しく理解したい方
参考資料
検証してみた
まず、公式ドキュメントで public
パラメータがどのように説明されているかを確認します。 Ticket Comments API のドキュメント によると、public
パラメータについて以下の記載があります。
Name | Type | Read-only | Mandatory | Description |
---|---|---|---|---|
public | boolean | false | false | true if a public comment; false if an internal note. The initial value set on ticket creation persists for any additional comment unless you change it |
この記事からは、「チケット作成時の初期値が、以降のコメント追加時も継続される」と読み取れますが、この「初期値が継続される」という動作が具体的にどのような挙動なのかが不明確です。したがって、実際に API を呼び出し検証してみることにしました。
検証環境
- Zendesk プラン: Enterprise Plus
- API バージョン: v2
- 認証方式: Basic 認証 (API Token)
- 実行環境: Node.js
- 検証日時: 2025年7月
検証方法
以下のパターンでコメント追加を行い、実際の動作を確認します。
- パターン1: 新規チケット作成時に
public: true
→ その後public
未指定でコメント追加 - パターン2: 新規チケット作成時に
public: false
→ その後public
未指定でコメント追加 - パターン3: 新規チケット作成時に
public
未指定 → その後public
未指定でコメント追加 - パターン4: 既存チケットに対して異なる
public
値でコメント追加後、再度public
未指定でコメント追加 - パターン5:
public: false
で作成したチケットに対して同様の検証 - パターン6: 初回コメント「パブリック返信」で Web UI で作成したチケットに対しコメント追加
- パターン7: 初回コメント「社内メモ」で Web UI で作成したチケットに対しコメント追加
検証用のコードは以下のとおりです。
検証用コード
const axios = require('axios');
const ZENDESK_DOMAIN = 'your-domain.zendesk.com';
const API_TOKEN = 'your-api-token';
const EMAIL = 'your-email@example.com';
const authHeader = Buffer.from(`${EMAIL}/token:${API_TOKEN}`).toString('base64');
// チケット作成関数
async function createTicket(publicValue = undefined) {
const commentData = {
body: "初回コメント",
author_id: 123456789 // 実際のユーザー ID
};
if (publicValue !== undefined) {
commentData.public = publicValue;
}
const response = await axios.post(`https://${ZENDESK_DOMAIN}/api/v2/tickets.json`, {
ticket: {
subject: "検証用チケット",
comment: commentData,
requester_id: 123456789 // 実際のユーザー ID
}
}, {
headers: {
'Authorization': `Basic ${authHeader}`,
'Content-Type': 'application/json'
}
});
return response.data.ticket.id;
}
// コメント追加関数
async function addComment(ticketId, publicValue = undefined) {
const commentData = {
body: "追加コメント",
author_id: 123456789
};
if (publicValue !== undefined) {
commentData.public = publicValue;
}
const response = await axios.put(`https://${ZENDESK_DOMAIN}/api/v2/tickets/${ticketId}.json`, {
ticket: {
comment: commentData
}
}, {
headers: {
'Authorization': `Basic ${authHeader}`,
'Content-Type': 'application/json'
}
});
return response.data;
}
// コメント一覧取得関数
async function getComments(ticketId) {
const response = await axios.get(`https://${ZENDESK_DOMAIN}/api/v2/tickets/${ticketId}/comments.json`, {
headers: {
'Authorization': `Basic ${authHeader}`,
'Content-Type': 'application/json'
}
});
return response.data.comments;
}
検証結果
public: true
→ 追加コメント public
未指定
パターン1: チケット作成時 // 実行
const ticketId1 = await createTicket(true);
await addComment(ticketId1); // public 未指定
const comments1 = await getComments(ticketId1);
console.log('パターン1の結果:');
comments1.forEach((comment, index) => {
console.log(`コメント${index + 1}: public = ${comment.public}`);
});
パターン1の結果:
コメント1: public = true
コメント2: public = true
public: false
→ 追加コメント public
未指定
パターン2: チケット作成時 // 実行
const ticketId2 = await createTicket(false);
await addComment(ticketId2); // public 未指定
const comments2 = await getComments(ticketId2);
console.log('パターン2の結果:');
comments2.forEach((comment, index) => {
console.log(`コメント${index + 1}: public = ${comment.public}`);
});
パターン2の結果:
コメント1: public = false
コメント2: public = false
public
未指定 → 追加コメント public
未指定
パターン3: チケット作成時 // 実行
const ticketId3 = await createTicket(); // public 未指定
await addComment(ticketId3); // public 未指定
const comments3 = await getComments(ticketId3);
console.log('パターン3の結果:');
comments3.forEach((comment, index) => {
console.log(`コメント${index + 1}: public = ${comment.public}`);
});
パターン3の結果:
コメント1: public = true
コメント2: public = true
public
値でコメント追加後、再度 public
未指定でコメント追加
パターン4: 既存チケットに対して異なる // 実行
const ticketId4 = await createTicket(true); // public: true で作成
await addComment(ticketId4, false); // public: false で追加
await addComment(ticketId4); // public 未指定で追加
const comments4 = await getComments(ticketId4);
console.log('パターン4の結果:');
comments4.forEach((comment, index) => {
console.log(`コメント${index + 1}: public = ${comment.public}`);
});
パターン4の結果:
コメント1: public = true
コメント2: public = false
コメント3: public = true
public: false
で作成したチケットに対して同様の検証
パターン5: // 実行
const ticketId5 = await createTicket(false); // public: false で作成
await addComment(ticketId5, true); // public: true で追加
await addComment(ticketId5); // public 未指定で追加
const comments5 = await getComments(ticketId5);
console.log('パターン5の結果:');
comments5.forEach((comment, index) => {
console.log(`コメント${index + 1}: public = ${comment.public}`);
});
パターン5の結果:
コメント1: public = false
コメント2: public = true
コメント3: public = true
パターン6: 初回コメント「パブリック返信」で Web UI で作成したチケットに対しコメント追加
// Web UI で作成されたチケット ID を使用
const webUITicketId = 12345; // 実際のチケット ID
// まず既存のコメントを確認
const existingComments = await getComments(webUITicketId);
console.log('Web UI で作成されたチケットの初期コメント:');
existingComments.forEach((comment, index) => {
console.log(`コメント${index + 1}: public = ${comment.public}`);
});
// API で public 未指定のコメントを追加
await addComment(webUITicketId); // public 未指定
const updatedComments = await getComments(webUITicketId);
console.log('パターン6の結果:');
updatedComments.forEach((comment, index) => {
console.log(`コメント${index + 1}: public = ${comment.public}`);
});
Web UI で作成されたチケットの初期コメント:
コメント1: public = true
パターン6の結果:
コメント1: public = true
コメント2: public = true
パターン7: 初回コメント「社内メモ」で Web UI で作成したチケットに対しコメント追加
// Web UI で作成されたチケット ID を使用
const internalNoteTicketId = 12346; // 実際のチケット ID
// 既存のコメントを確認
const internalComments = await getComments(internalNoteTicketId);
console.log('Web UI で作成されたチケットの初期コメント:');
internalComments.forEach((comment, index) => {
console.log(`コメント${index + 1}: public = ${comment.public}`);
});
// API で public 未指定のコメントを追加
await addComment(internalNoteTicketId); // public 未指定
const updatedInternalComments = await getComments(internalNoteTicketId);
console.log('パターン7の結果:');
updatedInternalComments.forEach((comment, index) => {
console.log(`コメント${index + 1}: public = ${comment.public}`);
});
Web UI で作成されたチケットの初期コメント:
コメント1: public = false
パターン7の結果:
コメント1: public = false
コメント2: public = false
検証結果の分析
これらの検証結果から、以下のことが明らかになりました。
-
デフォルト値は private ではなく public
チケット作成時にpublic
を未指定にした場合、デフォルトはtrue
(public) となります。 -
public: true
が優先される特殊な動作
パターン4とパターン5の結果、以下が明らかになりました。- パターン4:
true
で作成 →false
で追加 → 未指定で追加 →true
になる - パターン5:
false
で作成 →true
で追加 → 未指定で追加 →true
になる
両方のケースで未指定時に
true
になっていますが、その理由は以下の可能性が考えられます。- 仮説1:
public: true
が一度設定されると優先される - 仮説2: より複雑な内部ルールが存在する
現在の検証結果では、おそらく仮説1が有力と思われますが、確定的な結論は出せません。
- パターン4:
-
Web UI と API で一貫した動作
パターン6とパターン7の結果から、チケットの作成方法 (API または Web UI) に関係なく、同様の動作が確認できました。
実装上の注意点
この検証結果を踏まえ、実装時には以下の点に注意が必要です。
- 予期しない動作が発生する可能性があるため、明示的な public 指定を強く推奨
// 推奨: 常に明示的に指定
const commentData = {
body: "コメント内容",
public: false, // 明示的に指定
author_id: userId
};
- 特に社内メモを追加したい場合は要注意
// 危険: public 未指定
const commentData = {
body: "内部メモ", // 顧客に見せたくない内容
// public を指定していない → 過去に public: true があれば顧客に見える!
author_id: userId
};
// 安全: 明示的に指定
const commentData = {
body: "内部メモ",
public: false, // 必ず明示的に指定
author_id: userId
};
- 既存チケットへのコメント追加時は特に注意
既存のチケットにコメントを追加する場合、そのチケットで過去にpublic: true
が設定されたことがあるかを把握することは困難です。そのため、必ず明示的にpublic
を指定することを強く推奨します。
まとめ
Zendesk の Ticket Comments API における public
パラメータの動作について検証を行った結果、以下が明らかになりました。
- チケット作成時に
public
を未指定にした場合のデフォルトはtrue
(public) public
未指定時の動作は複雑で予測困難。特定の条件下で意図しないpublic: true
になる可能性がある。予測困難な動作により、意図せず顧客に内部情報を公開するリスクが存在する
したがって開発においては、public
パラメータの値を明示的に指定する対応が推奨されます。複雑で予測困難な動作のため、デフォルト動作に依存した実装は避けるべきでしょう。適切な理解に基づいて API を使用することで、意図しない情報漏洩を防ぐことができます。