TelDog合作伙伴API接口文档

代理开放接口文档

更新时间

  • 2026-05-25

适用范围

  • 本文档面向代理系统开发人员。
  • 当前已正式上线并可直接对接的开放能力有:
    • GET /openapi/agent/balance
    • GET /openapi/agent/countries
    • GET /openapi/agent/operators
    • GET /openapi/agent/products
    • POST /openapi/agent/orders
    • GET /openapi/agent/orders/{agent_order_id}
    • 平台状态回调:POST <agent callback_url>
  • 其它代理开放能力会在后续版本上线后补充到本文档。

接入概览

  • 接口协议:HTTPS + JSON
  • Base URL:由平台提供,例如 https://api.example.com
  • 当前可用前缀:/openapi/agent
  • 鉴权方式:请求头 X-API-Key
  • 安全策略:API Key + 白名单 IP
    • 若代理账号未配置启用中的白名单,只校验 X-API-Key
    • 若代理账号已配置启用中的白名单,来源 IP 必须命中白名单

统一请求规范

  • 所有请求和响应均使用 UTF-8。
  • GET 无请求体场景外,请求头建议固定带上:
    • Content-Type: application/json
    • Accept: application/json
    • X-API-Key: <your_api_key>
  • 所有金额字段使用十进制数字返回,当前示例以 JSON number 展示。

统一响应格式

  • 所有接口统一返回:
{
  "code": 0,
  "message": "",
  "data": {}
}

字段说明

  • code
    • 0 表示成功
    • 0 表示失败
  • message
    • 成功时通常为空字符串
    • 失败时返回可直接排查的错误描述
  • data
    • 成功时为业务数据
    • 失败时通常为 {}

常见错误码

  • 40101:未授权
    • 常见原因:缺少 X-API-KeyX-API-Key 无效、账号被禁用、账号不是代理账号
  • 40301:禁止访问
    • 常见原因:来源 IP 未命中已配置白名单
  • 40401:资源不存在
  • 42201:请求参数错误
  • 50000:系统异常

时间字段格式约定

  • 当前已上线的余额、国家、运营商、商品接口未返回时间字段。
  • 后续若返回时间,统一使用 ISO 8601 格式,例如:
    • 2026-03-17T08:30:00Z

订单号唯一性说明

  • 下单接口使用 agent_order_id 作为代理侧业务单号。
  • 固定约束:
    • agent_order_id 由代理系统生成
    • 同一代理下必须唯一
    • 只要同一代理重复提交相同 agent_order_id,服务端都会返回冲突错误

鉴权说明

  • Header 名称:X-API-Key
  • Header 示例:
X-API-Key: agt_xxxxxxxxxxxxxxxxxxxx
  • 白名单 IP 规则:
    • 若未配置白名单,合法 X-API-Key 可直接访问
    • 若已配置白名单,只允许白名单中的出口 IP 访问
    • 如代理服务器存在多个出口 IP,需全部加入白名单

接口列表

  1. 获取代理账户余额

接口信息

  • 方法:GET
  • 路径:/openapi/agent/balance
  • 描述:查询当前代理账户可用余额
  • 鉴权:需要 X-API-Key
  • 请求体:无

请求头

  • X-API-Key: <your_api_key>
  • Accept: application/json

成功响应

{
  "code": 0,
  "message": "",
  "data": {
    "balance": 1250.5
  }
}

成功字段说明

  • data.balance
    • 类型:number
    • 含义:当前代理账户可用余额

失败示例 1:缺少 API Key

{
  "code": 40101,
  "message": "缺少 api_key",
  "data": {}
}

失败示例 2:API Key 无效

{
  "code": 40101,
  "message": "无效的 api_key",
  "data": {}
}

失败示例 3:IP 未在白名单中

{
  "code": 40301,
  "message": "IP 未在白名单中",
  "data": {}
}

curl

curl --request GET \
  --url 'https://api.example.com/openapi/agent/balance' \
  --header 'Accept: application/json' \
  --header 'X-API-Key: agt_xxxxxxxxxxxxxxxxxxxx'

