开发者文档

API 参考

完整的接口说明、参数定义与代码示例——三行代码即可完成首次调用

Quantum Accounting Engine - API Reference

引擎版本:0.1.0

本文档为量子财务引擎的完整 API 参考,随引擎源码同步更新。

快速开始:本引擎是一个 量子会计 API 开放平台。只需:

  1. openentry.top 注册账号
  2. 创建 API Key
  3. 用 API Key 调用下方接口

所有接口均使用 API Key 鉴权X-API-Key Header 或 body 字段)。


目录


🔓 公开 API · 量子分录 (Quantum)

第三方开发者的主调用入口。使用 API Key 鉴权。

生成量子分录

POST /api/v1/quantum/generate
Content-Type: application/json

API Key 传入方式(任选其一)

  1. 请求体字段{ "api_key": "qa_xxx_yyy", ... }
  2. HTTP HeaderX-API-Key: qa_xxx_yyy(适用于不想把 Key 放入 body 的场景)

两者都提供时,请求体优先。

请求体

{
  "api_key": "qa_abc123_xxxxxxxxxxxxxxxxxxxx",
  "from_entity": "A公司",
  "to_entity": "B公司",
  "responsible_entity": "C公司",
  "from_container": "仓库1",
  "to_container": "仓库2",
  "from_container_owner_entity": "A公司",
  "to_container_owner_entity": "B公司",
  "transaction_amount": 10000.00,
  "non_transaction_amount": 500.00
}

金额路径说明:API 调用时只需关注 transaction_amount

  • transaction_amount ≠ 0 → 走交易路径(权责业务),使用交易金额
  • transaction_amount = 0 → 走非交易路径(非权责业务),使用非交易金额

non_transaction_amount 仅在 transaction_amount = 0 时生效,可以不传递(默认为 0)。

用户端边界控制建议: 引擎遵循简单规则:交易金额 ≠ 0 走交易路径,交易金额 = 0 走非交易路径。以下行为矩阵供用户端自行控制

正确行为矩阵: | 状态 | 交易金额 | 非交易金额 | 行为 | 说明 | |------|----------|------------|------|------| | 非结存态 | = 0 | ≠ 0 | ✅ 正常 | 非权责业务,使用非交易金额 | | 非结存态 | ≠ 0 | = 0 | ✅ 正常 | 权责业务,使用交易金额 | | 结存态 | = 0 | = 0 | ✅ 正常 | 结存态调拨,后续成本核算填充 | | 结存态 | = 0 | ≠ 0 | ✅ 正常 | 结存态非权责业务 | | 结存态 | ≠ 0 | = 0 | ✅ 正常 | 结存态权责业务 | | 结存态 | ≠ 0 | ≠ 0 | ✅ 正常 | 结存态权责+非权责业务 |

用户端应避免的错误场景: | 状态 | 交易金额 | 非交易金额 | 错误原因 | |------|----------|------------|----------| | 非结存态 | = 0 | = 0 | ❌ 无业务意义,生成0值凭证无价值 | | 非结存态 | ≠ 0 | ≠ 0 | ❌ 非结存态下两者不能同时非0,引擎会忽略非交易金额 |

建议用户端在调用前进行校验

  • 非结存态:确保 transaction_amountnon_transaction_amount 二选一(不能同时为0,不能同时非0)
  • 同一主体内部业务:确保 transaction_amount = 0
  • 结存态:金额任意,后置成本核算填充

隐私保护架构(推荐开发者使用):为保护用户数据隐私,建议开发者设计如下架构:

用户输入(真实数据)→ 系统生成临时映射表 → 转换为占位符调用引擎 → 引擎返回占位符凭证 → 逆向映射还原真实凭证

实现流程

  1. 用户输入真实数据from_entity: "A公司", to_entity: "B公司", transaction_amount: 10000
  2. 系统生成临时映射表(HashMap,内存中,不持久化):
    • 主体/容器:相同真实值 → 相同占位符(如 "A公司" → "A")
    • 金额:根据业务类型转换为 1 或 0(不传真实金额)
  3. 转换为占位符调用引擎from_entity: "A", to_entity: "B", transaction_amount: 1
  4. 引擎返回占位符凭证
  5. 系统逆向映射还原真实凭证返回给用户

