SportApi
API 文档 · 版本 1.2.0

赔率、投注和彩票 — API 技术文档

该文件包含连接 SportAPI 优惠券结算系统的简明独立指南。详细信息和罕见情况请参见完整文档。

核心流程 http
POST /api/partner/login
POST /api/partner/coupons/place
GET  /api/partner/coupons/calculated?time=10

1. 你需要从经理那里得到什么

  • 基本 URL API;
  • 客户帐户登录名和密码;
  • 使用回调时 - 启用该功能和秘密短语 callback_secret

这些示例使用条件地址:

BASE_URL="https://coupon-api.example.com"

在生产中,使用 HTTPS。所有日期都以毫秒为单位的 Unix 时间戳传输,货币值以没有固定精度的十进制数字传输。

2. API响应格式

成功:

{
  "code": 1,
  "body": {},
  "error_code": null,
  "error_message": null,
  "date": 1784970000000,
  "time_ms": 5,
  "path": "/api/partner/example"
}

业务错误通常还伴随HTTP 200

{
  "code": 0,
  "body": null,
  "error_code": 1002,
  "error_message": "Not all params",
  "date": 1784970000000,
  "time_ms": 5,
  "path": "/api/partner/example"
}

始终检查 HTTP 代码,然后是 code,然后是 error_code。请勿使用文本 error_message 作为软件密钥。

3. 授权

POST /api/partner/login
Content-Type: application/json
{
  "username": "partner-demo",
  "password": "strong-password"
}

支持字段 login 作为兼容别名 username

成功响应:

{
  "code": 1,
  "body": {
    "token": "<jwt-token>",
    "user_id": 17,
    "username": "partner-demo"
  },
  "error_code": null,
  "error_message": null
}

在所有受保护的请求中,传递:

Authorization: Bearer <jwt-token>

基本登录错误:

代码原因
1002未发送登录名或密码。
1003未知的登录名或密码不正确。
1004客户帐户已被禁用。
1006访问日期已过期。
1007客户余额为零或负数。

这些错误是从 HTTP 200code = 0 返回的。受保护方法的 HTTP 401 表示 JWT 丢失、无效、过期或撤销;再次登录。 HTTP 403 表示不适当的角色或访问被拒绝。

4. 投注指针

每个选定的结果都作为体育线路中的现成线路传输:

line_type#game_id#group_id#type_id#rate#coefficient[#player_id]

示例:

line#737779544#1#1#0#1.85
live#738917381|119|5869|0.5#3.6#149439538
  • line_typelinelive
  • rate:总/让分参数或0
  • player_id:可选玩家ID;
  • 支持分隔符 #|

不要手动收集或更正指针 - 将从行获得的值保持不变。

5. 优惠券放置

POST /api/partner/coupons/place
Authorization: Bearer <jwt-token>
Content-Type: application/json
{
  "list_bets": [
    "line#737779544#1#1#0#1.85"
  ],
  "amount": 10,
  "currency": "USD",
  "callback_url": "https://partner.example.com/api/coupon-result",
  "lang": "en",
  "mode": "reject",
  "mode_type": null,
  "multi": false
}
领域强制目的
list_bets是的一个或多个指针。
amount是的所创建的一张优惠券的正金额。
currency任何字符串名称,包括虚拟货币。
callback_url网址回调;如果没有回调,则无法发送它,您可以传递 null、空字符串或站点域。
lang大约 50 种受支持语言之一的两个字母代码。名字的语言在创造时就固定下来了。
moderejectaccept;默认reject
mode_type对于accept允许系数变化方向。
multi一张普通优惠券或个人单张;默认false

赔率

设置行为
mode = reject当赔率变化时拒绝创建。
mode = accept, mode_type = 1只接受赔率增加。
mode = accept, mode_type = 2只接受赔率降低。
mode = accept, mode_type = 3接受任何改变。

单打、多重彩和 multi

请求结果借方客户余额
一个结果一张单人amount
多种结果,multi = false1个蓄能器amount
多种结果,multi = true每个结果单独一个amount × 创建优惠券数量

一组累加器序列最多可包含 15 个事件。您不能在同一场比赛中合并多个投注,包括主比赛、半场、赛节、角球、犯规和其他相关子赛事。该组合返回 506

6. 确认优惠券和投注

完整成功响应,包含 events_data 内的优惠券和接受的投注数据:

