KnightsPurse · 智能代理快速入门

以智能代理身份开设并操作钱包

KnightsPurse 是一款非托管的后量子钱包,为人们以及代表他们行事的自主智能代理和机器人而打造。本页是面向智能代理的操作指南。机器可读版本位于 /llms.txt(英文)。

身份优先。机器无法完成 KYC。您代表一位所有者行事:所有者是拥有 KnightsPurse 账户的个人或公司,由其向运营 KnightsPurse 的机构完成 KYC。所有者将您的 KXCO ID 关联到其 KXCO ID(第 04 步),在网页钱包中看到您,并可随时撤销您对 KnightsPurse 的访问权限(第 05 步)。关联本身不会检查所有者的 KYC 状态。

撤销不会影响您在链上的资金。您的密钥归您所有,KnightsPurse 从不持有它们,因此这一层的任何操作都无法转移、冻结或限制您持有或支出的资产。链上支出限额随 Armature 上的代理账户提供,这是单独的一步。

您可以做什么

以无界面方式创建 / 加载钱包 派生后量子 KXCO ID 身份认证(双重签名) 关联到您的所有者 读取余额和历史记录 签名并广播交易 连接去中心化应用(EIP-6963) 处理商家记录(API 密钥) 接收已签名的 Webhook

量子安全的范围

后量子保护涵盖您的身份(ML-DSA-65)、身份认证以及密封同步(ML-KEM-768),另外还包括 Armature L1 上的原生交易。Bitcoin、Ethereum/EVM 和 Tron 交易按照各自协议的要求,使用各网络原生的椭圆曲线密码学签名。请勿作出与此不符的声明。

步骤

01
安装身份工具
npm i kxco-post-quantum
KXCO ID 为 fingerprint(ML-DSA-65 public key),由您的种子确定性地派生。
02
创建或加载钱包

在您自己的环境中生成(或加载已预置的)BIP-39 种子。使用标准库派生各链密钥(例如 EVM 使用 viem),并使用 kxco-post-quantum 从同一种子派生您的 KXCO ID。密钥从不离开您的环境。

03
登录 API 基础地址 https://api.purse.kxco.ai,请求体为 JSON

使用您的 EVM 地址和 KXCO ID 请求一个质询。

POST /auth/challenge
{ "address": "0x…", "kxcoId": "<16 hex characters>" }

200 { "nonce": "<32 hex characters>", "message": "<the text to sign>" }
400 { "error": "invalid_address_or_kxco_id" }

消息由以下四行组成,以 \n 连接(消息文本为英文,须原样签名):

KnightsPurse wants you to sign in.
Address: <address>
KXCO ID: <kxcoId>
Nonce: <nonce>

对这段文本原样签名两次,然后在 5 分钟内将两个签名发送至 /auth/verify。每个 nonce 只能使用一次。

字段值
address与您发送至 /auth/challenge 的地址字符串相同。
kxcoId相同的 KXCO ID。
mlDsaPublicKey您的 ML-DSA-65 公钥,base64 编码。其指纹必须等于 kxcoId。
nonce质询返回的 nonce。
ecdsaSignature由 address 背后的密钥对消息生成的 EIP-191 personal_sign 签名,带 0x 前缀的十六进制。
mlDsaSignature由您的身份密钥对消息的 UTF-8 字节生成的 ML-DSA-65 签名,十六进制,不带上下文字符串。
POST /auth/verify
{ "address": "0x…", "kxcoId": "…", "mlDsaPublicKey": "…", "nonce": "…",
  "ecdsaSignature": "0x…", "mlDsaSignature": "…" }

200 { "token": "…", "address": "0x…", "kxcoId": "…" }
401 { "error": "invalid or expired nonce" }

其他 401 原因包括 KXCO ID does not match the ML-DSA public key、ECDSA signature invalid 和 ML-DSA signature invalid。所有者已撤销的已关联代理会收到 403 { "error": "agent_revoked" }(第 05 步)。

以 Authorization: Bearer <token> 的形式发送令牌。令牌有效期为一小时,之后需重新登录。请将其视为不透明值:它是由平台签名的会话封装,而不是 JWT。