JavaScript

async function getAgentBalance() {
  const response = await fetch("https://api.example.com/openapi/agent/balance", {
    method: "GET",
    headers: {
      Accept: "application/json",
      "X-API-Key": "agt_xxxxxxxxxxxxxxxxxxxx",
    },
  });

  const result = await response.json();
  if (result.code !== 0) {
    throw new Error(result.message || "request failed");
  }
  return result.data.balance;
}

Python

import requests


def get_agent_balance():
    response = requests.get(
        "https://api.example.com/openapi/agent/balance",
        headers={
            "Accept": "application/json",
            "X-API-Key": "agt_xxxxxxxxxxxxxxxxxxxx",
        },
        timeout=10,
    )
    result = response.json()
    if result["code"] != 0:
        raise RuntimeError(result["message"])
    return result["data"]["balance"]
  1. 获取国家列表

接口信息

  • 方法:GET
  • 路径:/openapi/agent/countries
  • 描述:返回当前可售国家列表
  • 鉴权:需要 X-API-Key
  • 请求体:无

请求头

  • X-API-Key: <your_api_key>
  • Accept: application/json

成功响应

{
  "code": 0,
  "message": "",
  "data": [
    {
      "country_iso": "US",
      "name_cn": "美国",
      "name_en": "United States",
      "area_code": "+1",
      "flag_url": "https://api.example.com/static/flags/US.svg"
    }
  ]
}

成功字段说明

  • data[].country_iso
    • 类型:string
    • 含义:国家 ISO 编码
  • data[].name_cn
    • 类型:string
    • 含义:国家中文名
  • data[].name_en
    • 类型:string
    • 含义:国家英文名
  • data[].area_code
    • 类型:string | null
    • 含义:国家区号
  • data[].flag_url
    • 类型:string | null
    • 含义:国家旗帜图片地址

curl

curl --request GET \
  --url 'https://api.example.com/openapi/agent/countries' \
  --header 'Accept: application/json' \
  --header 'X-API-Key: agt_xxxxxxxxxxxxxxxxxxxx'

JavaScript

async function getCountries() {
  const response = await fetch("https://api.example.com/openapi/agent/countries", {
    method: "GET",
    headers: {
      Accept: "application/json",
      "X-API-Key": "agt_xxxxxxxxxxxxxxxxxxxx",
    },
  });

  const result = await response.json();
  if (result.code !== 0) {
    throw new Error(result.message || "request failed");
  }
  return result.data;
}

Python

import requests


def get_countries():
    response = requests.get(
        "https://api.example.com/openapi/agent/countries",
        headers={
            "Accept": "application/json",
            "X-API-Key": "agt_xxxxxxxxxxxxxxxxxxxx",
        },
        timeout=10,
    )
    result = response.json()
    if result["code"] != 0:
        raise RuntimeError(result["message"])
    return result["data"]
  1. 获取运营商列表

接口信息

  • 方法:GET
  • 路径:/openapi/agent/operators
  • 描述:根据国家代码返回该国家下可用运营商列表
  • 鉴权:需要 X-API-Key
  • 请求体:无

查询参数

  • country_iso
    • 类型:string
    • 必填:是
    • 长度:2-16
    • 含义:国家 ISO 编码,例如 US

请求头

  • X-API-Key: <your_api_key>
  • Accept: application/json

成功响应

{
  "code": 0,
  "message": "",
  "data": [
    {
      "operator_code": "att",
      "country_iso": "US",
      "name_cn": "AT&T",
      "name_en": "AT&T",
      "imgurl": "https://api.example.com/static/operators/att.png"
    }
  ]
}

成功字段说明

  • data[].operator_code
    • 类型:string
    • 含义:运营商编码
  • data[].country_iso
    • 类型:string
    • 含义:所属国家 ISO 编码
  • data[].name_cn
    • 类型:string
    • 含义:运营商中文名
  • data[].name_en
    • 类型:string
    • 含义:运营商英文名
  • data[].imgurl
    • 类型:string | null
    • 含义:运营商图片地址