{
  "code": 1,
  "body": {
    "coupons": [
      {
        "coupon_code": "000000000272",
        "amount": 10,
        "win": 18.5,
        "potential_win": 18.5,
        "real_win": null,
        "coef": 1.85,
        "original_coef": 1.85,
        "calculate_coef": null,
        "has_return": false,
        "date": 1784970000000,
        "status": 0,
        "asian": false,
        "calculate_date": null,
        "coupon_type": 1,
        "events_count": 1,
        "events_data": [
          {
            "id": 912,
            "game_id": 737779544,
            "main_game_id": 737779544,
            "is_sub_game": false,
            "parent_game_id": null,
            "sub_game_key": null,
            "raw_pointer": "line#737779544#1#1#0#1.85",
            "line_type": "line",
            "is_live": false,
            "bet_group_id": 1,
            "bet_group_name": "Match result",
            "bet_id": 1,
            "bet_name": "First team to win",
            "sport_id": 1,
            "sport_name": "Football",
            "tournament_id": 10001,
            "tournament": "National League",
            "event_date": 1784971800000,
            "status": 0,
            "opp1": "Team A",
            "opp2": "Team B",
            "coef": 1.85,
            "calc_coef": null,
            "bet_score": "line#737779544#1#1#0#1.85",
            "calculate_date": null,
            "calculate_score": null,
            "settlement_reason_code": null,
            "settlement_reason": null,
            "placement_score_full": null,
            "placement_score_periods": null,
            "calculation_score_full": null,
            "calculation_score_periods": null,
            "timer": null,
            "dop_name": null,
            "rate": "0",
            "sgame_id": null,
            "game_num": null,
            "stat_id": null,
            "team1_id": 101,
            "team2_id": 102,
            "opp_icon1": 101,
            "opp_icon2": 102
          }
        ]
      }
    ]
  },
  "error_code": null,
  "error_message": null,
  "date": 1784970000015,
  "time_ms": 45,
  "path": "/api/partner/coupons/place"
}

优惠券字段

每件商品 body.coupons[] 都是单独创建的优惠券。

领域类型含义
coupon_codestring公共 12 位优惠券代码。存储为字符串以避免丢失前导零。
amountnumber创建时转移的优惠券金额。
winnumber当前显示的中奖金额。
potential_winnumber最终结算前可能赢得的奖金。
real_winnumber/null计算后的实际支付金额;计算前 - null
coefnumber当前或最终票面利率。
original_coefnumber优惠券创建时的总系数。
calculate_coefnumber/null最终计算系数;计算前 - null
has_returnbooleantrue,如果优惠券包含退款状态的投注。
dateinteger优惠券创建日期,Unix 时间戳(以毫秒为单位)。
statusinteger当前优惠券状态。这些值在“优惠券和投注状态”部分中描述。
asianboolean存在亚洲结算的迹象,包括一半的赢利或损失。
calculate_dateinteger/null优惠券计算日期(以毫秒为单位);计算前 - null
coupon_typeinteger优惠券类型:1 - 普通,2 - 快递。
events_countinteger优惠券内的投注次数。
events_dataarray优惠券中包含完整的投注范围。

投注字段

events_data[] 的每个元素都描述了优惠券中特定的接受投注。

领域类型含义
idinteger/null已接受投注的内部 ID。与 coupon_code 结合使用,在优惠券中查找投注。
game_idinteger下注的赛事或子赛事的 ID。
main_game_idinteger/null赛事或子赛事所属的主比赛ID。
is_sub_gamebooleantrue,如果投注涉及半场、赛节、赛盘、角球或其他子赛事。
parent_game_idinteger/null直接父事件的 ID(如果存在)。
sub_game_keystring/null子事件或周期的技术要点。
raw_pointerstringAPI 接受的原始投注指针。
line_typestring线路类型:line - 赛前,live - 实时赛事。
is_livebooleantrue,如果投注是在实时盘线上创建的。
bet_group_idinteger投注组或市场的ID。
bet_group_namestring/null投注组的本地化名称。
bet_idinteger下注组中所选选项的 ID。
bet_namestring/null所选选项的本地化全名。
sport_idinteger/null运动ID。
sport_namestring/null运动的本地化名称。
tournament_idinteger/null比赛ID。
tournamentstring/null锦标赛的本地化名称。
event_dateinteger/null事件开始日期,Unix 时间戳(以毫秒为单位)。
statusinteger当前投注结算状态。不要与优惠券状态混淆。
opp1string/null第一个团队或参与者的名称。
opp2string/null第二支队伍或参赛者的姓名。
coefnumber接受投注的投注赔率。
calc_coefnumber/null计算的投注乘数;计算前 - null
bet_scorestring旧版 API 兼容字段包含投注指示符而不是比赛得分。
calculate_dateinteger/null投注结算日期(以毫秒为单位);计算前 - null
calculate_scorestring/null用于计算投注的帐户。
settlement_reason_codestring/null结算或退款原因的稳定机器码;计算前 - null
settlement_reasonstring/null结算或退款原因的说明文字;计算前 - null
placement_score_fullstring/null创建投注时的赛事总得分(如果有)。
placement_score_periodsstring/null按创建投注时的时段得分(如果有)。
calculation_score_fullstring/null投注结算时赛事的总得分。
calculation_score_periodsstring/null投注结算时按时段得分。
timerinteger/null数据保存时的事件计时器(如果有)。
dop_namestring/null子赛事名称:半场、赛段、局数、局数等。
ratestring结果参数,例如总分或让分的数值;对于没有参数的结果 - "0"
sgame_idstring/null子事件外键。
game_numinteger/null游戏编号(如果来源提供)。
stat_idstring/null外部统计事件ID。
team1_idinteger/null第一个队伍或参赛者的ID。
team2_idinteger/null第二支队伍或参赛者的ID。
opp_icon1integer/null第一个命令图标的兼容ID;匹配 team1_id
opp_icon2integer/null兼容第二队图标ID;匹配 team2_id

