PartnerShare
品牌主
营销方式
联盟增长找外部推广者来卖你的产品 推荐营销(老带新计划)让老用户带来新用户
使用案例
AI 工具站教程测评带来订阅转化 IP 代理服务站追踪首单、续费与佣金 电商独立站用分销和内容测评提升转化 指纹浏览器触达跨境和多账号运营人群
推广者 推广市场
导航站
跨境电商导航 AIGC 导航 全球 IP 代理导航 精选产品
价格
资源
博客增长方法、渠道拆解与产品更新 帮助中心接入文档、账户设置与常见问题 最新资讯出海营销动态与行业热点
品牌主
营销方式 联盟增长 推荐营销(老带新计划) 使用案例 AI 工具站 IP 代理服务站 电商独立站 指纹浏览器
推广者 推广市场
导航站
跨境电商导航 AIGC 导航 全球 IP 代理导航 精选产品
价格
资源
博客 帮助中心 最新资讯

选择入口

请选择适合您的身份入口。

管理产品和联盟计划 品牌主 创建产品、设置佣金规则并管理推广转化。 创建品牌主账号→ 发现好产品赚取佣金 推广者 发现高佣产品,一键获取专属推广链接。 免费入驻推广市场→ 发布产品资讯获取曝光 内容发布方 提交产品并发布资讯,获取中文内容曝光。 进入内容发布平台→

预约 1v1 演示

产品顾问将在 1 个工作日内与你约定 30 分钟在线演示,带你搭好第一个推广计划。

提交后我们会尽快与你联系。

想先自己体验?免费注册 →

提交即表示你同意 PartnerShare 为安排产品演示而联系你。

微信扫码联系

使用微信扫描二维码添加企业微信,产品顾问会尽快与你联系。

PartnerShare 企业微信二维码 PartnerShare Telegram 二维码 保存图片到本地 CHAT ON TELEGRAM
✓

申请已提交

我们会尽快联系你,安排演示和接入建议。你也可以先注册账号体验产品。

跳至内容
快速入门 - PartnerShare

快速入门

5
  • 什么是推荐营销/老带新计划
  • 什么是联盟营销
  • 如何创建推荐计划
  • 如何创建联盟营销活动
  • 如何提升推广效果
合作伙伴管理 - PartnerShare

推广运营

5
  • 活动管理
  • 产品管理
  • 推广者管理
  • 合作伙伴支持的提现方式
  • 查询合作伙伴提现状态
支付与交易 - ParterShare

支付与交易

2
  • 佣金结算
  • 提现托管功能
合作伙伴管理 - PartnerShare

账户管理

2
  • 团队管理功能
  • 企业认证提示
技术集成 - PartnerShare

技术集成

8
  • API 鉴权与签名机制
  • 推广转化事件回传
  • 推广点击跟踪 SDK 接入
  • 转化退款
  • 转化作废
  • 将 PartnerShare 内嵌到产品中
  • 推广者资源接口
  • PartnerShare 产品授权推广登录接入指南
常见问题 - PartnerShare

常见问题

2
  • 旧版帮助中心入口
  • 提现相关

更新日志

2
  • 更新日志 – 2026.05.15
  • 更新日志-2026.03.05
View Categories
  • 帮助中心
  • 技术集成
  • API 鉴权与签名机制

API 鉴权与签名机制