失败示例:缺少必填参数

{
  "code": 42201,
  "message": "请求参数错误",
  "data": {}
}

curl

curl --request GET \
  --url 'https://api.example.com/openapi/agent/operators?country_iso=US' \
  --header 'Accept: application/json' \
  --header 'X-API-Key: agt_xxxxxxxxxxxxxxxxxxxx'

JavaScript

async function getOperators(countryIso) {
  const url = new URL("https://api.example.com/openapi/agent/operators");
  url.searchParams.set("country_iso", countryIso);

  const response = await fetch(url.toString(), {
    method: "GET",
    headers: {
      Accept: "application/json",
      "X-API-Key": "agt_xxxxxxxxxxxxxxxxxxxx",
    },
  });

  const result = await response.json();
  if (result.code !== 0) {
    throw new Error(result.message || "request failed");
  }
  return result.data;
}

Python

import requests


def get_operators(country_iso: str):
    response = requests.get(
        "https://api.example.com/openapi/agent/operators",
        params={"country_iso": country_iso},
        headers={
            "Accept": "application/json",
            "X-API-Key": "agt_xxxxxxxxxxxxxxxxxxxx",
        },
        timeout=10,
    )
    result = response.json()
    if result["code"] != 0:
        raise RuntimeError(result["message"])
    return result["data"]
  1. 获取商品列表

接口信息

  • 方法:GET
  • 路径:/openapi/agent/products
  • 描述:根据国家和可选运营商条件返回代理可下单商品列表
  • 鉴权:需要 X-API-Key
  • 请求体:无

查询参数

  • country_iso
    • 类型:string
    • 必填:是
    • 长度:2-16
    • 含义:国家 ISO 编码,例如 US
  • operator_code
    • 类型:string
    • 必填:否
    • 长度:1-64
    • 含义:运营商编码;不传时返回该国家全部在售商品

请求头

  • X-API-Key: <your_api_key>
  • Accept: application/json

成功响应

{
  "code": 0,
  "message": "",
  "data": [
    {
      "product_code": "us-att-10",
      "country_iso": "US",
      "operator_code": "att",
      "name_cn": "美国 AT&T 10美金",
      "name_en": "US AT&T 10 USD",
      "product_type": "balance",
      "price": 9.0,
      "valid_days": 30,
      "badge": "热卖",
      "badge_en": "Hot"
    }
  ]
}

成功字段说明

  • data[].product_code
    • 类型:string
    • 含义:商品编码,后续下单接口将使用该字段
  • data[].country_iso
    • 类型:string
    • 含义:国家 ISO 编码
  • data[].operator_code
    • 类型:string | null
    • 含义:运营商编码;通用商品可能为 null
  • data[].name_cn
    • 类型:string
    • 含义:商品中文名
  • data[].name_en
    • 类型:string
    • 含义:商品英文名
  • data[].product_type
    • 类型:string
    • 含义:商品类型,例如 balancedatacard
  • data[].price
    • 类型:number
    • 含义:代理成交价
  • data[].valid_days
    • 类型:integer | null
    • 含义:有效期天数
  • data[].badge
    • 类型:string | null
    • 含义:商品中文标识
  • data[].badge_en
    • 类型:string | null
    • 含义:商品英文标识

失败示例:缺少必填参数

{
  "code": 42201,
  "message": "请求参数错误",
  "data": {}
}

curl

curl --request GET \
  --url 'https://api.example.com/openapi/agent/products?country_iso=US&operator_code=att' \
  --header 'Accept: application/json' \
  --header 'X-API-Key: agt_xxxxxxxxxxxxxxxxxxxx'

JavaScript

async function getProducts(countryIso, operatorCode) {
  const url = new URL("https://api.example.com/openapi/agent/products");
  url.searchParams.set("country_iso", countryIso);
  if (operatorCode) {
    url.searchParams.set("operator_code", operatorCode);
  }

  const response = await fetch(url.toString(), {
    method: "GET",
    headers: {
      Accept: "application/json",
      "X-API-Key": "agt_xxxxxxxxxxxxxxxxxxxx",
    },
  });

  const result = await response.json();
  if (result.code !== 0) {
    throw new Error(result.message || "request failed");
  }
  return result.data;
}