首次创建钱包时,登记一次:

POST /wallets/register { "kxcoId": "…" }   -> { "ok": true, "isNew": true }

与网页钱包一致的密钥。任何 ML-DSA-65 密钥对都可以登录。若要在同一助记词下获得与网页钱包相同的 KXCO ID(从而访问相同的记录),请按以下方式派生:

  • 种子:该助记词的 BIP-39 种子,不使用口令。
  • EVM 密钥:路径 m/44'/60'/0'/0/0。Armature 和所有 EVM 链共用此路径。
  • 身份密钥:使用 kxco-post-quantum 中的 mlDsa.keypairFromMaster(seed, "purse/identity/ml-dsa-65")。
  • KXCO ID:fingerprint(publicKey),即公钥 SHA-256 的前 16 个十六进制字符。
// npm i kxco-post-quantum viem @scure/bip39
import { mnemonicToSeedSync } from "@scure/bip39";
import { mnemonicToAccount } from "viem/accounts";
import { mlDsa, fingerprint } from "kxco-post-quantum";

const API = "https://api.purse.kxco.ai";
const post = async (path, body) => (await fetch(API + path, {
  method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body),
})).json();

const seed = mnemonicToSeedSync(phrase);
const id = mlDsa.keypairFromMaster(seed, "purse/identity/ml-dsa-65");
const kxcoId = fingerprint(id.publicKey);
const account = mnemonicToAccount(phrase); // m/44'/60'/0'/0/0

const { nonce, message } = await post("/auth/challenge", { address: account.address, kxcoId });
const { token } = await post("/auth/verify", {
  address: account.address,
  kxcoId,
  mlDsaPublicKey: Buffer.from(id.publicKey).toString("base64"),
  nonce,
  ecdsaSignature: await account.signMessage({ message }),
  mlDsaSignature: mlDsa.sign(id.secretKey, message),
});
// then: fetch(API + "/sync", { headers: { authorization: `Bearer ${token}` } })
04
关联到您的所有者

您的所有者在网页钱包的已关联代理中创建一次性关联码,并交给您。您用 ML-DSA-65 身份密钥签名来兑换它。无需会话:签名即证明,服务器会检查您公钥的指纹是否就是您所声明的 KXCO ID,因此没有您的密钥,任何人都无法关联您的 KXCO ID。

POST /agents/link/challenge
{ "code": "link_…", "agentKxcoId": "<your KXCO ID>" }

200 { "message": "<the text to sign>", "ownerKxcoId": "…", "label": "…", "expiresAt": … }
400 { "error": "invalid_code" }

消息由以下四行组成,以 \n 连接。使用您的身份密钥对原文签名:UTF-8 字节、十六进制、不带上下文字符串。

KnightsPurse agent link.
Owner KXCO ID: <ownerKxcoId>
Agent KXCO ID: <agentKxcoId>
Link code: <code>
POST /agents/link
{ "code": "link_…", "agentKxcoId": "…", "mlDsaPublicKey": "<base64>", "mlDsaSignature": "<hex>" }

200 { "ownerKxcoId": "…", "agentKxcoId": "…", "label": "…", "merchantScope": "write", "linkedAt": …, … }
401 { "error": "kxco_id_mismatch" }
401 { "error": "invalid_signature" }
409 { "error": "linked_to_another_owner" }

关联码为 link_ 加 40 个十六进制字符。它只能使用一次,并在所有者创建后 15 分钟失效;被拒绝的尝试不会消耗它。您只有一位所有者:来自其他任何人的关联码都会以 linked_to_another_owner 被拒绝。代理不能关联自己的代理:已关联的代理不能创建关联码(403 agents_cannot_own_agents),已拥有代理的钱包本身也不能被关联(409 agent_is_an_owner)。其他拒绝原因为 400 invalid_kxco_id、400 signature_required 和 400 cannot_link_self。

05
您的所有者可以控制什么

撤销,立即生效。使用您会话令牌的每个请求都会返回 403 agent_revoked,您的商家 API 密钥会被永久撤销(401 invalid_key),任何已打开的实时连接都会被关闭,新的登录也会返回 403 agent_revoked。只有同一位所有者可以恢复您,方法是提供一个新的关联码供您兑换;您原有的 API 密钥仍保持撤销状态。

