> ## Documentation Index
> Fetch the complete documentation index at: https://support.i.moneyforward.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Admina の自動化を Slack・Zapier・Google Apps Script と繋ぐ：双方向 6 パターンを解説

> Admina 自動化の Webhook トリガーと HTTP リクエストを使って Slack・Zapier・Google Apps Script と双方向連携する 6 つの方法を解説します

export const BlogAuthor = ({id}) => {
  const ICONS = "/images/blog/authors/icons";
  const FA_GLOBE = "https://d3gk2c5xim1je2.cloudfront.net/fontawesome/v7.2.0/regular/globe.svg";
  const AUTHORS = {
    howdy39: {
      name: "中野達也（@howdy39）",
      title: "Adminaエバンジェリスト",
      avatar: "/images/blog/authors/nakano.png",
      avatarAlt: "中野達也のプロフィール画像",
      bio: "SIer・フリーランスを経て、SaaSの使い手の体験を良くしたいとSTORESのフロントエンドエンジニアに転身。その後、社内で働く仲間の体験を良くしたいと、自ら手を挙げて情シス組織を立ち上げ、後にシニアマネージャーとして同組織を率いた。次のチャレンジとして、情シスのためのプロダクトを通じて情シスの体験を良くするため、Adminaエバンジェリストとしてマネーフォワードiに入社。",
      links: [{
        label: "X (@howdy39)",
        href: "https://x.com/howdy39",
        icon: `${ICONS}/x.svg`
      }, {
        label: "note",
        href: "https://note.com/howdy39",
        icon: `${ICONS}/note.svg`
      }, {
        label: "Qiita",
        href: "https://qiita.com/howdy39",
        icon: `${ICONS}/qiita.svg`
      }, {
        label: "Zenn",
        href: "https://zenn.dev/howdy39",
        icon: `${ICONS}/zenn.svg`
      }, {
        label: "GitHub",
        href: "https://github.com/howdy39",
        icon: `${ICONS}/github.svg`
      }, {
        label: "個人サイト",
        href: "https://howdy39.dev/",
        icon: FA_GLOBE
      }]
    }
  };
  const author = AUTHORS[id];
  if (!author) return null;
  return <div className="blog-author-card" data-author-id={id}>
      <div className="blog-author-avatar">
        <img src={author.avatar} alt={author.avatarAlt} />
      </div>
      <div className="blog-author-body">
        <div className="blog-author-name">{author.name}</div>
        <div className="blog-author-title">{author.title}</div>
        <p className="blog-author-bio">{author.bio}</p>
        <div className="blog-author-links">
          {author.links.map(link => <a key={link.href} href={link.href} aria-label={link.label}>
              <span className="blog-author-brand-icon" style={{
    WebkitMaskImage: `url(${link.icon})`,
    maskImage: `url(${link.icon})`
  }} />
            </a>)}
        </div>
      </div>
    </div>;
};

公開日: 2026 年 8 月 5 日

<Info>
  この記事は 2026 年 8 月時点の情報です。最新の設定手順は[Webhook のワークフローを設定する](/it-management/workflows/ptlpl2j0za-webhook)をご確認ください。
</Info>

Admina の自動化（オートメーション）は、入社・退社に伴うアカウント発行や削除など、あらかじめ用意されたテンプレートに沿って動く運用が基本でした。

[2026 年 7 月のアップデート](/it-management/changelog/2026-7-24-release)で、ワークフローに HTTP リクエストと Webhook トリガーを組み込めるようになりました。これにより、処理結果を外部システムへ繋いだり、外部システムから自動化を起動したりできます。