Python

import requests


def get_products(country_iso: str, operator_code: str | None = None):
    params = {"country_iso": country_iso}
    if operator_code:
        params["operator_code"] = operator_code

    response = requests.get(
        "https://api.example.com/openapi/agent/products",
        params=params,
        headers={
            "Accept": "application/json",
            "X-API-Key": "agt_xxxxxxxxxxxxxxxxxxxx",
        },
        timeout=10,
    )
    result = response.json()
    if result["code"] != 0:
        raise RuntimeError(result["message"])
    return result["data"]
  1. 代理下单

接口信息

  • 方法:POST
  • 路径:/openapi/agent/orders
  • 描述:创建代理余额支付订单,并自动进入充值流程
  • 鉴权:需要 X-API-Key
  • Content-Type:application/json

请求体

  • agent_order_id
    • 类型:string
    • 必填:是
    • 长度:1-64
    • 含义:代理侧业务订单号,用于唯一性控制
  • product_code
    • 类型:string
    • 必填:是
    • 长度:1-64
    • 含义:商品编码
  • phone
    • 类型:string | null
    • 必填:条件必填
    • 长度:最大 32
    • 含义:手机号;当商品类型不是 card 时必须传

请求示例

{
  "agent_order_id": "AGT-20260317-0001",
  "product_code": "LA_UNITEL_5000",
  "phone": "8562099810363"
}

成功响应

{
  "code": 0,
  "message": "",
  "data": {
    "agent_order_id": "AGT-20260317-0001",
    "order_id": "202603170000000003",
    "status": "processing",
    "actual_amount": 9.0
  }
}

成功字段说明

  • data.agent_order_id
    • 类型:string
    • 含义:代理侧业务订单号
  • data.order_id
    • 类型:string
    • 含义:平台订单号
  • data.status
    • 类型:string
    • 含义:当前订单状态;当前接口正常创建后通常为 processing
  • data.actual_amount
    • 类型:number
    • 含义:本次实际扣款金额

业务单号规则

  • 若同一代理重复提交相同的 agent_order_id,服务端直接返回冲突错误。
  • 服务端不会复用或返回旧订单数据,请代理侧自行保证 agent_order_id 唯一。

常见失败场景

  • 商品不存在或未在售:40401
  • 余额不足:40000
  • 非卡密商品未传手机号:40000
  • agent_order_id 重复:40901

失败示例:余额不足

{
  "code": 40000,
  "message": "余额不足",
  "data": {}
}

失败示例:重复业务单号冲突

{
 "code": 40901,
 "message": "订单号重复",
 "data": {}
}

curl

curl --request POST \
  --url 'https://api.example.com/openapi/agent/orders' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'X-API-Key: agt_xxxxxxxxxxxxxxxxxxxx' \
  --data '{
    "agent_order_id": "AGT-20260317-0001",
    "product_code": "us-att-10",
    "phone": "1234567890"
  }'

JavaScript

async function createAgentOrder(payload) {
  const response = await fetch("https://api.example.com/openapi/agent/orders", {
    method: "POST",
    headers: {
      Accept: "application/json",
      "Content-Type": "application/json",
      "X-API-Key": "agt_xxxxxxxxxxxxxxxxxxxx",
    },
    body: JSON.stringify(payload),
  });

  const result = await response.json();
  if (result.code !== 0) {
    throw new Error(result.message || "request failed");
  }
  return result.data;
}

Python

import requests


def create_agent_order():
    response = requests.post(
        "https://api.example.com/openapi/agent/orders",
        headers={
            "Accept": "application/json",
            "Content-Type": "application/json",
            "X-API-Key": "agt_xxxxxxxxxxxxxxxxxxxx",
        },
        json={
            "agent_order_id": "AGT-20260317-0001",
            "product_code": "us-att-10",
            "phone": "1234567890",
        },
        timeout=10,
    )
    result = response.json()
    if result["code"] != 0:
        raise RuntimeError(result["message"])
    return result["data"]
  1. 查询订单状态