占位符建议: | 字段 | 占位符 | 映射示例 | |------|--------|----------| | 转出主体 | A | "A公司" → A | | 转入主体 | B | "B公司" → B | | 权责主体 | R | "C公司" → R | | 转出容器 | 仓库A | "仓库1" → 仓库A | | 转入容器 | 仓库B | "仓库2" → 仓库B | | 容器归属主体 | 归属A / 归属B | 与主体相同则用相同占位符 |

金额占位符: | transaction_amount | 含义 | 说明 | |-------------------|------|------| | 1 | 权责业务 | 走交易路径 | | 0 | 非权责业务 | 走非交易路径 |

金额精度与核算责任说明: 本引擎对 transaction_amount / non_transaction_amount 仅做"是否为 0 / 正负"的分类判断与透传不做任何加减乘除或累计运算(无借贷求和、无分摊、无四舍五入)。因此即便字段类型为 f64不存在会计精度风险——占位符 0 / 1 为小整数,f64 可精确表示,== 0 判定可靠;且引擎已对接近 0 的浮点脏值做了归一化兜底(< 1e-9 视作 0,详见 entry_generator::normalize_amount)。真实金额的核算、对账与持久化精度由 quantum-accounting-erp 侧负责(该侧应使用定点十进制,如 NUMERIC / Decimal),不在本引擎职责范围内。

红冲(reversal)字段: 红冲一笔业务请使用显式布尔字段 reversal: true不要依赖负金额——占位符约定下金额只传 0/1,负数(-0 无效、-1 会被当作交易业务导致凭证形状错误)。reversal 是与金额解耦的纯信号,因此 transaction_amount = 0(非交易业务、结存态双 0 调拨)也能正确红冲:引擎生成与原业务同形的凭证组后统一翻转借贷方向。

输出 amount 的符号约定:返回的每条 QuantumEntry.amount 的符号编码借贷方向——Debit(借)为正、Credit(贷)为负;reversal 通过翻转 debit_credit 使 amount 被动反号,二者始终一致(等价)。ERP 侧填充真实金额时,应以 debit_credit 方向(或等价的 amount 符号)为依据,用真实金额的绝对值按该方向填入,不要对占位符 ±1 与真实金额符号做叠加。

amount_type 区分金额来源transaction → 对应 transaction_amountnon_transaction → 对应 non_transaction_amount

特点

  • 临时映射表仅在单次请求生命周期内存在,请求结束即销毁
  • 相同真实值自动映射到相同占位符,保证引擎相等性判定正确
  • 用户全程只接触真实数据,零感知占位符
  • 映射开销 < 0.01ms,不影响效率

结存态调拨业务(transaction_amount = 0non_transaction_amount = 0)返回的 0 值凭证,后续通过成本核算系统填充真实金额。

响应

{
  "success": true,
  "request_id": "uuid",
  "data": {
    "entries": [
      {
        "entry_type": "b2_monetary_outflow",
        "quantum_state": "monetary_state",
        "amount_type": "transaction",
        "balance_direction": "debit",
        "debit_credit": "credit",
        "amount": -10000.00,
        "owner_entity": "A公司",
        "container": "仓库1",
        "counterparty_entity": "B公司",
        "responsible_entity": null,
        "cash_flow_id": 0,
        "rule_id": "B2.M.OUT",
        "is_basic": true
      }
    ],
    "from_state": "monetary_state",
    "to_state": "monetary_state"
  },
  "error": null,
  "quota": {
    "used": 28,
    "limit": 100,
    "remaining": 72
  }
}

配额字段 quota:每次成功调用后会扣减本 Key 的当日配额,返回最新 used / limit / remaining。若超过 limit,接口返回 HTTP 403error.code = "QUOTA_EXCEEDED"(请求不计入配额)。

错误响应

{
  "success": false,
  "request_id": "uuid",
  "data": null,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "from_entity 不能为空"
  }
}

批量生成量子分录

POST /api/v1/quantum/generate-batch
Content-Type: application/json

认证:与单生成相同,使用 API Key 鉴权(body 传入或 X-API-Key Header)。

