한눈에 보기: 요약: 사기 책임을 방지하기 위해 클릭에 서명 유효성 검증을 추가하면 광고 네트워크에서 부정한 클릭이 발생하지 않습니다.
클릭 서명 정보
간단한 기술을 이용하여, 사기범들은 광고 네트워크를 대신하여 클릭을 전송할 수 있고, 수천 또는 심지어 수백만의 가짜 클릭을 생성하여 앱스플라이어에 전송할 수 있습니다. 광고 네트워크 자체가 이 문제를 인식하지 못하는 경우도 있습니다.
광고 네트워크가 실제로 앱스플라이어에 의해 어트리뷰트된 클릭이 가짜 클릭을 작성하는 사기범이 아니라 실제 광고 네트워크에서 클릭된 것인지 확인하기 위해, 광고 네트워크는 HMAC-SHA256 서명을 사용하여 클릭을 서명해야 합니다.
서명은 앱스플라이어가 클릭을 검증하고 사기꾼에 의해 클릭 정보가 조작되지 않았음을 확인할 수 있게 합니다.
- 검증된 클릭은 기록되어 애드 네트워크에 귀속됩니다.
- 무효화된 클릭은 거부되며:
- 광고 네트워크(광고주가 아님)용 Protect360 리포트에서 보실 수 있습니다. 더 알아보기
- 전환율이나 광고 네트워크의 클릭 차단 임계값에 영향을 주지 않습니다.
클릭 서명 연동
플로우
다음 차트는 초기 개발 및 기본 테스트, 생산 테스트, 마지막으로 생산까지의 흐름을 개략적으로 설명합니다.
절차
전제 조건: 필수 구성 요소: 클릭 서명 API를 인증하기 위한 관리자의 API V2.0 토큰.
클릭 서명 방법:
-
비밀 키 생성 API로 비밀 키를 생성합니다.
모범 사례: 모범 사례: 유효 기간을 36시간으로 하고 24시간마다 새 비밀 키를 생성하여 사용합니다. -
- 상기 코드는 다음 정보를 클릭 URL에 추가합니다.
- Unix 타임스탬프(UTC로)를 포함하는 만기 파라미터이며, 이후 광고 네트워크에서 클릭을 요청하지 않습니다.
- 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 | 예 |
|
| 2 | link_path | 예 | |
| 3 | pid | 예 | |
| 4 | af_prt | 아니요 | |
| 5 | af_siteid | 예 | |
| 6 | 클릭아이디 | 예 | |
| 7 | 예 | ||
| 8 | af_engagement_type | 아니요 | |
| 9 | af_클릭_룩백 | 아니요 | |
| 10 | af_viewthrough_lookback | 아니요 | |
| 11 | af_reengagement_window | 아니요 | |
| 12 | 리타겟팅 여부 | 아니요 | |
| 13 | af_ip | 아니요 | |
| 14 | advertising_id | 아니요 | |
| 15 | oaid | 아니요 | |
| 16 | fire_advertising_id | 아니요 | |
| 17 | idfa | 아니요 | |
| 18 | idfv | 아니요 |
-
-
예시:[["key-1","value-1"],["key-2","value-2"]...["key-n","value-n"]]
-
//generate a signature from the click url and encode it with base64 without padding String generatedSignature = Base64.getUrlEncoder().withoutPadding().encodeToString(mac.doFinal(jsonString.getBytes()));
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
[ ["link_domain","yourbrand.onelink.me"], ["link_path","qswl"], ["pid","mediasource_int"], ["af_siteid","my_site"], ["clickid","12345"], ["expires","1689695615"] ]
[["link_domain","yourbrand.onelink.me"],["link_path","qswl"],["pid","mediasource_int"],["template-id","qswl"],["af_siteid","my_site"],["clickid","12345"],["expires","1689695615"]]
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
앱스플라이어는 광고 네트워크가 클릭 서명 프로세스를 관리하고 테스트하는 데 사용할 수 있는 API를 제공합니다. 아래 표의 API 목록과 API 사용에 필요한 정보가 포함된 섹션을 참조하십시오.
클릭 서명 API
| API 메서드 | 비고 |
|---|---|
| 비밀 키를 생성합니다. | 서명에 사용할 비밀 키를 생성합니다. |
| 비밀 키를 취소합니다. | 손상된 비밀 키를 취소합니다. |
| 실험군 | 단일 클릭을 서명 테스트를 위해 전송합니다. |
| 설정 모드 |
클릭 서명 모드의 설정 모드:
|
| 회로 차단기 설정 |
광고 네트워크에 너무 많은 차단 클릭이 들어오는 것을 보호하는 회로 차단기의 모드를 설정합니다.
|
| 설정 가져오기 | 활성 비밀 키의 모드와 ID를 가져옵니다. |
| 보고서 | 시스템이 리포트 전용 모드 또는 사용가능 모드일 때 성공 클릭 및 실패 클릭에 대한 통계 가져오기. 이를 통해 프로덕션 및 실제 트래픽에 영향을 주지 않고 클릭 서명을 테스트합니다. |
| 앱 제외 | 클릭 서명에서 제외할 앱 ID를 구성합니다. |
| 제외된 앱 삭제 | 앱 ID가 제외된 후 서명 클릭에 포함되도록 구성합니다. |
V1(레거시)
비밀 키 메서드 생성
비밀 키 베이직 생성
| 카테고리 | 항목 | 설명 |
|---|---|---|
| 요청 | HTTP 메서드 | POST |
| 경로 | https://hq1.appsflyer.com/api/p360-click-signing/secret?ttlHours=<ttlHours> | |
| 권한 관리 헤더 |
|
|
| 응답 | 결과 | 비밀 키는 JSON 형식으로 반환됩니다. |
| 요청 제한 | 활성 비밀 키는 한 번에 최대 2개입니다. |
API 요청
방법
POST https://hq1.appsflyer.com/api/p360-click-signing/secret?ttlHours=<ttlHours>
파라미터
| 파라미터 | 설명 |
|---|---|
| ttlHours |
|
JSON 응답
| 키 | 설명 |
|---|---|
| secret-key-id | 비밀 키용 ID |
| Secret key | 클릭 서명을 위한 비밀 키 |
| 밀리초 단위의 에포크(Epoch) 시간 |
비밀 키 컬 예시와 응답을 생성합니다.
컬 요청
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 | 정상 | |
| 401 | 승인되지 않음 | 유효하지 않거나 누락된 권한 관리 헤더 |
비밀 키 메서드 취소
비밀 키 베이직 취소합니다
| 카테고리 | 항목 | 설명 |
|---|---|---|
| 요청 | HTTP 메서드 | DELETE |
| 경로 | https://hq1.appsflyer.com/api/p360-click-signing/secret/<secret-id> | |
| 권한 관리 헤더 |
|
|
| 응답 | 결과 | 비어있음 |
API 요청
방법
DELETE https://hq1.appsflyer.com/api/p360-click-signing/secret/<secret-id>
파라미터
| 파라미터 | 설명 |
|---|---|
| secret-id | 취소할 비밀 키의 ID |
비밀 키 컬 예시와 응답을 생성합니다.
컬 요청
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 | 정상 | |
| 401 | 승인되지 않음 | 유효하지 않거나 누락된 권한 관리 헤더 |
테스트 방법
테스트 기본
| 카테고리 | 항목 | 설명 |
|---|---|---|
| 요청 | HTTP 메서드 | POST |
| 경로 | https://hq1.appsflyer.com/api/p360-click-signing/test | |
| 권한 관리 헤더 |
|
|
| 응답 | 결과 | JSON 형식으로 반환 |
API 요청
방법
POST https://hq1.appsflyer.com/api/p360-click-signing/test
파라미터
| 파라미터 | 설명 |
|---|---|
| URL | 테스트할 클릭 URL(서명 포함) |
JSON 응답
| 키 | 설명 |
|---|---|
| 통과 또는 실패함 | |
| 메시지 |
테스트 실패 이유. 예를 들어:
|
컬 예시 및 응답 테스트
컬 요청
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 | 정상 | |
| 401 | 승인되지 않음 | 유효하지 않거나 누락된 권한 관리 헤더 |
모드 메서드 설정
모드 베이직 설정합니다
| 카테고리 | 항목 | 설명 |
|---|---|---|
| 요청 | HTTP 메서드 | POST |
| 경로 | https://hq1.appsflyer.com/api/p360-click-signing/config/mode/<mode> | |
| 권한 관리 헤더 |
|
|
| 응답 | 결과 | JSON 형식으로 반환 |
API 요청
방법
POST https://hq1.appsflyer.com/api/p360-click-signing/config/mode/<mode>
파라미터
| 파라미터 | 설명 |
|---|---|
| 모드 | 옵션:
|
모드 컬 예시 설정합니다
컬 요청
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 | 정상 | |
| 400 | 잘못된 요청 | 유효하지 않은 모드 |
| 401 | 승인되지 않음 | 유효하지 않거나 누락된 권한 관리 헤더 |
회로 차단기 메서드 설정
회로 차단기 베이직 설정
| 카테고리 | 항목 | 설명 |
|---|---|---|
| 요청 | HTTP 메서드 | POST |
| 경로 | https://hq1.appsflyer.com/p360-click-signing/config/circuit-breaker | |
| 권한 관리 헤더 |
|
|
| 응답 | 결과 | HTTP 상태 |
API 요청
방법
POST https://hq1.appsflyer.com/p360-click-signing/config/circuit-breaker
요청 본문 JSON
| 파라미터 | 설명 |
|---|---|
| 상태 |
|
회로 차단기 컬 예시 및 응답 설정
컬 요청
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 | 정상 | |
| 400 | 잘못된 요청 | 유효하지 않은 상태 |
| 401 | 승인되지 않음 | 유효하지 않거나 누락된 권한 관리 헤더 |
설정 메서드 가져오기
설정 베이직 가져오기
| 카테고리 | 항목 | 설명 |
|---|---|---|
| 요청 | HTTP 메서드 | GET |
| 경로 | https://hq1.appsflyer.com/api/p360-click-signing/config | |
| 권한 관리 헤더 |
|
|
| 응답 | 결과 | JSON 형식으로 반환 |
API 요청
방법
GET https://hq1.appsflyer.com/api/p360-click-signing/config
JSON 응답
| 키 | 설명 |
|---|---|
| 모드 |
다음 중 한 개:
|
| circuit-breaker-config |
다음 중 하나의 상태를 포함하는 JSON 개체:
|
| active-key-ids |
활성 키를 담고 있는 JSON 배열:
|
| excluded-app-ids | app-ids를 배제한 JSON 배열 |
설정 컬 예시 및 응답 가져오기
컬 요청
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 | 정상 | |
| 401 | 승인되지 않음 | 유효하지 않거나 누락된 권한 관리 헤더 |
리포트 메서드
리포트 베이직
| 카테고리 | 항목 | 설명 |
|---|---|---|
| 요청 | HTTP 메서드 | GET |
| 경로 | https://hq1.appsflyer.com/api/p360-click-signing/report | |
| 권한 관리 헤더 |
|
|
| 응답 | 결과 | CSV 형식으로 반환 |
API 요청
방법
GET https://hq1.appsflyer.com/api/p360-click-signing/report
파라미터
| 파라미터 | 설명 |
|---|---|
| 시작날짜 | 리포트 시작 날짜 및 시간. 형식: yyyy-mm-ddThh |
| 종료일. | 리포트 마감 날짜 및 시간. 형식: yyyy-mm-ddThh |
| API를 사용하려면 시작 날짜와 마감 날짜가 모두 필요하거나 둘 다 필요하지 않습니다. 시작/마감 날짜가 제공되지 않으면 리포트는 지난 24시간 동안의 결과를 표시합니다. | |
CSV 응답
| 열 | 설명 |
|---|---|
| 시간 | 클릭의 날짜 및 시간. 형식: yyyy-mm-ddThh |
| total_clicks | 리포트 기간 동안 총 클릭 수 |
| valid_clicks | 리포트 기간 동안 유효한 클릭 수 |
| missing_signature | 리포트 기간 동안 서명이 누락된 클릭 수 |
| expired_clicks | 리포트 기간 동안 만료된 클릭 수 |
| invalid_signature | 리포트 기간 동안 유효하게 서명한 클릭 수 |
| no_active_secrets | 시스템에 활성 비밀 키가 없기 때문에 거부된 클릭 수(일반적으로 시스템이 리포트 전용 모드인 경우) |
컬 예시 및 응답 테스트
컬 요청
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 응답
| 시간 | 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 | 정상 | |
| 401 | 승인되지 않음 | 유효하지 않거나 누락된 권한 관리 헤더 |
앱 메서드 제외
앱 메서드 베이직 제외
| 카테고리 | 항목 | 설명 |
|---|---|---|
| 요청 | HTTP 메서드 | POST |
| 경로 | ||
| 권한 관리 헤더 |
|
|
| 응답 | 결과 | 비어있음 |
API 요청
방법
POST https://hq1.appsflyer.com/api/p360-click-signing/config/excluded-app/<app-id>
파라미터
| 파라미터 | 설명 |
|---|---|
| app-id | 클릭 서명 유효성 검증에서 제외된 애플리케이션 ID |
앱 컬 예시 제외
컬 요청
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 | 정상 | |
| 401 | 승인되지 않음 | 유효하지 않거나 누락된 권한 관리 헤더 |
제외된 앱 메서드 삭제
제외된 앱 메서드 베이직 삭제
| 카테고리 | 항목 | 설명 |
|---|---|---|
| 요청 | HTTP 메서드 | DELETE |
| 경로 | ||
| 권한 관리 헤더 |
|
|
| 응답 | 결과 | 비어있음 |
API 요청
방법
DELETE https://hq1.appsflyer.com/api/p360-click-signing/config/excluded-app/<app-id>
파라미터
| 파라미터 | 설명 |
|---|---|
| app-id | 클릭 서명 유효성 검증에서 제외된 앱 목록에서 제거할 애플리케이션 ID |
제외된 앱 컬 예시 삭제
컬 요청
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 | 정상 | |
| 401 | 승인되지 않음 | 유효하지 않거나 누락된 권한 관리 헤더 |
코드 샘플
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;
추가 정보
문제 해결
앱스플라이어는 한 시간 동안 90% 이상의 클릭이 서명 유효성 검증에 실패하면 서명 유효성 검증을 중지하고 리포트 전용 모드로 돌아갑니다.
목적은 잠재적인 기술적 문제로부터 비즈니스를 보호하기 위한 것이며 이를 통해 다음과 같은 이상의 원인을 찾을 수 있습니다.
- 서명이 예상대로 작동하고 클릭이 올바르게 차단되는 경우 회로 차단기 설정 방법을 사용하여 회로 차단기를 비활성화합니다.
-
상기 클릭이 올바르게 차단되지 않은 경우:
- 설정 가져오기 방법을 사용하여 클릭 서명 설정을 검사하여 유효한 비밀 키가 있는지 확인합니다.
- 클릭 서명 리포트를 사용하여 차단된 클릭에 대한 자세한 정보를 얻고 잘못된 클릭의 출처(에이전시/앱- ID)와 이유를 조사합니다.
- 비표준 연동으로 인해 특정 앱에서 문제가 발견되면 앱 제외 API를 사용하여 서명 유효성 검증을 클릭하지 않도록 이 앱을 제외합니다.
-
설정에서 문제가 발견된 경우:
- 리포트 전용 모드에서 실행을 계속합니다.
- 사용자 쪽에서 클릭 서명 프로세스를 수정합니다.
- 클릭 서명 리포트에서 결과를 확인하고 클릭의 유효성을 예상대로 검증되는 경우 클릭 서명 유효성 검사를 다시 사용하도록 설정합니다.
자주 묻는 질문
|
질문: 질문: 프로덕션에 영향을 주지 않고 어떻게 클릭 서명을 테스트합니까? 답변: 답변: 클릭 서명을 테스트하는 방법에는 두 가지가 있습니다.
|
|
질문: 질문: API 토큰과 비밀 키의 차이점은 무엇입니까? 답변: api_token Secret key |
|
질문: 질문: 클릭 서명을 특정 캠페인에만 적용할 수 있나요? 답변: |
특성
| 특징 | 설명 |
|---|---|
| 클릭 서명 | 서명은 광고 네트워크 서버에 표시되어야 합니다. |
| Secret key |
|
| 리포트 API | 클릭 유효성에 대한 업데이트된 통계는 매시간 집계됩니다. |