概要:クリックに署名検証を導入することで、不正による損失や負担を防ぎ、不正なクリックが自社のアドネットワークのものとして扱われないようにします。
クリック署名について
不正行為者は、ごく簡単な技術でアドネットワークを装い、数千件から数百万件もの偽のクリックをAppsFlyerに送信できます。アドネットワーク自身が、この問題に気付いていない場合もあります。
アドネットワークは、クリックにHMAC-SHA256署名を付ける必要があります。これにより、AppsFlyerが自社にアトリビューションしたクリックが、不正行為者による偽のクリックではなく、実際に自社から発生したものであることを確認できます。
クリック署名は、クリック洪水によってアドネットワークのトラフィックがブロックされるのを防ぐことにも役立ちます。極端なクリック洪水によってクリックのブロック基準値に達すると、AppsFlyerはその日の残りの時間、当該アドネットワークのクリックの記録とアトリビューションを停止します。
AppsFlyerは署名を使ってクリックを検証し、クリック情報が不正行為者によって改ざんされていないことを確認します。
- 検証に成功したクリックは記録され、アドネットワークがアトリビューション先となります。
- 検証に失敗したクリックは拒否され、以下のように扱われます。
- 広告主向けではなく、アドネットワーク向けのProtect360レポートで確認できます。詳細はこちら
- アドネットワークのコンバージョン率や、クリックのブロック基準値には影響しません。
クリック署名の実装
実装の流れ
以下の図は、初期開発と基本テストから、本番環境でのテスト、本番運用の開始までの流れを示しています。
実装手順
事前準備:API V2.0トークンを管理者から取得します。クリック署名APIの認証に使用します。
クリックに署名する手順:
-
シークレットキー生成APIで、シークレットキーを生成します。
推奨:有効期限を36時間に設定した新しいシークレットキーを、24時間ごとに生成して使用します。 -
コードを開発し、自社サーバーからシークレットキー生成APIを呼び出して、取得したキーでHMAC-SHA256署名を生成できるようにします。コードサンプルを参照してください。
以下の表で説明するその他のAPIも使用できます。 - コードで、以下の情報をクリックURLに追加します。
- クリックの有効期限を示すUNIXタイムスタンプ(UTC)を含むexpiresパラメータ。この時刻以降、アドネットワークはそのクリックを有効とは認めません。
- HMAC-SHA256署名。
例:https://app.appsflyer.com/com.app.id?pid=adnetwork_int&c=my_campaign&clickid=sdkfjasksjskdfj9845weh&af_siteid=12345&expires=1597657118&signature_v2=8fnDVzZP_WRZnv3KNJaREOEfvB5p9oRc_XlKEvUo8gk
注意
リンク内の特殊文字やスペースのURLエンコードは、必ずクリック署名の生成前に行ってください。 先に署名を生成すると、検証に失敗します。
クリック署名の生成
クリック署名は、以下の手順で生成します。
属性の一覧
クリックとエンゲージメントの署名では、以下の属性を使用できます。
| 順序 | パラメータ | 必須 | 説明 |
|---|---|---|---|
| 1 | link_domain | はい | クリックURLのドメイン。例:
|
| 2 | link_path | はい | 先頭のバックスラッシュを除いたクリックURLのパス。 単一プラットフォームのリンクの場合はapp-id、OneLinkの場合はtemplate-idです。 |
| 3 | pid | はい | |
| 4 | af_prt | いいえ | |
| 5 | af_siteid | はい | |
| 6 | clickid | はい | クリックごとに1回限り使用する、一意の識別子。 |
| 7 | expires | はい | クリックの有効期限 |
| 8 | af_engagement_type | いいえ | |
| 9 | af_click_lookback | いいえ | |
| 10 | af_viewthrough_lookback | いいえ | |
| 11 | af_reengagement_window | いいえ | |
| 12 | is_retargeting | いいえ | |
| 13 | af_ip | いいえ | |
| 14 | advertising_id | いいえ | |
| 15 | oaid | いいえ | |
| 16 | fire_advertising_id | いいえ | |
| 17 | idfa | いいえ | |
| 18 | idfv | いいえ |
属性とJSONのルール
属性の指定と順序
- エンゲージメントURLに含まれる対応パラメータのうち、値が設定されているものは、JSONにも必ず含めてください。
- JSON内の属性は、上の表に記載された順序で指定してください。
空の属性値
- JSONに含める属性の値は、空文字列やスペースのみにはできません。
JSONのデータ構造
- JSONは、属性の配列として構成する必要があります。
- 各属性は["key", "value"]形式で指定します。
例:[["key-1","value-1"],["key-2","value-2"]...["key-n","value-n"]]
- 各属性は["key", "value"]形式で指定します。
属性値のエスケープ処理
- JSON内の値は、小文字の文字列で記述する必要があります。JSON標準の定義に従ってください。
JSON内の空白
- JSONは、余分な空白を除去した形式にしてください。値と値の間に、スペース、タブ、改行を含めないでください。
署名アルゴリズム
- シークレットキーとHmacSHA256を使用して、JSONの署名を生成します。
- 署名をBase64でエンコードします。パディングは付けないでください。
- signature_v2パラメータで、署名をクリックURLに追加します。
//generate a signature from the click url and encode it with base64 without padding String generatedSignature = Base64.getUrlEncoder().withoutPadding().encodeToString(mac.doFinal(jsonString.getBytes()));
署名の例
署名の作成例
OneLink(複数プラットフォーム対応)のクリックURLの例:
https://yourbrand.onelink.me/qsWL?pid=mediasource_int&advertising_id=12345678-1234-1234-1234-123456789012
&af_ad_type=video&af_adset=MMP&clickid=sdkfjasksjskdfj9845weh&af_siteid=my_site&af_viewthrough_lookback=2h&c=my_campaign
&expires=1689695615
署名用のJSONオブジェクトの例(空白の除去前):
[ ["link_domain","yourbrand.onelink.me"], ["link_path","qswl"], ["pid","mediasource_int"], ["af_siteid","my_site"], ["clickid","12345"], ["expires","1689695615"] ]
署名用のJSONオブジェクトの例(空白の除去後):
[["link_domain","yourbrand.onelink.me"],["link_path","qswl"],["pid","mediasource_int"],["template-id","qswl"],["af_siteid","my_site"],["clickid","12345"],["expires","1689695615"]]
署名を追加した最終的なクリックURL:
https://yourbrand.onelink.me/qsWL?pid=mediasource_int&advertising_id=12345678-1234-1234-1234-123456789012
&af_ad_type=video&af_adset=MMP&af_siteid=my_site&af_viewthrough_lookback=2h&c=my_campaign
&expires=1689695615
&signature_v2=WIfCmfLAPSsVrBTqCqfihMeLCnbE4dIAlhHF84WsiWA
コード例
signing-supported-params.json
[
{"index":1, "name":"pid", "mandatory":true},
{"index":2, "name":"af_prt", "mandatory":false},
{"index":3, "name":"af_siteid", "mandatory":true},
{"index":4, "name":"clickid", "mandatory":true},
{"index":5, "name":"expires", "mandatory":true},
{"index":6, "name":"af_engagement_type", "mandatory":false},
{"index":7, "name":"af_click_lookback", "mandatory":false},
{"index":8, "name":"af_viewthrough_lookback", "mandatory":false},
{"index":9, "name":"af_reengagement_window", "mandatory":false},
{"index":10, "name":"is_retargeting", "mandatory":false},
{"index":11, "name":"af_ip", "mandatory":false},
{"index":12, "name":"advertising_id", "mandatory":false},
{"index":13, "name":"oaid", "mandatory":false},
{"index":14, "name":"fire_advertising_id", "mandatory":false},
{"index":15, "name":"idfa", "mandatory":false},
{"index":16, "name":"idfv", "mandatory":false}
]
signature-example.go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"net/url"
"os"
"strings"
"time"
)
type Param struct {
Name string
Mandatory bool
}
func LoadSupportedParams() ([]Param, error) {
path := "./signing-supported-params.json"
jsonFile, _ := os.Open(path)
defer jsonFile.Close()
byteValue, err := io.ReadAll(jsonFile)
if err != nil {
return nil, errors.New("failed loading " + path)
}
var params []Param
_ = json.Unmarshal(byteValue, ¶ms)
return params, nil
}
func computeHmac256(message, secret string) (res string, errResult error) {
defer func() {
if r := recover(); r != nil {
errResult = r.(error)
fmt.Println("failed to invoke ComputeHmac256. err: %+v", errResult)
res = ""
return
}
}()
key := []byte(secret)
h := hmac.New(sha256.New, key)
h.Write([]byte(message))
return base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(h.Sum(nil)), nil
}
// this function accepts a click url, a ttl for the click in seconds, and the list of supported params
// the function:
// 1. adds the expiration to the click based on the provided ttl
// 2. builds a json for the signature
// 3. create an HMAC256 signature
// 4. adds the signature to the click url
func signURLV2(originalURL string, secret string, clickTtlSeconds int64, supportedParams []Param) (signedURL string, err error) {
//add an expiration to the click
expires := time.Now().UTC().Unix() + clickTtlSeconds
urlWithExpired := fmt.Sprintf("%s%s%d", originalURL, "&expires=", expires)
//parse the url
parsedURL, err := url.Parse(urlWithExpired)
if err != nil {
return "", errors.New("failed parsing URL")
}
//build a json from the url
jsonStr, err := buildJSONFromURLV2(parsedURL, supportedParams)
if err != nil {
return "", err
}
//create a signature
signatureV2, err := computeHmac256(jsonStr, secret)
if err != nil {
fmt.Println("Failed to computeHMAC256 for url %s. err: %+v", jsonStr, err)
return "", errors.New("fail to computeHMAC256 for url")
}
//add the signature to the url
signedURL = fmt.Sprintf("%s%s%s", urlWithExpired, "&signature_v2=", signatureV2)
return signedURL, nil
}
// this function builds a json from a given click url.
// It returns a string representation of the json ready to be signed.
func buildJSONFromURLV2(parsedURL *url.URL, supportedParams []Param) (string, error) {
//initiate an empty json in the structure [[key-1,val-1],[key-2,val-2]...[key-n,val-n]]
var jsonData [][2]string
//add the url host domain to the json
domain := parsedURL.Host
param := [2]string{"link_domain", domain}
jsonData = append(jsonData, param)
//add the path (app-id or template-id) to the json
path := parsedURL.Path
if len(path) > 1 {
param := [2]string{"link_path", path[1:]}
jsonData = append(jsonData, param)
}
//loop over the ordered list of supported parameters and add them to the json
for i := 0; i <len(supportedParams); i++ {name := supportedParams[i].Name val := parsedURL.Query().Get(name) if len(val) > 0 {
param := [2]string{name, val}
jsonData = append(jsonData, param)
} else if supportedParams[i].Mandatory {
return "", errors.New("missing mandatory param: " + name)
}
}
//generate string representation of the json object
jsonObj, _ := json.Marshal(jsonData)
return strings.ToLower(string(jsonObj)), nil
}
func main() {
supportedParams, err := LoadSupportedParams()
if err != nil {
fmt.Println("Error: ", err)
os.Exit(1)
}
var secretKey = "tqJU4Qd/eFTEWfqW7KCG9asDO0bmZoFzv8GY3VPSPAM="
var clickTtlSeconds int64 = 60
var originalUrl = "https://yourbrand.onelink.me/qsWL?pid=mediasource_int&advertising_id=12345678-1234-1234-1234-123456789012&clickid=1234&af_ad_type=video&af_adset=MMP&af_siteid=my_site&af_viewthrough_lookback=2h&c=my_campaign"
fmt.Println("Original URL: ", originalUrl)
signedUrl, err := signURLV2(originalUrl, secretKey, clickTtlSeconds, supportedParams)
if err != nil {
fmt.Println("Error: ", err)
os.Exit(1)
} else {
fmt.Println("Signed URL: ", signedUrl)
}
}クリック署名API
AppsFlyerは、アドネットワークがクリック署名の処理を管理・テストするためのAPIを提供しています。以下のAPI一覧と、各APIの使用に必要な情報を説明する後続のセクションを参照してください。
クリック署名API
| APIメソッド | 説明 |
|---|---|
| シークレットキーの生成 | 署名に使用するシークレットキーを生成します。 |
| シークレットキーの無効化 | 漏えいなどによって安全性が損なわれたシークレットキーを無効にします。 |
| テスト | クリックを1件ずつ送信し、署名をテストします。 |
| モードの設定 |
クリック署名のモードを設定します。
|
| サーキットブレーカーの設定 |
クリックが大量にブロックされることからアドネットワークを保護する、サーキットブレーカーのモードを設定します。
|
| 設定の取得 | 現在のモードと、有効なシークレットキーのIDを取得します。 |
| レポート | report-only(レポートのみ)またはenabled(有効)モードで、直近3日間の検証に成功・失敗したクリックの統計を取得します。本番環境や実際のトラフィックに影響を与えずにクリック署名をテストする場合に使用します。 |
| アプリの除外 | クリック署名の対象から除外するアプリIDを設定します。 |
| 除外したアプリの復帰 | クリック署名の対象から除外したアプリIDを、再び対象に戻します。 |
旧バージョン
以下は参考情報として掲載している旧バージョンです。使用しないでください。
V1 | 旧バージョン
シークレットキー生成API
シークレットキー生成APIの基本仕様
| 区分 | 項目 | 説明 |
|---|---|---|
| リクエスト | HTTPメソッド | POST |
| パス | https://hq1.appsflyer.com/api/p360-click-signing/secret?ttlHours=<ttlHours> | |
| Authorizationヘッダー |
|
|
| レスポンス | 取得結果 | シークレットキーがJSON形式で返されます。 |
| 利用上限 | 同時に有効にできるシークレットキーは、最大2つです。 |
APIリクエスト
メソッド
POST https://hq1.appsflyer.com/api/p360-click-signing/secret?ttlHours=<ttlHours>
パラメータ
| パラメータ | 説明 |
|---|---|
| ttlHours |
|
JSONレスポンス
| キー | 説明 |
|---|---|
| secret-key-id | シークレットキーのID。 |
| secret key | クリック署名に使用するシークレットキー。 |
| expiration | ミリ秒単位のエポック時刻。 |
シークレットキー生成のcurl例とレスポンス
curlリクエスト
curl --location --request POST 'https://hq1.appsflyer.com/api/p360-click-signing/secret?ttlHours=36' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}'
JSONレスポンス
{
"secret-key-id": "59ad6547-affc-45eb-a6c9-9805f88ee755",
"secret-key": "zGW6Rhrmb8+vuhHtL/Kp6rW5Ci9PNsjH1J5MGO9SIeg=",
"expiration": 1610533263
}
HTTPレスポンスコード
レスポンスコード
| コード | メッセージ | 説明 |
|---|---|---|
| 200 | OK | |
| 401 | Not authorized | Authorizationヘッダーが無効、または指定されていません。 |
シークレットキー無効化API
シークレットキー無効化APIの基本仕様
| 区分 | 項目 | 説明 |
|---|---|---|
| リクエスト | HTTPメソッド | DELETE |
| パス | https://hq1.appsflyer.com/api/p360-click-signing/secret/<secret-id> | |
| Authorizationヘッダー |
|
|
| レスポンス | 取得結果 | 空のレスポンス |
APIリクエスト
メソッド
DELETE https://hq1.appsflyer.com/api/p360-click-signing/secret/<secret-id>
パラメータ
| パラメータ | 説明 |
|---|---|
| secret-id | 無効にするシークレットキーのID。 |
シークレットキー生成のcurl例とレスポンス
curlリクエスト
curl --location --request DELETE 'https://hq1.appsflyer.com/api/p360-click-signing/secret/59ad6547-affc-45eb-a6c9-9805f88ee755' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}'
HTTPレスポンスコード
レスポンスコード
| コード | メッセージ | 説明 |
|---|---|---|
| 200 | OK | |
| 401 | Not authorized | Authorizationヘッダーが無効、または指定されていません。 |
テストAPI
テストAPIの基本仕様
| 区分 | 項目 | 説明 |
|---|---|---|
| リクエスト | HTTPメソッド | POST |
| パス | https://hq1.appsflyer.com/api/p360-click-signing/test | |
| Authorizationヘッダー |
|
|
| レスポンス | 取得結果 | JSON形式で返されます。 |
APIリクエスト
メソッド
POST https://hq1.appsflyer.com/api/p360-click-signing/test
パラメータ
| パラメータ | 説明 |
|---|---|
| url | テストするクリックURL(署名を含む)。 |
JSONレスポンス
| キー | 説明 |
|---|---|
| test-status | PassedまたはFailed。 |
| message |
テストが失敗した理由。例:
|
テストのcurl例とレスポンス
curlリクエスト
curl --location --request POST 'https://hq1.appsflyer.com/api/p360-click-signing/test' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}' \
--header 'Content-Type: application/json' \
--data-raw '{
"url": "https://app.appsflyer.com/com.app.id?pid=adnetwork_int&c=my_campaign&clickid=sdkfjasksjskdfj9845weh&af_site_id=12345&expires=1597657118&signature=8fnDVzZP_WRZnv3KNJaREOEfvB5p9oRc_XlKEvUo8gk"
}'
JSONレスポンス
{
"test-status":"Passed / Failed",
"message": "Invalid signature"
}
HTTPレスポンスコード
レスポンスコード
| コード | メッセージ | 説明 |
|---|---|---|
| 200 | OK | |
| 401 | Not authorized | Authorizationヘッダーが無効、または指定されていません。 |
モード設定API
モード設定APIの基本仕様
| 区分 | 項目 | 説明 |
|---|---|---|
| リクエスト | HTTPメソッド | POST |
| パス | https://hq1.appsflyer.com/api/p360-click-signing/config/mode/<mode> | |
| Authorizationヘッダー |
|
|
| レスポンス | 取得結果 | JSON形式で返されます。 |
APIリクエスト
メソッド
POST https://hq1.appsflyer.com/api/p360-click-signing/config/mode/<mode>
パラメータ
| パラメータ | 説明 |
|---|---|
| mode | 指定できる値:
|
モード設定のcurl例
curlリクエスト
curl --location --request POST 'https://hq1.appsflyer.com/api/p360-click-signing/config/mode/report-only' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}'
HTTPレスポンスコード
レスポンスコード
| コード | メッセージ | 説明 |
|---|---|---|
| 200 | OK | |
| 400 | Bad request | 無効なモードが指定されています。 |
| 401 | Not authorized | Authorizationヘッダーが無効、または指定されていません。 |
サーキットブレーカー設定API
サーキットブレーカー設定APIの基本仕様
| 区分 | 項目 | 説明 |
|---|---|---|
| リクエスト | HTTPメソッド | POST |
| パス | https://hq1.appsflyer.com/p360-click-signing/config/circuit-breaker | |
| Authorizationヘッダー |
|
|
| レスポンス | 取得結果 | HTTPステータス |
APIリクエスト
メソッド
POST https://hq1.appsflyer.com/p360-click-signing/config/circuit-breaker
リクエストボディのJSON
| パラメータ | 説明 |
|---|---|
| status |
|
サーキットブレーカー設定のcurl例とレスポンス
curlリクエスト
curl --location --request POST 'https://hq1.appsflyer.com/api/p360-click-signing/config/circuit-breaker' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}'
--data-raw '{
"status":"enabled"
}'
HTTPレスポンスコード
レスポンスコード
| コード | メッセージ | 説明 |
|---|---|---|
| 200 | OK | |
| 400 | Bad request | 無効なステータスが指定されています。 |
| 401 | Not authorized | Authorizationヘッダーが無効、または指定されていません。 |
設定取得API
設定取得APIの基本仕様
| 区分 | 項目 | 説明 |
|---|---|---|
| リクエスト | HTTPメソッド | GET |
| パス | https://hq1.appsflyer.com/api/p360-click-signing/config | |
| Authorizationヘッダー |
|
|
| レスポンス | 取得結果 | JSON形式で返されます。 |
APIリクエスト
メソッド
GET https://hq1.appsflyer.com/api/p360-click-signing/config
JSONレスポンス
| キー | 説明 |
|---|---|
| mode |
以下のいずれか:
|
| circuit-breaker-config |
statusを含むJSONオブジェクト。値は以下のいずれかです。
|
| active-key-ids |
有効なキーを含むJSON配列:
|
| excluded-app-ids | 除外対象のapp-idsを含むJSON配列。 |
設定取得のcurl例とレスポンス
curlリクエスト
curl --location --request GET 'https://hq1.appsflyer.com/api/p360-click-signing/config' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}'
JSONレスポンス
{
"mode": "report-only",
"active-key-ids": [
{
"secret-key-id": "59ad6547-affc-45eb-a6c9-9805f88ee755",
"expiration": 1610533263
}
],
"excluded-app-ids": [
"app-id-1", "app-id-2"
]
}
HTTPレスポンスコード
レスポンスコード
| コード | メッセージ | 説明 |
|---|---|---|
| 200 | OK | |
| 401 | Not authorized | Authorizationヘッダーが無効、または指定されていません。 |
レポートAPI
レポートAPIの基本仕様
| 区分 | 項目 | 説明 |
|---|---|---|
| リクエスト | HTTPメソッド | GET |
| パス | https://hq1.appsflyer.com/api/p360-click-signing/report | |
| Authorizationヘッダー |
|
|
| レスポンス | 取得結果 | CSV形式で返されます。 |
APIリクエスト
メソッド
GET https://hq1.appsflyer.com/api/p360-click-signing/report
パラメータ
| パラメータ | 説明 |
|---|---|
| start-date | レポートの対象期間の開始日時。形式:yyyy-mm-ddThh |
| end-date | レポートの対象期間の終了日時。形式:yyyy-mm-ddThh |
| start-dateとend-dateは、両方を指定するか、どちらも指定しないかのいずれかにする必要があります。開始日時と終了日時を指定しない場合、過去24時間の結果が表示されます。 | |
CSVレスポンス
| 列 | 説明 |
|---|---|
| time | クリックの発生日時。形式:yyyy-mm-ddThh |
| total_clicks | 対象期間中のクリックの総数 |
| valid_clicks | 対象期間中の有効なクリック数 |
| missing_signature | 対象期間中の署名が付いていないクリック数 |
| expired_clicks | 対象期間中の有効期限が切れたクリック数 |
| invalid_signature | 対象期間中の署名が無効なクリック数 |
| no_active_secrets | システム内に有効なシークレットキーがないために拒否されたクリック数(通常、レポートのみモードで発生)。 |
テストのcurl例とレスポンス
curlリクエスト
curl --location --request GET 'https://hq1.appsflyer.com/api/p360-click-signing/report?start-date=2021-01-07T07&end-date=2021-01-17T12' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}' \
CSVレスポンス
| time | total_clicks | valid_clicks | missing_signature | expired_clicks | invalid_signature | no_active_signatures |
|---|---|---|---|---|---|---|
| 2021-01-17T07 | 928082156 | 928082156 | 0 | 0 | 0 | 0 |
| 2021-01-17T08 | 923796132 | 923796132 | 0 | 0 | 0 | 0 |
| 2021-01-17T09 | 917541373 | 917541373 | 0 | 0 | 0 | 0 |
| 2021-01-17T10 | 909977064 | 909977064 | 0 | 0 | 0 | 0 |
| 2021-01-17T11 | 965104299 | 965104299 | 0 | 0 | 0 | 0 |
| 2021-01-17T12 | 975134824 | 975134824 | 0 | 0 | 0 | 0 |
HTTPレスポンスコード
レスポンスコード
| コード | メッセージ | 説明 |
|---|---|---|
| 200 | OK | |
| 401 | Not authorized | Authorizationヘッダーが無効、または指定されていません。 |
アプリ除外API
アプリ除外APIの基本仕様
| 区分 | 項目 | 説明 |
|---|---|---|
| リクエスト | HTTPメソッド | POST |
| パス | https://hq1.appsflyer.com/api/p360-click-signing/config/excluded-app/<app-id> | |
| Authorizationヘッダー |
|
|
| レスポンス | 取得結果 | 空のレスポンス |
APIリクエスト
メソッド
POST https://hq1.appsflyer.com/api/p360-click-signing/config/excluded-app/<app-id>
パラメータ
| パラメータ | 説明 |
|---|---|
| app-id | クリック署名の検証対象から除外するアプリのID。 |
アプリ除外のcurl例
curlリクエスト
curl --location --request POST 'https://hq1.appsflyer.com/api/p360-click-signing/config/excluded-app/appname.com' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}'
HTTPレスポンスコード
レスポンスコード
| コード | メッセージ | 説明 |
|---|---|---|
| 200 | OK | |
| 401 | Not authorized | Authorizationヘッダーが無効、または指定されていません。 |
除外したアプリの復帰API
除外したアプリの復帰APIの基本仕様
| 区分 | 項目 | 説明 |
|---|---|---|
| リクエスト | HTTPメソッド | DELETE |
| パス | https://hq1.appsflyer.com/api/p360-click-signing/config/excluded-app/<app-id> | |
| Authorizationヘッダー |
|
|
| レスポンス | 取得結果 | 空のレスポンス |
APIリクエスト
メソッド
DELETE https://hq1.appsflyer.com/api/p360-click-signing/config/excluded-app/<app-id>
パラメータ
| パラメータ | 説明 |
|---|---|
| app-id | クリック署名の検証対象の除外リストから削除するアプリのID。 |
除外したアプリの復帰のcurl例
curlリクエスト
curl --location --request DELETE 'https://hq1.appsflyer.com/api/p360-click-signing/config/excluded-app/appname.com' \
-H 'Authorization: Bearer {API V2.0 token available to the admin in the dashboard.}'
HTTPレスポンスコード
レスポンスコード
| コード | メッセージ | 説明 |
|---|---|---|
| 200 | OK | |
| 401 | Not authorized | Authorizationヘッダーが無効、または指定されていません。 |
コードサンプル
package sign;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
.
.
.
String clickUrl = "https://app.appsflyer.com/com.app.id?pid=adnetwork_int&c=my_campaign&clickid=sdkfjasksjskdfj9845weh&af_site_id=12345";
String secretKey = "secret_key";
int ttlMinutes = 5;
//add expiration to the click URL
long expiration = System.currentTimeMillis() + (60000L * ttlMinutes);
clickUrl += "&expires="+expiration;
//create a SecretKey object from the given key string
SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
//generate a signature from the click url and encode it with base64 without padding
String generatedSignature =
Base64.getUrlEncoder().withoutPadding().encodeToString(mac.doFinal(clickUrl.getBytes()));
//add the signature to the click URL
String signedClickUrl = clickUrl + "&signature=" + generatedSignature;
補足情報
トラブルシューティング
1時間のクリックの90%超が署名検証に失敗すると、AppsFlyerはクリック署名の検証を停止し、レポートのみモードに戻ります。
これは、技術的な問題によってビジネスに影響が及ぶのを防ぎ、異常の原因を調査できるようにするためです。
- 署名が想定どおりに動作し、クリックが正しくブロックされている場合は、サーキットブレーカー設定APIでサーキットブレーカーを無効にしてください。
-
クリックが誤ってブロックされている場合:
- 設定取得APIでクリック署名の設定を確認し、有効なシークレットキーがあることを確認してください。
- クリック署名レポートでブロックされたクリックの詳細を取得し、無効なクリックの流入元(代理店IDやアプリID)と理由を調査してください。
- 標準とは異なる連携方法が原因で、特定のアプリに問題がある場合は、アプリ除外APIでそのアプリをクリック署名の検証対象から除外してください。
-
設定に問題がある場合:
- レポートのみモードでの動作を継続します。
- 自社側のクリック署名の処理を修正します。
- クリック署名レポートで結果を確認し、クリックが想定どおりに検証されるようになったら、署名検証を再び有効にします。
よくある質問
|
Q:本番環境に影響を与えずにクリック署名をテストする方法はありますか? A:以下の2つの方法があります。
|
|
Q:APIトークンとシークレットキーの違いは何ですか? A:APIトークン:クリック署名APIの認証と実行に使用します。アドネットワークごとに1つだけ存在します。 AppsFlyer API V2.0トークンは、管理者から取得する必要があります。 シークレットキー:署名の生成に使用します。シークレットキー生成APIで生成できます。新しいシークレットキーの生成は、アドネットワーク自身が行う必要があります。詳しくは、仕様のセクションを参照してください。 |
|
Q:特定のキャンペーンにだけクリック署名を適用できますか? A:いいえ。クリック署名は、そのアドネットワークのすべてのクリックに適用されます。特定のアプリを対象から除外することはできますが、特定のキャンペーンだけを除外することはできません。 |
仕様
| 項目 | 説明 |
|---|---|
| クリック署名 | 署名の生成は、アドネットワークのサーバーで行う必要があります。 |
| シークレットキー |
|
| レポートAPI | クリックの有効性に関する最新の統計が、1時間単位で集計されます。 |