アクションフローとは、ユーザーが定義した自動化ワークフローです。各アクションフローは、フローを開始するアクションフロートリガと、1つ以上のアクションで構成されます。
カスタムコードステップを使用すると、事前定義されたアクションやステップでは実現できない複雑なデータ変換、フォーマット処理、高度なロジックを実行できます。たとえば、カスタムコードステップを使用して、メールアドレスの機密部分をマスクしたり、メールIDや注文IDの形式を検証したり、フォローアップリマインダーの次回実行日を計算したりできます。
カスタムコードステップの追加と設定
アクションフローの一部としてコードを実行する必要がある場合に、カスタムコードステップを追加できます。カスタムコードステップの入力と出力でサポートされるデータ型については、「サポートされるデータ型」を参照してください。
- アクションフローを開きます。
- アクションビルダーで、既存のステップの下にあるステップを追加アイコン(
)をクリックします。 - ステップサイドバーの「フロー制御とユーティリティ」で、「カスタムコード」をクリックします。
- ステップサイドバーで、「入力を追加」をクリックしてカスタムコードの入力を追加します。
- ステップのサイドバーで「出力を追加」をクリックし、以下の手順に従って出力を少なくとも1つ追加します。
- ステップサイドバーの「コード」で、カスタムJavaScriptコードを入力します。
- 「保存」をクリックします。
カスタムコードが期待どおりに動作するか確認するには、アクションフローをテストします。問題が発生した場合は、「カスタムコードステップのトラブルシューティング」を参照してください。
カスタムコードステップに入力を追加する
カスタムコードステップには最大25個の入力が設定可能です。
- アクションフローを開きます。
- アクションビルダーで、既存のカスタムコードステップをクリックするか、ステップを追加アイコン(
)をクリックしてカスタムコードステップを追加します。 - ステップのサイドバーで、「入力を追加」をクリックします。
- 「変数を選択」で、直前のステップまたはアクションフローのトリガから変数を選択します。メモ:入力データの型は選択した変数から推測されます。
- 入力の「名前」の値を確認します。この値は選択した変数に基づいて自動入力されますが、編集可能です。入力の名前はこれらの要件に従う必要があります。
- 「保存」をクリックします。
カスタムコードステップに出力を追加する
- アクションフローを開きます。
- アクションビルダーで、既存のカスタムコードステップをクリックするか、ステップを追加アイコン(
)をクリックしてカスタムコードステップを追加します。 - ステップのサイドバーで、「出力を追加」をクリックします。
- 出力の一意の「名前」を入力します。
これらの要件を満たす必要があります。
- 出力データのタイプを選択します。
- 「保存」をクリックします。
カスタムコードを追加する
カスタムコードステップ内のJavaScriptは、入力オブジェクトを受け取り、出力オブジェクトを返す関数をエクスポートする必要があります。アクションフローにカスタムコードステップを追加すると、そのたびにこの基本構造があらかじめ入力された状態で表示されます。必要に応じて編集、拡張、または削除して新しく作成し直すことができます。
カスタムコードステップは可能な限りユーザーフレンドリーに設計されていますが、実装時には管理者がエンジニアのサポートを必要とする場合があります。
- ステップのコードは最大10,000文字です。
- ステップに定義された各出力に対して、カスタムコードは値を返す必要があります。
- アクションフローで使用するコードは、迅速に実行され、適切な量のメモリを使用する必要があります。
- 以下のJavaScriptの制限が適用されます。
- 関数は同期的に実行される必要があります。つまり、
async、await、promiseはサポートされていません。 -
fetch、XMLHttpRequest、jQuery AJAXなどのネットワークリクエストはサポートされていません。 - 外部ライブラリやモジュールを
importまたはrequireすることはできません。
- 関数は同期的に実行される必要があります。つまり、
- アクションフローを開きます。
- アクションビルダーで、既存のカスタムコードステップをクリックするか、ステップを追加アイコン(
)をクリックしてカスタムコードステップを追加します。 - 「コード」セクションで、提供されたサンプルを展開するか、サンプルを削除して独自のロジックを記述するか、AIプロンプトを使用してカスタムコードを生成します。コードは、入力オブジェクトを受け取り、出力オブジェクトを返す関数をエクスポートする必要があります。以下はその例です。
// In the Inputs section for this step, add an input named status. // In the Outputs section for this step, add a text output named message. module.exports = (inputs) => { // Access inputs using inputs.<name> const msg = 'Your text was ' + inputs.status + '.' // This return must include all outputs. return { message: msg } }メモ:コードを記述すると、エディターに有効なJavaScript操作の候補が表示され、記述を支援します。誤字や無効なコードは、赤い下線で強調表示されます。下線部分にマウスを合わせるとエラーメッセージが表示されます。 - 「保存」をクリックします。
カスタムコードの入出力でサポートされるデータ型
カスタムコードステップは、以下のタイプのデータを受け取り、返します。各データの型は、コード内では対応するJavaScriptのデータ型で表示されます。
| 入力データの型 | JavaScriptのデータ型 | 例 |
|---|---|---|
| 本文 | 文字列 | "こんにちは!" |
| 数値 | 数値 | 123、-5、0 |
| 小数 | 数値 | 12.67、1.0、0.0 |
| true/false | ブール値 | true、false |
| 日付* | 文字列 | "2025-10-27" |
| 日時* | 文字列 |
UTC日時 "2025-10-27T10:30:00Z" タイムゾーンの時差を含む日時: "2025-06-22T05:11:28+10:00" ミリ秒を含むUTC日時: "2025-03-08T06:01:21.415Z" タイムゾーンの時差とミリ秒を含む日時:"2025-07-23T13:33:17.031-3:00" |
| テキスト配列 | 文字列の配列 | ["こんにちは!", "お元気ですか"] |
| 数値配列 | 数値の配列 | [12, 34, 56, 0] |
| 十進数配列 | 数値の配列 | [2.1, 6.3, 6.01, 0.1] |
| true/false配列 | ブール値の配列 | [true, true, false] |
| 日付配列 | 文字列の配列 | ["1997-08-29", "2004-07-25", "2011-04-21"] |
| 日時配列 | 文字列の配列 | ["1977-05-25T12:45Z", "1980-05-21T15:00Z", "1983-05-25T19:30Z"] |
- オブジェクト
- オブジェクト配列
- 混合配列
- 配列配列
アクションフローステップ用のカスタムJavaScriptコードを生成するAIプロンプトテンプレート
以下のプロンプトは、ChatGPTなどのAIツールでカスタムコードステップの生成に使用できます。プロンプトには、サポートされるデータの型とコードに必要な構造についてのガイダンスが含まれています。
プロンプト1
Write a piece of JavaScript code. The code must export a function that takes an inputs object and returns an outputs object, for example:
module.exports = (inputs) => {
let msg = "Your text was " + inputs.inputText + "."
return {
outputMessage: msg
}
}
Supported data types:
Strings, numbers, booleans, dates (YY-MM-DD) and datetimes (YY-MM-DDTHH:mm:SSZ) are supported. Arrays of those are supported too.
Objects, arrays of arrays, and arrays of objects are not supported. When used as inputs or outputs they must be stringified and passed as strings.
Check for missing or invalid data, and ensure it is handled gracefully by returning a valid output:
for strings, output the empty string ""
for numbers, output -1
for booleans, output false
for arrays, output the empty array []
for objects, output the empty object {}
Comment the code:
Include a comment at the top which briefly describes what the code does.
Include comments directing the reader to create the inputs and outputs, for example: // Make sure to create the following inputs: field_tag (Text).
In comments, refer to variable types with the following friendly names:
string: use "Date" for dates, "Date and time" for datetimes, else use "Text"
number: use "Number” or "Decimal"
boolean: use "True/False"
array: use "Number array", "Text array" etc
The code should... <DESCRIBE WHAT YOU WANT YOUR CODE TO DO HERE>
プロンプト2
Write a piece of JavaScript code. The code must export a function that takes an inputs object and returns an outputs object, for example:
module.exports = (inputs) => {
let msg = "Your text was " + inputs.inputText + "."
return {
outputMessage: msg
}
}
Supported input and output data types:
Strings, numbers, booleans, dates (YY-MM-DD) and datetimes (YY-MM-DDTHH:mm:SSZ) are supported. Arrays of those are supported too.
Objects, arrays of arrays, and arrays of objects are not supported. When used as inputs or outputs they must be stringified and passed as strings.
Comment the code:
Include a comment at the top which briefly describes what the code does.
Include comments directing the reader to create the inputs and outputs, for example: // Make sure to create the following inputs: field_tag (Text).
In comments, refer to variable types with the following friendly names:
string: use "Date" for dates, "Date and time" for datetimes, else use "Text"
number: use "Number" or "Decimal"
boolean: use "True/False"
array: use "Number array", "Text array" etc
The code should... <DESCRIBE WHAT YOU WANT YOUR CODE TO DO HERE>
カスタムコードステップの例
チケットの基本情報を人間が読める形式のコメントにフォーマットする
module.exports = (inputs) => {
// This code takes text inputs 'status' and 'priority', and a number input 'ticket_id', and outputs a friendly message combining these values.
// Make sure to create the following inputs:
// status (Text)
// priority (Text)
// ticket_id (Number)
const message = `Ticket ${inputs.ticket_id} has status ${inputs.status} and priority ${inputs.priority}.`
// Make sure to create the following outputs:
// message (Text)
return {
message,
}
}
今から1時間後の時刻を計算する
この例では、現在の時刻は 2025-10-27T09:17:00Z です。したがって、以下のコードは 2025-10-27T10:00:00Z を返します。
module.exports = (inputs) => {
// This code calculates the next full hour from the current UTC time
// No inputs required
// Make sure to create the following outputs:
// nextHour (Date and time)
// Create a Date object for the current time
const nextHour = new Date()
// Round up to the next hour by:
// 1. Setting minutes, seconds, and milliseconds to 0
nextHour.setUTCMinutes(0, 0, 0)
// 2. Adding 1 hour
nextHour.setUTCHours(nextHour.getUTCHours() + 1)
return {
nextHour: nextHour.toISOString(),
}
}
メールアドレスの書式を検証する
module.exports = (inputs) => {
// This code takes a text input 'emailAddress',
// uses regex to do a basic check whether it is a valid email format,
// and outputs a boolean 'emailIsValid'.
// Make sure to create the following inputs:
// emailAddress (Text)
// Simple email regex pattern
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
const emailIsValid = emailRegex.test(inputs.emailAddress)
// Make sure to create the following outputs:
// emailIsValid (True/False)
return {
emailIsValid
}
}
メールアドレスをマスクする
この例では、メールアドレスの一部をアスタリスク文字で置き換えています。たとえば、「メールアドレスが d******n@zendesk.comであることを確認していただけますか?」
// This code takes an email address input and returns a masked version where the local part is partially replaced with '*', preserving the first and last characters.
// Make sure to create the following input:
// emailToMask (Text)
// Make sure to create the following output:
// maskedEmail (Text)
module.exports = (inputs) => {
const [emailName, emailDomain] = inputs.emailToMask.split("@")
let maskedEmailName = emailName
if (emailName.length > 2) {
maskedEmailName = emailName[0]
maskedEmailName += "*".repeat(emailName.length-2)
maskedEmailName += emailName[emailName.length-1]
}
return {
maskedEmail: `${maskedEmailName}@${emailDomain}`
}
}
内部識別子を人間が読める名前にマッピングする
このマッピングは、ドロップダウンチケットフィールドのタグなどの内部IDを、ドロップダウンに表示される値のようなユーザーフレンドリーな名前に変換するのに役立ちます。
- SlackチャンネルのIDをチャンネル名に変換する
- JIRAプロジェクトのIDをプロジェクト名に変換する
- Zendeskチケットのステータスを対応するJIRA課題のステータスにマッピングする
const optionMap = {
option_01_ivory: 'ivory',
option_02_cream: 'cream',
option_03_white: 'white',
option_04_bone: 'bone',
}
module.exports = (inputs) => {
// This code takes a text input 'optionTag',
// and outputs the corresponding 'optionName' based on a predefined mapping.
// If the input is missing or does not match any tag, it returns an empty string.
// Make sure to create the following inputs:
// optionTag (Text)
const optionName = optionMap[inputs.optionTag] || ''
// Make sure to create the following outputs:
// optionName (Text)
return {
optionName,
}
}
リスト内の項目が特定の文字で始まるかどうかを確認する
この例は、リスト内の項目が特定の文字で始まるかどうかを確認します。たとえば、「customer」で始まる項目を検索する場合、タグのリストが [“critical_bug”, “customer_24601”, “escalation”] であれば、結果は true となります。なぜなら「customer_24601」は「customer」で始まるからです。
module.exports = (inputs) => {
// This code takes a text array 'tags' and a text string 'searchTerm',
// and outputs a boolean 'matchFound' indicating whether any tag begins with the searchTerm.
// Make sure to create the following inputs:
// tags (Text array)
// searchTerm (Text)
const matchFound = inputs.tags.some(tag => tag.startsWith(inputs.searchTerm))
// Make sure to create the following outputs:
// matchFound (True/False)
return {
matchFound
}
}
値のリストを2つ比較する
この例では、2つのリストを比較し、最初のリストから2番目のリストにも存在するすべての値を削除します。
たとえば、チケットのCCリストと禁止ユーザーリストが与えられているとき、CCリスト内に禁止ユーザーが含まれている場合は、出力リスト(cleanCCs)から除外されます。この方法は、チケットやユーザーから削除すべきタグをフィルタリングする際にも使用できます。
module.exports = (inputs) => {
// This code takes two number arrays: ticketCCs and disallowedUsers,
// and outputs a number array cleanCCs which includes only those items from ticketCCs that are NOT in disallowedUsers.
// Make sure to create the following inputs:
// ticketCCs (Number array)
// disallowedUsers (Number array)
const cleanCCs = inputs.ticketCCs.filter(cc => !inputs.disallowedUsers.includes(cc))
// Make sure to create the following outputs:
// cleanCCs (Number array)
return {
cleanCCs,
}
}
テキスト内の注文IDを特定する
この例は、チケットのコメントなどのテキスト文字列から注文IDを抽出します。特定の注文ID形式に合わせるため、必要に応じて正規表現(/GO-\d{8,9}/)を調整できます。
// Regex for order number: "GO-" followed by 8 or 9 digits
const ORDER_NUMBER_REGEX = /GO-\d{8,9}/
// Searches comment for order number and returns it if found.
const findOrderNumber = comment => comment.match(ORDER_NUMBER_REGEX)[0]
module.exports = (inputs) => {
// This code uses regex to look for an orderNumber with pattern "GO-" followed by 8 or 9 digits
// Make sure to create the following inputs:
// commentBody (Text)
const orderNumber = findOrderNumber(inputs.commentBody)
// Make sure to create the following outputs:
// orderNumber (Text)
// matchFound (True/False)
return {
orderNumber,
matchFound: Boolean(orderNumber),
}
}
乱数を生成する
この例は、指定した範囲内で乱数を生成します。52 の値を変更することで、乱数の上限値を設定できます。
module.exports = (inputs) => {
// This code outputs a random integer number between 1 and 52 inclusive.
// No inputs required.
// Make sure to create the following outputs:
// randomNumber (Number)
const randomNumber = Math.floor(Math.random() * 52) + 1
return {
randomNumber
}
}
1から7の間の乱数を3つ生成する
module.exports = (inputs) => {
// This code outputs three unique random integer numbers between 1 and 7 inclusive.
// No inputs required.
// Make sure to create the following outputs:
// randomNumber1 (Number)
// randomNumber2 (Number)
// randomNumber3 (Number)
const numbers = []
while (numbers.length < 3) {
const candidate = Math.floor(Math.random() * 7) + 1
if (!numbers.includes(candidate)) {
numbers.push(candidate)
}
}
return {
randomNumber1: numbers[0],
randomNumber2: numbers[1],
randomNumber3: numbers[2]
}
}
module.exports = (inputs) => {
// This code outputs an array of three unique random numbers between 1 and 7 inclusive.
// No inputs required.
// Make sure to create the following outputs:
// randomNumbers (Number array)
const numbers = []
while (numbers.length < 3) {
const candidate = Math.floor(Math.random() * 7) + 1
if (!numbers.includes(candidate)) {
numbers.push(candidate)
}
}
return {
randomNumbers: numbers
}
}