Skip to main content
预算子密钥是从普通 Sunra API key 创建的短期子密钥,带有 USD 支出上限和独立的 call receipt。为每个 agent turn 或 run 创建一把预算子密钥,可以限制 agent 的 LLM 访问,并分别核算每位终端用户的用量。该上限通过估算成本控制请求准入:实际结算支出可能超过上限,因此请在您自己的 authorization hold 中预留余量。Sunra 仍向父密钥所属的 organization 计费;预算子密钥提供额度限制和用量归属,并不是 wallet。

生命周期概览

  1. Mint:使用普通密钥创建预算子密钥。保存子密钥 id、业务 ref 和仅返回一次的 secret。
  2. 调用:在到期前,使用子密钥 secret 发起一次或多次 LLM 调用,显式指定输出上限并设置 call tag。
  3. 查看:使用普通密钥读取实时支出和 call receipt。
  4. 关闭:turn 结束后关闭子密钥。轮询直到 status: closed,再根据最终 spent_usd 结算用户的 authorization hold。
所有管理请求均使用 https://api.sunra.aiAuthorization: Key $SUNRA_KEY,其中 SUNRA_KEY 必须是有效的普通密钥。预算子密钥不能调用管理端点。参见鉴权

创建预算子密钥

POST /v1/budget-keys 发送 JSON body: 可选字段请直接省略,不要发送 null。未知的顶层字段会被拒绝。省略 models 时,子密钥继承父密钥的模型限制;设置后,每次调用都必须同时满足该列表和父密钥当前的 allowlist。 以下示例使用 jq 将到期时间设为一小时后,并创建上限为 $0.05 的密钥:
201 response 直接返回资源,不包含 data 包装层。示例值如下:
请立即保存 secret_key:mint 仅返回一次。 GET、list、receipt 和 close 均不会返回它。Mint 不具备幂等性:重复请求即使使用相同的 ref,也会创建不同的子密钥。如果 response 丢失,请先使用下文的恢复端点找到并关闭遗留密钥,再决定是否重新 mint。

使用子密钥调用 LLM API

使用 https://api-llm.sunra.aiAuthorization: Bearer <child secret>。仅支持以下端点: 其他 API 操作,包括预算子密钥管理和 native/media embeddings,均以 403 budget_key_route_forbidden 拒绝子密钥。已过期或已撤销的凭证可能先在鉴权阶段失败;无法识别的 URL 仍可能返回 404 使用 Chat Completions 时,每次子密钥请求都必须发送 max_tokensmax_completion_tokens,并选择模型支持的字段。两者都缺失时返回 400 max_tokens_required。值必须是正的 safe integer;如果同时提供两个字段,它们必须相等。Messages 使用 max_tokens,Responses 使用 max_output_tokens。后两种 API 可以根据模型配置的输出上限补充缺失值;显式发送上限可以明确本次调用的输出额度。 n 可以省略,但提供时必须为数字 1best_of 即使为 1 也会被拒绝。 子密钥请求只能携带下列 portable 生成参数,以及所调用端点对应的输出上限字段。其他字段——provider extension bag 和其他写法的 ceiling,例如 extra_bodygeneration_configgenerationConfigmax_new_tokens——一律返回 400 invalid_input:它们可能在转换后放大真实输出上限,使 reservation 失效。允许的顶层字段为:model, provider, stream, stream_options, messages, input, system, instructions, tools, tool_choice, parallel_tool_calls, response_format, text, temperature, top_p, top_k, stop, stop_sequences, seed, presence_penalty, frequency_penalty, logit_bias, logprobs, top_logprobs, user, metadata, store, previous_response_id, include, truncation, reasoning, reasoning_effort, thinking, service_tier, safety_identifier, prompt_cache_key, prompt_cache_retention, verbosity, n, encoding_format, dimensions。使用普通密钥发起的请求不受此限制。 使用 x-sunra-call-tag 标记调用,值最多为 128 个 printable ASCII 字符。它会作为 tag 出现在 receipt 中。如果密钥设置了 metadata.allowed_tags,缺失 tag 或 tag 不在集合内会返回 403 budget_call_tag_forbidden;否则该 header 为可选。普通密钥完全忽略该 header。 将返回的 secret 赋给 CHILD-i 会显示 response header:
保存 x-sunra-prediction-id,用于将本次调用关联到对应的 receipt。Receipt 的 id 与该 header 的值逐字节一致;不要用 provider response ID 替代它。

跟踪支出

读取密钥

将 mint 返回的子密钥 id 赋给 ID
Response 包含与 mint 相同的资源字段,但不含 secret_key 准入会在调用前预留估算售价。实际结算成本可能因在途调用的估算误差而超过上限。请在您自己的 authorization hold 中留出余量;不要根据 open 密钥的支出或 LLM response 已结束就释放 hold。未知的实时值不等于零。

读取逐调用 receipt

