知識庫 開發者
餘額、儲值與密鑰
查看您的餘額、透過 Lightning 儲值、從您自己的 錢包自動儲值、查看每次請求的費用,並從程式碼管理金鑰。
為了方便起見,此頁面是機器翻譯的。英文原件為適用版本。
正在查詢餘額
您的兩筆餘額,以及這把金鑰的配額已使用了多少。
GET https://nymbot.ai/api/v1/credits/balance — 需要一個 API 金鑰。 POST 對於有此需求的客戶來說,這也行得通。
balance 這兩個餘額以目前比特幣價格換算成美元後,總計為
對於預期單一數值的工具(null (如果無法讀取價格)。其餘部分是以
credits 和 sats 計算,這才是實際保存餘額的方式。 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);
付款方式
如何儲值以及限制。Lightning 是唯一的方法。
GET https://nymbot.ai/api/v1/topup/payment-methods — 不需要金鑰。
儲值金額為 10 至 1,000,000 sats;Pro 儲值必須購買至少一個 Pro 點數,因此從
100 sats 開始。美元限制隨比特幣價格變動。 bulk_bonus 列出大額儲值的額外紅利,與 App 中的內容相同:標準儲值滿 500、1,000 或 5,000 sats 可額外獲得 10%、15% 或 20%,Pro 儲值滿 5,000、10,000 或 50,000 sats 亦同。
回應
{
"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);
透過 Lightning 儲值
建立一個 Lightning 發票,將額度增加到該金鑰所屬的 nym。從任何 Lightning 錢包支付它,然後 檢查一下 以獲得額度添加。
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), 超過 1,000,000 sats (amount_too_large) 或被 Lightning 錢包拒絕 (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 並非來自建立呼叫(create call)的 64 位元字元 ID。 |
404 | 找不到該 ID 對應您 nym 的發票 (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);
查詢歷史
每筆請求佔一行:內容為何、使用哪個模型、多少 token 以及費用。 不會保留提示詞或回答,因此不會回傳任何內容。 資料保留 90 天,由新到舊排列。 已達到上限的金鑰仍可讀取其歷史紀錄。
GET https://nymbot.ai/api/v1/queries/history — 需要一個 API 金鑰,它會看到自己的請求,或者一個 已簽署的請求 從你的化名,它窺視著每一把鑰匙的。
| 領域 | 類型 | 需要 | 描述 |
|---|---|---|---|
page | 整數 (查詢) | 不 | 預設 1,最多 1,000;較高的頁面是 400 invalid_value. |
page_count | 整數 (查詢) | 不 | 每頁列數。預設 20,最多 100。 |
start_dateend_date | 字串 (查詢) | 不 | ISO 8601 日期或時間。 |
model | 字串 (查詢) | 不 | 只有這個模型。 |
type | 字串 (查詢) | 不 | chat, responses, messages, image, video, speech, transcription 或者 embedding. |
all_keys | 布林 (查詢) | 不 | 帶著一把鑰匙: true 包含所有相同名稱的鍵。預設 false. |
key_id | 字串 (查詢) | 不 | 透過簽署的請求,或透過 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 的簽章,因此即使金鑰洩漏,也最多只能花費其上限金額,但 永遠無法建立另一個金鑰或提高其自身的上限。
這款應用程式為您完成這一切:一切都在其內 API 工作表使用這些端點。 您只需要此部分來從您自己的程式碼中管理金鑰。
該簽名是一個種類為 27235 (NIP-98) 的 Nostr 事件,以 base64 編碼形式發送於
Authorization 帶有該單字的標題 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 值,以十六進位格式表示。這是在...上所必需的POST和PATCH,且你發送的內容必須與你進行雜湊處理的內容完全一致。created_at必須與伺服器的時鐘誤差在 60 秒以內。- 每個事件只運作一次,a
GET已包含,因此擷取到的標頭無法 被重放。請為每個請求簽署一個新的。增加一個nonce使用隨機值進行標記 因此即使在同一秒內簽署的兩個請求,其內容仍會有所不同。 - 簽署請求的正文最多為 64 KB,且正文需要
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,不受影響。
簽署需要您的 nym 密鑰 (the nsec), 它控制著
一切:您的身分、您的歷史紀錄以及您的餘額。請務必只將其放在您信任的機器腳本中,從環境變數中讀取而非直接寫入檔案,並且在可能的情況下優先使用應用程式。
這些輔助程式建構標頭。此頁面隨後的範例會使用它們。它們以十六進位格式讀取金鑰,位置在 NOSTR_SECRET_HEX; cURL 的那個使用
想要 命令列工具,可接收 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 — 需要一個 已簽署的請求.
回應
{
"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 | 布林 (查詢) | 不 | 包含已撤銷的金鑰。預設 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 | 字串或整數 | 不 | 當按鍵停止運作時: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 但非整數的上限;一個沒有上限的重置週期;一個已過期的到期日;一個未知的欄位 (unknown_parameter); 或已有 25 個活動金鑰 (too_many_keys). |
429 | 在一小時內,由此匿名者製作了超過 60 個密鑰,或由此地址產生了 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": {…}} 使用 key object,或者 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 連接 Lightning 錢包,當 API 支出導致餘額不足時,Nymbot 會自動儲值。應用程式的 API 頁面具有相同的設定;這些是其背後的端點。所有這些都需要一個 已簽署的請求.
運作方式:在 API 請求從您選擇監控的餘額中扣除後,如果該 餘額低於您的閾值,Nymbot 會針對您的儲值金額開立發票,要求 您的錢包進行支付,並增加點數。對於每個 nym 和餘額,它每 5 分鐘最多儲值一次,因此突發的請求不會耗盡錢包。在應用程式中的花費不會觸發此機制。上次儲值的時間、金額以及最後一次錯誤都記錄在設定中;如果支付在錯誤後成功完成,請透過以下方式檢查其發票 儲值狀態 歸功於它。
連接字串讓持有者可以要求您的錢包進行支付。Nymbot
以加密方式儲存它,且僅用於支付自身的儲值發票,但請針對此用途
建立一個僅限於此的連接,並在您的錢包中設定支出預算,因此它最多
只能支付您所設定的金額。錢包必須支援 pay_invoice.
連接錢包
POST https://nymbot.ai/api/v1/nwc-auto-topup/connect — 已簽署。
| 領域 | 類型 | 需要 | 描述 |
|---|---|---|---|
nwc_url | 字串 | 是的 | 連線字串,開始 nostr+walletconnect://. Nymbot 向錢包請求 get_info 在儲存之前,並將其加密儲存。 |
threshold_sats | 整數 | 是的 | 當餘額低於此數量的 sats 時進行儲值。至少 1,000。 |
topup_sats | 整數 | 是的 | 每次要增加多少。1,000 到 1,000,000 sats。 |
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 — 已簽署。
回傳與 connecting 相同的物件,包含 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 從同一個後端說出兩種版本的同一個想法:Lightning Labs'
L402 (亦可使用其舊名, LSAT) 與 IETF 草案
付款 搭配 HTTP 認證方案的 lightning 方法與
charge 意圖。使用您的客戶能理解的任何方式。
不使用金鑰支付僅在以下情況開啟 API_L402_SECRET 包含至少 32 個隨機
位元組,以十六進位 (64 個字元) 或 base64 (44 個字元) 表示。製作一個如下: openssl rand -hex 32.
較短或可猜測的值會關閉此功能並記錄原因。若要輪替它,請將舊
值移至 API_L402_SECRET_PREVIOUS 在一天內:憑證、狀態 URL 以及在此之下進行的挑戰,在過期之前將持續有效。
挑戰
發送不帶任何內容的請求 Authorization 標題。如果它是有效的,則不會執行任何操作,且
你會得到 402 Payment Required 附上與該請求成本完全一致的發票:
價格與 Key 所支付的價格相同,轉換率為 1 個標準積分等於 10 sats,或 1 個 Pro 積分等於 100 sats
並向上取整至整數 sat(至少 1 sat,且至少為 0.05 credit 的最小值)。該
回應包含三個 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 (其媒體類型,且對於
multipart,包含其邊界)以及您所發送的確切主體位元組之 SHA-256,並持續 15
分鐘。付款後,請發送 完全相同 再次請求:同樣的
Content-Type 以及相同的 JSON 位元組,或用於 multipart 端點
(/images/edits, /audio/transcriptions, /audio/translations)
使用相同的 boundary 傳送相同的 multipart body。大多數 HTTP 函式庫在每次編碼表單時都會選擇一個新的 boundary,因此請編碼一次並傳送兩次這些位元組。
每個地址每分鐘可以要求 30 次挑戰(一個 IPv6 地址計為其整個 /64)。
地址未知的請求則共用更嚴格的每分鐘 10 次限制,且 Nymbot 對所有地址發出的挑戰總量設有上限;在發出挑戰前被拒絕的請求(例如主體不是有效的 JSON)不會計入其中。除此之外,答案是 429 與 Retry-After,在讀取主體之前傳送。未透過金鑰或憑證呼叫的付費端點,也會計入每個地址每分鐘 120 次未經身份驗證請求的一般限制中。憑證會在讀取主體之前進行檢查,而一個其... Content-Type 不是 application/json (或
multipart/form-data (用於上傳) 被拒絕,錯誤訊息為 415 且從未收到
發票。
Embeddings 的定價是根據輸入 token 的估算值,並加上 1.5 倍的利潤, 因為實際數量只有在處理完後才能得知。您支付的是實際使用的 token,而 多付的部分將以退款形式退回。 退款代幣.
正在付款
使用任何 Lightning 錢包支付發票。錢包會給你 preimage,即 64 個十六進位字元。 然後使用其中之一發送相同的請求:
| 方案 | 標題 |
|---|---|
| L402 | 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 標頭。A
使用付款方案支付的請求也會獲得 Payment-Receipt 標頭 (base64url
包含挑戰 ID 的 JSON,以及支付雜湊值作為 reference, status 和
timestamp). 付款請求不與任何 nym 綁定,因此不會顯示在
查詢歷史記錄中。
| 狀態 | 何時 |
|---|---|
402 payment_already_used | 每一筆付款都支付一次請求。回應是對此請求的一個全新挑戰,因此,快取其最後憑證的用戶端(如 lnget does) 只是再次付款。 |
402 payment_mismatch | 該憑證是為另一個端點核發的, Content-Type 或者身體,或者現在支付低於此請求的成本。此請求帶來了一個新的挑戰;如果付款太少,你所支付的金額將會以 a 的形式退回 退款代幣 (refund_token 和 refund_sats (在正文中)。 |
402 payment_expired | 距離挑戰結束已超過 15 分鐘。隨之而來的是一個新的挑戰。如果前像顯示您已付款,您所支付的金額將以 a 的形式返還 退款代幣 (refund_token 和 refund_sats 在主體中),僅限一次;該憑證隨後即會失效。 |
401 invalid_preimage | 原像未雜湊至發票的付款雜湊值。該付款尚未耗盡。 |
401 invalid_payment_credential | 憑證格式錯誤、在 Nymbot 發行後被更改,或指向一個 Nymbot 從未針對其發行過發票的付款雜湊。含有 Nymbot 不認識的限制條件或含有衝突限制條件的 macaroon 將被拒絕。 |
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 使用 Lightning 方法讓他們自行處理付款挑戰;將他們引導至端點並讓他們完成付款。
影片
已付費 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");
如果未結算的渲染失敗,款項將會落入其中。狀態 URL 顯示
refund_sats 對於已退款但從未取得 token 的工作,因此分享狀態 URL 並不會分享退款資訊。檢查 token 也會結算那些沒有人輪詢的失敗工作。
退款
如果付費請求失敗且供應商針對該次嘗試向 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 天後過期。它持有 sat 餘額,您可以:
- 用它支付。 傳送
Authorization: Bearer REFUND-…在上述任何端點上(OpenAI SDK 將其視為其 API 金鑰)。價格取決於 token,且剩餘部分將保留在上面(refund_token_sats在nymbot物件)。一個價值低於請求的權杖回答了402refund_insufficient; 一次未結算的失敗會將 sats 放回同一個代幣上。 - 檢查一下。
GET /api/v1/l402/refunds使用相同的標頭 回傳{"sats": 237, "status": "open", "expires_at": "..."}. - 一個代幣每分鐘最多可以使用 60 次。
- 將它移至一個匿名帳號。 貼上到 兌換禮品 在
Nymbot app 中,或致電
POST /api/v1/l402/refunds/redeem帶有一個 已簽署的請求 和{"refund_token": "REFUND-...", "balance": "standard"}(或"pro"). 所有額度都歸入餘額(標準版每個 10 sats,Pro 版 100 sats);不足一個完整額度的 sats 將保留在 token 中以供 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 } }