接口信息

  • 方法:GET
  • 路径:/openapi/agent/orders/{agent_order_id}
  • 描述:根据代理侧业务订单号查询订单状态与结果
  • 鉴权:需要 X-API-Key
  • 请求体:无

路径参数

  • agent_order_id
    • 类型:string
    • 必填:是
    • 长度:1-64
    • 含义:代理侧业务订单号

请求头

  • X-API-Key: <your_api_key>
  • Accept: application/json

成功响应

{
  "code": 0,
  "message": "",
  "data": {
    "agent_order_id": "AGT-20260317-0001",
    "order_id": "202603170000000003",
    "status": "success",
    "product_code": "us-att-10",
    "quantity": 1,
    "phone": "1234567890",
    "actual_amount": 9.0,
    "remark": "充值成功",
    "remark_en": "Recharge succeeded",
    "created_at": "2026-03-17T08:30:00Z"
  }
}

成功字段说明

  • data.agent_order_id
    • 类型:string
    • 含义:代理侧业务订单号
  • data.order_id
    • 类型:string
    • 含义:平台订单号
  • data.status
    • 类型:string
    • 含义:订单状态,可能值包括 processingsuccessfailedrefundingrefunded
  • data.product_code
    • 类型:string | null
    • 含义:商品编码
  • data.quantity
    • 类型:integer
    • 含义:下单数量;当前代理下单接口固定为 1
  • data.phone
    • 类型:string
    • 含义:下单手机号
  • data.actual_amount
    • 类型:number
    • 含义:实际扣款金额
  • data.remark
    • 类型:string | null
    • 含义:中文备注,例如失败原因或处理说明
  • data.remark_en
    • 类型:string | null
    • 含义:英文备注
  • data.created_at
    • 类型:string
    • 含义:订单创建时间,ISO 8601 格式

注意事项

  • 本接口按代理账号维度查询,只能查询当前 X-API-Key 对应代理账号自己的订单。

失败示例:订单不存在

{
  "code": 40401,
  "message": "订单不存在",
  "data": {}
}

curl

curl --request GET \
  --url 'https://api.example.com/openapi/agent/orders/AGT-20260317-0001' \
  --header 'Accept: application/json' \
  --header 'X-API-Key: agt_xxxxxxxxxxxxxxxxxxxx'

JavaScript

async function getAgentOrder(agentOrderId) {
  const response = await fetch(`https://api.example.com/openapi/agent/orders/${encodeURIComponent(agentOrderId)}`, {
    method: "GET",
    headers: {
      Accept: "application/json",
      "X-API-Key": "agt_xxxxxxxxxxxxxxxxxxxx",
    },
  });

  const result = await response.json();
  if (result.code !== 0) {
    throw new Error(result.message || "request failed");
  }
  return result.data;
}

Python

import requests


def get_agent_order(agent_order_id: str):
    response = requests.get(
        f"https://api.example.com/openapi/agent/orders/{agent_order_id}",
        headers={
            "Accept": "application/json",
            "X-API-Key": "agt_xxxxxxxxxxxxxxxxxxxx",
        },
        timeout=10,
    )
    result = response.json()
    if result["code"] != 0:
        raise RuntimeError(result["message"])
    return result["data"]

对接建议

  • 代理服务端应把 X-API-Key 保存在服务端安全配置中,不要暴露到浏览器前端。
  • 若启用了白名单,请在部署切换或扩容前确认出口 IP 是否变化。
  • 建议调用方同时记录:
    • HTTP 状态码
    • 响应体 code
    • 响应体 message
  1. 状态回调通知