<Columns cols={2}>
  <Frame caption="HTTP リクエストのノードを追加する画面">
    <img src="https://mintcdn.com/moneyforwardi/J76nwWtWxAGWuFvz/images/blog/automation-webhook-integrations/add-http-request-node.png?fit=max&auto=format&n=J76nwWtWxAGWuFvz&q=85&s=9f5d0863b90a51354bb1fae364a0cd2d" alt="Admina のワークフロービルダーでノードを追加する画面。コミュニケーションのカテゴリにHTTPリクエストが表示されている" width="570" height="816" data-path="images/blog/automation-webhook-integrations/add-http-request-node.png" />
  </Frame>

  <Frame caption="Webhook トリガーを選択する画面">
    <img src="https://mintcdn.com/moneyforwardi/J76nwWtWxAGWuFvz/images/blog/automation-webhook-integrations/add-webhook-trigger-node.png?fit=max&auto=format&n=J76nwWtWxAGWuFvz&q=85&s=0b0ab55a189b940cb75c4d7717a6f39d" alt="Admina のワークフロービルダーでトリガーを選択する画面。トリガーの一覧にWebhookが表示されている" width="792" height="964" data-path="images/blog/automation-webhook-integrations/add-webhook-trigger-node.png" />
  </Frame>
</Columns>

Admina の Webhook では、安全のために SHA256 でハッシュ化した署名を要求する処理を設けています。この記事では、少し難しいハッシュ化のサンプルコードを、よく使われる言語である Google Apps Script・TypeScript（Slack Workflow Builder）・Python（Zapier）で書きました。送受信の両方向・計 6 パターンを解説します。

## 全体解説：2 つの接続口

Admina の自動化と外部システムの接続には 2 つの方向があります。方向によって、必要な実装が大きく変わります。

<Frame caption="Admina 自動化の 2 つの接続口">
  <img src="https://mintcdn.com/moneyforwardi/J76nwWtWxAGWuFvz/images/blog/automation-webhook-integrations/two-connection-directions.svg?fit=max&auto=format&n=J76nwWtWxAGWuFvz&q=85&s=16f31558b91fe95383b7446f1faaf2a9" alt="Admina から外部サービスへの HTTP リクエストはコード不要で繋がり、外部から Admina への Webhook トリガーは署名の計算が必要であることを示した図" style={{ maxWidth: "min(100%, 800px)", height: "auto" }} width="1200" height="586" data-path="images/blog/automation-webhook-integrations/two-connection-directions.svg" />
</Frame>

### Admina → 外部：HTTP リクエスト