配额注意:批量接口facts 数量扣减日配额(每个 fact 计 1 单位),与单条 generate 口径一致;配额不足时整体返回 HTTP 403 且不计入任何配额。详见下文「限流与配置」。

请求体

{
  "api_key": "qa_abc123_xxxxxxxxxxxxxxxxxxxx",
  "facts": [
    {
      "from_entity": "A公司",
      "to_entity": "B公司",
      "transaction_amount": 10000.00
    },
    {
      "from_entity": "C公司",
      "to_entity": "D公司",
      "transaction_amount": 20000.00
    }
  ]
}

响应

{
  "success": true,
  "total_count": 2,
  "success_count": 2,
  "failed_count": 0,
  "results": [...]
}

Legacy 路径(向后兼容)

为兼容旧版集成,以下路径已废弃但仍可用,新代码请使用上面的 /api/v1/quantum/* 路径:

| Legacy 路径 | 推荐路径 | |------------|---------| | POST /api/v1/generate | POST /api/v1/quantum/generate | | POST /api/v1/generate-batch | POST /api/v1/quantum/generate-batch | | POST /api/v1/verify-key | POST /api/v1/quantum/verify-key |


验证密钥

POST /api/v1/quantum/verify-key
Content-Type: application/json

请求体

{
  "api_key": "qa_abc123_xxxxxxxxxxxxxxxxxxxx"
}

响应

{
  "success": true,
  "valid": true,
  "user_id": "uuid",
  "plan": "free",
  "quota": {
    "used": 27,
    "limit": 100,
    "remaining": 73
  }
}

🔓 公开 API · 用量统计 (Usage)

第三方开发者查询本 API Key 的用量消耗。


获取指定 API Key 的当日用量

GET /api/v1/usage/daily
X-API-Key: qa_abc123_xxxxxxxxxxxxxxxxxxxx

别名:与 GET /api/v1/usage 完全等效。

响应

{
  "success": true,
  "error": null,
  "quota": {
    "used": 27,
    "limit": 100,
    "remaining": 73,
    "period": "daily"
  }
}

响应字段说明

| 字段 | 类型 | 说明 | |------|------|------| | quota.used | Integer | 当日已消耗配额单位数(来自 api_keys.daily_quota_used);单条 generate 每次计 1 单位,批量 generate-batch 按 fact 数计费(每个 fact 计 1 单位) | | quota.limit | Integer | 当日配额上限(来自 api_keys.daily_quota_limit) | | quota.remaining | Integer | 剩余可用单位数(limit - used,下限 0) | | quota.period | String | 周期标识,固定为 "daily" |

错误响应

| HTTP | 场景 | |------|------| | 400 | 缺少 X-API-Key Header | | 401 | API Key 无效 | | 500 | 数据库错误 |


查询当前用户用量统计(需登录)

GET /api/v1/usage/stats
Cookie: session_token=<登录会话令牌>

该接口面向登录用户(控制台),使用 session_token Cookie 鉴权,返回该用户下所有 API Key 的聚合调用统计。

与上方基于 X-API-Key当日配额查询(只看单个 Key 的配额字段 daily_quota_used)不同,此处统计来自 usage_logs 调用记录(由 generate / generate-batch 计费成功后写入),反映历史累计调用次数与趋势。

响应

{
  "stats": {
    "totalCalls": 128,
    "apiKeysCount": 3,
    "currentPlan": "free",
    "todayCalls": 12,
    "weekCalls": 56,
    "dailyTrend": [ { "date": "2026-07-26", "count": 12 } ],
    "topEndpoints": [ { "endpoint": "/api/v1/quantum/generate", "count": 80 } ]
  }
}

响应字段说明

| 字段 | 类型 | 说明 | |------|------|------| | stats.totalCalls | Integer | 该用户历史累计调用次数(来自 usage_logs) | | stats.apiKeysCount | Integer | 该用户拥有的 API Key 数量 | | stats.currentPlan | String | 当前套餐(free / pro 等) | | stats.todayCalls | Integer | 当日调用次数 | | stats.weekCalls | Integer | 近 7 日调用次数 | | stats.dailyTrend | Array | 按日聚合的调用趋势(用于图表) | | stats.topEndpoints | Array | 按端点聚合的调用排行 |

错误响应

| HTTP | 场景 | |------|------| | 401 | 未登录或 session_token 无效 / 缺失 | | 500 | 数据库错误 |


错误码

所有业务接口(/api/v1/quantum/generate/api/v1/quantum/generate-batch 等)现在都使用真实的 HTTP 状态码,而非统一返回 200 + success:false,便于网关、负载均衡器和监控按状态码统一拦截与统计。错误码与 HTTP 状态码的对应关系如下:

| 错误码 | HTTP 状态码 | 说明 | |--------|-------------|------| | MISSING_API_KEY | 400 Bad Request | 缺少 API 密钥(未传 X-API-Key 也未在 body 提供) | | VALIDATION_ERROR | 400 Bad Request | 请求参数校验失败 | | KEY_NOT_ACTIVATED | 403 Forbidden | API 密钥未激活 | | KEY_EXPIRED | 403 Forbidden | API 密钥已过期 | | KEY_NOT_FOUND | 403 Forbidden | API 密钥不存在 | | INVALID_API_KEY | 403 Forbidden | API 密钥无效(批量接口) | | QUOTA_EXCEEDED | 403 Forbidden | 当日配额用尽 | | UNAUTHORIZED | 401 Unauthorized | 未登录或登录已过期(usage 统计类接口) | | FORBIDDEN | 403 Forbidden | 无权限访问 | | INTERNAL_ERROR | 500 Internal Server Error | 服务器内部错误(数据库异常等) | | RATE_LIMITED | 429 Too Many Requests | 请求过于频繁(令牌桶限速) |

限流与配置

引擎提供两层防护:

  1. 日配额(daily quota):每个 API Key 每日总调用量上限(api_keys.daily_quota_limit / daily_quota_used),超限返回 QUOTA_EXCEEDED(HTTP 403)。
  2. 令牌桶(token bucket):按 API Key 维度的瞬时速率/突发限制,超限返回 HTTP 429 RATE_LIMITED不扣除日配额。与日配额互补——日配额管"总量",令牌桶管"突发速率"。

批量接口也计日配额/api/v1/quantum/generate-batchfacts 数量计日配额,每个 fact 计 1 个单位;配额不足时整体返回 HTTP 403 且不计入任何配额,保证调用方不会因部分失败而白白消耗配额。

令牌桶策略通过配置文件(config.toml)或环境变量调整:

| 配置项 | TOML 路径 | 环境变量 | 默认值 | 说明 | |---|---|---|---|---| | 稳态速率 | [rate_limit].requests_per_second | RATE_LIMIT_RPS | 5 | 每 Key 每秒平均可请求数 | | 突发容量 | [rate_limit].burst_capacity | RATE_LIMIT_BURST | 10 | 令牌桶容量(应 ≥ 稳态速率) |

配置加载顺序:优先读取 config.toml(可用 CONFIG_PATH 指定路径),文件缺失或解析失败时回退到环境变量 / 内置默认值。完整示例见仓库 config.example.toml

多 worker 注意:在单个进程内,RateLimiterArc 包裹并在各 worker 间共享同一组令牌桶,因此全局允许速率就是配置的单桶速率(requests_per_second),并非 workers × 单桶速率,进程内跨 worker 限速已是准确的,无需 Redis。只有在多进程部署(多副本 / 多 pod / 真正的多进程模式)时,每个进程才维护独立令牌桶,真实全局速率约为 进程数 × 单桶速率,此时才需把状态后端改为共享存储(如 Redis)做精确跨进程限速。


四态体系

转移单定义

一笔资源转移由以下输入参数定义:

T = (from_entity, to_entity,
     from_container?, to_container?,
     from_container_owner?, to_container_owner?,
     responsible_entity?,
     transaction_amount?, non_transaction_amount?)

关键设计:用户只需提供业务事实(谁、给谁、什么容器、多少钱),引擎自动推导每条分录的资源形态和金额路径。quantum_stateamount_type 是引擎的输出,不是输入。

资源形态推导规则

资源形态(quantum_state)由容器及其归属主体、权责主体的存在性动态推导,对每条分录独立判定:

container ≠ ∅ ∧ owner ≠ ∅  ⇒  monetary_state(货币态)
container ≠ ∅ ∧ owner = ∅  ⇒  inventory_state(结存态)
container = ∅ ∧ resp ≠ ∅    ⇒  responsible_state(权责态)
container = ∅ ∧ resp = ∅    ⇒  quantum_state(量子态)

| 条件 | 推导形态 | 说明 | |------|----------|------| | 有容器 + 容器有归属主体 | 货币态 | 如银行账号,归属某主体("谁的钱") | | 有容器 + 容器无归属主体 | 结存态 | 如仓库,不归属特定主体("存了什么") | | 无容器 + 有权责主体 | 权责态 | 如合同签订,仅涉及权责关系 | | 无容器 + 无权责主体 | 量子态 | 如服务购销、收入、损益、在建工程、制造费用等 |

容器的两类归属:容器分为有归属主体和无归属主体两类。有归属主体的容器(如银行账号,归属 A 公司)判定为货币态;无归属主体的容器(如仓库)判定为结存态。这对应 API 中的 from_container_owner_entity / to_container_owner_entity 字段——有值则货币态,无值则结存态。

金额路径判定规则

金额分为交易金额(transaction_amount)和非交易金额(non_transaction_amount),其本质是权责金额非权责金额

transaction_amount ≠ 0  ⇒  权责路径(交易金额)
transaction_amount = 0   ⇒  非权责路径(非交易金额)

二维判定矩阵

资源形态(由容器/权责主体决定)与金额路径(由交易金额是否为 0 决定)两个维度正交组合,决定引擎最终生成的分录组:

| 资源形态 \ 金额路径 | 权责路径 (tx≠0) | 非权责路径 (tx=0) | |----------------------|------------------|---------------------| | 货币态 | 付款(货币流出 + 权责消除) | 资金调拨(纯转移) | | 结存态 | 赊购入库(物资入库 + 应付) | 调拨入库(纯转移) | | 量子态 | 服务购销(服务 + 应收/应付) | — | | 权责态 | 合同签订(权责确认) | — |

一次转移 T 不是产生单一形态,而是产生一组分录 G(T) = {E₁, E₂, ..., Eₙ},每条分录的 quantum_stateamount_type 由引擎独立推导,同一笔业务中多种形态可同时出现。

四态总览

| 状态 | 说明 | 典型场景 | |------|------|----------| | monetary_state | 货币态 | 收款、付款 | | inventory_state | 结存态 | 入库、出库 | | quantum_state | 量子态 | 服务购销、收入、损益、在建工程 | | responsible_state | 权责态 | 合同签订 |


量子分录字段说明

| 字段名 | 类型 | 说明 | |--------|------|------| | entry_type | String | 条目类型枚举,snake_case 格式,如 b2_monetary_outflow / d5_inventory_transition_debit | | quantum_state | String | 量子态类型(引擎推导输出,非用户输入),取值:monetary_state / inventory_state / quantum_state / responsible_state。由容器归属和权责主体动态判定,详见四态体系 | | amount_type | String | 金额类型(引擎推导输出,非用户输入),取值:transaction(权责金额) / non_transaction(非权责金额)。由 transaction_amount 是否为 0 判定 | | balance_direction | String | 余额方向,取值:debit(余额在借方,资产/费用类) / credit(余额在贷方,负债/权益/收入类) | | debit_credit | String | 借贷方向,取值:debit(借) / credit(贷) | | amount | Number | 金额(符号编码借贷方向:借为正、贷为负) | | owner_entity | String | 归属主体 | | container | String/Null | 归属容器(结存态 / 货币态携带) | | counterparty_entity | String | 对方主体 | | responsible_entity | String/Null | 权责主体(权责态 / 转移方式必填) | | cash_flow_id | Integer/Null | 现金流 ID,取值:0=流出 / 1=流入 / null=不适用 | | rule_id | String | 规则编号,B/D 规则体系,如 B2.M.OUT(基本规则)/ D5.D(衍生规则) | | is_basic | Boolean | 是否为基本规则(B 系列)。true=基本规则 B1-B3,false=衍生规则 D1-D6 |

准备好开始了吗?

在沙盒中免费体验,或注册创建你的第一个 API Key