调用钉钉`创建并投放卡片`API失败,返回space of card is empty.

阿里云服务器

这个错误 space of card is empty 是钉钉开放平台在 2023-2024 年架构升级 后引入的典型错误。

🔴 错误原因

钉钉现在的卡片消息机制发生了重大变化:卡片模板(Card Template)不再内嵌在 API 请求的 JSON body 中,而是必须预先在钉钉后台创建好,并获得一个唯一的 cardKey

  • 旧模式:发送消息时,把整个卡片的 JSON 结构(标题、按钮、布局)直接发给接口。

  • 新模式

    1. 先在钉钉开发者后台设计卡片,生成模板,拿到 cardKey

    2. 调用 API 时,只需传入这个 cardKey 和动态数据 (cardData)。

    3. 如果你还在用旧模式(请求体里没有 cardKey,或者 cardKey 为空),服务端解析不到模板标识,就会报 space of card is empty


✅ 解决方案 (三步走)

第一步:在钉钉后台创建卡片模板

  1. 登录 钉钉开发者后台

  2. 进入你的应用详情 -> “卡片管理” (或“互动卡片”)。

  3. 点击 “创建卡片” -> 选择 “代码编辑”“可视化编辑”

  4. 设计好你的卡片布局(标题、文本、按钮等)。

  5. 发布/保存 后,你会获得一个 cardKey (通常格式如 sample_card_key_xxxxx 或自定义的字符串)。

    • 注意:记下这个 cardKey,后面要用。

第二步:修改 API 调用代码

你需要将请求体从“直接写死卡片结构”改为“引用 cardKey + 传入动态数据”。

❌ 错误的请求体 (旧模式,会导致该报错):

{
  "msgKey": "sampleCard",
  "msgParam": {
    "type": "card",
    "card": {  // <--- 这里直接放卡片结构是错误的
      "type": "markdown",
      "title": "...",
      "content": "..."
    }
  }
}

✅ 正确的请求体 (新模式):
假设你调用的接口是 /v1.0/robot/oToMessages/send (机器人发送) 或 /v1.0/im/agents/messages/send (工作通知)。

{
  "msgKey": "sampleCard", 
  "msgParam": {
    "cardKey": "你的_cardKey_在这里",  // <--- 核心:填入后台创建的 cardKey
    "cardData": {                      // <--- 核心:只传动态变量
      "title": "报警通知",
      "content": "服务器 CPU 使用率过高",
      "btnText": "查看详情",
      "url": "http://example.com"
    }
  },
  "receiverIds": ["用户 ID 或 群聊 ID"]
}
  • cardKey: 必须与后台创建的完全一致。

  • cardData: 这是一个 JSON 对象,里面的字段名必须与你卡片模板中定义的 变量名 (Variable Name) 一一对应。例如模板里写的是 ${title},这里 key 就是 title

第三步:检查权限与发布状态

  1. 卡片是否发布:确保卡片模板在后台状态是 “已发布” (Published),如果是“草稿”状态,API 可能无法读取。

  2. 应用权限

    • 如果是群机器人:确保机器人已添加到群,且卡片模板权限对机器人可见。

    • 如果是工作通知:确保接收用户在应用的可见范围内。

  3. 版本匹配:确认你调用的 API 版本支持互动卡片。

    • 推荐接口:POST /v1.0/im/agents/messages/send (工作通知) 或 POST /v1.0/robot/oToMessages/send (群机器人)。


🐍 Python 代码示例 (修正版)

import requests
import json

# 配置信息
ACCESS_TOKEN = "你的 access_token"
CARD_KEY = "sample_card_key_12345"  # 【关键】从钉钉后台获取

# 动态数据 (必须与卡片模板中的变量名一致)
card_data = {
    "title": "系统告警",
    "content": "OpenClaw 检测到异常流量",
    "time": "2026-02-26 12:00:00",
    "btn_url": "https://www.aliyun.com"
}

# 请求体
payload = {
    "msgKey": "sampleCard", # 这里的 msgKey 通常固定为 sampleCard 或你在后台配置的 Key
    "msgParam": {
        "cardKey": CARD_KEY,  # 【关键】填入 cardKey
        "cardData": json.dumps(card_data) # 注意:部分接口要求 cardData 是 JSON 字符串,部分是对象,视具体接口文档而定
    },
    "receiverIds": ["群聊 ID 或 用户 ID"]
}

# 如果接口要求 cardData 是字符串,则上面用 json.dumps()
# 如果接口要求 cardData 是对象,则直接传 card_data 对象
# 钉钉新版接口通常建议 cardData 为对象,但为了兼容,有时需序列化,请查阅具体接口文档
# 修正:大多数 v1.0 接口 msgParam 整体是个对象,cardData 也是对象
payload_correct = {
    "msgKey": "sampleCard",
    "msgParam": {
        "cardKey": CARD_KEY,
        "cardData": card_data 
    },
    "receiverIds": ["chatId123"]
}

url = "https://api.dingtalk.com/v1.0/robot/oToMessages/send" # 以机器人为例
headers = {
    "x-acs-dingtalk-access-token": ACCESS_TOKEN,
    "Content-Type": "application/json"
}

response = requests.post(url, headers=headers, data=json.dumps(payload_correct))

print(response.status_code)
print(response.text)

💡 快速自查清单

  1. 我是否在钉钉后台创建了卡片模板

  2. 我是否复制了正确的 cardKey 到代码中?

  3. 我的 cardData 里的字段名是否与模板里的 ${变量名} 完全一致?

  4. 卡片模板是否已经点击了 “发布”

  5. 我调用的 API 接口是否是 v1.0 新版本接口?(旧版 send 接口可能不支持新卡片)

只要补上 cardKey 并确保模板已发布,这个 space of card is empty 错误就会立即消失。