PartnerShare 开放接口(/api/open/v1/*)采用 API Key + API Secret 签名鉴权。

每次请求需携带 API Key、秒级时间戳和签名。服务端校验通过后处理请求。

签名算法分为 v1、v2 两个版本,由 API Key 决定,与调用接口无关。

  • v2:当前版本。v2 发布后创建的 API Key 默认使用 v2。
  • v1:历史版本。仅适用于 v2 发布前创建的 API Key。

接入前,请在品牌主后台「产品管理 → 基础设置 → 开发者集成」查看 API Key 的签名版本,并使用对应算法生成签名完成集成。

1. 鉴权概览 #

项目说明
请求域名https://api-service.partnershare.net
鉴权方式请求头 X-Api-Key + X-Api-Timestamp + X-Api-Sign。API Secret 只用于本地计算签名,不随请求发送
时间窗X-Api-Timestamp 与服务端时间相差不超过 300 秒,超出则拒绝请求
签名版本v2(当前版本):HMAC-SHA256,签名覆盖请求方法、路径、query、时间戳和请求体。v1(旧版本):仅请求参数字段名参与 SHA256 计算,仍可使用
版本判定由 API Key 决定。每组密钥的版本在「产品管理 → 基础设置 → 开发者集成」中显示;新创建的密钥均为 v2,v2 发布前创建的密钥为 v1
接口支持范围部分接口仅接受 v2 密钥,以各接口文档中的「支持的 API Key 版本」为准。v1 密钥调用这类接口返回 This endpoint requires signature version 2
IP 白名单密钥配置了白名单时,只放行名单内的来源 IP,支持单个 IP 和 CIDR;未配置则不限制
接口权限密钥配置了权限列表时,调用接口需包含该接口要求的权限(如 conversion:adjust、promoter:read);未配置则不限制
响应格式业务失败和鉴权失败均返回 HTTP 200,以响应体 code 判断,0 为成功

2. 获取 API Key 和 API Secret #

在品牌主后台「产品管理 → 基础设置 → 开发者集成」中创建和管理密钥。API Key 以 pk_ 开头,API Secret 以 sk_ 开头,每组密钥的签名版本在列表的「签名版本」列显示。

开发者集成页面中的 API Keys 列表与签名版本
开发者集成页面的密钥列表,「签名版本」列标明每组密钥使用 v1 还是 v2
  • Secret 只在创建成功时明文返回一次,之后列表和详情只显示掩码。丢失后无法找回,需新建一组密钥。
  • 新创建的密钥签名版本为 v2。调用仅接受 v2 的接口时,需使用 v2 密钥。
  • 删除密钥后立即失效,后续请求返回 The API key was not found。
  • Secret 只保存在服务端,不写入浏览器、移动端包体、公开仓库或共享的调试环境。
安全建议:将 v1 密钥轮换为 v2

v2 是当前的签名版本,对请求内容提供更完整的校验,新接口仅支持 v2。建议将仍在使用 v1 的密钥全部轮换为 v2。

轮换步骤:在「开发者集成」新建一组密钥(默认 v2),服务端切换到 v2 算法并验证调用正常后,删除原有的 v1 密钥。轮换期间新旧密钥可并存,删除后旧密钥立即失效。

3. 请求头 #

Header必填说明
X-Api-Key是产品的 API Key
X-Api-Timestamp是秒级 Unix 时间戳。v2 密钥缺失时拒绝请求;v1 密钥缺失时服务端以当前时间参与校验,签名将无法通过
X-Api-Sign是按密钥版本计算的签名,小写十六进制
Content-Type是POST 请求使用 application/json

4. 签名 v2 #

4.1 待签名字符串 #

将以下 6 行按顺序以 \n(LF)拼接,末尾不含换行:

PS-HMAC-SHA256
{METHOD}
{PATH}
{QUERY}
{TIMESTAMP}
{BODY_SHA256}
行取值说明
1PS-HMAC-SHA256固定字符串
2HTTP 方法大写,如 GET、POST
3请求路径URL 中域名之后、? 之前的部分,如 /api/open/v1/track/refund。路径含编码字符时按实际发送的编码形式
4原始 query 字符串URL 中 ? 之后的部分,不含 ?,与实际发送的参数顺序和编码逐字一致。没有 query 时为空行
5时间戳与 X-Api-Timestamp 相同
6请求体 SHA256对实际发送的原始请求体字节计算 SHA256,小写十六进制。GET 或空请求体时为 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

4.2 计算签名 #

signature = hex( HMAC-SHA256( key = api_secret, message = 待签名字符串 ) )

结果写入 X-Api-Sign。请求头不参与签名。

4.3 示例推导 #

以下两个示例均使用 api_secret = sk_your_api_secret、timestamp = 1776677721,可用于校验本地实现。

示例一:POST 请求,带 JSON 请求体

POST /api/open/v1/track/refund HTTP/1.1
Host: api-service.partnershare.net
Content-Type: application/json
X-Api-Key: pk_xxxxxxxxxxxxxxxxxxxxx
X-Api-Timestamp: 1776677721
X-Api-Sign: 66e6795c27b7b1cfc60ac1b2474d83524bc1db23074501afa39ce228a92446be

请求体原文(参与哈希的就是这段字节,发送时保持完全一致):

{"transaction_id":"order_202604220001","reason":"customer refund"}

请求体 SHA256:771425a965e46ff8d3e685b0deba9d6642965d3c93db4fe95b02d6885c22b9b6

待签名字符串(无 query,第 4 行为空行):

PS-HMAC-SHA256
POST
/api/open/v1/track/refund

1776677721
771425a965e46ff8d3e685b0deba9d6642965d3c93db4fe95b02d6885c22b9b6

签名:66e6795c27b7b1cfc60ac1b2474d83524bc1db23074501afa39ce228a92446be

示例二:GET 请求,带 query,无请求体

GET /api/open/v1/promoters/user_10001/statistics?start_date=2026-04-01&end_date=2026-04-30 HTTP/1.1
Host: api-service.partnershare.net
X-Api-Key: pk_xxxxxxxxxxxxxxxxxxxxx
X-Api-Timestamp: 1776677721
X-Api-Sign: fd1b625fc2c1580f21b87ecf08e7ddb21824730d043b746fd843efbc8f23d847

请求体为空,SHA256 为空字符串的哈希:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

待签名字符串:

PS-HMAC-SHA256
GET
/api/open/v1/promoters/user_10001/statistics
start_date=2026-04-01&end_date=2026-04-30
1776677721
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

签名:fd1b625fc2c1580f21b87ecf08e7ddb21824730d043b746fd843efbc8f23d847

4.4 代码示例 #

各示例中 body 为最终发送的原始请求体字符串,GET 传空字符串;query 为 URL 中 ? 之后的原始字符串,无 query 传空字符串。

<?php
function signV2(string $method, string $path, string $query, int $timestamp, string $body, string $apiSecret): string
{
    $canonical = implode("\n", [
        'PS-HMAC-SHA256',
        strtoupper($method),
        $path,
        $query,
        (string) $timestamp,
        hash('sha256', $body),
    ]);

    return hash_hmac('sha256', $canonical, $apiSecret);
}

$timestamp = time();
$body      = json_encode([
    'transaction_id' => 'order_202604220001',
    'reason'         => 'customer refund',
]);
$sign      = signV2('POST', '/api/open/v1/track/refund', '', $timestamp, $body, $apiSecret);
// 发送时使用同一个 $body 字符串
const crypto = require('crypto');

function signV2(method, path, query, timestamp, body, apiSecret) {
  const bodyHash = crypto.createHash('sha256').update(body, 'utf8').digest('hex');
  const canonical = [
    'PS-HMAC-SHA256',
    method.toUpperCase(),
    path,
    query,
    String(timestamp),
    bodyHash,
  ].join('\n');
  return crypto.createHmac('sha256', apiSecret).update(canonical, 'utf8').digest('hex');
}

const timestamp = Math.floor(Date.now() / 1000);
const body = JSON.stringify({ transaction_id: 'order_202604220001', reason: 'customer refund' });
const sign = signV2('POST', '/api/open/v1/track/refund', '', timestamp, body, apiSecret);
// 发送时使用同一个 body 字符串
import hashlib
import hmac
import json
import time

def sign_v2(method: str, path: str, query: str, timestamp: int, body: str, api_secret: str) -> str:
    body_hash = hashlib.sha256(body.encode("utf-8")).hexdigest()
    canonical = "\n".join([
        "PS-HMAC-SHA256", method.upper(), path, query, str(timestamp), body_hash,
    ])
    return hmac.new(api_secret.encode("utf-8"), canonical.encode("utf-8"), hashlib.sha256).hexdigest()

timestamp = int(time.time())
body = json.dumps(
    {"transaction_id": "order_202604220001", "reason": "customer refund"},
    separators=(",", ":"),
)
sign = sign_v2("POST", "/api/open/v1/track/refund", "", timestamp, body, api_secret)
# 发送时使用同一个 body 字符串
package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"strconv"
	"strings"
)

func SignV2(method, path, query string, timestamp int64, body []byte, apiSecret string) string {
	bodyHash := sha256.Sum256(body)
	canonical := strings.Join([]string{
		"PS-HMAC-SHA256",
		strings.ToUpper(method),
		path,
		query,
		strconv.FormatInt(timestamp, 10),
		hex.EncodeToString(bodyHash[:]),
	}, "\n")

	mac := hmac.New(sha256.New, []byte(apiSecret))
	mac.Write([]byte(canonical))
	return hex.EncodeToString(mac.Sum(nil))
}

4.5 注意事项 #

  • 先序列化请求体,再使用同一字符串计算哈希并发送。若哈希后重新序列化,键顺序、空白或 Unicode 转义的差异会导致签名不匹配。
  • 网关、SDK 或代理层修改请求体、调整 query 参数顺序或编码,均会导致签名不匹配。排查时以实际发出的请求行和请求体为准。
  • query 参数值需要 URL 编码时,签名使用编码后的字符串。
  • 时间戳取服务器当前时间,并保持时钟与标准时间同步。

5. 签名 v1(旧版) #

v1 密钥仍可使用,算法保持不变:仅请求参数的字段名参与计算,字段值和请求头均不参与。新接口不再支持 v1,建议按第 2 节的安全建议轮换为 v2。

5.1 算法 #

  1. 收集 URL query、表单 body、JSON body 的顶层字段名,嵌套字段不参与。
  2. 字段名统一转小写。
  3. 按自然顺序排序(PHP SORT_NATURAL)。
  4. 用 & 连接字段名。
  5. 追加时间戳和 API Secret,计算 SHA256,小写十六进制。
signature = sha256( sorted_lowercase_keys_joined_by_& + timestamp + api_secret )

5.2 示例推导 #

请求体:

{"event_name":"signup","invited_user_id":"user_10001","invite_code":"abc123"}

字段名排序拼接:event_name&invite_code&invited_user_id

待签名字符串(timestamp = 1776677721,api_secret = sk_your_api_secret):

event_name&invite_code&invited_user_id1776677721sk_your_api_secret

签名:a01880c87f291e09edf069d0fae34d2243879a4612f2d5eed7147b73ca5d61f7

5.3 代码示例 #

<?php
function signV1(array $params, int $timestamp, string $apiSecret): string
{
    $keys = array_map('strtolower', array_keys($params));
    sort($keys, SORT_NATURAL);

    return hash('sha256', implode('&', $keys) . $timestamp . $apiSecret);
}
const crypto = require('crypto');

function signV1(params, timestamp, apiSecret) {
  const keys = Object.keys(params)
    .map((key) => key.toLowerCase())
    .sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
  return crypto.createHash('sha256').update(keys.join('&') + timestamp + apiSecret).digest('hex');
}
import hashlib

def sign_v1(params: dict, timestamp: int, api_secret: str) -> str:
    keys = sorted(key.lower() for key in params.keys())
    return hashlib.sha256(("&".join(keys) + str(timestamp) + api_secret).encode("utf-8")).hexdigest()
func SignV1(params map[string]interface{}, timestamp int64, apiSecret string) string {
	keys := make([]string, 0, len(params))
	for key := range params {
		keys = append(keys, strings.ToLower(key))
	}
	sort.Strings(keys)
	sum := sha256.Sum256([]byte(strings.Join(keys, "&") + strconv.FormatInt(timestamp, 10) + apiSecret))
	return hex.EncodeToString(sum[:])
}

6. 错误响应 #

鉴权失败返回 HTTP 200,code 为 1000004,message 为英文,data 为 null。

{
  "code": 1000004,
  "message": "Signature verification failed",
  "data": null
}
message原因处理
The API key and signature are required缺少 X-Api-Key 或 X-Api-Sign检查请求头是否被网关或代理移除
The API key was not foundAPI Key 不存在或已删除核对 API Key,必要时在后台重新创建
This endpoint requires signature version 2v1 密钥调用了仅接受 v2 的接口使用 v2 版本的密钥
The request timestamp is requiredv2 密钥请求缺少 X-Api-Timestamp补充 X-Api-Timestamp 请求头
The request timestamp is invalid or expired时间戳与服务端相差超过 300 秒使用秒级时间戳,校准服务器时间
Signature verification failed签名不匹配确认密钥版本与算法一致;v2 核对方法、路径、query、请求体原文;v1 核对字段名与排序
The API key is disabled密钥已禁用在后台启用或更换密钥
The API key has expired密钥已过期创建新密钥
The client IP address is not allowlisted来源 IP 不在密钥白名单内在后台更新白名单,确认服务器出口 IP
Missing required permission: {permission}密钥权限列表未包含该接口要求的权限为密钥补充权限或更换密钥

7. 排查清单 #

  • 在「开发者集成」页面确认密钥版本,v1 与 v2 算法不能混用。
  • 签名密钥为 API Secret,而非 API Key。
  • v2:输出待签名字符串逐行比对,重点检查 query 与请求体原文。
  • v1:输出参与签名的字段名列表,确认与实际发送的顶层字段一致。
  • 时间戳为秒级且在 300 秒窗口内。
  • 生产环境与测试环境使用不同的密钥;怀疑 Secret 泄露时立即删除该密钥并重新创建。
更新 07/09/2026

分享这篇文章 :
  • Facebook
  • X
  • LinkedIn
  • Pinterest
将 PartnerShare 内嵌到产品中
大纲
  • 1. 鉴权概览
  • 2. 获取 API Key 和 API Secret
  • 3. 请求头
  • 4. 签名 v2
    • 4.1 待签名字符串
    • 4.2 计算签名
    • 4.3 示例推导
    • 4.4 代码示例
    • 4.5 注意事项
  • 5. 签名 v1(旧版)
    • 5.1 算法
    • 5.2 示例推导
    • 5.3 代码示例
  • 6. 错误响应
  • 7. 排查清单
PartnerShare

帮出海 SaaS 找到推广者、跑起联盟、放大用户推荐。先免费接入,跑出数据再升级。 Find promoters, run affiliate, and turn user referrals into a tracked growth channel. Start free, upgrade after data.

产品 Product

  • 联盟增长Affiliate growth
  • 邀返系统Referral program
  • 推广市场Marketplace
  • 价格Pricing

资源 Resources

  • 博客Blog
  • 帮助中心Help center
  • 最新资讯Latest news

导航站 Directory

  • 跨境电商导航Cross-border Ecommerce Directory
  • AIGC 导航AIGC Directory
  • 全球 IP 代理导航Global IP Proxy Directory
  • 精选产品Featured Products

联系方式 Contact

联系Contact business@partnershare.net
PartnerShare 公众号二维码
in XHS

版权所有© 广州标品科技创新有限公司, SAASBASE PTE. LTD. 丨 粤ICP备2022116046号 © Guangzhou Biaopin Technology Innovation Co., Ltd., SAASBASE PTE. LTD. · ICP 2022116046

服务协议Terms of Service 隐私政策Privacy