Admina からの [HTTP リクエスト](/it-management/workflows/ptlpl2j0za-webhook#http-request)は、URL を自由に入力でき、HTTP メソッドも選択できます。静的なヘッダーの追加と BASIC 認証にも対応しています。つまり、**一般的な Webhook 受信口を持つサービスであれば呼び出せます**。

### 外部 → Admina：Webhook トリガーと署名

一方、外部から Admina のワークフローを起動する場合は、リクエストごとの **HMAC-SHA256 署名**が必須です。

| 項目                       | 指定値                                         |
| ------------------------ | ------------------------------------------- |
| ヘッダー：X-Webhook-Timestamp | Unix タイムスタンプ（ミリ秒、文字列）                       |
| ヘッダー：X-Webhook-Signature | `sha256=HMAC-SHA256(secret, "{ts}.{body}")` |
| リクエストボディ                 | 空白・インデントなしのコンパクトな JSON                      |

Admina のワークフローはアカウントの作成や削除まで実行できるため、URL を知っているだけでは起動できない設計になっています。合言葉のような固定トークンではなく、タイムスタンプとボディから毎回計算する署名を要求する、一般的な Webhook より強い認証です。

外部ツール側に求められる条件は 2 つです。

1. 任意の HTTP ヘッダーを付けられること
2. sha256 でハッシュ化した署名を毎回計算してヘッダーに付けられること

1 は多くのツールが対応しています。分かれ目は 2 で、**ワークフローの途中に任意のスクリプトを組み込めるツールだけが Admina を起動できます**。

## Admina から呼ぶ（HTTP リクエスト）：3 つの接続先

受け側は POST を受信できればよいので、いずれも署名の計算は不要です。受信後の処理は各サービス側で用意します。

<Frame caption="Admina から外部を呼ぶ：3 つの接続先">
  <img src="https://mintcdn.com/moneyforwardi/J76nwWtWxAGWuFvz/images/blog/automation-webhook-integrations/http-request-destinations.svg?fit=max&auto=format&n=J76nwWtWxAGWuFvz&q=85&s=397ea5105d8a768f946e28b466164d47" alt="Admina の HTTP リクエストから Slack・Zapier・Google Apps Script へ接続する構成と、それぞれの受け口・必要なものを整理した図" style={{ maxWidth: "min(100%, 800px)", height: "auto" }} width="1200" height="546" data-path="images/blog/automation-webhook-integrations/http-request-destinations.svg" />
</Frame>

### Slack：Workflow Builder の Webhook トリガー

Slack の Workflow Builder で「Webhook」開始条件のワークフローを作り、発行された URL を Admina の HTTP リクエストに設定します。Admina のワークフロー実行をきっかけに、Slack のワークフローが起動します。

### Zapier：Webhooks by Zapier（Catch Hook）

Zapier の `Catch Hook` トリガーで発行された URL に POST するだけで Zap が起動します。受信したデータは後続のステップで利用できるため、Zapier がハブになって他のサービスへ広げられます。

<Note>
  `Webhooks by Zapier` はプレミアムアプリのため、利用には Zapier の有料プランが必要です。
</Note>

```bash theme={null}
curl -i -X POST "<ZAPIER_CATCH_HOOK_URL>" \
  -H "Content-Type: application/json" \
  -d '{"text": "AdminaからZapierを起動"}'
```

### Google Apps Script：ウェブアプリとして公開した doPost

Google Apps Script 側は `doPost` を実装し、アクセスできるユーザーに全員を指定してウェブアプリとして公開するだけです。受信後の処理（スプレッドシート書き込みや Slack 通知など）を自由に書けます。

```javascript theme={null}
// Admina Automation から Google Apps Script を起動
function doPost(e) {
    try {
        const body = e.postData.contents;
        const json = JSON.parse(body);

        console.log('Received webhook:', json);

        // ここでスプレッドシート書き込みや Slack 通知などを実装できます

        return ContentService
            .createTextOutput(JSON.stringify({ status: 'ok' }))
            .setMimeType(ContentService.MimeType.JSON);
    } catch (err) {
        console.error('Error handling webhook:', err);
        return ContentService
            .createTextOutput(JSON.stringify({ status: 'error', message: err.message }))
            .setMimeType(ContentService.MimeType.JSON);
    }
}
```

## Admina を呼ぶ（Webhook トリガー）：3 つの実装方法

こちらは前述の署名計算があるため、**3 サービスともスクリプトを書けるステップが必要です**。ノーコードの Webhook 送信機能だけでは署名を計算できず、いずれも接続できません。

<Frame caption="Admina を呼ぶ：3 つの実装方法">
  <img src="https://mintcdn.com/moneyforwardi/J76nwWtWxAGWuFvz/images/blog/automation-webhook-integrations/webhook-trigger-implementations.svg?fit=max&auto=format&n=J76nwWtWxAGWuFvz&q=85&s=0bcdb87b9c5f72fedd2038885a5f2fa0" alt="Google Apps Script・Zapier・Slack のそれぞれで署名を計算して Admina の Webhook トリガーを起動する構成と、前提条件を整理した図" style={{ maxWidth: "min(100%, 800px)", height: "auto" }} width="1200" height="546" data-path="images/blog/automation-webhook-integrations/webhook-trigger-implementations.svg" />
</Frame>

### Slack：カスタムステップを自作して送信

Slack の Workflow Builder には、標準ではコードを実行できるステップがありません。そのため、Slack CLI（Deno SDK）でカスタムステップを自作します。Web Crypto API で署名を計算し、Admina の Webhook URL へ POST します。

```typescript theme={null}
import { DefineFunction, Schema, SlackFunction } from "deno-slack-sdk/mod.ts";

export const SendAdminaWebhookFunction = DefineFunction({
  callback_id: "send_admina_webhook",
  title: "Admina のワークフローを起動",
  description: "Admina の Webhook トリガーにテキストを送信してワークフローを起動します",
  source_file: "functions/send_admina_webhook.ts",
  input_parameters: {
    properties: {
      text: {
        type: Schema.types.string,
        description: "Admina 側に送信するメッセージ本文",
      },
    },
    required: ["text"],
  },
  output_parameters: {
    properties: {
      status_code: {
        type: Schema.types.number,
        description: "Admina から返却された HTTP ステータスコード",
      },
      response_body: {
        type: Schema.types.string,
        description: "Admina から返却されたレスポンスボディ",
      },
    },
    required: ["status_code", "response_body"],
  },
});

async function computeSignature(
  secret: string,
  message: string,
): Promise<string> {
  const encoder = new TextEncoder();
  const key = await crypto.subtle.importKey(
    "raw",
    encoder.encode(secret),
    { name: "HMAC", hash: "SHA-256" },
    false,
    ["sign"],
  );
  const signatureBuffer = await crypto.subtle.sign(
    "HMAC",
    key,
    encoder.encode(message),
  );
  return new Uint8Array(signatureBuffer).toHex();
}

export default SlackFunction(
  SendAdminaWebhookFunction,
  async ({ inputs, env }) => {
    const webhookUrl = env.WEBHOOK_URL;
    const secret = env.SECRET;

    if (!webhookUrl || !secret) {
      return {
        error: "WEBHOOK_URL または SECRET が未設定です。`slack env add` で設定してください。",
      };
    }

    // 署名の計算対象文字列と送信するボディは完全に同一の文字列にする
    // (インデントや改行が入ると署名検証エラーになる)
    const body = JSON.stringify({ text: inputs.text });
    const timestamp = Date.now().toString();
    const signature = await computeSignature(secret, `${timestamp}.${body}`);

    let response: Response;
    try {
      response = await fetch(webhookUrl, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-Webhook-Timestamp": timestamp,
          "X-Webhook-Signature": `sha256=${signature}`,
        },
        body,
      });
    } catch (error) {
      return { error: `Admina へのリクエストが失敗しました: ${error}` };
    }

    const responseBody = await response.text();

    if (!response.ok) {
      return {
        error: `Admina の Webhook がエラーを返しました (status=${response.status}): ${responseBody}`,
      };
    }

    return {
      outputs: {
        status_code: response.status,
        response_body: responseBody,
      },
    };
  },
);
```

<Warning>
  カスタムステップ自体に追加料金はありません。ただし利用には Slack の有料プランと、自作アプリのワークスペースへのインストールが必要です。組織のアプリ管理ポリシーによっては管理者の承認が必要になるため、事前にご確認ください。
</Warning>

### Zapier：Code by Zapier で署名を計算して送信

素の `Webhooks by Zapier` アクションは静的なヘッダーしか設定できないため、単体では署名を計算できません。`Code by Zapier`（Python）を使うと、署名の計算から HTTP リクエストの送信までを 1 つのステップで完結できます。

```python theme={null}
import json
import hmac
import hashlib
import time
import requests

webhook_url = input_data.get('webhook_url', '')
secret_key = input_data.get('secret_key', '')

if not webhook_url or not secret_key:
    return {'error': 'webhook_url and secret_key are required', 'status_code': None}

payload = {"event": "test", "message": "hello"}

# 空白なしのコンパクトな JSON にする（署名対象と送信ボディを完全に一致させる）
json_string = json.dumps(payload, separators=(',', ':'))

timestamp = str(int(time.time() * 1000))
signature_string = f"{timestamp}.{json_string}"

signature = hmac.new(
    secret_key.encode(),
    signature_string.encode(),
    hashlib.sha256
).hexdigest()

headers = {
    'Content-Type': 'application/json',
    'X-Webhook-Timestamp': timestamp,
    'X-Webhook-Signature': f"sha256={signature}"
}

response = requests.post(webhook_url, data=json_string, headers=headers)

return {
    'status_code': response.status_code,
    'response_text': response.text
}
```

### Google Apps Script：UrlFetchApp で署名を計算して送信

Google Apps Script は `Utilities.computeHmacSha256Signature` で署名を計算できます。

```javascript theme={null}
// Google Apps Script から Admina Automation を起動
function sendWebhook() {
    const props = PropertiesService.getScriptProperties();
    const WEBHOOK_URL = props.getProperty('WEBHOOK_URL');
    const SECRET = props.getProperty('SECRET');

    const body = JSON.stringify({ event: 'user.created', data: { text: 'hello gas' } });
    const timestamp = Date.now();

    const signBytes = Utilities.computeHmacSha256Signature(`${timestamp}.${body}`, SECRET);
    const signature = signBytes
        .map(b => ((b < 0 ? b + 256 : b).toString(16)).padStart(2, '0'))
        .join('');

    const options = {
        method: 'post',
        contentType: 'application/json',
        payload: body,
        headers: {
            'X-Webhook-Timestamp': String(timestamp),
            'X-Webhook-Signature': `sha256=${signature}`,
        },
        muteHttpExceptions: true,
    };

    const res = UrlFetchApp.fetch(WEBHOOK_URL, options);
    console.log(res.getResponseCode());
    console.log(res.getContentText());
}
```

### 実装時につまずきやすいポイント

どの言語で実装する場合も、ハマりどころは共通です。エラーの症状から原因を特定できるよう、まとめておきます。

| 症状          | 原因                            | 対処                                                    |
| ----------- | ----------------------------- | ----------------------------------------------------- |
| 400 エラー     | タイムスタンプを「秒」で送っている             | Unix タイムスタンプは**ミリ秒**の文字列で送ります                         |
| 401 エラー     | 署名した JSON と送信した JSON が一致していない | 文字列化は 1 回だけ行い、改行・インデントなしの同一文字列（同一 JSON）を署名と送信の両方に使います |
| 突然 401 になった | Webhook シークレットを再生成した          | シークレットは再生成すると旧シークレットが無効になります。送信元の設定も更新してください          |

また、いきなり本実装せず、Admina 側の「Webhook テスト」（受信待機モード）へテスト用のペイロードを 1 回 POST して、署名検証が OK になることを先に確認するのが確実です。詳細は[Webhook のワークフローを設定する](/it-management/workflows/ptlpl2j0za-webhook)をご確認ください。

## 6 パターンのまとめ

| 接続                          | 方向           | 必要なもの                 |
| --------------------------- | ------------ | --------------------- |
| Admina → Slack WF           | HTTP リクエスト   | なし（Webhook トリガーで受信）   |
| Admina → Zapier             | HTTP リクエスト   | なし（Catch Hook で受信）    |
| Admina → Google Apps Script | HTTP リクエスト   | doPost の実装（受信後の処理は自由） |
| Slack WF → Admina           | Webhook トリガー | カスタムステップの自作（Deno SDK） |
| Zapier → Admina             | Webhook トリガー | Code by Zapier での署名計算 |
| Google Apps Script → Admina | Webhook トリガー | UrlFetchApp での署名計算    |

まとめると次の 2 点です。

* **Admina から外部への HTTP リクエストは、一般的な Webhook 受信口があれば繋がります。** 3 サービスともコードなしで受信できます
* **外部から Admina のワークフロー起動には署名計算のコードが必要です。** スクリプトを組み込めるツールなら繋がります

## おわりに

設定手順の詳細は次のドキュメントをご確認ください。

* [ご利用開始までの流れ（自動化）](/it-management/workflows/90k8f1lee0-workflows)
* [Webhook のワークフローを設定する](/it-management/workflows/ptlpl2j0za-webhook)

Admina の導入をご検討中の方は、下記から資料をご請求いただけます。

<Card title="Admina の資料を請求する（資料 3 点セット）" icon="file-lines" href="https://admina.moneyforward.com/jp/3set" />

このブログでは、Admina の活用方法を今後も紹介していきます。記事一覧は[ブログトップ](/blog/index)からご覧ください。

<BlogAuthor id="howdy39" />