能力说明

  • 方向:平台主动回调代理系统
  • 方法:POST
  • 回调地址:代理账号配置的固定 callback_url
  • Content-Type:application/json
  • 触发时机:当代理订单状态发生结果性变化时,平台会主动推送最新状态
  • 当前实现会在以下场景触发回调:
    • 充值成功后状态变为 success
    • 充值失败并已原路退回余额后状态变为 refunded
    • 退款处理中时状态变为 refunding

回调请求头

  • Content-Type: application/json
  • Accept: application/json
  • X-Callback-Timestamp: <unix_timestamp_seconds>
  • X-Callback-Signature: <hmac_sha256_hex>

回调请求体

  • agent_order_id
    • 类型:string
    • 含义:代理侧业务订单号
  • order_id
    • 类型:string
    • 含义:平台订单号
  • status
    • 类型:string
    • 含义:最新订单状态
  • product_code
    • 类型:string | null
    • 含义:商品编码
  • phone
    • 类型:string
    • 含义:下单手机号
  • quantity
    • 类型:integer
    • 含义:下单数量
  • actual_amount
    • 类型:number
    • 含义:实际扣款金额
  • remark
    • 类型:string | null
    • 含义:中文备注
  • remark_en
    • 类型:string | null
    • 含义:英文备注
  • callback_time
    • 类型:string
    • 含义:本次回调发起时间,ISO 8601 格式

回调示例

POST /agent/callback HTTP/1.1
Content-Type: application/json
Accept: application/json
X-Callback-Timestamp: 1773741600
X-Callback-Signature: 0f28d97b5d5d88e23bb9a5b6a8ce0d760dc8d2f5c44a6d9ac7e5705f0f3b4f6f
{
  "agent_order_id": "AGT-20260317-0001",
  "order_id": "202603170000000003",
  "status": "success",
  "product_code": "us-att-10",
  "phone": "1234567890",
  "quantity": 1,
  "actual_amount": 9.0,
  "remark": "充值成功",
  "remark_en": "Recharge succeeded",
  "callback_time": "2026-03-17T10:00:00Z"
}

签名算法

  • X-Callback-Signature = HMAC_SHA256_HEX(api_key, "timestamp.raw_body")
  • 其中:
    • timestampX-Callback-Timestamp 头中的秒级 Unix 时间戳
    • raw_body 为回调请求体原始字节串
    • api_key 为该代理账号自己的 X-API-Key

签名示例

timestamp = 1773741600
raw_body = {"agent_order_id":"AGT-20260317-0001","order_id":"202603170000000003","status":"success","product_code":"us-att-10","phone":"1234567890","quantity":1,"actual_amount":9.0,"remark":"充值成功","remark_en":"Recharge succeeded","callback_time":"2026-03-17T10:00:00Z"}
signing_text = "1773741600." + raw_body
signature = HMAC_SHA256_HEX(api_key, signing_text)

Python 验签示例

import hashlib
import hmac


def verify_callback(api_key: str, timestamp: str, raw_body: bytes, signature: str) -> bool:
    expected = hmac.new(
        api_key.encode("utf-8"),
        timestamp.encode("utf-8") + b"." + raw_body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

JavaScript 验签示例

import crypto from "node:crypto";

function verifyCallback(apiKey, timestamp, rawBody, signature) {
  const expected = crypto
    .createHmac("sha256", apiKey)
    .update(`${timestamp}.`)
    .update(rawBody)
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

对接要求

  • 代理回调地址必须可被平台服务访问,且建议使用 HTTPS。
  • 代理服务端收到回调后,应先使用原始请求体做签名校验,再处理业务逻辑。
  • 代理回调接口只要处理成功,就应返回任意 2xx HTTP 状态码。

重试规则

  • 若代理回调接口返回非 2xx,或请求超时、网络异常,平台会自动重试。
  • 当前默认重试参数为:
    • 最大尝试次数:5
    • 单次请求超时:10
    • 相邻两次重试间隔:3
  • 如代理已成功处理回调但响应异常,需保证自身按 agent_order_id 做幂等处理。

变更说明

  • 本文档当前版本已覆盖余额、国家、运营商、商品、下单、查单、状态回调和共享接入规范。