生命周期概览
- Mint:使用普通密钥创建预算子密钥。保存子密钥
id、业务ref和仅返回一次的 secret。 - 调用:在到期前,使用子密钥 secret 发起一次或多次 LLM 调用,显式指定输出上限并设置 call tag。
- 查看:使用普通密钥读取实时支出和 call receipt。
- 关闭:turn 结束后关闭子密钥。轮询直到
status: closed,再根据最终spent_usd结算用户的 authorization hold。
https://api.sunra.ai 和 Authorization: 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.ai 和 Authorization: Bearer <child secret>。仅支持以下端点:
其他 API 操作,包括预算子密钥管理和 native/media embeddings,均以
403 budget_key_route_forbidden 拒绝子密钥。已过期或已撤销的凭证可能先在鉴权阶段失败;无法识别的 URL 仍可能返回 404。
使用 Chat Completions 时,每次子密钥请求都必须发送 max_tokens 或 max_completion_tokens,并选择模型支持的字段。两者都缺失时返回 400 max_tokens_required。值必须是正的 safe integer;如果同时提供两个字段,它们必须相等。Messages 使用 max_tokens,Responses 使用 max_output_tokens。后两种 API 可以根据模型配置的输出上限补充缺失值;显式发送上限可以明确本次调用的输出额度。
n 可以省略,但提供时必须为数字 1。best_of 即使为 1 也会被拒绝。
子密钥请求只能携带下列 portable 生成参数,以及所调用端点对应的输出上限字段。其他字段——provider extension bag 和其他写法的 ceiling,例如 extra_body、generation_config、generationConfig、max_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:
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。
以下为包含一次已付费调用的密钥在关闭后的示例页面:
PAID、VOID、PENDING 和 UNCOLLECTIBLE 尝试。只有 PAID 行具有结算成本;其他状态的 cost_usd 均为 "0.00000000"。在创建调用记录之前被拒绝的请求不计入。completed_at 和 tag 可以为 null;usage 可包含 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 并不表示密钥已关闭。
关闭密钥
401 budget_key_revoked。Close 不会取消已经准入的调用,它们仍可能继续结算。
Close 具有幂等性。密钥关闭后,重复请求返回相同的最终 snapshot;没有调用的密钥也会返回支出为零的 snapshot。也可以轮询 GET by ID,但即使
status 为 finalizing,GET 也返回 HTTP 200:请始终检查 body。不保证 finalization 在固定时间内完成。
端到端示例
使用 Bash、支持--fail-with-body 的 curl 和 jq 运行以下示例。按照鉴权中的说明将普通密钥赋给 SUNRA_KEY。示例使用 google/gemini-2.5-flash,父密钥必须允许该模型。它会创建一把上限为 $0.05、有效期为一小时的密钥,发起一次调用、读取 receipt、关闭密钥并打印最终支出。Close 前读取的 receipt 仍可能处于 pending 状态。
如果调用或 receipt 读取失败,exit handler 也会尝试关闭密钥。请在应用中保存打印出的 ref 和子密钥 ID,以便在执行中断后恢复处理。
closed 后重新读取全部 receipt 分页。重复发送 LLM 请求不会被去重,可能再次产生费用。
找回丢失的 ticket
如果 mint response 或本地 ticket 记录丢失,可使用已保存的ref 找回子密钥 ID:
{ "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_exhausted 和 budget_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;终端用户的授权和账目由您的应用管理。