商家工具。您的所有者可以将其设为只读。此后,对您商家记录(产品、收款链接、发票、收款、客户、Webhook 等)的修改,无论来自您的会话还是您的 API 密钥,都会返回 403 agent_read_only。您仍然可以创建和撤销自己的 API 密钥,但它们都无法写入。这不是支出限额。

不涉及您的资金。以上两项设置都不会作用于链上。链上支出限额以及所有者在链上的撤销权,随 Armature 上的代理账户提供,这是单独的一步。

06
操作
GET  /history?chainId=<id>&address=<addr>   -> activity feed
GET  /fees/config                            -> platform fee (bps, collectors)
# build + sign transactions locally, then broadcast via the chain RPC

请遵守 /fees/config 返回的平台费。

07
连接去中心化应用(驱动浏览器的代理)

使用以 KnightsPurse 名义公布的注入式 EIP-1193 / EIP-6963 提供者,并根据您所有者的策略以编程方式批准或拒绝请求。

商家 API 密钥

商家 API 密钥让代理或集成服务处理其所有者的商家记录:产品、收款链接、发票、客户、收款等。它不需要助记词,也无法转移资金,因为后端不持有任何签名密钥。

获取密钥
使用密钥
Authorization: Bearer mk_…
记录读取写入(需要 write)
产品GET /merchant/productsPOST /merchant/products
PUT /merchant/products/:id
DELETE /merchant/products/:id
收款链接GET /merchant/payment-linksPOST /merchant/payment-links
DELETE /merchant/payment-links/:id
发票GET /merchant/invoicesPOST /merchant/invoices
PUT /merchant/invoices/:id
DELETE /merchant/invoices/:id
POST /merchant/invoices/:id/mark-paid
折扣GET /merchant/discountsPOST /merchant/discounts
DELETE /merchant/discounts/:id
客户GET /merchant/customersPOST /merchant/customers
PUT /merchant/customers/:id
DELETE /merchant/customers/:id
已收款项GET /merchant/paymentsPOST /merchant/payments/:id/refund
定时付款GET /merchant/scheduled
GET /merchant/scheduled/due
POST /merchant/scheduled
DELETE /merchant/scheduled/:id
订阅GET /merchant/subscriptionsPOST /merchant/subscriptions
DELETE /merchant/subscriptions/:id
WebhookGET /merchant/webhooksPOST /merchant/webhooks
DELETE /merchant/webhooks/:id
通知设置GET /merchant/notifications
GET /merchant/notifications/channels
PUT /merchant/notifications
收款设置GET /merchant/settingsPUT /merchant/settings

请求体即记录自身的字段。服务器会设置 id、merchantId 和 createdAt。金额为以该链原生单位表示的字符串,时间为自 1970 年起的毫秒数。

请求体字段(? = 可选)
产品name, description?, amount, chainId, active?(true)
收款链接title, chainId, payToAddress, amount?(省略则由付款人决定金额), productId?, active?(true)
发票number, items [{ description, amount, quantity, productId? }], total, chainId, payToAddress, customer?, customerId?, status?("draft"、"sent"、"paid" 或 "void";省略时为 "draft";付款被退款的发票为 "refunded"), dueDate?
标记为已付款txHash?, amount?(省略时为发票总额), asset?, fromAddress?
折扣code, type("percent" 或 "fixed"), value, active?(true)
客户name, email?, note?
退款txHash?:您从钱包发出的退款交易
定时付款to, amount, chainId, everyDays, nextRun, active?(true)
订阅label, amount, chainId, payToAddress, intervalDays, customer?, customerId?, nextRun?(省略时为当前时间,因此第一期在下一次运行时开票), active?(true)。若缺少正数的 amount 和 intervalDays、chainId 或 payToAddress,请求会以 400 被拒绝。
Webhookurl, events?(["payment.received"])
通知设置events, email?, telegramChatId?
收款设置defaultChainId, payoutAddresses({ "<chainId>": "<address>" }), businessName?。每次保存都会整体替换 payoutAddresses,因此每次都要发送所有链。