对于尚未计算或不可用的数据,值 null 是正常的。不要自动将其替换为 0 或空字符串。

仅当 code = 1body.coupons 中存在对象时才考虑接受优惠券。在此之前,篮子是一个初步选择:选择可能会消失、被阻止或赔率发生变化。

成功后:

  1. 保存所有 body.coupons 对象,而不仅仅是第一个;
  2. coupon_code 存储为带有前导零的字符串;
  3. events_data中保存所需数据;
  4. 将优惠券与最终用户相匹配;
  5. 在合作伙伴的系统中记录用户的财务交易。

标识符:

领域目的
coupon_code公共优惠券代码。
events_data[].id优惠券内特定接受投注的 ID。
回调 events_data[].uuid相同的投注 ID,作为字符串传递。
batchId回调套餐版本ID,不是优惠券或费率。

完整模型和回调中不返回currency。如果需要货币,请保存创建请求中的值。

7. 创建错误

代码原因行动
10无请求正文。更正请求。
11无效指针。从该行获取当前指针。
12无效 amount传递一个正数。
501胜算已经改变。显示新值或更改 mode
502没有结果。删除/更新购物车中的出价。
503结果被封锁了。报告暂时不可用。
504结果验证错误。不考虑接受优惠券;稍后重复。
506多重彩包含来自同一场比赛的投注。保留一个结果或使用单独的单项。
507客户余额不足。充值您的余额或减少总金额。
1002参数集无效。正确的参数。
10000内部错误。记录错误并在重试之前检查结果。

对于 501504,新 API 返回 body.changes[] 中的有问题的费率。字段change_type1 - 系数已增加,2 - 减少,null - 方向不适用。

超时后不要盲目重试 POST /coupons/place:第一个请求可能已被接受,重试将创建重复的请求。

8. 领取优惠券

操作端点结果
一张优惠券GET /api/partner/coupons/get?coupon_code={code}优惠券位于body
活跃GET /api/partner/coupons/active数组位于 body[]
最近的计算GET /api/partner/coupons/calculated?time=10数组在body[];最多 120 分钟。
按代码/期间POST /api/partner/coupons/results数组位于 body.coupons 中。
客户余额GET /api/partner/balancebody.balance

您可以使用代码传输最多 100 个值:

{
  "coupon_ids": ["000000000272", "000000000273"]
}

或者传递创建周期不超过24小时:

{
  "start_date": 1784880000000,
  "end_date": 1784966400000
}

请勿在同一查询中组合 coupon_ids 和日期。 results 按创建时间过滤,calculated 按最终结算时间过滤。

9. 优惠券和投注状态

优惠券状态:

代码含义决赛
0活跃或部分定居。
2赢了。是的
4迷失了。是的
8全额退款。是的
15返回重新计算;期待新的结果。

投注状态:

代码含义calc_coef
0没有计算。null
1获胜。原始系数
2输了。0
3返回。1
4等待重新计算。null
21奖金的一半。(coef + 1) / 2
22损失一半。0.5
23推。1

对于最终用户的财务应计,请使用现成的 real_win。请勿使用potential_win,也不要自行重新计算支出。计算前,real_wincalculate_coefcalc_coefcalculate_date 等于null,而不是0

在优惠券 15 的第一个状态下,如果先前的结果已进行财务处理,则合作伙伴再次从最终用户处借记 amount,期望新的最终状态并收取新的 real_win。保护操作免受再处理。

