LINE広告APIのPOSTリクエストの認証とその実例（備忘録）

やっしです。本記事は、[**TechCommit AdventCalendar2024**](https://adventar.org/calendars/10584) の7日目の記事です。前日は [maeさん](https://note.com/mae616/n/n8ada07a01c7a) が素晴らしい記事を書かれているので、ぜひそちらもご覧ください。

## 目次
1. [はじめに](#はじめに)  
2. [LINE広告APIとは](#line-ads-platform-ads-management-apiとは)  
3. [事前準備](#事前準備)  
   - [アクセスキー・シークレットキーの取得](#アクセスキーシークレットキーの取得)  
   - [APIアクセス権限有効化](#apiアクセス権限有効化)
4. [JWSによる署名付きリクエストの概要](#jwsによる署名付きリクエストの概要)
5. [GASでのPOSTリクエスト実装例](#gasでのpostリクエスト実装例)
6. [まとめ](#まとめ)

## はじめに
Google Apps Script（以下、GAS）を用いて、**LINE広告API** のレポート作成API（pfreports）を実行するまでの手順を紹介します。公式ドキュメントにはPythonによるGETリクエストの実例があるのですが、POSTリクエストのケースがないので備忘録として書きました。
本記事では、APIリクエストの署名方式（JWS）に触れながら、実際にPOSTリクエストでレポートを作成するコード例を示します。

## LINE広告APIとは
LINE広告APIを使うと、広告アカウント、キャンペーンなどのデータに対する読み取り・作成・更新・削除や、レポートデータの読み取りが行えます。
これにより、広告出稿やパフォーマンス計測を自動化し、効率的な運用が可能になります。

## 事前準備

### アクセスキー・シークレットキーの取得
- LINE Ads Manager UI上で対象の広告アカウントに対応するアクセスキーとシークレットキーを取得します。  
- 初回はシークレットキーが表示されない場合はUI上で再生成してください。

### APIアクセス権限有効化
- 招待メールのリンクをクリックし、APIアクセス権限を有効化します。

## JWSによる署名付きリクエストの概要
LINE広告APIは、**JOSEヘッダー（JWSヘッダー）** とペイロードを用いてHMAC-SHA256署名を生成し、`Authorization: Bearer <署名>` ヘッダーとして付与することでリクエストを認証します。

基本的な流れは以下のとおりです。

1. JOSEヘッダー(JSON)をBase64URLエンコード  
2. ペイロード（Digest-SHA-256、Content-Type、Date(YYYYMMDD)、CanonicalURI）をBase64URLエンコード  
3. `ヘッダーBase64URL . ペイロードBase64URL` をシークレットキーでHMAC-SHA256署名 → Base64URLエンコード  
4. `Authorization: Bearer ヘッダー.ペイロード.署名` ヘッダーを付与したリクエストを送信

## GASでのPOSTリクエスト実装例
以下は、`pfreports` エンドポイントに対してPOSTリクエストを行う例です。  
レポート期間やフォーマットなどを指定し、CSV形式でのパフォーマンスレポート生成をリクエストできます。

```js
function createReport() {
  // 必要な情報を設定
  const adaccountId = 'YOUR_ADACCOUNT_ID'; // 対象のAd Account IDを入力
  const accessKey = 'YOUR_ACCESS_KEY'; // LINE Ads Manager UIで取得したAccess Key
  const secretKey = 'YOUR_SECRET_KEY'; // LINE Ads Manager UIで取得したSecret Key
  const endpoint = `https://ads.line.me/api/v3/adaccounts/${adaccountId}/pfreports`;

  // リクエストボディ
  const requestBody = {
    level: "ADGROUP", // レポートのレベル（ADACCOUNT, CAMPAIGN, ADGROUP, AD）
    since: "2024-12-01", // レポート期間の開始日
    until: "2024-12-07", // レポート期間の終了日
    breakdown: { time: "DAY" }, // 時間単位のブレイクダウン
    filtering: { idType: "ADACCOUNT", ids: [adaccountId] }, // フィルタリング
    fileFormat: "CSV", // ファイル形式（CSVまたはCSV_EXCEL）
    locale: "ja" // 言語（ja, en, th, など）
  };

  const jsonBody = JSON.stringify(requestBody);
  const bodyHash = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, jsonBody);
  const digestSHA256 = bodyHash.map(b => ('0' + (b & 0xFF).toString(16)).slice(-2)).join('');
  
  // JOSEヘッダー作成
  const joseHeader = {
    alg: "HS256",
    kid: accessKey,
    typ: "text/plain"
  };
  const joseHeaderBase64 = Utilities.base64EncodeWebSafe(JSON.stringify(joseHeader));

  // 現在の日付
  const now = new Date();
  const date = Utilities.formatDate(now, 'Asia/Tokyo', 'yyyyMMdd');

  // JWSペイロード作成
  const canonicalURI = `/api/v3/adaccounts/${adaccountId}/pfreports`;
  const payload = [
    digestSHA256,
    "application/json", // Content-Type
    date,
    canonicalURI
  ].join("\n");
  const payloadBase64 = Utilities.base64EncodeWebSafe(payload);

  // 署名作成
  const signature = Utilities.computeHmacSha256Signature(`${joseHeaderBase64}.${payloadBase64}`, secretKey);
  const signatureBase64 = Utilities.base64EncodeWebSafe(signature);

  // Authorization ヘッダー
  const authorizationHeader = `${joseHeaderBase64}.${payloadBase64}.${signatureBase64}`;

  // HTTP リクエストオプション
  const options = {
    method: "post",
    headers: {
      Authorization: authorizationHeader,
      "Content-Type": "application/json",
      Date: date
    },
    payload: jsonBody,
    muteHttpExceptions: true
  };

  // リクエスト送信
  const response = UrlFetchApp.fetch(endpoint, options);
  
  // レスポンスの確認
  Logger.log(response.getResponseCode());
  Logger.log(response.getContentText());
}
```

## まとめ
基本的な流れは、**アクセスキーとシークレットキーの用意 → JOSEヘッダーとペイロードの準備 → HMAC-SHA256署名生成 → UrlFetchAppでPOST** という手順です。

レポートの自動取得や広告アカウント運用効率化を検討している方は、ぜひこの手順を活用してみてください。