渠道商总体接入流程

本文档基于 cl-cloud 的渠道商开放接口实现和 ipv-sdk 的 Go SDK 封装整理,用于说明渠道商从申请密钥、同步产品、下单、处理回调到后续运维的整体接入顺序。

1. 接入边界

渠道商调用的是平台开放接口,统一路径前缀为:

/api/open/app/{resource}/v2

cl-cloud/modules/open/service/supplier 是平台对上游供应商的适配层,渠道商接入时通常不需要实现该部分接口。渠道商只需要:

  • 向平台申请 appKeyappSecret、产品授权和回调地址配置。
  • 使用 ipv-sdk 或自行按统一加密规则请求 /api/open/app/.../v2
  • 保存平台返回的 orderNoinstanceNo,按回调或轮询补齐订单、实例最终状态。

2. 环境和密钥

环境地址
沙盒https://sandbox.ipipv.com
生产https://api.ipipv.com

生产环境会真实开通代理并产生费用。上线前建议先在沙盒完成加密、下单、回调、订单查询和实例查询的完整闭环。

3. 统一加密请求

所有 v2 业务请求外层都是统一报文:

{
  "version": "v2",
  "encrypt": "AES",
  "appKey": "渠道商 appKey",
  "reqId": "每次请求的唯一编号",
  "params": "业务参数 JSON 经 AES-CBC 加密后 Base64"
}

加密规则:

  • params 的明文是具体业务参数 JSON。
  • AES-CBC,PKCS5/PKCS7 Padding。
  • 密钥使用 appSecret,长度必须是 16、24 或 32 字节。
  • IV 使用 appSecret 的前 16 字节。
  • 响应成功时,外层 data 也是 AES-CBC 加密后 Base64,需要用同一个 appSecret 解密。

响应外层结构:

{
  "reqId": "请求编号",
  "code": 200,
  "msg": "ok",
  "data": "加密后的业务响应"
}

如果 code != 200,按 msg 和状态码处理错误,不要按成功响应解析 data/api/open/app/proxy/user/flow/limit/v2 成功时只返回普通成功结果,不返回加密业务数据。

使用 Go SDK 时,SDK 会自动封装加密、解密和基础错误处理:

client, err := sdk.NewClient(
    "https://sandbox.ipipv.com",
    "your_app_key",
    "your_app_secret",
    sdk.Encrypt_AES,
)

4. 接入总流程

申请密钥和配置回调
  -> 联调统一加密和 GetAppInfo
  -> 同步地域、城市、项目和产品
  -> 按产品类型选择静态或动态开通流程
  -> 提交订单,保存平台 orderNo
  -> 等待 order 回调或轮询 GetOrder
  -> 查询订单实例,保存 instanceNo
  -> 使用实例,后续按需续费、释放、更换代理、重置密码或查询动态流量

5. 前置初始化

5.1 获取渠道商信息

调用 GetAppInfo

POST /api/open/app/info/v2

用于确认渠道商状态、余额、授信额度、桥配置和回调地址。status=1 才表示渠道商可正常使用。

5.2 同步基础字典

建议启动时或定时同步:

目的接口SDK 方法
洲/国家/州/城市树/api/open/app/area/v2GetArea
城市列表/api/open/app/city/list/v2GetCityList
项目列表/api/open/app/project/list/v2GetProjectList
产品列表/api/open/app/product/query/v2GetProductStock
单产品实时信息/api/open/app/product/info/v2GetProductInfo

产品返回中的关键字段:

  • productNo:平台产品编号,下单优先使用该字段。
  • proxyType:101/102/103 为静态代理,104/105 为动态代理。
  • enable=1:可购买。
  • inventory:库存。
  • durationunit:产品最小购买周期。
  • productType=2:共享产品,下单需要 projectId
  • cidrBlockscidrStatus:是否支持按网段购买。
  • assignIp:是否支持指定 IP 购买。
  • changeProxy:是否支持更换代理。
  • resetPassword:是否支持重置密码。
  • 动态能力字段:drawTypeipWhiteListpwdDrawProxyUserproxyUserFlowLimitflowUseLogproxyGlobalRandomapiDrawGlobalRandom 等。

6. 静态代理开通流程

适用代理类型:101 静态云平台、102 静态国内家庭、103 静态国外家庭、201 WhatsApp 等非动态产品。

  1. 查询并选择产品。 推荐传 productNo 下单。也可以不传 productNo,由平台按 proxyTypecountryCodecityCodesupplierCodeunitispType 等条件匹配产品,但推荐只在明确需要自动匹配时使用。

  2. 提交开通订单。

POST /api/open/app/instance/open/v2
SDK: InstanceOpen

核心参数:

参数说明
appOrderNo渠道商订单号,普通订单最长 32 位,同一渠道商下保持唯一
params购买项数组,最多 100 项
params[].productNo平台产品编号,推荐必传
params[].count静态实例数量,单项最大 100,默认 1
params[].cycleTimes购买周期数,推荐使用;表示购买几个产品最小周期
params[].duration兼容字段,不传时使用产品最小周期
params[].extBandWidth额外带宽,单位 Mbps
params[].useBridge0=随渠道商配置,1=不使用桥,2=使用桥
params[].cidrBlocks支持网段购买时可传,所有 count 之和必须等于购买数量
params[].projectId共享产品必填,取项目列表返回的 code
  1. 处理下单响应。 开通接口返回的是异步订单受理结果:
{
  "orderNo": "平台订单号",
  "appOrderNo": "渠道商订单号",
  "amount": "订单金额"
}

