知识库 开发者
平衡,顶点和钥匙
检查你拥有的东西,升级到闪电,自动从自己的钱包上升级,查看每个请求的成本,并从代码中管理密钥。
为了方便起见,此页面是机器翻译的。英文原件为适用版本。
检查平衡
你的平衡,以及这把钥匙的帽子使用了多少。
GET https://nymbot.ai/api/v1/credits/balance 需要一个 API 密钥。 POST 它也适用于那些期待它的人。
balance 是目前比特币价格中的两种平衡,对于期望单个数字的工具(null 如果价格无法读取),其余的都是信用和利息,这就是实际存储余额的方式。 key 描述了请求的密钥. 已达到其上限的密钥仍然可以检查余额。
回应
{
"balance": 49.18,
"balance_sats": 42037,
"standard": { "credits": 120.4, "sats": 1204 },
"pro": { "credits": 408.33, "sats": 40833 },
"key": {
"id": "4f0c9a1be27d3856",
"name": "laptop scripts",
"limit_sats": 20000,
"period_used_sats": 3412,
"total_used_sats": 18230,
"reset_period": "monthly",
"reset_at": "2026-10-01T00:00:00Z"
}
}
| 状态 | 何时 |
|---|---|
401 | 密钥丢失、未知、撤销或过期。 |
cURL
curl https://nymbot.ai/api/v1/credits/balance \
-H "Authorization: Bearer $NYMBOT_API_KEY"
Python
import os
import requests
res = requests.get(
"https://nymbot.ai/api/v1/credits/balance",
headers={"Authorization": "Bearer " + os.environ["NYMBOT_API_KEY"]},
)
balance = res.json()
print(balance["standard"]["sats"], balance["pro"]["sats"])
JavaScript
const res = await fetch("https://nymbot.ai/api/v1/credits/balance", {
headers: { "Authorization": "Bearer " + process.env.NYMBOT_API_KEY },
});
const balance = await res.json();
console.log(balance.standard.sats, balance.pro.sats);
付款方式
怎样才能顶上,以及界限?闪电是唯一的方法。
GET https://nymbot.ai/api/v1/topup/payment-methods 不需要钥匙。
一个顶级是10到1万分;一个Pro顶级必须购买至少一个Pro信用,所以它从100分开始。 bulk_bonus 列出了较大的顶点上的额外信用额度,与应用程序相同:在标准顶点上增加10%,15%或20%从500,1000或5000 sats,以及从5000,10,000或50,000 sats的Pro顶点上。
回应
{
"supported_methods": [
{
"method": "btc-lightning",
"display_name": "Bitcoin Lightning",
"supported_currencies": ["SATS", "USD", "BTC"],
"limits": {
"SATS": { "min": 10, "max": 1000000 },
"USD": { "min": 0.02, "max": 1170 },
"BTC": { "min": 1e-7, "max": 0.01 }
},
"tiers": ["standard", "pro"],
"default_tier": "pro",
"tier_min_sats": { "standard": 10, "pro": 100 },
"sats_per_credit": { "standard": 10, "pro": 100 },
"bulk_bonus": [
{ "bonus": 0.1, "standard_sats": 500, "pro_sats": 5000 },
{ "bonus": 0.15, "standard_sats": 1000, "pro_sats": 10000 },
{ "bonus": 0.2, "standard_sats": 5000, "pro_sats": 50000 }
]
}
]
}
cURL
curl https://nymbot.ai/api/v1/topup/payment-methods
Python
import requests
methods = requests.get("https://nymbot.ai/api/v1/topup/payment-methods").json()
print(methods["supported_methods"][0]["limits"])
JavaScript
const methods = await (await fetch("https://nymbot.ai/api/v1/topup/payment-methods")).json();
console.log(methods.supported_methods[0].limits);
超越闪电的顶峰
创建一个闪电发票,将信贷添加到钥匙所属的密钥中。 检查它 要增加信用额度。
POST https://nymbot.ai/api/v1/topup/create/btc-lightning 需要一个 API 密钥。
| 场地 | 类型 | 需要 | 描述 |
|---|---|---|---|
amount | 号码 | 是的 | 多少,在 currency一个完整的数字为 sats。 |
currency | 线条 | 没有 | SATS (缺陷) USD 或 BTC美元以当前的比特币价格进行转换。 |
tier | 线条 | 没有 | pro (故障)或 standard:信用的平衡去哪。 |
一个标准的信用是10 sats和一个Pro信用100 sats,加上任何批量奖金;
credits 告诉你这张账单会添加什么。
回应
{
"invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
"payment_request": "lnbc100u1p5...",
"amount_sats": 10000,
"credits": 115,
"tier": "pro",
"expires_at": "2026-09-30T09:27:00Z",
"status": "pending"
}
| 状态 | 何时 |
|---|---|
400 | 另一条路径( )unsupported_method(未知货币)unsupported_currency)或等级,缺少的金额,或低于最低的金额(amount_too_small超過10萬人( )amount_too_large)或拒绝由闪电钱包(amount_out_of_range). |
429 | 此分類上一篇: 超過 60 個請求單位,或 120 個從這個地址,在一個小時內(rate_limit_exceeded,与 Retry-After). |
502 | 此时此刻不能发票( )invoice_unavailable,与 Retry-After). |
cURL
curl https://nymbot.ai/api/v1/topup/create/btc-lightning \
-H "Authorization: Bearer $NYMBOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"amount": 10000, "currency": "SATS", "tier": "pro"}'
Python
import os
import requests
res = requests.post(
"https://nymbot.ai/api/v1/topup/create/btc-lightning",
headers={"Authorization": "Bearer " + os.environ["NYMBOT_API_KEY"]},
json={"amount": 10000, "currency": "SATS", "tier": "pro"},
)
invoice = res.json()
print(invoice["payment_request"])
JavaScript
const res = await fetch("https://nymbot.ai/api/v1/topup/create/btc-lightning", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.NYMBOT_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ amount: 10000, currency: "SATS", tier: "pro" }),
});
const invoice = await res.json();
console.log(invoice.payment_request);
检查一个顶点
询问是否已经支付了发票,一旦有,会添加信用。 检查是什么信用,所以付款后,检查直到状态是 credited随后再次检查是安全的:信用降落一次,无论你问多少次。
GET https://nymbot.ai/api/v1/topup/status/{invoice_id} 需要从发票的 nym 的钥匙。
status 是 pending (尚未付款) paid (已付款,但尚未发票;再次检查), credited (在你的平衡)或 expired (不按时付款) 资产负债表是指发票顶部的层次。
回应
{
"invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
"status": "credited",
"amount_sats": 10000,
"credits": 115,
"tier": "pro",
"expires_at": null,
"balance_credits": 523.33,
"balance_sats": 52333
}
| 状态 | 何时 |
|---|---|
400 | id 不是创建呼叫的 64 个字符 ID。 |
404 | 此分類上一篇: 無人用你的NIMM(invoice_not_found). |
cURL
curl https://nymbot.ai/api/v1/topup/status/$INVOICE_ID \
-H "Authorization: Bearer $NYMBOT_API_KEY"
Python
import os, time
import requests
headers = {"Authorization": "Bearer " + os.environ["NYMBOT_API_KEY"]}
url = "https://nymbot.ai/api/v1/topup/status/" + invoice["invoice_id"]
while True:
status = requests.get(url, headers=headers).json()["status"]
if status in ("credited", "expired"):
break
time.sleep(3)
print(status)
JavaScript
const headers = { "Authorization": "Bearer " + process.env.NYMBOT_API_KEY };
const url = "https://nymbot.ai/api/v1/topup/status/" + invoice.invoice_id;
let status;
do {
await new Promise((r) => setTimeout(r, 3000));
status = (await (await fetch(url, { headers })).json()).status;
} while (status !== "credited" && status !== "expired");
console.log(status);
希望历史
每个请求一行:它是什么,哪个模型,多少代币和它花了多少钱. 没有提示或答案被保留,所以没有返回. 行被保留90天,最新的第一。
GET https://nymbot.ai/api/v1/queries/history 需要一个 API 密钥,它可以看到自己的请求,或 签署请求 从你的尼姆,谁看到每一个钥匙。
| 场地 | 类型 | 需要 | 描述 |
|---|---|---|---|
page | 整数(Query) | 没有 | 默认值为1,最多为1000;较高的页面为 400 invalid_value. |
page_count | 整数(Query) | 没有 | 每页的行. 默认 20,最多100。 |
start_dateend_date | 查询(Query) | 没有 | ISO 8601 日期或时间。 |
model | 查询(Query) | 没有 | 只有这个模型。 |
type | 查询(Query) | 没有 | chat, responses, messages, image, video, speech, transcription 或 embedding. |
all_keys | 布莱尔(Query) | 没有 | 一个钥匙: true 包含相同的所有密钥. 默认 false. |
key_id | 查询(Query) | 没有 | 通过签名的请求,或与 all_keys=true只有这个钥匙。 |
回应
{
"data": [
{
"id": "q_71c4e9a0",
"timestamp": "2026-09-30T08:12:00Z",
"model": "anthropic/claude-sonnet-5",
"type": "chat",
"input_tokens": 1240,
"output_tokens": 380,
"cached_tokens": 0,
"cost_sats": 16.2,
"cost_usd": 0.01895,
"balance": "pro",
"key_id": "4f0c9a1be27d3856",
"web_search": false,
"status": "ok"
}
],
"pagination": { "page": 1, "page_count": 20, "total": 311, "total_pages": 16 }
}
cURL
curl "https://nymbot.ai/api/v1/queries/history?page_count=50&type=chat" \
-H "Authorization: Bearer $NYMBOT_API_KEY"
Python
import os
import requests
res = requests.get(
"https://nymbot.ai/api/v1/queries/history",
headers={"Authorization": "Bearer " + os.environ["NYMBOT_API_KEY"]},
params={"page_count": 50, "type": "chat"},
)
for row in res.json()["data"]:
print(row["timestamp"], row["model"], row["cost_sats"])
JavaScript
const res = await fetch("https://nymbot.ai/api/v1/queries/history?page_count=50&type=chat", {
headers: { "Authorization": "Bearer " + process.env.NYMBOT_API_KEY },
});
for (const row of (await res.json()).data) console.log(row.timestamp, row.model, row.cost_sats);
帐户签名请求
创建、更改和撤销密钥、帐户摘要和自动上下载不需要 API 密钥,它们会从您的 nym 拿出一个签名,因此泄漏的密钥可以花费到其上限,但不能再创建另一个密钥或提高自己的上限。
该应用程序为您做到了这一点:其中的所有东西 火焰 sheet 使用这些端点. 您只需要此部分来管理您自己的代码中的密钥。
该签名是Nostr事件类型27235(NIP-98),发送的 base64编码在
Authorization Header 与 字 Nostr 在前面:
事件
{
"kind": 27235,
"created_at": 1790726400,
"tags": [
["u", "https://nymbot.ai/api/v1/keys"],
["method", "POST"],
["nonce", "9c4e21f07a3b...16 random bytes in hex"],
["payload", "3f1a0d7c8e2b...sha256 of the exact request body in hex"]
],
"content": "",
"pubkey": "your public key in hex",
"id": "...",
"sig": "..."
}
u是请求的完整URL,包含了查询字符串,正如发送一样。method这是 HTTP 方法。payload是原始请求体的 SHA-256 值,以 hex。POST和PATCH,并且你发送的身体必须是你哈希的字节。created_at必须在服务器时钟的60秒内。- 每个事件都工作一次,a
GET包含,因此无法重播被捕获的标题. 每一个请求签署一个新的标题。nonce使用随机值标记,以便在同一秒内签署的两个请求仍然不同。 - 签署请求的体积最多可以是64KB,并且需要一个体积。
Content-Type: application/json.
失落的事件返回 401 missing_nostr_auth;一个形成不良,签名不良,过于老,或返回不同的URL,方法或身体
invalid_nostr_auth,在消息中的理由;一个重复使用一个返回
nostr_auth_replayed. 向这些终端发送的 API 密钥被拒绝. 签名在读取身体之前被检查,每个地址每分钟都可以失败 30 次(IPv6 地址作为其整体计算 /64);然后它得到 429 与
Retry-After.
浏览器只能从Nymbot自己的网站调用这些终端(https://nymbot.ai,
https://nymchat.app 任何其他网站上的页面都没有 CORS 标题返回,所以它无法读取它们返回的内容。
Origin,不受影响。
签名需要你的NIM的秘密密密钥( nsec),它控制一切:你的身份,你的历史和你的平衡. 只把它放在你信任的机器上的脚本中,从环境中读取它,而不是将它写入文件中,并在你可以的时候选择应用程序。
这些助手构建标题. 此页面上的后面的示例使用它们. 他们读取六字符中的秘密密密钥 NOSTR_SECRET_HEX; cURL one 使用
尼克 命令行工具,使用 nsec 或 hex 键,并 sha256sum 在 macOS 中, shasum -a 256).
cURL
nostr_auth() {
method="$1"; url="$2"; body="$3"
nonce=$(openssl rand -hex 16)
if [ -n "$body" ]; then
hash=$(printf '%s' "$body" | sha256sum | cut -d' ' -f1)
event=$(nak event --sec "$NOSTR_SECRET_HEX" -k 27235 -t "u=$url" -t "method=$method" -t "nonce=$nonce" -t "payload=$hash")
else
event=$(nak event --sec "$NOSTR_SECRET_HEX" -k 27235 -t "u=$url" -t "method=$method" -t "nonce=$nonce")
fi
printf 'Nostr %s' "$(printf '%s' "$event" | base64 | tr -d '\n')"
}
Python
# pip install coincurve requests
import base64, hashlib, json, os, time
from coincurve import PrivateKey, PublicKeyXOnly
SECRET = bytes.fromhex(os.environ["NOSTR_SECRET_HEX"])
def nostr_auth(method, url, body=b""):
pubkey = PublicKeyXOnly.from_secret(SECRET).format().hex()
tags = [["u", url], ["method", method], ["nonce", os.urandom(16).hex()]]
if body:
tags.append(["payload", hashlib.sha256(body).hexdigest()])
created_at = int(time.time())
serialized = json.dumps([0, pubkey, created_at, 27235, tags, ""], separators=(",", ":"), ensure_ascii=False)
event_id = hashlib.sha256(serialized.encode()).digest()
event = {
"id": event_id.hex(),
"pubkey": pubkey,
"created_at": created_at,
"kind": 27235,
"tags": tags,
"content": "",
"sig": PrivateKey(SECRET).sign_schnorr(event_id).hex(),
}
return "Nostr " + base64.b64encode(json.dumps(event).encode()).decode()
JavaScript
// npm install nostr-tools
import { createHash, randomBytes } from "node:crypto";
import { finalizeEvent } from "nostr-tools/pure";
const secret = Buffer.from(process.env.NOSTR_SECRET_HEX, "hex");
export function nostrAuth(method, url, body = "") {
const tags = [["u", url], ["method", method], ["nonce", randomBytes(16).toString("hex")]];
if (body) tags.push(["payload", createHash("sha256").update(body).digest("hex")]);
const event = finalizeEvent(
{ kind: 27235, created_at: Math.floor(Date.now() / 1000), tags, content: "" },
secret,
);
return "Nostr " + Buffer.from(JSON.stringify(event)).toString("base64");
}
账户总结
应用程序API表顶部显示的内容:您的公共密钥、两者均衡、有多少个密钥活跃(未撤销或过期),以及 自动升级 设置,或
null 当服务器不提供它们时。
GET https://nymbot.ai/api/v1/account 需要 a 签署请求.
回应
{
"data": {
"pubkey": "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d",
"balances": {
"standard": { "credits": 120.4, "sats": 1204 },
"pro": { "credits": 408.33, "sats": 40833 }
},
"keys_active": 3,
"nwc_auto_topup": {
"connected": true, "threshold_sats": 5000, "topup_sats": 20000, "tier": "pro",
"last_topup_at": null, "last_topup_sats": null, "last_error": null
}
}
}
cURL
URL=https://nymbot.ai/api/v1/account
curl "$URL" -H "Authorization: $(nostr_auth GET "$URL")"
Python
import requests
url = "https://nymbot.ai/api/v1/account"
print(requests.get(url, headers={"Authorization": nostr_auth("GET", url)}).json())
JavaScript
const url = "https://nymbot.ai/api/v1/account";
const res = await fetch(url, { headers: { "Authorization": nostrAuth("GET", url) } });
console.log(await res.json());
管理钥匙
应用程序的关键列表背后的终点. 它们都需要一个 签署请求每个密钥都以以下形式返回,在ISO 8601中的时间和数值为 sats:
关键对象
{
"id": "4f0c9a1be27d3856",
"name": "laptop scripts",
"hint": "sk-nymbot-Qm7x…c2Lw",
"limit_sats": 20000,
"reset_period": "monthly",
"reset_at": "2026-10-01T00:00:00Z",
"expire_at": null,
"period_used_sats": 3412,
"total_used_sats": 18230,
"created_at": "2026-08-14T09:21:07Z",
"updated_at": "2026-09-02T17:40:55Z",
"last_used_at": "2026-09-30T08:12:00Z",
"revoked_at": null
}
hint 它足以识别一个密钥,但不使用它,当它被创建时,密钥本身只返回一次。
列表钥匙
GET https://nymbot.ai/api/v1/keys 签了。
| 场地 | 类型 | 需要 | 描述 |
|---|---|---|---|
include_revoked | 布莱尔(Query) | 没有 | 包含被取消的密钥. 默认 false. |
回应
{ "data": [ { "id": "4f0c9a1be27d3856", "name": "laptop scripts", "hint": "sk-nymbot-Qm7x…c2Lw", "...": "..." } ] }
cURL
URL=https://nymbot.ai/api/v1/keys
curl "$URL" -H "Authorization: $(nostr_auth GET "$URL")"
Python
import requests
url = "https://nymbot.ai/api/v1/keys"
for key in requests.get(url, headers={"Authorization": nostr_auth("GET", url)}).json()["data"]:
print(key["id"], key["name"], key["period_used_sats"], key["limit_sats"])
JavaScript
const url = "https://nymbot.ai/api/v1/keys";
const { data } = await (await fetch(url, { headers: { "Authorization": nostrAuth("GET", url) } })).json();
for (const key of data) console.log(key.id, key.name, key.period_used_sats, key.limit_sats);
创建一个钥匙
POST https://nymbot.ai/api/v1/keys 签名 返回 201.
| 场地 | 类型 | 需要 | 描述 |
|---|---|---|---|
name | 线条 | 是的 | 1 至 40 个字符,不同于您的其他活跃密钥(忽略案例)。 |
limit_sats | 整體 | 没有 | 支出上限在 sats,至少1. 把它放出没有上限。 |
reset_period | 线条 | 没有 | daily, weekly 或 monthly需要 limit_sats. 把它留给一个永远不会重置的帽子。 |
expire_at | string 或整数 | 没有 | 当密钥停止工作时:ISO 8601 时间,或自 1970 年以来的毫秒。 |
答案(201)
{
"data": {
"id": "4f0c9a1be27d3856",
"name": "laptop scripts",
"hint": "sk-nymbot-Qm7x…c2Lw",
"limit_sats": 20000,
"reset_period": "monthly",
"key": "sk-nymbot-Qm7x...c2Lw",
"...": "the rest of the key object"
}
}
| 状态 | 何时 |
|---|---|
400 | 缺少或太长的名称;已使用的名称(duplicate_name);一个不等于1的整数;一个不等于1的重置期;一个过去的到期期;一个未知的字段(unknown_parameter);或已有25个活跃的密钥(too_many_keys). |
429 | 超过 60 个键由这个 nimm,或 120 个来自这个地址,在一个小时内(rate_limit_exceeded,与 Retry-After). |
cURL
URL=https://nymbot.ai/api/v1/keys
BODY='{"name":"laptop scripts","limit_sats":20000,"reset_period":"monthly"}'
curl "$URL" \
-H "Authorization: $(nostr_auth POST "$URL" "$BODY")" \
-H "Content-Type: application/json" \
-d "$BODY"
Python
import json
import requests
url = "https://nymbot.ai/api/v1/keys"
body = json.dumps({"name": "laptop scripts", "limit_sats": 20000, "reset_period": "monthly"}).encode()
res = requests.post(
url,
data=body,
headers={"Authorization": nostr_auth("POST", url, body), "Content-Type": "application/json"},
)
print(res.json()["data"]["key"])
JavaScript
const url = "https://nymbot.ai/api/v1/keys";
const body = JSON.stringify({ name: "laptop scripts", limit_sats: 20000, reset_period: "monthly" });
const res = await fetch(url, {
method: "POST",
headers: { "Authorization": nostrAuth("POST", url, body), "Content-Type": "application/json" },
body,
});
console.log((await res.json()).data.key);
阅读一个钥匙
GET https://nymbot.ai/api/v1/keys/{id} 签了。
返回 {"data": {…}} 与关键对象,或 404
key_not_found 如果你的密钥没有这个ID。
cURL
URL=https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856
curl "$URL" -H "Authorization: $(nostr_auth GET "$URL")"
Python
import requests
url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856"
print(requests.get(url, headers={"Authorization": nostr_auth("GET", url)}).json()["data"])
JavaScript
const url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856";
console.log((await (await fetch(url, { headers: { "Authorization": nostrAuth("GET", url) } })).json()).data);
改变一个钥匙
PATCH https://nymbot.ai/api/v1/keys/{id} 签了。
发送任何 name, limit_sats, reset_period 和
expire_at,按照相同的规则,当做一个钥匙。 null 清除一个字段:没有覆盖,没有重置,没有到期. 更改重置期开始一个新的时期从零。400 key_revoked)返回
{"data": {…}} 更新的关键对象。
cURL
URL=https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856
BODY='{"limit_sats":50000,"expire_at":null}'
curl -X PATCH "$URL" \
-H "Authorization: $(nostr_auth PATCH "$URL" "$BODY")" \
-H "Content-Type: application/json" \
-d "$BODY"
Python
import json
import requests
url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856"
body = json.dumps({"limit_sats": 50000, "expire_at": None}).encode()
res = requests.patch(
url,
data=body,
headers={"Authorization": nostr_auth("PATCH", url, body), "Content-Type": "application/json"},
)
print(res.json()["data"])
JavaScript
const url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856";
const body = JSON.stringify({ limit_sats: 50000, expire_at: null });
const res = await fetch(url, {
method: "PATCH",
headers: { "Authorization": nostrAuth("PATCH", url, body), "Content-Type": "application/json" },
body,
});
console.log((await res.json()).data);
取消一个钥匙
DELETE https://nymbot.ai/api/v1/keys/{id} 签了。
立即停止密钥,永远保持在列表中 revoked_at 设置,并可见与 include_revoked=true取消已取消的密钥的答案是相同的,只有最新取消的 50 个密钥被保留;旧的密钥在取消另一个密钥时被删除。
回应
{ "data": { "id": "4f0c9a1be27d3856", "revoked": true } }
cURL
URL=https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856
curl -X DELETE "$URL" -H "Authorization: $(nostr_auth DELETE "$URL")"
Python
import requests
url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856"
print(requests.delete(url, headers={"Authorization": nostr_auth("DELETE", url)}).json())
JavaScript
const url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856";
const res = await fetch(url, { method: "DELETE", headers: { "Authorization": nostrAuth("DELETE", url) } });
console.log(await res.json());
NWC 自动升级
将闪电钱包连接到Nostr Wallet Connect,当API支出低时,Nymbot会自行平衡。 签署请求.
它是如何工作的:一旦 API 请求被收取到您选择观看的余额,如果余额下降到您的门槛以下,Nymbot 会发出您的上限金额的发票,请您的钱包支付它,并添加信用额度。 它每 5 分钟最高升值一次,所以请求的爆炸无法排出钱包。 在应用中花费不会触发它。 最后上限的时间和大小,以及最后的错误,都在设置中;如果付款经过错误后,检查其发票。 顶级状态 信用它。
连接链允许持有人请求您的钱包支付。Nymbot将其加密存储,并且只使用它来支付自己的上层发票,但只为此建立连接,在您的钱包中有一个支出预算,所以它可以支付的最多是您选择的号码。 pay_invoice.
连接一个钱包
POST https://nymbot.ai/api/v1/nwc-auto-topup/connect 签了。
| 场地 | 类型 | 需要 | 描述 |
|---|---|---|---|
nwc_url | 线条 | 是的 | 连接链接,开始 nostr+walletconnect://Nymbot 要求钱包 get_info 在保存它之前,并存储它加密。 |
threshold_sats | 整體 | 是的 | 当资产负债表低于这些许多 sats. 至少1000。 |
topup_sats | 整體 | 是的 | 每次加多少? 1000 到 1000 万分。 |
tier | 线条 | 没有 | pro (故障)或 standard:平衡观察和顶上。 |
回应
{
"data": {
"connected": true,
"threshold_sats": 5000,
"topup_sats": 20000,
"tier": "pro",
"last_topup_at": null,
"last_topup_sats": null,
"last_error": null
}
}
| 状态 | 何时 |
|---|---|
400 | 没有连接链接(invalid_nwc_url);钱包没有回复其传输(nwc_unreachable)或拒绝检查(nwc_rejected);连接不能支付发票(nwc_missing_permission)或超出限额的金额。 |
501 | 此服务器上未启用自动上传(nwc_unavailable)同样适用于其他两个终点。 |
cURL
URL=https://nymbot.ai/api/v1/nwc-auto-topup/connect
BODY='{"nwc_url":"nostr+walletconnect://...","threshold_sats":5000,"topup_sats":20000,"tier":"pro"}'
curl "$URL" \
-H "Authorization: $(nostr_auth POST "$URL" "$BODY")" \
-H "Content-Type: application/json" \
-d "$BODY"
Python
import json, os
import requests
url = "https://nymbot.ai/api/v1/nwc-auto-topup/connect"
body = json.dumps({
"nwc_url": os.environ["NWC_URL"],
"threshold_sats": 5000,
"topup_sats": 20000,
"tier": "pro",
}).encode()
res = requests.post(
url,
data=body,
headers={"Authorization": nostr_auth("POST", url, body), "Content-Type": "application/json"},
)
print(res.json())
JavaScript
const url = "https://nymbot.ai/api/v1/nwc-auto-topup/connect";
const body = JSON.stringify({
nwc_url: process.env.NWC_URL,
threshold_sats: 5000,
topup_sats: 20000,
tier: "pro",
});
const res = await fetch(url, {
method: "POST",
headers: { "Authorization": nostrAuth("POST", url, body), "Content-Type": "application/json" },
body,
});
console.log(await res.json());
阅读设置
GET https://nymbot.ai/api/v1/nwc-auto-topup 签了。
返回与连接相同的对象,与 connected: false 以及其他领域
null 当没有钱包连接时,连接字符串本身永远不会返回。
cURL
URL=https://nymbot.ai/api/v1/nwc-auto-topup
curl "$URL" -H "Authorization: $(nostr_auth GET "$URL")"
Python
import requests
url = "https://nymbot.ai/api/v1/nwc-auto-topup"
print(requests.get(url, headers={"Authorization": nostr_auth("GET", url)}).json())
JavaScript
const url = "https://nymbot.ai/api/v1/nwc-auto-topup";
console.log(await (await fetch(url, { headers: { "Authorization": nostrAuth("GET", url) } })).json());
断开连接
DELETE https://nymbot.ai/api/v1/nwc-auto-topup/connection 签了。
删除已存储的连接字符串. 不会再创建顶级。 为了确保,您也可以取消在您的钱包中的连接。
回应
{ "data": { "connected": false, "threshold_sats": null, "topup_sats": null, "tier": null, "last_topup_at": null, "last_topup_sats": null, "last_error": null } }
cURL
URL=https://nymbot.ai/api/v1/nwc-auto-topup/connection
curl -X DELETE "$URL" -H "Authorization: $(nostr_auth DELETE "$URL")"
Python
import requests
url = "https://nymbot.ai/api/v1/nwc-auto-topup/connection"
print(requests.delete(url, headers={"Authorization": nostr_auth("DELETE", url)}).json())
JavaScript
const url = "https://nymbot.ai/api/v1/nwc-auto-topup/connection";
const res = await fetch(url, { method: "DELETE", headers: { "Authorization": nostrAuth("DELETE", url) } });
console.log(await res.json());
按要求付款,无钥匙
固定价格的终端点可在 Lightning 上一次支付一次请求,没有密钥,没有帐户和余额: POST /images/generations, POST /images/edits,
POST /videos, POST /audio/speech, POST /audio/transcriptions,
POST /audio/translations 和 POST /embeddings. 聊天、回复和消息总是需要一个密钥. 带有密钥的请求会像往常一样向余额发票; 付款流只在没有发送密钥时才开始。
Nymbot 讲述了同一个想法的两种版本,来自一个后端:闪电实验室
第402章 (也接受了它的旧名称, LSAT)和IETF草案
付款 HTTP 身份验证计划与 lightning 方法及
charge 意图:使用您客户理解的内容。
没有钥匙的付款只有当 API_L402_SECRET 至少包含 32 个随机字节,例如六字节(64 个字符)或 base64(44 个字节)。 openssl rand -hex 32更短或可猜测的值会关闭该功能并记录为什么。 API_L402_SECRET_PREVIOUS 一天:凭证、状态 URL 和在其下提出的挑战继续工作,直到它们到期。
挑战
发送请求 无 Authorization header. 如果它是有效的,没有什么运行,你得到 402 Payment Required 用一个发票来确切地描述这个请求的成本:一个密钥会支付相同的价格,转换为10 sats一个标准信用或100 sats一个Pro信用,并到一个完整的SAT(至少1 sat,至少0.05信用最小)。 WWW-Authenticate 同一发票的挑战:
HTTP/1.1 402 Payment Required
Content-Type: application/problem+json; charset=utf-8
Cache-Control: no-store
WWW-Authenticate: L402 macaroon="AgJC...", invoice="lnbc2370n1..."
WWW-Authenticate: LSAT macaroon="AgJC...", invoice="lnbc2370n1..."
WWW-Authenticate: Payment id="kM9x...", realm="nymbot", method="lightning", intent="charge",
request="eyJhbW91bnQiOiIyMzciLC...", description="Nymbot API POST /images/generations (237 sats)",
digest="sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:", expires="2026-09-30T12:15:00.000Z",
opaque="eyJlbmRwb2ludCI6IlBPU1QgL2ltYWdlcy9nZW5lcmF0aW9ucyJ9"
{
"type": "https://paymentauth.org/problems/payment-required",
"title": "Payment Required",
"status": 402,
"detail": "This request costs 237 sats. Pay the Lightning invoice, then send the identical request again ...",
"challengeId": "kM9x...",
"amount_sats": 237,
"invoice": "lnbc2370n1...",
"payment_hash": "9db1370f...",
"expires_at": "2026-09-30T12:15:00.000Z",
"error": { "message": "This request costs 237 sats. ...", "type": "payment_required", "code": "payment_required", "param": null }
}
付款 request 参数是 base64url JSON:
{"amount":"237","currency":"sat","methodDetails":{"invoice":"lnbc...","network":"mainnet","paymentHash":"..."}}.
一个挑战是连接到终点,到 Content-Type (其媒介类型和,多部分,其边界)和SHA-256的确切的身体字节,你发送,并持续15分钟。 相同 再次要求:相同
Content-Type 和相同的 JSON 字节,或为多部分终端点(/images/edits, /audio/transcriptions, /audio/translations大多数 HTTP 库每次编码表单时都会选择一个新的边界,所以编码一次并发送这些字节两次。
每个地址可以要求每分钟 30 个挑战(一个 IPv6 地址被视为其完整 /64)。 未知地址的请求每分钟共享一个更严格的 10 个,并且在所有地址中都有 Nymbot 挑战的问题的总体限制;在提出挑战之前被拒绝的请求(例如,没有有效的 JSON 实体)不会对其进行计算。 429 与 Retry-After没有密钥或凭证的付费端点也被计算为每地址每分钟120个未经验证的请求的通用限制。 Content-Type 不是 application/json (或
multipart/form-data 被拒绝(被拒绝) 415 永远不会收到发票。
嵌入式是根据输入中的代币的估计定价,具有 1.5 次的边缘,因为真正的计数只有在之后才知道。 返回代码.
发送付款
用任何闪电钱包支付发票。钱包给你预图像,64个六角形字符,然后发送相同的请求,其中一个:
| 方案 | 头部 |
|---|---|
| 第402章 | Authorization: L402 <macaroon>:<preimage> (LSAT 工作也) |
| 付款 | Authorization: Payment <base64url JSON>JSON 所在的位置 {"challenge": {every parameter of the challenge, as sent}, "payload": {"preimage": "<hex>"}} |
付费请求的响应完全与用钥匙完成的请求一样,除非 nymbot
对象没有平衡字段: {"payment": "l402", "tier": "pro", "paid_sats": 237,
"charged_sats": 237},而且没有 X-Nymbot-Balance-Sats header. 通过付款计划付款的请求也获得了 Payment-Receipt header (base64url JSON with the challenge id,付款哈希为 reference, status 和
timestamp付费请求不与任何 nym 相关联,因此它们不会出现在查询历史中。
| 状态 | 何时 |
|---|---|
402 payment_already_used | 每个付款支付一个请求,答案是这个请求的新挑战,因此一个客户端缓存其最后的凭证(如 lnget 只不过,又一次地。 |
402 payment_mismatch | 信号是发给另一个终点的, Content-Type 或身体,或支付低于这个请求现在的成本。 这个请求的新的挑战伴随着它;如果付款太小,你付出的回归作为一个 返回代码 (refund_token 和 refund_sats 在身体里)。 |
402 payment_expired | 自挑戰以來已經過了超過15分鐘,新挑戰也隨之而來;如果前圖顯示你付了錢,你付的錢就會回來。 返回代码 (refund_token 和 refund_sats 在身体中),一次;然后,凭证被消耗了。 |
401 invalid_preimage | 预图像不会哈希到发票的付款哈希,付款不会被消耗。 |
401 invalid_payment_credential | 身份证是错误的,在Nymbot发行后被更改,或名称付款哈希 Nymbot从未发行发票。 |
429 rate_limit_exceeded | 超过30个未能验证的凭证或密钥在一分钟内来自此地址,或者一份退款令牌在一分钟内发送超过60次。 Retry-After. |
cURL
BODY='{"model":"nano-banana","prompt":"a lighthouse at dusk","response_format":"b64_json"}'
URL=https://nymbot.ai/api/v1/images/generations
# 1. Get the challenge
CH=$(curl -s -D - -o /dev/null "$URL" -H "Content-Type: application/json" -d "$BODY" | grep -i '^www-authenticate: L402')
MAC=$(echo "$CH" | sed -E 's/.*macaroon="([^"]+)".*/\1/')
INVOICE=$(echo "$CH" | sed -E 's/.*invoice="([^"]+)".*/\1/')
# 2. Pay $INVOICE with your wallet and copy the preimage
PREIMAGE=...
# 3. Send the identical request with the credential
curl "$URL" -H "Content-Type: application/json" -H "Authorization: L402 $MAC:$PREIMAGE" -d "$BODY"
lnget
# lnget (Lightning Labs) pays L402 challenges from your own lnd node and retries for you
lnget -X POST -H "Content-Type: application/json" \
-d '{"model":"nano-banana","prompt":"a lighthouse at dusk","response_format":"b64_json"}' \
https://nymbot.ai/api/v1/images/generations
Python
import base64, json, re
import requests
url = "https://nymbot.ai/api/v1/images/generations"
body = json.dumps({"model": "nano-banana", "prompt": "a lighthouse at dusk", "response_format": "b64_json"}).encode()
headers = {"Content-Type": "application/json"}
challenge = requests.post(url, data=body, headers=headers)
assert challenge.status_code == 402
info = challenge.json()
print("Pay", info["amount_sats"], "sats:", info["invoice"])
preimage = pay_with_your_wallet(info["invoice"]) # 64 hex characters
# L402
mac = re.search(r'L402 macaroon="([^"]+)"', challenge.headers["WWW-Authenticate"]).group(1)
res = requests.post(url, data=body, headers={**headers, "Authorization": f"L402 {mac}:{preimage}"})
print(res.json()["nymbot"])
JavaScript
const url = "https://nymbot.ai/api/v1/images/generations";
const body = JSON.stringify({ model: "nano-banana", prompt: "a lighthouse at dusk", response_format: "b64_json" });
const headers = { "Content-Type": "application/json" };
const challenge = await fetch(url, { method: "POST", headers, body });
const www = challenge.headers.get("www-authenticate");
// The Payment scheme: echo every challenge parameter back with the preimage
const start = www.indexOf("Payment ");
const params = Object.fromEntries([...www.slice(start + 8).matchAll(/(\w+)="((?:[^"\\]|\\.)*)"/g)].map((m) => [m[1], m[2]]));
const { invoice } = JSON.parse(Buffer.from(params.request, "base64url").toString()).methodDetails;
const preimage = await payWithYourWallet(invoice);
const credential = Buffer.from(JSON.stringify({ challenge: params, payload: { preimage } })).toString("base64url");
const res = await fetch(url, { method: "POST", headers: { ...headers, Authorization: `Payment ${credential}` }, body });
console.log((await res.json()).nymbot, res.headers.get("payment-receipt"));
客户建立在 mppx 用闪电方法处理付款挑战自己;指点他们到终点,让他们付钱。
视频
A 付款 POST /videos 答案 202 像一个密钥,加上一个
status_url: GET 它没有任何密钥来跟踪工作. 它被签署并工作24小时,只要工作被保留。
{
"id": "vid_...",
"status": "in_progress",
"status_url": "https://nymbot.ai/api/v1/videos/vid_...?exp=1790000000&sig=...",
"nymbot": {
"payment": "l402", "tier": "pro", "paid_sats": 4800, "charged_sats": 4800,
"refund_token": "REFUND-5E0B..."
}
}
保持它 refund_token 此分類上一篇: 此分類下一篇: 此分類下一篇: 此分類下一篇: 此分類下一篇: 此分類下一篇: 此分類下一篇: 此分類下一篇: 此分類下一篇: (GET /api/v1/l402/refunds 答案 "status": "pending");如果渲染未发票,付款将降落在其上。
refund_sats 对于退款的工作,但从来没有代币,所以共享状态URL不会共享退款。
退款
如果付费请求失败,并且提供商为尝试收取了Nymbot的费用,则付款将保留,错误表示如此,但 charged_sats,就像一个密钥请求一样. 如果它失败而没有被发票,错误会带来一个 返回代码 您付出的值:
{
"error": {
"message": "The image generator failed. Nothing was charged. Please try again. The 237 sats you paid are on refund token REFUND-...",
"type": "api_error",
"code": "upstream_error",
"refund_token": "REFUND-0C15DBED145D59131BA70298A413ADEB3D9B9AB082C476EA70A5BD38FCA5DE6D",
"refund_sats": 237,
"refund_expires_at": "2026-10-30T12:00:00.000Z"
}
}
未使用的零件以同样的方式返回:如果您要求两张照片,而一个没有发票,成功的响应 nymbot 对象为缺失的代币带有退款代币;一个长度无法读取的转录被定价为文件的最长时间(永不超过30分钟),而与实际长度的差异作为退款代币返回;如果结果超过30分钟,则被拒绝。 413
嵌入式返回了估计的值,失败的视频返回了其提交返回的代币。
退款代币是一个随机的256位代码,Nymbot仅存储其哈希,并且在30天后到期。
- 付出它。 发送
Authorization: Bearer REFUND-…此分類上一篇:refund_token_sats在该nymbot一个代币的价值小于请求的答案402refund_insufficient一个未计价的失败将 sats 放回同一个代币上。 - 检查它。
GET /api/v1/l402/refunds同一个 header 返回{"sats": 237, "status": "open", "expires_at": "..."}. - 一个代币每分钟最多可以使用60次。
- 把它移到一个nym。 把它放在 送回礼物 在 Nymbot 应用程序中,或拨打
POST /api/v1/l402/refunds/redeem与A 签署请求 和{"refund_token": "REFUND-...", "balance": "standard"}(或"pro"全额信贷进入平衡(每个在标准上10分,在Pro上100分);对于API请求,不使整个信贷留在代币上。
cURL
URL=https://nymbot.ai/api/v1/l402/refunds/redeem
BODY='{"refund_token":"REFUND-...","balance":"standard"}'
curl "$URL" \
-H "Authorization: $(nostr_auth POST "$URL" "$BODY")" \
-H "Content-Type: application/json" \
-d "$BODY"
回应
{ "data": { "credited": 23, "tier": "standard", "balance_credits": 123, "remaining_sats": 7 } }