来自 Shopee 官方资料快照 ·
- 当前资料结构化阅读页
- 固定快照已留存,可追溯
- 官方原文可核对
资料正文
§1 授权与鉴权
授权是使用 Open API 的必要流程,卖家需将操作店铺的权限授予开发者。只有在获得卖家授权后,您的 App 才能调用除公共接口之外的接口。
Open API 会根据您传入的公共参数进行鉴权。若鉴权不通过,API 调用将失败并返回相应报错信息。
§2 授权流程
授权流程包含 3个核心步骤:生成授权链接、获取店铺授权、获取及刷新访问令牌(access_token)。以下将详细说明授权前准备、流程细节及如何使用返回信息完成平台认证。
§3 生成授权链接
生成授权链接
为提升对接效率,平台提供了新的授权链接生成方式。授权链接由固定授权 URL 和授权参数拼接而成,所有类型的应用均可按以下规范生成授权链接。
注:对于卖家自研(Seller In House System) App,直接登陆开放平台> 进入App list>点击 “Authorize”>填写 redirect URL 生成授权链接
对于所有类型App,要实现v2店铺授权,开发者需要根据下列规范创建一个授权链接,授权链接是由固定授权url和其他所需参数拼接而成。
固定授权URL:
其他所需参数:
| 参数名称 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
| partner_id | int | 是 | 应用的合作方 ID,由 Shopee 开放平台分配。 |
| auth_type | string | 是 | 需授权的角色类型,枚举值如下:- seller:授权shop或merchant时选择;- supplier:授权供应商时选择(适用于 SCS 用户);- user:授权用户时选择(适用于直播类型应用,详见https://open.shopee.com/announcements/1190 )。 |
| redirect_uri | string | 是 | 卖家完成授权后接收授权码(code)的 URL。生产环境:若当前应用的生产环境回调 URL 域名为空,则不校验 redirect_uri 域名;若不为空,则需与应用的生产环境回调 URL 域名一致;沙箱测试环境:若当前应用的测试环境回调 URL 域名为空,则不校验 redirect_uri 域名;若不为空,则需与应用的测试环境回调 URL 域名一致。 |
| response_type | string | 是 | 授权类型,固定值为 "code"。 |
| state | string | 否 | 用于防范跨站请求伪造攻击的随机字符串(不可猜测),授权完成后原值将回调至 redirect_uri。 |
§4 域名校验要求
域名校验要求
为保障卖家数据安全,平台对授权链接中的回调地址(redirect URL)新增域名校验。所有开发者需在控制台(Console)为每个应用申报测试环境回调 URL 域名(Test Redirect URL Domain)和生产环境回调 URL 域名(Live Redirect URL Domain)。
上述参数中的redirect_uri为开发者在app信息中填写的回调地址,查看方式如下:
域名校验注意事项
- 对于已创建但未申报回调 URL 域名的应用,开发者需尽快登录控制台,进入应用编辑页完成申报。申报完成前,平台暂不执行域名校验,不影响现有授权流程;
- 若生成授权链接时传入的 redirect_uri(或旧链接中的 redirect)对应的域名与控制台申报域名不一致,将返回错误:"The domain of redirect_uri is not consistent with the Redirect URL Domain declared in console"(回调地址域名与控制台申报的回调 URL 域名不一致)。
§5 授权链接示例
授权链接示例
以下是生产环境和沙箱测试环境中的授权链接示例,供您参考。
生产环境:
生产环境(中国大陆)
生产环境(巴西)
沙箱测试环境::
沙箱测试环境(中国大陆)
沙箱测试环境(巴西)
§6 卖家登陆授权
卖家登陆授权
将授权链接分享给卖家后,卖家需登录账号完成授权流程。
账号类型:
- 店铺账号授权单个店铺
- 使用主账号授权多个商家 / 店铺 (子账号无法登录授权页面).
§7 Shop account授权
Shop account授权
1、卖家输入账号、密码,点击 “Log In”;
2、卖家输入手机接收的验证码,点击 “Verify”;
3、登录后,卖家在授权页面点击 “Confirm Authorization”;
4、系统将弹出授权期限选择器,卖家可选择预设期限(7 天、30 天、90 天、180 天、365 天),或选择 “自定义到期时间” 设置 365 天内的任意日期;
5、授权完成后,前端页面将跳转至授权链接中指定的 redirect_uri,并附带授权码(code)和店铺 ID(shop_id):https://open.shopee.com/?code=xxxxxxxxxx&shop_id=xxxxxx
§8 Main account授权
Main account授权
1、登录页面中,点击 “Switch to Sub Account” 以主账号登录;
2、输入主账号账号、密码,点击 “Log In”;
3、展开商家店铺列表,选择需授权的店铺。跨境卖家如需调用Merchant API,需提醒卖家勾选 “授权商家”(Auth Merchant)复选框;
4、若未勾选授权框,将弹出提醒窗口;
5、点击确认授权,完成操作。
6、授权完成后,前端页面将跳转至授权链接中指定的 redirect_uri,并附带授权码(code)和主账号 ID(main_account_id):https://open.shopee.com/?code=xxxxxx&main_account_id=xxxxxx
§9 获取及使用code
获取及使用code
卖家完成授权后,前端页面将跳转至授权链接中指定的 redirect_uri,并附带授权码(code)和shop_id/main_account_id,以main_account_id为例:https://open.shopee.com/?code=xxxxxx&main_account_id=xxxxxx
您可通过该 授权码(code) 获取首次访问令牌(access_token)。
§10 跳转 URL 中的返回参数
跳转 URL 中的返回参数
| 参数名称 | 类型 | 描述 |
|---|---|---|
| code | string | 调用成功时返回,用于获取access_token和refresh_token。仅一次有效,10分钟后过期。 |
| shop_id | int | 本次授权给开发者的店铺shop_id。使用店铺账号授权后返回。 |
| main_account_id | int | 本次授权给开发者的主账号main_account_id。使用主账号授权后返回。 |
注:若生成授权链接时传入的 redirect_uri(或旧链接中的 redirect)对应的域名与控制台申报域名不一致,将返回错误:"The domain of redirect_uri is not consistent with the Redirect URL Domain declared in console"(回调地址域名与控制台申报的回调 URL 域名不一致)。
§11 获取与刷新access_token
获取与刷新access_token
access_token 是调用非公共 API 必需的动态令牌,有效期为 4 小时,有效期内可多次使用。需在过期前通过 refresh_token 调用刷新访问令牌 API(RefreshAccessToken)获取新的 access_token,refresh_token 有效期为 30 天。
⚠️ 注意事项
- 每个 shop_id /merchant_id/user_id/supplier_id 对应的 access_token 和 refresh_token 需单独存储;
- 新 access_token 生成后,旧 access_token 仍可有效 5 分钟;
- 重新授权将触发 refresh_token 和 access_token 刷新;
- 需在授权有效期内调用 RefreshAccessToken API。
- 如果丢失了最新可用的refresh_token和access_token,请查看此FAQ
§12 GetAccesstoken
GetAccesstoken
授权成功后,使用跳转 URL 中的 code 及 shop_id(或 main_account_id)调用该 API,获取 shop_id、merchant_id、access_token 和 refresh_token。
路径:https://partner.shopeemobile.com/api/v2/auth/token/get
https://openplatform.sandbox.test-stable.shopee.sg/api/v2/auth/token/get (沙箱测试环境)
请求方式: Post
公共参数:
| 参数名称 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
| sign | string | 是 | 根据sign base string以partner key作为加密key通过HMAC-SHA256哈希得出的签名。 |
| partner_id | int | 是 | 从APP中获取到的partner_id,此partner_id放入query。 |
| timestamp | int | 是 | 时间戳,有效期为5分钟。 |
业务参数:
| 参数名称 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
| code | string | 是 | 授权后位于redirect URL中的code。仅一次性有效,10分钟后过期。 |
| partner_id | int | 是 | 从APP中获取到的partner_id,此partner_id放入body。 |
| shop_id | int | 条件必填 | 授权给开发者的主账号shop_id,只能选shop_id或main_account_id中的一个作为入参。 |
| main_account_id | int | 条件必填 | 授权给开发者的主账号main_account_id,只能选shop_id或main_account_id中的一个作为入参。 |
返回参数:
| 参数名称 | 类型 | 描述 |
|---|---|---|
| request_id | string | 必返回,每个接口请求的ID,用于定位问题。 |
| error | string | 必返回,错误码,当调用成功时返回为空。 |
| refresh_token | string | 调用成功时返回,使用refresh_token去获取新的access_token。针对每个shop_id和merchant_id分别有效,有效期为30天。 |
| access_token | string | 调用成功时返回,动态令牌,可多次使用,4小时后过期。 |
| expire_in | int | 调用成功时返回,access_token有效时间,单位:秒。 |
| message | string | 必返回,详细报错信息。 |
| merchant_id_list | int[ ] | 当入参中有main_account_id时返回,包括main account下本次授权的所有merchant_id。 |
| shop_id_list | int[ ] | 当入参中有main_account_id时返回,包括main account下本次授权的所有shop_id。 |
| supplier_id_list | int[] | auth_type=supplier时返回 |
| user_id_list | int[] | auth_type=user时返回 |
计算sign
Sign是每次调用时用来鉴权的参数,此部分将会解释如何通过HMAC-SHA256生成作为公共参数用于鉴权的签名。
创建sign base string:
目前共有三类接口需要用不同的参数创建sign base string(与其公共参数一致):
按照先后次序, 将api path(不带host) 和下列公共参数拼接为单一字符串,即sign base string:
Shop APIs: partner_id, api path, timestamp, access_token, shop_id
Merchant APIs: partner_id, api path, timestamp, access_token, merchant_id
Public APIs: partner_id, api path, timestamp
鉴权签名计算:
使用HMAC-SHA256对sign base string进行哈希,partner key作为加密key,得出16进制全小写的哈希值即为鉴权签名。
Python Code Demo:
import hmac
import json
import time
import requests
import hashlib
def shop_auth():
timest = int(time.time())
host = "https://partner.shopeemobile.com"
path = "/api/v2/shop/auth_partner"
redirect_url = "https://www.baidu.com/"
partner_id = 80001
tmp = "test...."
partner_key = tmp.encode()
tmp_base_string = "%s%s%s" % (partner_id, path, timest)
base_string = tmp_base_string.encode()
sign = hmac.new(partner_key, base_string, hashlib.sha256).hexdigest()
##generate api
url = host + path + "?partner_id=%s×tamp=%s&sign=%s&redirect=%s" % (partner_id, timest, sign, redirect_url)
print(url)
Go Code Demo:
func auth_shop(){
timest := strconv.FormatInt(time.Now().Unix(),10)
host := "https://partner.test.shopeemobile.com"
path := "/api/v2/shop/auth_partner"
redirectUrl := "https://www.baidu.com/"
partnerId := strconv.Itoa(2006566)
partnerKey := "1391fd986fe8ec7569bebed75b0c33ee35eb5a305bed7038657a5cd5f75b1c88"
baseString := fmt.Sprintf("%s%s%s", partnerId,path,timest)
h := hmac.New(sha256.New,[]byte(partnerKey))
h.Write([]byte(baseString))
sign := hex.EncodeToString(h.Sum(nil))
url := fmt.Sprintf(host+path+"?partner_id=%s×tamp=%s&sign=%s&redirect=%s", partnerId,timest,sign, redirectUrl)
fmt.Println(url)
}
Java Code Demo:
//generate auth url
public static void shop_auth(){
long timest = System.currentTimeMillis() / 1000L;
String host = "https://partner.shopeemobile.com";
String path = "/api/v2/shop/auth_partner";
String redirect_url = "https://www.baidu.com/";
long partner_id = 123456L;
String tmp_partner_key = "...";
String tmp_base_string = String.format("%s%s%s", partner_id, path, timest);
byte[] partner_key;
byte[] base_string;
String sign = "";
try {
base_string = tmp_base_string.getBytes("UTF-8");
partner_key = tmp_partner_key.getBytes("UTF-8");
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(partner_key, "HmacSHA256");
mac.init(secret_key);
sign = String.format("%064x",new BigInteger(1,mac.doFinal(base_string)));
} catch (Exception e) {
e.printStackTrace();
}
String url = host + path + String.format("?partner_id=%s×tamp=%s&sign=%s&redirect=%s", partner_id,timest, sign, redirect_url);
System.out.println(url);
}
PHP Code Demo:
<?php
function authShop($partnerId, $partnerKey) {
global $host;
$path = "/api/v2/shop/auth_partner";
$redirectUrl = "https://www.baidu.com/";
$timest = time();
$baseString = sprintf("%s%s%s", $partnerId, $path, $timest);
$sign = hash_hmac('sha256', $baseString, $partnerKey);
$url = sprintf("%s%s?partner_id=%s×tamp=%s&sign=%s&redirect=%s", $host, $path, $partnerId, $timest, $sign, $redirectUrl);
return $url;
}
$host="https://partner.shopeemobile.com";
$partnerId = 847892;
$partnerKey = "57615053704d6470644f554a78656d50484143644964436a5568777544524579";
echo authShop($partnerId, $partnerKey);
?>
GetAccesstoken Demo
Python Code Demo:
print(shop_auth())
# first time request token
def get_token_shop_level(code, partner_id, tmp_partner_key, shop_id):
timest = int(time.time())
host = "https://partner.shopeemobile.com"
path = "/api/v2/auth/token/get"
body = {"code": code, "shop_id": shop_id, "partner_id": partner_id}
tmp_base_string = "%s%s%s" % (partner_id, path, timest)
base_string = tmp_base_string.encode()
partner_key = tmp_partner_key.encode()
sign = hmac.new(partner_key, base_string, hashlib.sha256).hexdigest()
url = host + path + "?partner_id=%s×tamp=%s&sign=%s" % (partner_id, timest, sign)
# print(url)
headers = {"Content-Type": "application/json"}
resp = requests.post(url, json=body, headers=headers)
ret = json.loads(resp.content)
access_token = ret.get("access_token")
new_refresh_token = ret.get("refresh_token")
return access_token, new_refresh_token
def get_token_account_level(code, partner_id, tmp_partner_key, main_account_id):
timest = int(time.time())
host = "https://partner.test.shopeemobile.com"
path = "/api/v2/auth/token/get"
body = {"code": code, "main_account_id": main_account_id, "partner_id": partner_id}
tmp_base_string = "%s%s%s" % (partner_id, path, timest)
base_string = tmp_base_string.encode()
partner_key = tmp_partner_key.encode()
sign = hmac.new(partner_key, base_string, hashlib.sha256).hexdigest()
url = host + path + "?partner_id=%s×tamp=%s&sign=%s" % (partner_id, timest, sign)
headers = {"Content-Type": "application/json"}
resp = requests.post(url, json=body, headers=headers)
ret = json.loads(resp.content)
access_token = ret.get("access_token")
new_refresh_token = ret.get("refresh_token")
return access_token, new_refresh_token
Java Code Demo:
import com.alibaba.fastjson.JSONObject;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.HashMap;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import com.alibaba.fastjson.JSON;
public class shop_auth {
public static void main(String[] args) throws ParseException, IOException {
shop_auth();
//get_token_shop_level(code,partner_id,partner_key,shop_id);
}
//generate auth url
public static void shop_auth(){
long timest = System.currentTimeMillis() / 1000L;
String host = "https://partner.shopeemobile.com";
String path = "/api/v2/shop/auth_partner";
String redirect_url = "https://www.baidu.com/";
long partner_id = 123456L;
String tmp_partner_key = "...";
String tmp_base_string = String.format("%s%s%s", partner_id, path, timest);
byte[] partner_key;
byte[] base_string;
String sign = "";
try {
base_string = tmp_base_string.getBytes("UTF-8");
partner_key = tmp_partner_key.getBytes("UTF-8");
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(partner_key, "HmacSHA256");
mac.init(secret_key);
sign = String.format("%064x",new BigInteger(1,mac.doFinal(base_string)));
} catch (Exception e) {
e.printStackTrace();
}
String url = host + path + String.format("?partner_id=%s×tamp=%s&sign=%s&redirect=%s", partner_id,timest, sign, redirect_url);
System.out.println(url);
}
//shop request for access token for the first time
public static String[] get_token_shop_level(String code,long partner_id,String tmp_partner_key,long shop_id) throws ParseException,IOException{
String[] res = new String[2];
long timest = System.currentTimeMillis() / 1000L;
String host = "https://partner.shopeemobile.com";
String path = "/api/v2/auth/token/get";
String tmp_base_string = String.format("%s%s%s", partner_id, path, timest);
byte[] partner_key;
byte[] base_string;
BigInteger sign = null;
String result = "";
try {
base_string = tmp_base_string.getBytes("UTF-8");
partner_key = tmp_partner_key.getBytes("UTF-8");
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(partner_key, "HmacSHA256");
mac.init(secret_key);
sign = new BigInteger(1,mac.doFinal(base_string));
} catch (Exception e) {
e.printStackTrace();
}
String tmp_url = host + path + String.format("?partner_id=%s×tamp=%s&sign=%s", partner_id,timest, String.format("%032x",sign));
URL url = new URL(tmp_url);
HttpURLConnection conn = null;
PrintWriter out = null;
BufferedReader in = null;
try {
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setConnectTimeout(30000);
conn.setReadTimeout(10000);
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
Map<String,Object> map = new HashMap<>();
map.put("code",code);
map.put("shop_id",shop_id);
map.put("partner_id",partner_id);
String json = JSON.toJSONString(map);
conn.connect();
out = new PrintWriter(conn.getOutputStream());
out.print(json);
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = "";
while((line=in.readLine())!=null){
result +=line;
}
JSONObject jsonObject = JSONObject.parseObject(result);
res[0] = (String) jsonObject.get("access_token");
res[1] = (String) jsonObject.get("refresh_token");
} catch(Exception e){
e.printStackTrace();
}finally {
try{
if(out != null){
out.close();
}
if(in != null){
in.close();
}
}catch (IOException ioe){
ioe.printStackTrace();
}
}
return res;
}
//main account request for the access token for the first time
public static String[] get_token_account_level(String code,long partner_id,String tmp_partner_key,long main_account_id) throws ParseException,IOException{
String[] res = new String[2];
long timest = System.currentTimeMillis() / 1000L;
String host = "https://partner.test.shopeemobile.com";
String path = "/api/v2/auth/token/get";
String tmp_base_string = String.format("%s%s%s", partner_id, path, timest);
byte[] partner_key;
byte[] base_string;
BigInteger sign = null;
String result = "";
try {
base_string = tmp_base_string.getBytes("UTF-8");
partner_key = tmp_partner_key.getBytes("UTF-8");
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(partner_key, "HmacSHA256");
mac.init(secret_key);
sign = new BigInteger(1,mac.doFinal(base_string));
} catch (Exception e) {
e.printStackTrace();
}
String tmp_url = host + path + String.format("?partner_id=%s×tamp=%s&sign=%s", partner_id,timest, String.format("%032x",sign));
URL url = new URL(tmp_url);
HttpURLConnection conn = null;
PrintWriter out = null;
BufferedReader in = null;
try {
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setConnectTimeout(30000);
conn.setReadTimeout(10000);
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
Map<String,Object> map = new HashMap<>();
map.put("code",code);
map.put("main_account_id",main_account_id);
map.put("partner_id",partner_id);
String json = JSON.toJSONString(map);
conn.connect();
out = new PrintWriter(conn.getOutputStream());
out.print(json);
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = "";
while((line=in.readLine())!=null){
result +=line;
}
JSONObject jsonObject = JSONObject.parseObject(result);
res[0] = (String) jsonObject.get("access_token");
res[1] = (String) jsonObject.get("refresh_token");
} catch(Exception e){
e.printStackTrace();
}finally {
try{
if(out != null){
out.close();
}
if(in != null){
in.close();
}
}catch (IOException ioe){
ioe.printStackTrace();
}
}
return res;
}
PHP Code Demo:
<?php
function getTokenShopLevel($code, $partnerId, $partnerKey, $shopId) {
global $host;
$path = "/api/v2/auth/token/get";
$timest = time();
$body = array("code" => $code, "shop_id" => $shopId, "partner_id" => $partnerId);
$baseString = sprintf("%s%s%s", $partnerId, $path, $timest);
$sign = hash_hmac('sha256', $baseString, $partnerKey);
$url = sprintf("%s%s?partner_id=%s×tamp=%s&sign=%s", $host, $path, $partnerId, $timest, $sign);
$c = curl_init($url);
curl_setopt($c, CURLOPT_POST, 1);
curl_setopt($c, CURLOPT_POSTFIELDS, json_encode($body));
curl_setopt($c, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
$resp = curl_exec($c);
echo "raw result: $resp";
$ret = json_decode($resp, true);
$accessToken = $ret["access_token"];
$newRefreshToken = $ret["refresh_token"];
echo "\naccess_token: $accessToken, refresh_token: $newRefreshToken raw: $ret"."\n";
return $ret;
}
function getTokenAccountLevel($code, $partnerId, $partnerKey, $mainAccountId) {
global $host;
$path = "/api/v2/auth/token/get";
$timest = time();
$body = array("code" => $code, "main_account_id" => $mainAccountId, "partner_id" => $partnerId);
$baseString = sprintf("%s%s%s", $partnerId, $path, $timest);
$sign = hash_hmac('sha256', $baseString, $partnerKey);
$url = sprintf("%s%s?partner_id=%s×tamp=%s&sign=%s", $host, $path, $partnerId, $timest, $sign);
$c = curl_init($url);
curl_setopt($c, CURLOPT_POST, 1);
curl_setopt($c, CURLOPT_POSTFIELDS, json_encode($body));
curl_setopt($c, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($c);
echo "\nraw result ".$result."\n";
$ret = json_decode($result, true);
$accessToken = $ret["access_token"];
$newRefreshToken = $ret["refresh_token"];
echo "\naccess_token: ".$accessToken.", refresh_token: ".$newRefreshToken."\n";
return $ret;
}
$host="https://partner.shopeemobile.com";
$partnerId = 847892;
$partnerKey = "57615053704d6470644f554a78656d50484143644964436a5568777544524579";
$code="494d7a4a4f5a66524556776f66425453";
// $shopId=200520705;
// getTokenShopLevel($code, $partnerId, $partnerKey, $shopId);
$accountId=19479;
getTokenAccountLevel($code, $partnerId, $partnerKey, $accountId)
?>
§13 RefreshAccessToken
RefreshAccessToken
接口描述: access_token过期前,使用refresh_token调用此接口刷新access_token。调用后会同时返回一个新refresh_token和access_token,需要在下一次调用此接口时使用新refresh_token。
路径: https://partner.shopeemobile.com/api/v2/auth/access_token/get(生产环境)
https:// https://openplatform.sandbox.test-stable.shopee.sg/api/v2/auth/access_token/get(沙箱测试环境)
请求方式: Post
注意⚠️: 对于同一个main_account_id,首次调用GetAccessToken时获取到的首个access_token和refresh_token相同。但是,通过首次调用RefreshAccessToken接口分别对每个shop_id和merchant_id调用刷新后,各个shop_id和merchant_id将会生成一套独立的新的access_token和refresh_token。
例如,在GetAccessToken获得首个access_token和refresh_token给7个shop_ids和3个merchant_ids。首个access_token过期后,使用首个refresh_token调用RefreshAccessToken,获得10组独立的access_token和refresh_token给每个shop_id和merchant_id。 此后,shop_id和merchant_id不再共享任何access_token或refresh_token。
公共参数:
与 GetAccessToken API 的公共参数一致。
| 参数名称 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
| sign | string | 是 | 根据sign base string以partner key作为加密key通过HMAC-SHA256哈希得出的签名。 |
| partner_id | int | 是 | 从APP中获取到的partner_id,此partner_id放入query。 |
| timestamp | int | 是 | 时间戳,有效期为5分钟。 |
业务参数:
| 参数名称 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
| refresh_token | string | 是 | 使用refresh_token去获取新的access_token。针对每个shop_id和merchant_id分别有效,有效期为30天。 |
| partner_id | int | 是 | 从APP中获取到的partner_id,此partner_id放入body。 |
| shop_id | int | 条件必填 | 授权给开发者的主账号shop_id,只能选shop_id和merchant_id必须分开refresh,只能选其中一个作为入参。 |
| merchant_id | int | 条件必填 | 授权给开发者的主账号merchant_id,每个merchant的身份标识。shop_id和merchant_id必须分开refresh,只能选其中一个作为入参。 |
返回参数:
| 参数名称 | 类型 | 描述 |
|---|---|---|
| request_id | string | 必返回,每个接口请求的ID,用于定位问题。 |
| error | string | 必返回,错误码,当调用成功时返回为空。 |
| refresh_token | string | 调用成功时返回,新的refresh_token,使用refresh_token去获取新的access_token。针对每个shop_id和merchant_id分别有效,有效期为30天。 |
| access_token | string | 调用成功时返回,新的access_token,动态令牌,可多次使用,4小时后过期。 |
| expire_in | int | 调用成功时返回,access_token有效时间,单位:秒。 |
| message | string | 必返回,详细报错信息。 |
| merchant_id | int | 调用成功时返回,本次刷新的merchant_id,每个merchant的身份标识。 |
| shop_id | int | 调用成功时返回,本次刷新的shop_id。 |
| partner_id | int | 调用成功时返回,您本次刷新使用的partner_id |
| supplier_id_list | int[] | auth_type=supplier时返回 |
| user_id_list | int[] | auth_type=user时返回 |
RefreshAccessToken Demo
Python Code Demo:
# refresh token
def get_access_token_shop_level(shop_id, partner_id, tmp_partner_key, refresh_token):
timest = int(time.time())
host = "https://partner.test.shopeemobile.com"
path = "/api/v2/auth/access_token/get"
body = {"shop_id": shop_id, "refresh_token": refresh_token,"partner_id":partner_id}
tmp_base_string = "%s%s%s" % (partner_id, path, timest)
base_string = tmp_base_string.encode()
partner_key = tmp_partner_key.encode()
sign = hmac.new(partner_key, base_string, hashlib.sha256).hexdigest()
url = host + path + "?partner_id=%s×tamp=%s&sign=%s" % (partner_id, timest, sign)
# print(url)
headers = {"Content-Type": "application/json"}
resp = requests.post(url, json=body, headers=headers)
ret = json.loads(resp.content)
access_token = ret.get("access_token")
new_refresh_token = ret.get("refresh_token")
return access_token, new_refresh_token
def get_access_token_merchant_level(merchant_id, partner_id, tmp_partner_key, refresh_token):
timest = int(time.time())
host = "https://partner.test.shopeemobile.com"
path = "/api/v2/auth/access_token/get"
body = {"merchant_id": merchant_id, "refresh_token": refresh_token}
tmp_base_string = "%s%s%s" % (partner_id, path, timest)
base_string = tmp_base_string.encode()
partner_key = tmp_partner_key.encode()
sign = hmac.new(partner_key, base_string, hashlib.sha256).hexdigest()
url = host + path + "?partner_id=%s×tamp=%s&sign=%s" % (partner_id, timest, sign)
headers = {"Content-Type": "application/json"}
resp = requests.post(url, json=body, headers=headers)
ret = json.loads(resp.content)
access_token = ret.get("access_token")
new_refresh_token = ret.get("refresh_token")
return access_token, new_refresh_token
partner_id = 2006566
partner_key = "1a78dde5d6c3342f56ac939cbdd81607654c0e87725e118736ba5e3ae31c579c"
shop_id = 602226924
main_account_id = 31219
merchant_id = 45719
code = "c01204cada7b4cd0e4688154f5a256ca"
print(shop_auth())
# access_token,refresh_token = get_token_shop_level(code,partner_id,partner_key,602226924)
# print(access_token)
# print(refresh_token)
# print(get_access_token_shop_level(shop_id,partner_id,partner_key,refresh_token))
access_token,refresh_token = get_token_account_level(code,partner_id,partner_key,main_account_id)
print(access_token)
print(refresh_token)
print(get_access_token_merchant_level(merchant_id,partner_id,partner_key,refresh_token))
Java Code Demo:
//shop refresh the access token
public static String[] get_access_token_shop_level(String refresh_token,long partner_id,String tmp_partner_key,long shop_id) throws ParseException,IOException{
String[] res = new String[2];
long timest = System.currentTimeMillis() / 1000L;
String host = "https://partner.shopeemobile.com";
String path = "/api/v2/auth/access_token/get";
String tmp_base_string = String.format("%s%s%s", partner_id, path, timest);
byte[] partner_key;
byte[] base_string;
BigInteger sign = null;
String result = "";
try {
base_string = tmp_base_string.getBytes("UTF-8");
partner_key = tmp_partner_key.getBytes("UTF-8");
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(partner_key, "HmacSHA256");
mac.init(secret_key);
sign = new BigInteger(1,mac.doFinal(base_string));
} catch (Exception e) {
e.printStackTrace();
}
String tmp_url = host + path + String.format("?partner_id=%s×tamp=%s&sign=%s", partner_id,timest, String.format("%032x",sign));
URL url = new URL(tmp_url);
HttpURLConnection conn = null;
PrintWriter out = null;
BufferedReader in = null;
try {
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setConnectTimeout(30000);
conn.setReadTimeout(10000);
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
Map<String,Object> map = new HashMap<>();
map.put("refresh_token",refresh_token);
map.put("shop_id",shop_id);
map.put("partner_id",partner_id);
String json = JSON.toJSONString(map);
conn.connect();
out = new PrintWriter(conn.getOutputStream());
out.print(json);
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = "";
while((line=in.readLine())!=null){
result +=line;
}
JSONObject jsonObject = JSONObject.parseObject(result);
res[0] = (String) jsonObject.get("access_token");
res[1] = (String) jsonObject.get("refresh_token");
} catch(Exception e){
e.printStackTrace();
}finally {
try{
if(out != null){
out.close();
}
if(in != null){
in.close();
}
}catch (IOException ioe){
ioe.printStackTrace();
}
}
return res;
}
//merchant refresh the access token
public static String[] get_access_token_merchant_level(String refresh_token,long partner_id,String tmp_partner_key,long merchant_id) throws ParseException,IOException{
String[] res = new String[2];
long timest = System.currentTimeMillis() / 1000L;
String host = "https://partner.shopeemobile.com";
String path = "/api/v2/auth/access_token/get";
String tmp_base_string = String.format("%s%s%s", partner_id, path, timest);
byte[] partner_key;
byte[] base_string;
BigInteger sign = null;
String result = "";
try {
base_string = tmp_base_string.getBytes("UTF-8");
partner_key = tmp_partner_key.getBytes("UTF-8");
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(partner_key, "HmacSHA256");
mac.init(secret_key);
sign = new BigInteger(1,mac.doFinal(base_string));
} catch (Exception e) {
e.printStackTrace();
}
String tmp_url = host + path + String.format("?partner_id=%s×tamp=%s&sign=%s", partner_id,timest, String.format("%032x",sign));
URL url = new URL(tmp_url);
HttpURLConnection conn = null;
PrintWriter out = null;
BufferedReader in = null;
try {
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setConnectTimeout(30000);
conn.setReadTimeout(10000);
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
Map<String,Object> map = new HashMap<>();
map.put("refresh_token",refresh_token);
map.put("merchant_id",merchant_id);
map.put("partner_id",partner_id);
String json = JSON.toJSONString(map);
conn.connect();
out = new PrintWriter(conn.getOutputStream());
out.print(json);
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = "";
while((line=in.readLine())!=null){
result +=line;
}
JSONObject jsonObject = JSONObject.parseObject(result);
res[0] = (String) jsonObject.get("access_token");
res[1] = (String) jsonObject.get("refresh_token");
} catch(Exception e){
e.printStackTrace();
}finally {
try{
if(out != null){
out.close();
}
if(in != null){
in.close();
}
}catch (IOException ioe){
ioe.printStackTrace();
}
}
return res;
}
}
PHP Code Demo:
<?php
function getAccessTokenShopLevel($partnerId, $partnerKey, $shopId, $refreshToken) {
global $host;
$path = "/api/v2/auth/access_token/get";
$timest = time();
$body = array("partner_id" => $partnerId, "shop_id" => $shopId, "refresh_token" => $refreshToken);
$baseString = sprintf("%s%s%s", $partnerId, $path, $timest);
$sign = hash_hmac('sha256', $baseString, $partnerKey);
$url = sprintf("%s%s?partner_id=%s×tamp=%s&sign=%s", $host, $path, $partnerId, $timest, $sign);
$c = curl_init($url);
curl_setopt($c, CURLOPT_POST, 1);
curl_setopt($c, CURLOPT_POSTFIELDS, json_encode($body));
curl_setopt($c, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($c);
echo "\nraw result ".$result."\n";
$ret = json_decode($result, true);
$accessToken = $ret["access_token"];
$newRefreshToken = $ret["refresh_token"];
echo "\naccess_token: ".$accessToken.", refresh_token: ".$newRefreshToken."\n";
return $ret;
}
function getAccessTokenMerchantLevel($partnerId, $partnerKey, $merchantId, $refreshToken) {
global $host;
$path = "/api/v2/auth/access_token/get";
$timest = time();
$body = array("partner_id" => $partnerId, "merchant_id" => $merchantId, "refresh_token" => $refreshToken);
$baseString = sprintf("%s%s%s", $partnerId, $path, $timest);
$sign = hash_hmac('sha256', $baseString, $partnerKey);
$url = sprintf("%s%s?partner_id=%s×tamp=%s&sign=%s", $host, $path, $partnerId, $timest, $sign);
$c = curl_init($url);
curl_setopt($c, CURLOPT_POST, 1);
curl_setopt($c, CURLOPT_POSTFIELDS, json_encode($body));
curl_setopt($c, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($c);
echo "\nraw result ".$result."\n";
$ret = json_decode($result, true);
$accessToken = $ret["access_token"];
$newRefreshToken = $ret["refresh_token"];
echo "\naccess_token: ".$accessToken.", refresh_token: ".$newRefreshToken."\n";
return $ret;
}
$host="https://partner.shopeemobile.com";
$partnerId = 847892;
$partnerKey = "57615053704d6470644f554a78656d50484143644964436a5568777544524579";
// $shopId=200520705;
// $shopRefreshToken="71724c4e68746b546965424c70617244";
// getAccessTokenShopLevel($partnerId, $partnerKey, $shopId, $shopRefreshToken)
$merchantId=1018829;
$merchantRefreshToken="546e5064627042696756455277774f53";
getAccessTokenMerchantLevel($partnerId, $partnerKey, $merchantId, $merchantRefreshToken)
?>
§14 Shop account示例
Shop account示例
1、用redirect url:https://open.shopee.com/?code=7867624d4e76616648544f6e52625557&shop_id=54804中的code与shop_id调用GetAccesstoken接口获取第一对access_token与refresh_token.
{"shop_id":54804,
"code":"7867624d4e76616648544f6e52625557",
"partner_id":1000016
}
2、保存返回的第一对access_token与refresh_token。
{
"refresh_token": "456e416149664b76745a6a794156794a",
"access_token": "6a55746e61546f707579627656637464",
"expire_in": 13859,
"request_id": "c040b886cfcabdfa5a23af51c595cd1b",
"error": "",
"message": ""
}
3、调用RefreshAccessToken接口刷新access_token与refresh_token。
https://partner.shopeemobile.com/api/v2/auth/access_token/get?partner_id=1000016×tamp=1657263479&sign=9c685bc7e4a74e90f45fe1933f1d72b2d9705acda4093a9fb1ec7e2b57ccea2a
{"shop_id":54804,
"refresh_token":"456e416149664b76745a6a794156794a",
"partner_id":1000016
}
4、保存新的access_token与refresh_token。
{
"partner_id": 1000016,
"refresh_token": "666478546b6c63464867685554477a57",
"access_token": "7a5970754768697552654a466f425573",
"expire_in": 14400,
"request_id": "6d79dd0ffe4e070e185c71ca5153cd51",
"error": "",
"message": "",
"shop_id": 54804
}
§15 Main account示例
Main account示例
1、用授权拿到的https://open.shopee.com/?code=644d4e48787873706c5a444c776d4b59&main_account_id=10208中的code与main_account_id调用GetAccesstoken接口获取第一对access_token与refresh_token.
{"main_account_id":10208,
"code":"644d4e48787873706c5a444c776d4b59",
"partner_id":1000016
}
2、保存返回的第一对access_token与refresh_token。
{
"refresh_token": "684d42685667777868597a4477587455",
"access_token": "44776151594778486943647644745361",
"expire_in": 14344,
"request_id": "9199e13ee74b22411498209cb5516e24",
"merchant_id_list": [
1001705
],
"shop_id_list": [
33142,
46154
],
"error": "",
"message": ""
}
3、调用RefreshAccessToken接口分别刷新出shop_id与merchant_id的access_token与refresh_token
{"shop_id":33142,
"refresh_token":"684d42685667777868597a4477587455",
"partner_id":1000016
}
{"merchant_id":1001705,
"refresh_token":"684d42685667777868597a4477587455",
"partner_id":1000016
}
4、保存新的access_token与refresh_token。
{
"partner_id": 1000016,
"refresh_token": "417472546e73504949676279576c477a",
"access_token": "646d474965714a696177764963775743",
"expire_in": 14400,
"request_id": "78e64d11cb6dec6f6669282839fca916",
"error": "",
"message": "",
"shop_id": 33142
}
{
"partner_id": 1000016,
"refresh_token": "715075736d6c6570544364774f437369",
"access_token": "69634c664a7350696c6b466d5a53714a",
"expire_in": 14400,
"request_id": "51eacbc81bd6fa8fddddf1e0ef2dee16",
"error": "",
"message": "",
"merchant_id": 1001705
}
通过以上方式,您可以在四小时内调用RefreshAccessToken接口拿到新的access_token与refresh_token,保持循环调用将能在授权有效期内持续获得可用的access_token与refresh_token。如果丢失了返回的新的refresh_token和access_token,可以参考这篇 FAQ。
§16 取消授权
可通过生成取消授权链接或在卖家中心操作取消授权。
§17 通过取消授权URL
通过取消授权URL
与授权的URL生成规则一致,但固定授权url需变为固定取消授权的url:
固定取消授权 URL
取消授权链接示例
- 生产环境:https://open.shopee.com/cancel_auth?partner_id=10090&auth_type=seller&redirect_uri=https://open.shopee.com&response_type=code
- 沙箱测试环境:https://open.test-stable.shopee.com/cancel_auth?partner_id=1000016&auth_type=seller&redirect_uri=https://open.test-stable.shopee.com&response_type=code
取消流程
1、按上述规范生成取消授权链接;
2、卖家通过取消授权链接登录账号;
3、卖家点击 “取消授权” 完成操作,取消后应用将不再有权访问卖家信息。
§18 Seller Center取消授权
Seller Center取消授权
Local卖家:
- 卖家登录卖家中心,进入 “Home Page > Platform Partner;
- 在Platform Partner页面,卖家可查看店铺 / 主账号授权的所有应用及授权到期时间;
- 卖家点击操作列中的 “Separate”,取消对应应用的授权。
CNSC卖家
“首页 > 开放平台管理”:卖家可以去查看这主账号被授权给了哪些app,在授权管理页面,卖家可以在该界面直接解除merchant或shop的授权关系。
若授权过程中遇到错误,可参考官方常见问题(FAQ)排查。
如有其他疑问,可联系 Shopee 开放平台支持团队。