此时不代表实例已经可用。渠道商需要保存 orderNo,等待回调或轮询订单。

  1. 查询订单和实例。
POST /api/open/app/order/v2
SDK: GetOrder

可用平台 orderNo 或渠道商 appOrderNo 查询。订单 status

状态说明
1待处理
2处理中
3处理成功
4处理失败
5部分完成

订单成功或部分完成后,读取返回的 instances,保存每个实例的 instanceNoipportusernamepwduserExpiredproductNo。后续续费、释放、更换代理、重置密码都使用平台 instanceNo

7. 动态代理开通和提取流程

适用代理类型:104 动态国外、105 动态国内。

7.1 创建主账号

动态代理必须先创建渠道商主账号:

POST /api/open/app/user/v2
SDK: CreateUser

核心参数:

参数说明
appUsername渠道商主账号,同一渠道商下唯一;不传则平台生成
password不传则平台生成
phoneemail可选
authTypeauthNameno实名信息,可创建时传,也可后续同步
status1=正常,2=禁用

创建主账号时,平台会自动创建一个同名代理子账号。若业务需要多个独立子账号,可继续调用 CreateProxyUser

7.2 可选同步实名

POST /api/open/app/userAuth/v2
SDK: UserAuth

usernameappUsername 二选一,必须属于当前渠道商。

7.3 可选创建子账号

POST /api/open/app/proxy/user/v2
SDK: CreateProxyUser

核心参数:

参数说明
appMainUsername渠道商主账号;与 mainUsername 二选一
mainUsername平台主账号;与 appMainUsername 二选一
appUsername渠道商子账号,不传则平台生成
password子账号密码,不传则平台生成
limitFlow子账号流量上限,创建时字段为 MB;独立设置上限接口使用 B
status1=正常,2=禁用

7.4 购买动态套餐

动态产品也通过开通接口下单:

POST /api/open/app/instance/open/v2
SDK: InstanceOpen

动态购买项必须关注:

参数说明
productNo动态产品编号
appUsername渠道商主账号,必须已创建
flow动态流量,单位 MB;普通流量型动态产品必填
cycleTimes有固定周期的产品按周期数购买
count默认 1;按 IP 数量售卖的产品需结合产品 ipCountipDuration 规则

下单后同样等待 order 回调或轮询 GetOrder。动态套餐对应的实例主要用于记录套餐和余额,实际代理地址通过提取接口获取。

7.5 查询余额和区域

目的接口SDK 方法
动态余额/api/open/app/proxy/info/v2ProxyInfo
动态区域/api/open/app/product/area/v2ProductAreaList

余额查询中的 totalusedbalance 单位为 MB;流量明细中的 usedtotalbalance 单位为 B。

7.6 提取动态代理

账密提取:

POST /api/open/app/proxy/draw/pwd/v2
SDK: DrawByPwd

使用渠道商子账号 appUsernamesessTime 默认为 5 分钟,通常支持 1 到 120 分钟;传 0-1 表示每次切换代理。addressCode 可传洲、国家、州省或城市代码,空值表示混播,前提是产品支持。

API 提取:

POST /api/open/app/proxy/draw/api/v2
SDK: DrawByApi

使用渠道商主账号 appUsername。返回 proxyUrl,业务方再访问该 URL 获取代理结果。protocol 默认为 socks5,支持 socks5httpreturnType 支持 txtjson

如产品要求 IP 白名单,提取前先调用:

POST /api/open/app/proxy/addIpWhiteList/v2
POST /api/open/app/proxy/delIpWhiteList/v2

8. 续费、释放和售后

8.1 续费静态实例

POST /api/open/app/instance/renew/v2
SDK: InstanceRenew

核心规则:

  • appOrderNo 同一渠道商下唯一,最长 32 位。
  • instances 不能为空,不能重复,单次最多 100 个。
  • 只支持静态代理;动态代理不支持续费接口。
  • 实例必须属于当前渠道商,且状态为运行中。
  • 实例不能超过供应商续费宽限期。
  • cycleTimes 优先;不传时默认按原购买周期续费。

续费是异步订单,返回平台 orderNo 后继续按回调或 GetOrder 查询最终结果。

8.2 释放静态实例

POST /api/open/app/instance/release/v2
SDK: InstanceRelease

注意:请求参数里的 orderNo 是渠道商释放订单号,不是平台订单号。

核心规则:

  • 渠道商释放订单号同一渠道商下唯一,最长 32 位。
  • instances 不能为空,不能重复,单次最多 100 个。
  • 只支持运行中的静态代理;动态代理不支持释放接口。
  • 已转移、已释放、正在释放、超过无理由释放期限或超过渠道商释放额度的实例会失败。

