跳到主要内容

章鱼预算方 API 对接文档


1. 文档下载

章鱼预算方 API 对接文档

章鱼预算方 API proto文件下载

注意事项:

价格加密使用的是 base64 没有用 base64-url-safe 编码因此上报曝光时 get 请求可能会造成+号变成空格 这个需特殊处理一下 将空格改为+号

2. 版本历史

版本日期备注
1.0.02019-01-28初版
2.0.02019-07-28新增 oaid 等字段标识
3.0.02021-04-1支持 RTB 竞价
3.3.02022-01-17支持 价格宏替换加密
3.4.192023-03-6支持 idfamd5、oaidmd5 等字段标识
3.4.202023-06-15新增 paid 参数
3.4.212024-04-10新增 caid 相关参数
3.5.12024-08-08新增下载类相关参数
3.5.22025-09-28新增监测上报时间宏替换
3.5.32025-11-07新增请求限制时间、接口超时时间戳
3.6.12025-12-10请求:
1、是否支持点击宏替换
2、是否支持点击时间上报(点击宏替换的秒级、毫秒级)
响应:
1、广告来源(用于点击坐标宏替换)1:oppo 2:华为
点击宏替换:
1、点击宏替换 新版本修改为__oct_click_type__

3.请求参数生成示例

以 json 为示例 转换成 pb 序列化后的格式 并生成文件

import com.googlecode.protobuf.format.JsonFormat;
import com.octopus.bidder.api.openrtb.Zy_Proto;

import java.io.FileOutputStream;

/**
* @author Kari
* @date 2022年10月10日下午3:04
*/
public class Test {
public static void main(String[] args) {
Zy_Proto.Request.Builder request = Zy_Proto.Request.newBuilder();
String jsonFormat = "{\n" +
" \"version\": 2,\n" +
" \"id\": \"oFcXvbXQFyVR19LuKNnR08sZbEiA8N5IwGs63mZC\",\n" +
" \"imp\": [\n" +
" {\n" +
" \"id\": 0,\n" +
" \"pid\": \"202607310\",\n" +
" \"width\": 720,\n" +
" \"height\": 1280,\n" +
" \"bid_floor\": 0\n" +
" }\n" +
" ],\n" +
" \"device\": {\n" +
" \"ip\": \"223.96.182.139\",\n" +
" \"user_agent\": \"Mozilla%2F5.0%28Linux%3BAndroid10%3BAQM-AL00Build%2FHUAWEIAQM-AL00%3Bwv%29AppleWebKit%2F537.36%28KHTML%2ClikeGecko%29Version%2F4.0Chrome%2F88.0.4324.93MobileSafari%2F537.36\",\n" +
" \"idfa\": \"\",\n" +
" \"imei\": \"\",\n" +
" \"imei_md5\": \"\",\n" +
" \"paid\": \"\",\n" +
" \"mac\": \"94:37:F7:92:A6:1F\",\n" +
" \"mac_md5\": \"\",\n" +
" \"device_type\": 0,\n" +
" \"brand\": \"HUAWEI\",\n" +
" \"model\": \"AQM-AL00\",\n" +
" \"os\": \"Android\",\n" +
" \"osv\": \"10\",\n" +
" \"network\": 1,\n" +
" \"operator\": 0,\n" +
" \"width\": 1080,\n" +
" \"height\": 2198,\n" +
" \"pixel_ratio\": 0,\n" +
" \"geo\": {\n" +
" \"lat\": 0.0,\n" +
" \"lon\": 0.0\n" +
" },\n" +
" \"installed_app\": [\n" +
" \"com.xunmeng.pinduoduo\",\n" +
" \"com.eg.android.AlipayGphone\"\n" +
" ],\n" +
" \"oaid\": \"b7eef53f-67f8-47tf-f7fa-ffe2fef35972\",\n" +
" \"idfa_md5\": \"\",\n" +
" \"android_id\": \"\"\n" +
" },\n" +
" \"app\": {\n" +
" \"package_name\": \"com.saveworry.wifi\",\n" +
" \"app_name\": \"wifishengxin\",\n" +
" \"version\": \"3.4.19\"\n" +
" }\n" +
"}";
try {
JsonFormat.merge(jsonFormat, request);
Zy_Proto.Request rtbRequest = request.build();
rtbRequest.writeTo(System.out);
rtbRequest.writeTo(new FileOutputStream("./zyRequest.txt"));
} catch (Exception e) {
e.printStackTrace();
}
}
}
package main

import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"errors"
"strings"
)

func main() {
ADX_OUT_ZHANGYU_AES_KEY := "19be45687c64a0cd"
auctionPrice := "JQFrGfwBmkgdu389VD84Vw=="
priceEncrypt := ECBPk5DecryptPrice(strings.Replace(auctionPrice, " ", "+", -1), ADX_OUT_ZHANGYU_AES_KEY)
println(priceEncrypt)
_ = priceEncrypt
}

func ECBPk5DecryptPrice(s string, token string) string {
defer func() {
r := recover()
if r != nil {
}
}()

by := []byte(token)
res, _ := base64.StdEncoding.DecodeString(s)
dst, _ := AesECBDecrypt(res, by, 1)
return string(dst)
}

func AesECBDecrypt(ciphertext, key []byte, padding int) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}

if len(ciphertext)%aes.BlockSize != 0 {
return nil, errors.New("crypto/cipher: input not full blocks")
}

mode := NewECBDecrypter(block)
plaintext := make([]byte, len(ciphertext))
mode.CryptBlocks(plaintext, ciphertext)

if padding == 1 {
plaintext = PKCS5Unpadding(plaintext)
}

return plaintext, nil
}
func PKCS5Unpadding(src []byte) []byte {
length := len(src)
if length == 0 {
return src
}
unpadding := int(src[length-1])
if unpadding > length {
return src
}
return src[:(length - unpadding)]
}

type ecb struct {
b cipher.Block
blockSize int
}

func newECB(b cipher.Block) *ecb {
return &ecb{
b: b,
blockSize: b.BlockSize(),
}
}

type ecbDecrypter ecb

func NewECBDecrypter(b cipher.Block) cipher.BlockMode {
return (*ecbDecrypter)(newECB(b))
}

func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
blk := (*ecb)(x)
size := blk.blockSize
if len(src)%size != 0 {
panic("crypto/cipher: input not full blocks")
}
for len(src) > 0 {
blk.b.Decrypt(dst[:size], src[:size])
src = src[size:]
dst = dst[size:]
}
}

func (x *ecbDecrypter) BlockSize() int {
return (*ecb)(x).blockSize
}