10. 计算原因

完整模型和回调中的每个投注都有:

领域目的
settlement_reason_code稳定的结算/退款原因代码。
settlement_reason解释性源文本。

计算前,两个字段均等于null。对于本地化通知,请使用如下代码:

  • MATCH_POSTPONED - 比赛已推迟;
  • MATCH_CANCELLED - 比赛取消;
  • MARKET_PUSH——按照市场规则回报。

如果代码未知,请将其保存并使用非空 settlement_reason 作为后备文本。请勿根据原因 - 使用状态和 real_win 计算支出。

这些字段解释已经执行的计算或返回,并不是比赛状态的单独实时反馈。

11. 回调

回调是可选的。合作伙伴只能通过投票的方式进行工作。对于回调,管理器必须启用该功能并创建callback_secret; URL 会在创建的每张优惠券中发送。

回调URL由合作伙伴自主决定。在生产中应该使用https://;在测试环境中,允许使用http://

系统发送:

POST {callback_url}
Content-Type: application/json
X-Coupon-Signature: sha256=<hex_hmac_sha256>

短有效负载:

{
  "event": "coupons.settled",
  "batchId": "d407e986f3a64d9d36a77bf532322ef8",
  "couponCount": 1,
  "coupons": [
    {
      "coupon_code": "000000000272",
      "realWin": 18.5,
      "calculate_coefficient": 1.85,
      "status": 2,
      "calculate_date": 1784973600000,
      "events_data": [
        {
          "uuid": "912",
          "status": 1,
          "calculate_coefficient": 1.85,
          "calculate_date": 1784973600000,
          "calculate_score": "2:1",
          "settlement_reason_code": "REMOTE_WIN",
          "settlement_reason": "Win",
          "timer": 0
        }
      ]
    }
  ]
}

强制性规则:

  1. 在 JSON 解析之前从正文的确切源字节计算 sha256=<hex(HMAC-SHA256(raw_body, callback_secret))> 并以安全的方式比较签名;
  2. 处理所有商品coupons,包裹最多可包含100张优惠券;
  3. 使用唯一索引存储 batchId
  4. 重复batchId不应重复借记或应计;
  5. 一个coupon_code在渐进计算和重新计算时可以配备不同的batchId
  6. 只有在整个数据包被安全存储后才返回 HTTP 200

最小成功响应是空 HTTP 200。高级:

{
  "success": true,
  "processed": 1
}

processed 必须等于 couponCount。响应 201202204 不被视为成功。

仅在超时、传输错误或 HTTP 500502503504 的情况下执行重播:立即,然后在 1、5、15 和 60 分钟后 - 发送不超过 5 次。对于带有 success: false 或部分 processed 的 HTTP 200 没有自动重试。

12. 轮询回退

即使有回调,也要定期检查结果:

GET /api/partner/coupons/calculated?time=10

休息时间超过 120 分钟后,可在保存的 coupon_ids 或创建时间长达 24 小时内使用 POST /api/partner/coupons/results。再次接收相同的状态不应重复金融交易。

13. 安全和存储

  • 仅在服务器上存储登录名、密码、JWT 和 callback_secret
  • 不要在 URL 中传递 JWT,也不要将完整令牌写入日志中;
  • 使用小数类型表示货币;
  • coupon_code 存储为字符串;
  • 保存amount、所需的投注数据和currency(如果使用);
  • 区分优惠券和投注状态;
  • 接受未知字段和原因代码,不会出现错误;
  • 使所有最终用户金融交易幂等。

14. 旧 API 和提现

继续支持旧路由,但新集成必须使用 /api/partner/**。旧的答案和错误有不同的格式。要更新现有客户端,请使用单个文件“从旧 API 迁移”。

Cashout 正在开发中,尚未经过充分测试,不建议用于生产。

15. 最终清单

  • 收到BASE_URL、登录名和密码。
  • JWT 作为承载令牌传输。
  • 指针取自该行,未经修改。
  • 仅在 code = 1 之后,购物车才会保存为接受的优惠券。
  • 已处理 multi、累加器限制和错误 501507
  • 已考虑客户余额的自动借记。
  • 所有 coupon_code 和投注 ID 均已保存。
  • 最终支出取自real_win
  • 根据源字节检查回调并使用 batchId 进行重复数据删除。
  • 备份轮询已配置。
  • 用户余额与客户余额SportAPI是分开的。

详细文档以API概述开始。完整的端点映射在手册中。

需要更多文档或集成帮助吗?