释放同样是异步订单,最终结果以回调后查询订单为准。

8.3 售后释放

POST /api/open/app/instance/aftersale/v2
SDK: InstanceAfterSale

该能力需要渠道商单独开通。适用于下架、断网、卡顿、地区异常、黑白名单、业务不支持等售后场景。请求中 orderNo 是渠道商售后释放订单号。

9. 可选能力

9.1 指定 IP 购买

先查询指定 IP 是否可购买:

POST /api/open/app/assign/ip/info/v2
SDK: GetAssignIpInfo

确认 canBuyStatus=true 后提交指定 IP 开通:

POST /api/open/app/instance/open/assign/ip/v2
SDK: InstanceOpenAssignIp

指定 IP 购买仅支持静态产品,产品和供应商都必须支持该能力。productNoassignIpcycleTimes 必填。

9.2 更换代理

POST /api/open/app/instance/change/v2
SDK: ChangeProxy

核心规则:

  • 渠道商和供应商都必须开通更换代理能力。
  • 产品列表返回 changeProxy=1 才能作为判断依据之一。
  • 实例必须属于当前渠道商且为运行中。
  • appOrderNo 为更换代理订单号,最长 64 位,同一渠道商下唯一。
  • 同一实例同一时间只允许一个更换代理任务处理中。
  • reason 最长 64 字符。

更换代理成功后,实例的 IP、端口、账号密码等连接信息会被更新。收到 op=5 的订单回调后,通过 GetOrderGetInstance 获取最新实例信息。

9.3 重置实例密码

POST /api/open/app/instance/reset/password/v2
SDK: ResetProxyPassword

核心规则:

  • 以产品 resetPassword=1 和实际供应商能力为准。
  • resetNo 必填,最长 32 位,同一渠道商下用于幂等。
  • instanceNoList 不能为空,不能重复。
  • 实例必须属于当前渠道商且为运行中。
  • 重复提交相同 resetNo 时,实例列表必须一致,平台返回第一次请求的处理结果。

返回结果中 status 为 1=待处理、2=处理中、3=成功、4=失败;newPassword 为空表示尚未成功生成或处理失败。

9.4 动态子账号流量上限

POST /api/open/app/proxy/user/flow/limit/v2
SDK: SetProxyUserFlowLimit

产品和供应商必须支持 proxyUserFlowLimit=1limitFlow=-1 表示不限制;如果设置正数,单位为 B,且不能小于 1024000B。

查询子账号信息:

POST /api/open/app/proxy/user/info/v2
SDK: GetProxyUserInfo

9.5 动态流量明细和回收

流量明细:

POST /api/open/app/proxy/flow/use/log/v2
SDK: ProxyFlowUseLog

默认查询近 7 天;分页默认 page=1pageSize=10,最大 100。

流量回收:

POST /api/open/app/proxy/return/v2
SDK: DynamicProxyReturn

流量型产品使用 flowNum,单位 MB;按 IP 数量购买的产品使用 ipNum。平台会校验当前剩余量并按产品授权价格计算退回金额。

10. 回调处理

平台在订单、实例或产品变化时,向渠道商配置的回调地址发起 GET 请求:

{callbackUrl}?type={type}&no={no}&op={op}

常见回调:

typenoop处理建议
order平台订单号1=创建,2=续费,3=释放,5=更换代理调用 GetOrder 拉取订单和实例最终状态
instance平台实例编号实例变化操作类型调用 GetInstance 拉取实例最新信息
product产品编号0调用 GetProductInfoGetProductStock 刷新产品

渠道商回调接口必须返回 JSON:

{
  "code": "success",
  "msg": "ok"
}

如果没有返回 code=success,平台会重试。渠道商需要按 type + no + op 做幂等;同一个回调已经处理成功后,再次收到也应返回 success

11. 幂等和重试建议

  • 普通开通、续费、释放、售后订单使用渠道商订单号幂等,建议最长 32 位。
  • 更换代理使用独立 appOrderNo 幂等,最长 64 位。
  • 重置密码使用 resetNo 幂等,最长 32 位。
  • 同一个订单号不要跨业务类型复用;例如开通订单号不能再用于续费或释放。
  • 网络超时或未收到响应时,使用相同 reqId 和相同业务单号重试。
  • 如果接口已返回平台 orderNo,后续以订单查询和回调为准,不要重复生成新的渠道商订单号补单。
  • 保存平台 orderNo、渠道商订单号、instanceNoproductNo、账号映射关系,便于后续续费、释放、售后和对账。

12. 推荐最小联调清单

  1. GetAppInfo:验证密钥、加密和响应解密。
  2. GetAreaGetCityList:验证地域字典。
  3. GetProductStock:验证产品授权和产品字段解析。
  4. 静态产品:InstanceOpen -> 回调 -> GetOrder -> GetInstance
  5. 动态产品:CreateUser -> InstanceOpen -> ProxyInfo -> DrawByApiDrawByPwd
  6. 后续操作:选择一个实例完成 InstanceRenewInstanceReleaseChangeProxy 的沙盒闭环。
  7. 回调:验证订单回调重复通知时仍返回 success