limit 默认为 100,允许 1–500。只要 has_more 为 true,就将 next_cursor 作为 after 请求下一页;该值是本页最后一行的 id。请原样传回并进行 URL encoding。无效 cursor 或属于其他子密钥的 cursor 会返回 400 invalid_input 以下为包含一次已付费调用的密钥在关闭后的示例页面:
Receipt 包含 PAIDVOIDPENDINGUNCOLLECTIBLE 尝试。只有 PAID 行具有结算成本;其他状态的 cost_usd 均为 "0.00000000"。在创建调用记录之前被拒绝的请求不计入。completed_attag 可以为 nullusage 可包含 cache token 计数,wire_id 为可选字段。 calls_count 是 receipt 所有分页中的尝试总数,不只是当前页的行数。只有 closed 密钥的 complete 才为 true;open 和 finalizing 状态的 receipt 仍可能变化。最终对账时,请先关闭密钥,从第一页重新读取全部 receipt,并使用 decimal arithmetic 对 status: "PAID" 行的 cost_usd 求和。该总和等于 closed 后的 spent_usd,总行数等于 closed 后的 calls 和 receipt 的 calls_count。仅有 has_more: false 并不表示密钥已关闭。

关闭密钥

Close 不需要 body,并会阻止新调用。使用已关闭的子密钥调用会返回 401 budget_key_revoked。Close 不会取消已经准入的调用,它们仍可能继续结算。 Close 具有幂等性。密钥关闭后,重复请求返回相同的最终 snapshot;没有调用的密钥也会返回支出为零的 snapshot。也可以轮询 GET by ID,但即使 statusfinalizing,GET 也返回 HTTP 200:请始终检查 body。不保证 finalization 在固定时间内完成。

端到端示例

使用 Bash、支持 --fail-with-bodycurljq 运行以下示例。按照鉴权中的说明将普通密钥赋给 SUNRA_KEY。示例使用 google/gemini-2.5-flash,父密钥必须允许该模型。它会创建一把上限为 $0.05、有效期为一小时的密钥,发起一次调用、读取 receipt、关闭密钥并打印最终支出。Close 前读取的 receipt 仍可能处于 pending 状态。 如果调用或 receipt 读取失败,exit handler 也会尝试关闭密钥。请在应用中保存打印出的 ref 和子密钥 ID,以便在执行中断后恢复处理。
Mint 结果不明确时,不要自动重试 mint。应用需要最终的逐调用账目时,请按上文说明,在 closed 后重新读取全部 receipt 分页。重复发送 LLM 请求不会被去重,可能再次产生费用。

找回丢失的 ticket

如果 mint response 或本地 ticket 记录丢失,可使用已保存的 ref 找回子密钥 ID:
Response 形如 { "data": [...], "has_more": false, "next_cursor": null }data 中包含预算子密钥资源,不含 secret。ref 必填、非空且最多 256 个字符。limit 默认为 100,允许 1–100。如果 has_more 为 true,将不透明的 next_cursor 进行 URL encoding 后作为 after 请求下一页。多个密钥可以共用同一个 ref;请检查所有匹配项并关闭遗留密钥。 List 用于找回密钥。请使用 GET by ID 或 close 获取最终账目状态,不要根据 open 状态的 list 结果结算 authorization hold。Secret 无法找回。 同一 organization 内任何有效的普通密钥都可以对预算子密钥执行 get、list、close 和读取 calls。 不必使用最初 mint 它的密钥。在轮换或撤销父密钥后,请使用该 organization 内另一把有效的普通密钥完成未结 ticket。撤销原父密钥会使新的子密钥调用返回 401 budget_key_revoked,但不会自动完成子密钥的最终账目处理。

错误

请同时检查 HTTP status 和 error.details.reason;下表说明预算相关错误的处理方式。已有的 model-access、parameter-validation、organization-balance 和 upstream 错误可能保留原有的 response 格式。 402 budget_reserved body 示例:
budget_exhaustedbudget_reserved 包含准入决策时的全部四个 USD 字符串。对于这些金额字段,budget_state_unknown 只返回 cap_usd;不能将缺失的 spend 和 reservation 值视为零。

限制与保证

  • 有效期: 从 mint 校验时起最多 24 小时。到期后停止新调用;最终账目仍需获取 closed snapshot。
  • Best-effort cap: 准入预留的是估算售价。实际支出可能因在途调用的估算误差而超过 cap_usd。请在自己的 authorization hold 中预留余量。
  • 实时值与最终值: Open 和 finalizing 状态的数值可能变化。只有 status: closed 提供权威且不可变的 snapshot;其 receipt 标记为 complete: true。Snapshot 覆盖已记录的结算,因此从未记录或在 snapshot 之后才到达的结算可能不包含在最终金额中。
  • 计费: 父密钥所属的 organization 仍按原有方式计费,并继续受现有余额和访问限制约束。预算子密钥不会为 wallet 注资,也不会将终端用户的资金转入 Sunra;终端用户的授权和账目由您的应用管理。