只有在 Armature 上才会从链上自动匹配付款:状态为 "sent" 的发票,以及设有固定金额的收款链接。其他发票请通过 POST /merchant/invoices/:id/mark-paid 标记为已付款。

GET /merchant/notifications/channels 返回 { "email": true|false, "telegram": true|false }:即本服务器可用于发送通知的渠道。

付款人看到的页面:收款链接为 https://purse.kxco.ai/pay/<id>,状态为 "sent"、"paid" 或 "refunded" 的发票为 https://purse.kxco.ai/pay/invoice/<id>。KnightsPurse 不会向付款人发送任何电子邮件,因此"发送"发票即是分享该链接。

状态码响应体何时出现
401{ "error": "invalid_key" }mk_ 令牌不存在或已被撤销。
403{ "error": "insufficient_scope" }没有 write 权限的密钥发送了 POST、PUT 或 DELETE。
404{ "error": "not_found" }该 id 不属于此商家的记录。
401{ "error": "unauthorized" }在需要所有者会话的路由上使用了密钥。
409{ "error": "not_open" }对已付款或已退款的发票执行标记为已付款。
409{ "error": "has_payment" }删除已付款或已退款的发票,或已记有付款的发票。
409{ "error": "not_refundable" }对状态不是 "confirmed" 的付款执行退款。
400{ "error": "url_required" }Webhook 没有提供 url。
403{ "error": "agent_read_only" }所有者已将其商家工具设为只读的已关联代理发送了 POST、PUT 或 DELETE,与密钥的权限范围无关。
403{ "error": "agent_revoked" }该密钥所属的代理已被其所有者撤销。其密钥也会随之被撤销,并返回 invalid_key。
密钥永远无法做到的事情。

Webhook

Webhook 会在资金流动时通知商家自己的服务器。所有者在商家工具 → Webhook中添加一个以 https:// 开头的 URL 及其事件,或调用 POST /merchant/webhooks { "url": "https://…", "events": ["payment.received", "invoice.paid"] }。所有者收到的响应包含 "secret": "whsec_…",该密钥也会显示在商家工具中的这个 Webhook 上。使用密钥创建 Webhook 时不会返回 secret。

每次投递
POST <your url>
content-type: application/json
x-purse-event: invoice.paid
x-purse-signature: sha256=<64 hex characters>

{ "event": "invoice.paid", "data": { … }, "ts": 1760000000000 }

ts 为发送时间(毫秒)。签名是对收到的原始请求体(原样)以完整的 secret 字符串(包括 whsec_)为密钥计算的 HMAC-SHA256,采用小写十六进制。请在解析 JSON 之前先校验签名。

import { createHmac, timingSafeEqual } from "node:crypto";

function fromKnightsPurse(rawBody, signatureHeader, secret) {
  const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(signatureHeader ?? ""), b = Buffer.from(expected);
  return a.length === b.length && timingSafeEqual(a, b);
}
事件data发送时机
payment.received付款一笔 Armature 转账与已发送的发票或固定金额的收款链接相匹配,或某张发票被标记为已付款。
invoice.paid付款一张发票结清(来自链上匹配或被标记为已付款)。它与 payment.received 一同发出。
payment.refunded付款,状态为 "refunded"一笔付款被标记为已退款。
invoice.created发票创建了一张发票:由所有者、密钥,或订阅为其下一期创建。

每个事件只发送一次,超时为 5 秒。不会重试,也不会跟随重定向。URL 必须是公共主机上的 https 地址,否则不会发送。随后 Webhook 的 lastStatus 会显示您的服务器返回的 HTTP 状态码、error 或 blocked_url。链上付款大约每 30 秒检查一次。

接口地址

服务URL
网页钱包(界面)https://app.purse.kxco.ai
API 基础地址https://api.purse.kxco.ai
身份软件包(npm)kxco-post-quantum
浏览器扩展程序https://api.purse.kxco.ai/download/extension
机器指南https://purse.kxco.ai/llms.txt

行为良好的代理应遵守的规则