目录

开发者文档

开放接口文档

阳28开放平台提供免费、只读的开奖数据面(加拿大28)。覆盖开奖与倒计时、Keno 源数据、已开 / 遗漏 / 长龙、四维人工智能预测,以及公开算法大厅与详情。HTTPS only,需 API Key;数据面读 Redis 缓存。个人 Key 无账号配额、不限流;门户 Demo Key 按 IP 软限流。短路径与旧开放面对齐。

Base URL
https://yu28.top
鉴权
X-Api-Key / Bearer
格式
JSON(可改 .xml)
时区
北京时间展示
费用
免费,无配额
限流
个人 Key 不限流

提供

  • 最近 N 期 / 按期号单期,含下期倒计时(加拿大28)
  • Keno 二十码源数据
  • 当日已开统计(带 date)、遗漏与长龙(期号版本)
  • 单双 / 大小 / 双组 / 杀组预测
  • 公开算法列表与命中摘要(展示序号 id)

不提供

  • 算法公式 steps / 私密说明
  • 投注、资金、会员账本
  • 站内会话接口 /bff/*
  • 探活 /api/health(公网不开放)

接口一览

12 个端点与 开放接口门户 一一对应。路径为短码(兼容旧开放面),不是 REST 资源名。所有数据接口均为 GET。

接入约定

下列语义已与现网对齐。对接时按此实现,不要按字段名猜测。

约定说明
nbr 两种含义/api/kj、/api/keno、四维预测:条数,1–100,省略为 1。/api/qh:期号,必填正整数。两种含义不要混用。
game不传、传 pc28、或任何未知值,一律按加拿大28;未知值不返回 400。例外:game=hx28(大小写不限)→ 400 VALIDATION(哈希28已下线)。Keno 为加拿大28 二十码。
参数对错非法条数、非法期号、缺失/非法算法 id、未知 category → 400 VALIDATION,不会改成默认值。未知 sort 回落到近 20 或近 100 期胜率降序(看 window)。非法 page / pageSize 回落为 1 / 20;pageSize 上限 50。
开奖串/api/kj 的 number 是三位和式,如 1+8+3=12。预测接口把式子与和值拆开:number 为 1+8+3,num 为 12。
待开空值预测接口待开用 JSON null。算法详情 records 待开行用空串 "",hit 仍为 null。两套不要混判。
期号类型开奖 / 预测 / 长龙起止期号均为字符串。大厅算法 id 为数字(展示序号,不是 UUID)。
长龙 status中文文案,现网为「进行中」「已断开」。按字符串比较,不要当稳定枚举码。
时间开奖 time 为北京时间字符串,如 2026-07-31 11:25:00,不是 ISO 8601 UTC。
路径后缀.json、无后缀(JSON)或 .xml。其它后缀 404 NOT_FOUND。成功才按后缀返回 XML;出错 body 始终是 JSON。XML 里 JSON null 写成空标签(如 <number/>)。

AI 读版

AI 对接请直接读 Markdown 契约,不要爬本页 HTML。

一键提示词

请阅读 https://yu28.top/developers/open-api.llms.md
按其中的白名单路径、鉴权,以及「推荐连接与读取」,用我的 YU28_API_KEY 写对接代码。
跟开奖复用同一个 HTTP 客户端,只读 /api/kj.json?nbr=1,期号变化才算新开奖。
不要依赖 /bff/*;算法 id 用展示序号而非 UUID。
nbr 在 kj/keno/预测是条数,在 qh 是期号。
用 PHP 时:命令行 + curl 扩展,一个句柄复用;不要 file_get_contents,不要 Composer,不要 curl_close,不要放进网页请求。

快速开始

  1. 1在 /app?tab=api 生成 Key(明文只显示一次,请立刻保存)
  2. 2请求头携带 X-Api-Key: yu28_…,不要把个人 Key 放进 URL
  3. 3拉取 /api/kj.json?nbr=1 验证连通

cURL

curl -sS -H "X-Api-Key: $YU28_API_KEY" \
  "https://yu28.top/api/kj.json?nbr=1"

JavaScript

const res = await fetch("https://yu28.top/api/kj.json?nbr=1", {
  headers: { "X-Api-Key": process.env.YU28_API_KEY },
});
const body = await res.json();
if (!res.ok) throw new Error(body?.error?.message ?? res.statusText);

Python

import os, requests

r = requests.get(
    "https://yu28.top/api/kj.json",
    params={"nbr": 1},
    headers={"X-Api-Key": os.environ["YU28_API_KEY"]},
    timeout=15,
)
r.raise_for_status()
print(r.json())

PHP

命令行即可,用系统自带的 curl 扩展,不必安装 Composer。不要用 file_get_contents:很多主机 allow_url_fopen 是关的。已开 / 遗漏里的数字键(JSON "10")用 $row["10"] 或 $row[10] 都能读到。不要调用 curl_close:PHP 8.5 起会报弃用,句柄离开作用域会自己释放。

<?php
// YU28_API_KEY=yu28_… php kj.php
// 不要用 file_get_contents:很多主机 allow_url_fopen 是关的,也带不上稳定请求头。

$key = getenv("YU28_API_KEY");
$ch = curl_init("https://yu28.top/api/kj.json?nbr=1");
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => ["X-Api-Key: " . $key, "Accept: application/json"],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 15,
    CURLOPT_USERAGENT => "yu28-php",
]);
$raw = curl_exec($ch);
$status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($raw === false) {
    fwrite(STDERR, "网络失败\n");
    exit(1);
}
$body = json_decode($raw, true);
if ($status !== 200) {
    $message = (is_array($body) && isset($body["error"]["message"]))
        ? $body["error"]["message"]
        : $raw;
    fwrite(STDERR, $message . "\n");
    exit(1);
}
print_r($body);
跟开奖的节奏见下一节「连接与读取」。算法链路:先 /api/dt 拿展示序号 id,再调 /api/sf?id=。已知期号用 /api/qh?nbr=,不要用 /api/kj 的条数参数去查期号。

连接与读取

加拿大28大约每 3.5 分钟一期。跟开奖时复用同一个 HTTPS 客户端,平时只读 /api/kj.json?nbr=1,用期号判断有没有新开奖。

推荐连接

  • 只发 GET https://yu28.top/api/…。整个进程共用一个客户端(Python 用 requests.Session;PHP 在命令行里 curl_init 一次,循环中只改 URL、不要 curl_close)。不要每次新建客户端。PHP 跟开奖不要放进网页请求,请求结束连接就断了。
  • 请求头 X-Api-Key(Authorization: Bearer 也可以)。个人 Key 放环境变量,不要放进 URL,也不要写进前端仓库。
  • 路径用 .json,不写后缀同样是 JSON。超时大约 10 秒。
  • 400 / 401 是参数或 Key 有误,改完再调。503 或网络失败隔几秒再试。不需要 Cookie,也不要调用 /bff/*。

推荐读取

  • data[0] 是最新一期。nbr 是字符串期号,和本地记下的不同才是新开奖;比较大小时先转成整数。
  • number 是三位和式(如 1+8+3=12),time 是北京时间。
  • countdown 是距下一次理论开奖的剩余时间(mm:ss 或 hh:mm:ss)。还剩超过 15 秒时,睡到大约还剩 10 秒再读,单次最多睡 20 秒,用来对齐时钟,不必每秒请求。
  • 最后 15 秒大约每秒读一次,直到 nbr 变化。countdown 变成 00:00 时,新期号通常还要几秒才出现,这几秒里期号仍是上一期。
  • 到点后紧跟大约 20 秒,期号仍没变,就改成每 15 秒读一次。每日维护空档会停在 00:00 较久,不要一直每秒打。
  • 期号前进之后,再按需拉 /api/yk、/api/yl、/api/cl。已经知道期号时用 /api/qh.json?nbr=期号(这里的 nbr 是期号)。补历史用 nbr=条数(最多 100),不要用 nbr=1 连打。
  • 算法先 /api/dt 取展示序号,再 /api/sf?id=,不必每期都拉大厅。

跟开奖(Python)

import os, time, requests

s = requests.Session()
s.headers["X-Api-Key"] = os.environ["YU28_API_KEY"]
last = None
unchanged = 0

def seconds(text):
    parts = text.split(":") if text else []
    if not parts or any(not p.isdigit() for p in parts):
        return None
    nums = [int(p) for p in parts]
    if len(nums) == 2:
        return nums[0] * 60 + nums[1]
    if len(nums) == 3:
        return nums[0] * 3600 + nums[1] * 60 + nums[2]
    return None

while True:
    try:
        r = s.get(
            "https://yu28.top/api/kj.json",
            params={"nbr": 1},
            timeout=10,
        )
    except requests.RequestException:
        time.sleep(5)
        continue
    if r.status_code in (400, 401):
        raise SystemExit(r.text)
    if r.status_code != 200:
        time.sleep(5)
        continue
    body = r.json()
    row = body["data"][0]
    if row["nbr"] != last:
        print(row["nbr"], row["time"], row["number"], row["combination"])
        last = row["nbr"]
        unchanged = 0
        # 新期到了再按需请求 /api/yk /api/yl /api/cl
    else:
        unchanged += 1
    left = seconds(body.get("countdown") or "")
    if left is not None and left > 15:
        time.sleep(min(20, left - 10))
    elif unchanged < 20:
        time.sleep(1)
    else:
        time.sleep(15)

跟开奖(PHP,命令行)

保存为 follow.php 后执行 php follow.php。网页里每次请求都会结束,不能用来跟开奖。

<?php
// YU28_API_KEY=yu28_… php follow.php
// 不要放进网页请求:执行时间有上限,结束即断开。

$key = getenv("YU28_API_KEY");
if ($key === false || $key === "") {
    fwrite(STDERR, "请设置环境变量 YU28_API_KEY\n");
    exit(1);
}

$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => ["X-Api-Key: " . $key, "Accept: application/json"],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_TCP_KEEPALIVE => 1,
    CURLOPT_USERAGENT => "yu28-php",
]);
$last = null;
$unchanged = 0;

function yu28_seconds($text) {
    if (!is_string($text) || $text === "") {
        return null;
    }
    $parts = explode(":", $text);
    foreach ($parts as $part) {
        if ($part === "" || !ctype_digit($part)) {
            return null;
        }
    }
    $nums = array_map("intval", $parts);
    if (count($nums) === 2) {
        return $nums[0] * 60 + $nums[1];
    }
    if (count($nums) === 3) {
        return $nums[0] * 3600 + $nums[1] * 60 + $nums[2];
    }
    return null;
}

while (true) {
    curl_setopt($ch, CURLOPT_URL, "https://yu28.top/api/kj.json?nbr=1");
    $raw = curl_exec($ch);
    if ($raw === false) {
        sleep(5);
        continue;
    }
    $status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    if ($status === 400 || $status === 401) {
        fwrite(STDERR, $raw . "\n");
        exit(1);
    }
    if ($status !== 200) {
        sleep(5);
        continue;
    }
    $body = json_decode($raw, true);
    if (!is_array($body) || !isset($body["data"][0])) {
        sleep(5);
        continue;
    }
    $row = $body["data"][0];
    if ($row["nbr"] !== $last) {
        echo $row["nbr"], " ", $row["time"], " ", $row["number"], " ", $row["combination"], "\n";
        $last = $row["nbr"];
        $unchanged = 0;
        // 新期到了再按需请求 /api/yk /api/yl /api/cl(继续用 $ch,只改 URL)
    } else {
        $unchanged += 1;
    }
    $left = yu28_seconds($body["countdown"] ?? "");
    if ($left !== null && $left > 15) {
        sleep(min(20, $left - 10));
    } elseif ($unchanged < 20) {
        sleep(1);
    } else {
        sleep(15);
    }
}

鉴权与 Key

Key 形态为 yu28_ + 16 位十六进制;每账号最多 5 个有效 Key。生产环境请放在请求头,勿写入前端公开仓库。

GET /api/kj.json?nbr=1 HTTP/1.1
Host: yu28.top
X-Api-Key: yu28_你的密钥

# 等价
Authorization: Bearer yu28_你的密钥
  • 个人 Key 禁止放在 URL ?key= 或 ?api_key=(二者同等;仅门户 Demo Key 可用 query)。误传个人 Key 会 401
  • 个人 Key 数据面不限流、不配额计费。Demo Key 按 IP 每分钟最多 60 次,超出 429 RATE_LIMIT
  • 管理入口:用户中心 / 接口管理

响应格式

本文示例一律 JSON。成功 HTTP 200;路径加 .json 或省略后缀(默认 JSON)。字段为驼峰 / 短英文键。

需要 XML 时把后缀改成 .xml(如 /api/kj.xml)。字段语义与 JSON 相同,仅序列化不同:根节点 <response>,数组元素多为 <item>;已开/遗漏里纯数字键写成 <k_10>(JSON 仍为 "10")。出错时 body 仍是 JSON,与后缀无关。

错误处理

失败时 HTTP 为 4xx / 5xx,body 始终为 JSON(含请求 .xml 时):

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "无效的 API Key"
  }
}
HTTPcode含义
400VALIDATION参数无效:非法条数 / 期号、缺失或非法算法 id、未知 category、game=hx28(哈希28已下线)
401UNAUTHORIZED缺少或错误的 Key,或把个人 Key 放进了 URL
404NOT_FOUND期号不存在、算法不存在或未公开、路径后缀不是 json/xml
429RATE_LIMIT仅 Demo Key:同一 IP 每分钟超过 60 次
503UNAVAILABLE / OPENAPI_UNAVAILABLE对应数据面未就绪,或开放 Key 服务未启用

开奖数据

/api/kj

最近 N 期开奖(最新在前)。此处 nbr 是条数,不是期号。省略为 1;写出则须为 1–100 的正整数,否则 400。未知 game 按加拿大28;game=hx28 → 400 VALIDATION(哈希28已下线)。

GET /api/kj.json?nbr=3

{
  "countdown": "02:40",
  "data": [
    {
      "nbr": "3463701",
      "time": "2026-07-31 11:25:00",
      "number": "4+8+2=14",
      "combination": "小双"
    }
  ]
}
字段说明
countdown相对最新一期的下期倒计时,形如 02:40;未知可能为空串
data[].nbr期号(字符串)
data[].time开奖时间,北京时间
data[].number三位和式,如 4+8+2=14
data[].combination大小单双组合文案,如 小双

按期号查开奖

/api/qh

按期号取单期;字段与 /api/kj 单条一致。此处 nbr 是期号,必填正整数;缺参 400,查无 404。countdown 始终相对当前最新一期,不是所查那一期。

GET /api/qh.json?nbr=3463701

{
  "countdown": "02:40",
  "data": [
    {
      "nbr": "3463701",
      "time": "2026-07-31 11:25:00",
      "number": "4+8+2=14",
      "combination": "小双"
    }
  ]
}

Keno 开奖源数据

/api/keno

最近 N 期 Keno 二十码(加拿大28)。nbr 与 /api/kj 相同,表示条数。game=hx28 → 400 VALIDATION(哈希28已下线)。

GET /api/keno.json?nbr=1

{
  "data": [
    {
      "nbr": "3463701",
      "time": "2026-07-31 11:25:00",
      "nbrs": "1,4,7,9,20,23,25,26,27,31,38,39,49,52,54,56,58,62,72,74"
    }
  ]
}

nbrs:20 个号码,逗号分隔、无空格。time 为源日期与时刻拼接(如 2026-07-31 11:25:00),不是 ISO。

已开统计

/api/yk

当日已开次数(北京日历日)。date 为该份次数所属日;data 为扁平 map(数字键 / 玩法文案键)。大+小约等于该日已开期数。客户端须核 date,隔日包勿当今日。

GET /api/yk.json

{ "date": "2026-08-30", "data": { "10": 8, "大": 102, "小单": 48 } }

遗漏

/api/yl

data 扁平 map,值为遗漏期数;没有 date(以期号为版本)。

GET /api/yl.json

长龙

/api/cl

当前长龙列表。现网含进行中与已断开;status 为中文文案(「进行中」「已断开」),不要当机器枚举码。

GET /api/cl.json

{
  "data": [
    {
      "type": "周期",
      "content": "单双",
      "status": "进行中",
      "count": 8,
      "start": "3463693",
      "current": "3463700"
    }
  ]
}
字段说明
type / content长龙类型与玩法内容(中文)
status状态文案
count连续期数
start / current起始 / 当前期号(字符串)

人工智能·单双

/api/ds

四维路径:/api/ds(单双)· /api/dx(大小)· /api/sz(双组)· /api/sha(杀组)。nbr 为条数(最近 N 条,含待开期),规则同 /api/kj。

GET /api/ds.json?nbr=10

{
  "data": [
    {
      "nbr": "3466878",
      "predict": "双",
      "number": null,
      "num": null,
      "result": null,
      "hit": null
    },
    {
      "nbr": "3466877",
      "predict": "单",
      "number": "1+2+3",
      "num": "6",
      "result": "单",
      "hit": true
    }
  ]
}
字段说明
predict预测文案(杀组为组合名,不含「杀」前缀)
number / num已开:开奖串(无和值)/ 和值字符串;待开:均为 null
result开奖维度结果:单双取组合第二字,大小取第一字,双组/杀组为完整组合;待开 null
hittrue / false / null(待开)

人工智能·大小

/api/dx

字段与 /api/ds 相同;predict / result 为大小维度。

GET /api/dx.json?nbr=10

人工智能·双组

/api/sz

字段与 /api/ds 相同;predict / result 为双组组合文案。

GET /api/sz.json?nbr=10

人工智能·杀组

/api/sha

字段与 /api/ds 相同;predict 为组合名(不含「杀」前缀)。

GET /api/sha.json?nbr=10

算法大厅

/api/dt

公开算法排序列表。返回的 id 是主站展示序号(如 #909),不是 UUID。未知 category 返回 400;未知 sort 回落到近 20 期胜率降序,响应里的 sort 是服务端实际键。

参数说明
sort别名 rate_desc / rate_asc 配合 window;或直接 rate20_desc / rate20_asc / rate100_desc / rate100_asc / streak_desc / miss_desc / created_desc / favorites_desc / max_streak_desc / max_miss_desc。未知值回落到近窗胜率降序。主序相同时按大厅复合次序(连挂再按近20胜率升序,胜率再按近100/连中/收藏/#no)
window / nbr胜率窗口只认 20 或 100(默认 20)。大厅的 nbr 是窗口别名,不是条数
page / pageSize页码从 1;pageSize 默认 20、上限 50。非法值回落默认,不 400
category可选:big_small / odd_even / combo_predict / kill_group / double_group;未知 → 400
q可选关键词(名称等)
game未知值忽略(加拿大28);hx28 → 400 VALIDATION(哈希28已下线)
GET /api/dt.json?sort=rate_desc&window=20&pageSize=5

{
  "items": [
    {
      "id": 909,
      "name": "组合440",
      "category": "combo_predict",
      "author": "昵称",
      "hit20": "20/20",
      "hit100": "86/100",
      "streak": 24,
      "miss": 0,
      "maxStreak": 24,
      "maxMiss": 2
    }
  ],
  "page": 1,
  "pageSize": 5,
  "total": 8222,
  "category": null,
  "sort": "rate20_desc"
}

hit20 / hit100 为命中比(命中率 = 分子÷分母);author 为昵称,可能为 null。响应 sort 是服务端实际键。

算法详情

/api/sf

id 必填(该彩展示序号,可带 #)。不存在或未公开 → 404。在大厅字段上增加预测与近窗记录,不含公式。predict / predictNbr 在尚无下期预测时为 null。

  • records:最多 100 条已开 + 可选待开一行(插在最前)
  • 已开 number 为三位和式(与 /api/kj 相同,如 1+8+3=12);待开行 time / number 为空串,hit 为 null
GET /api/sf.json?id=909
可先调 /api/dt 取 id,再调本接口。