Sciobazo Programistoj
Saldo, reŝargoj kaj ŝlosiloj
Kontrolu kion vi havas, plenigu per Lightning, plenigu aŭtomate el via propra monujo, vidu kiom ĉiu peto kostis, kaj administru ŝlosilojn el kodo.
Ĉi tiu paĝo estas maŝintradukita por komforto. La angla originalo estas la versio kiu validas.
Kontrolante la saldon
Ambaŭ viaj saldoj, kaj kiom de la limo de ĉi tiu ŝlosilo estas uzata.
GET https://nymbot.ai/api/v1/credits/balance — bezonas API-ŝlavenon. POST funkcias ankaŭ, por klientoj kiuj atendas tion.
balance ĉu la du saldoj kune en dolaroj laŭ la nuna Bitcoin-prezo, por
iloj kiuj atendas ununumbron (null se la prezo ne povas esti legata). La resto estas en
kreditoj kaj sats, kiel la saldoj estas fakte konservataj. key priskribas la ŝlosilon
kiun ĝi petis. Ŝlosilo, kiu atingis sian limon, ankoraŭ povas kontroli la saldon.
Respondo
{
"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"
}
}
| Stato | Kiam |
|---|---|
401 | La ŝlosilo mankas, estas nekonata, revokita aŭ expirita. |
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);
Pagmetodoj
Kiel vi povas reŝarĝi, kaj la limoj. Lightning estas la sola metodo.
GET https://nymbot.ai/api/v1/topup/payment-methods — neniu ŝlosilo bezonata.
Plenigo estas de 10 ĝis 1 000 000 sats; Pro-plenigo devas aĉeti almenaŭ unu Pro-krediton, do ĝi komenciĝas
je 100 sats. La dolaraj limoj sekvas la Bitcoin-prezon. bulk_bonus listigas la plustonon de kredito ĉe pli grandaj reŝargoj, same kiel en la aplikaĵo: 10%, 15% aŭ 20% pli ĉe normaj reŝargoj de
500, 1,000 aŭ 5,000 sats, kaj ĉe Pro-reŝargoj de 5,000, 10,000 aŭ 50,000 sats.
Respondo
{
"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);
Aldonado de kreditो per Lightning
Kreas Lightning-fakturon, kiu aldonas krediton al la nym, al kiu la ŝlosilo apartenas. Pagu ĝin el iu ajn Lightning-portfolio, tiam kontrolu ĝin por havi la krediton aldonitan.
POST https://nymbot.ai/api/v1/topup/create/btc-lightning — bezonas API-ŝlavenon.
| Kampo | Skribi | Dezirindata | Priskribo |
|---|---|---|---|
amount | numero | Jes | Kiom, en currency. Plena nombro por satoj. |
currency | ŝnuro | Ne | SATS (la defaŭlto), USD aŭ BTC. Dolároj estas konvertitaj laŭ la nuna Bitcoin-prezo. |
tier | ŝnuro | Ne | pro (la defaŭlto) aŭ standard: al kiu saldo la kredito iras. |
Standarda kredito estas 10 sats kaj Pro-kredito 100 sats, kune kun iu ajn amasa bonuso;
credits diras kion ĉi tiu fakturo aldonos.
Respondo
{
"invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
"payment_request": "lnbc100u1p5...",
"amount_sats": 10000,
"credits": 115,
"tier": "pro",
"expires_at": "2026-09-30T09:27:00Z",
"status": "pending"
}
| Stato | Kiam |
|---|---|
400 | Alia metodo en la vojo (unsupported_method), nekonata valuto (unsupported_currency) aŭ nivelo, manka kvanto, aŭ kvanto sub la minimumo (amount_too_small), super 1,000,000 sats (amount_too_large) aŭ rifuzita de la Lightning-monoŝlupo (amount_out_of_range). |
429 | Plej ol 60 fakturoj por ĉi tiu nomo, aŭ 120 de ĉi tiu adreso, en unu horo (rate_limit_exceeded, kun Retry-After). |
502 | Neniu fakturo povus esti farita nun (invoice_unavailable, kun 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);
Kontrolante reŝargilon
Demandas ĉu la fakturo estas pagita kaj, post kiam ĝi estas, aldonas la krediton. Kontrolado estas tio, kio
kreditas ĝin, do post pagado, kontrolu ĝis la stato estas credited. Re-kontrolado poste estas sekura: la kredito alvenas unufoje, ĉu kiom ajn multajn fojojn vi petas.
GET https://nymbot.ai/api/v1/topup/status/{invoice_id} — bezonas ŝlosilon de la nimo, kiu faris la fakturon.
status estas pending (ankoraŭ ne pagita), paid (pagita, sed ankoraŭ ne
kredita; kontrolu denove), credited (sur via saldo) aŭ expired (ne pagita
tempovide). La kampoj de saldo estas por la nivelo, kiun la fakturo plenigas.
Respondo
{
"invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
"status": "credited",
"amount_sats": 10000,
"credits": 115,
"tier": "pro",
"expires_at": null,
"balance_credits": 523.33,
"balance_sats": 52333
}
| Stato | Kiam |
|---|---|
400 | La identigilo ne estas la 64-karakterlonga identigilo el la krea vokado. |
404 | Neniu fakturo per tiu ID por via pseudonimo (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);
Historio de demandoj
Unu rondo por peto: kio ĝi estis, kiu modelo, kiom da tokenoj kaj kio ĝi kostis. Neniuj promptoj aŭ respondoj estas konservataj, do neniu estas redonita. Rondoj estas konservataj dum 90 tagoj, plej novaj unuaj. Klavo kiu atingis sian limon ankoraŭ povas legi sian historion.
GET https://nymbot.ai/api/v1/queries/history — bezonas API-ŝlosilon, kiu vidas siajn proprajn petojn, aŭ subskribita peto el via nomo, kiu vidas ĉiun ŝlosilon.
| Kampo | Skribi | Dezirindata | Priskribo |
|---|---|---|---|
page | entiero (kvrido) | Ne | Defaŭlto 1, maksimume 1,000; pli alta paĝo estas 400 invalid_value. |
page_count | entiero (kvrido) | Ne | Linioj por paĝo. Defaŭlte 20, maksimume 100. |
start_dateend_date | ĉeno (demando) | Ne | ISO 8601 datoj aŭ tempoj. |
model | ĉeno (demando) | Ne | Nur ĉi tiu modelo. |
type | ĉeno (demando) | Ne | chat, responses, messages, image, video, speech, transcription aŭ embedding. |
all_keys | booleana (demando) | Ne | Kun ŝlosilo: true inkluzivas ĉiun ŝlosilon de la sama sufikso. Defaalto false. |
key_id | ĉeno (demando) | Ne | Per subskribita peto, aŭ per all_keys=true: nur ĉi tiu ŝlosilo. |
Respondo
{
"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);
Subskribado de kontaj petoj
Krei, ŝanĝi kaj revoki ŝlosilojn, la kontosummunon kaj aŭtomatajn plenigojn ne postulas API-ŝlosilon. Ili postulas subskribon de via nym, do fuŝita ŝlosilo povas elspezi ĝis sian limon, sed neniam povas krei alian ŝlosilon aŭ levni sian propran limon.
La aplikaĵo faras tion por vi: ĉion en ĝia API tabulo uzas ĉi tiujn finpunktojn. Vi nur bezonas ĉi tiun sekcion por administri ŝlosilojn el via propra kodo.
La subskribo estas Nostr-evento de speco 27235 (NIP-98), sendita base64-ŝifrite en la
Authorization ĉeftitolo kun la vorto Nostr antaŭe:
La evento
{
"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ĉu la plena URL de la peto, inkluzive de la demando-ĉeno, estas tute tiel kiel sendita.methodestas la HTTP-metodo.payloadestas la SHA-256 de la ruĝa peto-korpo, en hex. Ĝi estas postulata enPOSTkajPATCH, kaj la korpo kiun vi sendas devas esti bajto post bajto la unu kiun vi haseis.created_atdevas esti ene de 60 sekundoj de la horloĝo de la servilo.- Ĉiu evento funkcias unufoje, a
GETinkluzivite, do kaptita ĉefliko ne povas esti reŝaltita. Subskribu novan por ĉiu peto. Aldonu ĵaŭnonceetendo kun hazardvaloro tiel du petoj subskribitaj en la sama sekundo ankoraŭ diferencas. - La korpo de subskribita peto povas esti maksimume 64 KB, kaj korpo bezonas
Content-Type: application/json.
Mankanta evento revenas 401 missing_nostr_auth; unu kiu estas malbone
formita, malbone subskribita, tro malnova, aŭ por malsama URL, metodo aŭ korpo revenas
invalid_nostr_auth, kun la kialo en la mesaĝo; reuzita revenas
nostr_auth_replayed. API-ŝlosilo sendita al tiuj estponoj estas malakceptita. La subskribo
estas kontrolita antaŭ ol la korpo estas legita, kaj ĉiu adreso povas malsukcesi pri ĝi 30 fojojn minute (IPv6-adreso
kalkulas kiel sia tuta /64); post tio ĝi ricevas 429 kun
Retry-After.
Retumiloj povas voki tiujn finpunktojn nur el la propraj retejoj de Nymbot (https://nymbot.ai,
https://nymchat.app kaj iliaj subdomenoj). Paĝo sur iu ajn alia retejo ne ricevas CORS
intestarojn, do ĝi ne povas legi tion, kion ili redonas. Skriptoj kaj denaskaj aplikaĵoj, kiuj ne sendas
Origin, ne estas afektitaj.
Subskribado bezonas la sekretan ŝlosilon de via nimo (la nsec), kiu kontrolas
ĉion: vian identecon, vian historion kaj vian saldon. Metu ĝin nur en skripton en
maŝino, kiun vi fidas, legu ĝin el la medio anstataŭ skribi ĝin en la dosieron, kaj
preferu la aplikaĵon kiam vi povas.
Tiuj helpiloj konstruas la ĉeflinion. La postaĵaj ekzemploj sur ĉi tiu paĝo uzas ilin. Ili legas la sekretan ŝlosilon en heksadecimala formo el NOSTR_SECRET_HEX; la cURL-ia uzas la
nak komandlinia ilo, kiu akceptas nsec- aŭ hex-
ŝlosilon, kaj sha256sum (sur 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");
}
La kontsumo de la konto
Kion la API-foldeEstas de la apliko montras ĉe la supro: via publika ŝlosilo, ambaŭ saldoj, kiom da ŝlosiloj estas
aktivaj (ne revokitaj aŭ expirintaj), kaj la aŭtomata reŝargado agordoj, aŭ
null kiam la servilo ne proponas ilin.
GET https://nymbot.ai/api/v1/account — bezonas subskribita peto.
Respondo
{
"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());
Administrado de ŝlosiloj
La finepunktoj malantaŭ la ŝlosillisto de la aplikaĵo. Ili ĉiuj bezonas subskribita peto. Ĉiu ŝlosilo estas redonita en ĉi tiu formo, kun tempoj en ISO 8601 kaj montoj en sats:
Ŝlosila objekto
{
"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 sufiĉas por rekoni ŝlosilon sed ne por uzi ĝin. La ŝlosilo mem estas redonata
nur unufoje, kiam ĝi estas farita.
Listigo de ŝlosiloj
GET https://nymbot.ai/api/v1/keys — subskribite.
| Kampo | Skribi | Dezirindata | Priskribo |
|---|---|---|---|
include_revoked | booleana (demando) | Ne | Inkluzivu revokitajn ŝlosilojn. Defaŭlto false. |
Respondo
{ "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);
Fabrikado de ŝlosilo
POST https://nymbot.ai/api/v1/keys — subskribita. Returoj 201.
| Kampo | Skribi | Dezirindata | Priskribo |
|---|---|---|---|
name | ŝnuro | Jes | De 1 ĝis 40 karakteroj, malsama de viaj aliaj aktivaj ŝlosiloj (ignorante la distingon inter majuskloj kaj malgrandaj literoj). |
limit_sats | entiera nombro | Ne | La elspezlimo en sats, almenaŭ 1. Lasu ĝin for por sen limigo. |
reset_period | ŝnuro | Ne | daily, weekly aŭ monthly. Bezonoj limit_sats. Lasu ĝin eksteren por ĉapelo, kiu neniam reaseta. |
expire_at | ĉeno aŭ entiero | Ne | Kiam la ŝlosilo ĉesas funkcii: ISO 8601 tempo, aŭ milisekundoj ekde 1970. |
Respondo (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"
}
}
| Stato | Kiam |
|---|---|
400 | Mankanta aŭ tro longa nomo; nomo jam uzata (duplicate_name); limigo, kiu ne estas tuta nombro de almenaŭ 1; nuliga periodo sen limigo; eksvalidigo en la pasinteco; nekonata kampo (unknown_parameter); aŭ jam 25 aktivaj ŝlosiloj (too_many_keys). |
429 | Plej ol 60 ŝlosiloj faritaj de ĉi tiu nimeco, aŭ 120 de ĉi tiu adreso, en unu horo (rate_limit_exceeded, kun 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);
Legi unu ŝlosilon
GET https://nymbot.ai/api/v1/keys/{id} — subskribite.
Revenoj {"data": {…}} per la ŝlosila objekto, aŭ 404
key_not_found se neniu de viaj ŝlosiloj havas tiun identigilon.
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);
ŝanĝi ŝlosilon
PATCH https://nymbot.ai/api/v1/keys/{id} — subskribite.
Sendu ajen de name, limit_sats, reset_period kaj
expire_at, kun la samaj reguloj kiel kiam farante ŝlosilon. null malplenigas kampon: sen limigo, sen reinitialigo, sen eksvalidigo. Ŝanĝi la reinitialigan periodon komencas novan periodon ĉe nulo. Revokita ŝlosilo ne povas esti ŝanĝita (400 key_revoked). Revenoj
{"data": {…}} kun la ĝisdatigita ŝlosila objekto.
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);
Revokado de ŝlosilo
DELETE https://nymbot.ai/api/v1/keys/{id} — subskribite.
Haltenas la ŝlosilon tuj, por ĉiam. Ĝi restas en la listo kun revoked_at fiksita, kaj povas esti vidata kun include_revoked=true. Revoki ŝlosilon, kiu jam estas revokita, respondas laŭ la sama maniero. Nur la plej novaj 50 revokitaj ŝlosiloj estas konservataj; pli malnovajoj estas fordelataj kiam alia ŝlosilo estas revokita.
Respondo
{ "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 aŭtomata plenigo
Konektu Lightning-portofolon per Nostr Wallet Connect kaj Nymbot memstare plenigas saldon kiam API-elspezoj malpliigas ĝin. La API-tabulo de la aplikaĵo havas la samajn agordojn; ĉi tiuj estas la terminalpunktoj malantaŭ ĝi. Ĉiuj de ili bezonas a subskribita peto.
Kiel ĝi funkcias: post kiam API-peto estas elŝutita el la saldo, kiun vi elektis por spuri, se tiu saldo falis sub vian limvaloron, Nymbot faras fakturon por via pleniga sumo, petas vian monofonon pagi ĝin, kaj aldonas la krediton. Ĝi plenigas plej multiveke unufoje ĉiun 5 minuton por ĉiu nym kaj saldo, do fulmveto da petoj ne povas elĉuigi la monofonon. Elspezoj en la apoj ne provokas ĝin. La tempo kaj grandeco de la lasta plenigo, kaj la lasta eraro, estas en la agordoj; se pagado sukcesis post eraro, kontroli ĝian fakturon per la stato de la reaplikuĝo kreditas ĝin.
Konekstra stringo permesas al iu ajn, kiu posedas ĝin, peti vian portfolion pagi. Nymbot
konservas ĝin ĉifrite kaj ĉiam uzas ĝin nur por pagi siajn propriajn plenigon-fakturojn, sed kreu
konekton nur por tio, kun elspezbudjeto en via portfolio, por ke la plej multa, kion ĝi iam
povus pagi, estu nombro, kiun vi elektis. La portfolio devas subteni pay_invoice.
Konekti portfolion
POST https://nymbot.ai/api/v1/nwc-auto-topup/connect — subskribite.
| Kampo | Skribi | Dezirindata | Priskribo |
|---|---|---|---|
nwc_url | ŝnuro | Jes | La konekstraĵo, komencante nostr+walletconnect://. Nymbot petas la portfolion pri get_info antaŭ konservado de ĝi, kaj konservas ĝin ĉifrite. |
threshold_sats | entiera nombro | Jes | Ŝarĝu kiam la saldo falas sub ĉi tiom da sats. Almenaŭ 1,000. |
topup_sats | entiera nombro | Jes | Kiom aldonu ĉiumerke. 1,000 ĝis 1,000,000 sats. |
tier | ŝnuro | Ne | pro (la defaŭlto) aŭ standard: la saldo por viglidi kaj reŝargi. |
Respondo
{
"data": {
"connected": true,
"threshold_sats": 5000,
"topup_sats": 20000,
"tier": "pro",
"last_topup_at": null,
"last_topup_sats": null,
"last_error": null
}
}
| Stato | Kiam |
|---|---|
400 | Ne konekstra ĉeno (invalid_nwc_url); la portfolio ne respondis per sia rellegio (nwc_unreachable) aŭ rifuzis la ĉekon (nwc_rejected); la konekto ne povas pagi fakturojn (nwc_missing_permission); aŭ kvanto ekster la limoj. |
501 | Aŭtomataj plenigas ne estas aktivigitaj por ĉi tiu servilo (nwc_unavailable). La sama aplikiĝas al la aliaj du finiĝpunktoj. |
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());
Legante la agordojn
GET https://nymbot.ai/api/v1/nwc-auto-topup — subskribite.
Redonas la saman objekton kiel koneki, kun connected: false kaj la aliaj kampoj
null kiam neniu portfolio estas konektita. La konektiga ĉeno mem neniam
estas revenigita.
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());
Mal konektiĝante
DELETE https://nymbot.ai/api/v1/nwc-auto-topup/connection — subskribite.
Forvortigas la konservitan konekstrigon. Neniuj plenigoj plu estos farataj. Por esti certa, vi ankaŭ povas revoki la konekton en via portmoneo.
Respondo
{ "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());
Pagado po peto sen ŝlosilo
La fiksprezaj defrenĉoj povas esti pagitaj por unu peto foje tuj per Lightning, sen ŝlosilo,
sen konto kaj sen saldo: POST /images/generations, POST /images/edits,
POST /videos, POST /audio/speech, POST /audio/transcriptions,
POST /audio/translations kaj POST /embeddings. Babiloj, Respondoj kaj
Mesagoj ĉiam bezonas ŝlosilon. Peto, kiu portas ŝlosilon, estas fakturita al la saldo kiel kutime; la
pagfluo nur komenciĝas kiam neniu ŝlosilo estas sendita.
Nymbot parolas du versiojn de la sama ideo, el unu backend: Lightning Labs'
L402 (ankaŭ akceptita sub sia malnova nomo, LSAT) kaj la IETF-ŝarpon
Pagado HTTP-aŭtentikiga skemo kun la lightning metodo kaj
charge intenco. Uzu tion, kiun via kliento komprenas.
Pagado sen ŝlosilo estas aktiva nur kiam API_L402_SECRET tenas almenaŭ 32 hasardajn
bajtojn, kiel hex (64 karakteroj) aŭ base64 (44). Faru unu kun openssl rand -hex 32.
Mallonga aŭ atributebla valoro malŝaltas la funkcion kaj registras kial. Por rotigi ĝin, movu la malnovan
valoron al API_L402_SECRET_PREVIOUS dum unu tago: kredencialoj, status-URL-oj kaj
defioj faritaj sub ĝi daŭre funkcias ĝis ili ekspiras.
La defio
Sendu la peton sen neniu Authorization intesto. Se ĝi estas valida, nenio funkcias, kaj
vi ricevas 402 Payment Required kun fakturo por precize tio, kion tiu peto kostas: la sama prezo, kiun ŝlosilo pagus, konvertita al 10 satoj por standarda kredito aŭ 100 satoj por Pro-kredito kaj rondigita supraŭ al tuta sato (almenaŭ 1 sato, kaj almenaŭ la 0,05-kredita minimumo). La respondo portas tri WWW-Authenticate defioj por la sama fakturo:
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 }
}
La pago request parametro estas base64url JSON:
{"amount":"237","currency":"sat","methodDetails":{"invoice":"lnbc...","network":"mainnet","paymentHash":"..."}}.
Defio estas ligita al la fino, al la Content-Type (Ĝia mediatipo kaj, por
multipart, ĝia limo) kaj al la SHA-256 de la precizaj korpaj bajtoj kiujn vi sendis, kaj daŭras 15
minutojn. Post pagado, sendu la identika petu denove: la sama
Content-Type kaj la samaj JSON-bajtoj, aŭ por la multipart-unuopunktoj
(/images/edits, /audio/transcriptions, /audio/translations)
la saman multipart-korpon kun la sama limo. Plej multaj HTTP-bibliotekoj elektas novan limon ĉiu
foje kiam ili kodas formularon, do kodu ĝin unufoje kaj sendu tiujn bajtojn dufoje.
Ĉiu adreso povas peti 30 defiojn je minuto (IPv6-adreso okazas kiel sia tuta /64). Petoj, kies adreso ne estas konata, dividas pli striktan limigon de 10 je minuto, kaj ekzistas ĝenerala supra limo de la defioj, kiujn Nymbot eldonas tra ĉiuj adresoj; peto malakceptita antaŭ ol defio estas farita (ekzemple per korpo, kiu ne estas valida JSON) ne kalkulas al ĝi. Preter tio la respondo estas 429 kun Retry-After, sendita antaŭ ol la korpo estas legata. Pagitaj
punktoj vokitaj sen ŝlosilo aŭ kredencialo ankaŭ kalkulas al la ĝenerala limo de 120
neautentikitaj petoj po minuto por adreso. Kredencialo estas kontrolita antaŭ ol la korpo estas
legata, kaj peto kies Content-Type ne estas application/json (aŭ
multipart/form-data por ŝarĝoj) estas rifuzata per 415 kaj neniam ricevas
fakturon.
Embedoj estas prezigitaj laŭ estimato de la tokenoj en la enigo, kun 1.5× margeno, ĉar la reala nombro estas konata nur poste. Vi pagas por la tokenoj efektive uzataj, kaj la neuzata parto de la pago revenas kiel bonpaga jetono.
Sendante la pagon
Pagu la fakturon per iu ajn Lightning-portfolio. La portfolio donas al vi la preimagenon, 64 heksadecimajn karakterojn. Tiam sendu la saman peton per unu el ĉi tiuj:
| 로도 | Headero |
|---|---|
| L402 | Authorization: L402 <macaroon>:<preimage> (LSAT funkcias ankaŭ) |
| Pagado | Authorization: Payment <base64url JSON>, kie estas la JSON {"challenge": {every parameter of the challenge, as sent}, "payload": {"preimage": "<hex>"}} |
Pagita peto respondas tute same kiel unu farita per ŝlosilo, krom ke la nymbot
objekto ne havas balansajn kampojn: {"payment": "l402", "tier": "pro", "paid_sats": 237,
"charged_sats": 237}, kaj ne estas X-Nymbot-Balance-Sats kapo. Peto pagita per la pagskemo ankaŭ ricevas Payment-Receipt header (base64url
JSON kun la defio-id, la pag-hasto kiel reference, status kaj
timestamp). Pagitaj petoj ne estas ligitaj al iu ajn nimo, do ili ne aperas en la
kverio-historio.
| Stato | Kiam |
|---|---|
402 payment_already_used | Ĉiu pagado pagas por unu peto. La respondo estas freŝa defio por ĉi tiu peto, do kliento, kiu kaŝas sian lastan kredencialon (kiel lnget simple vereなje pagas denove. |
402 payment_mismatch | La kredencialo estis eldonita por alia fino, Content-Type a korpo, aŭ pagas malpli ol ĉi tiu peto nun kostas. Nova defio por ĉi tiu peto venas kun ĝi; se la pago estis tro malgranda, tio kion vi pagis revenas kiel bonpaga jetono (refund_token kaj refund_sats en la korpo). |
402 payment_expired | Plej ol 15 minutoj pasis ekde la defio. Nova defio venas kun ĝi. Se la antaŭbildo montras, ke vi pagis, tio kion vi pagis revenas kiel bonpaga jetono (refund_token kaj refund_sats en la korpo), unufoje; la kredencaĵo tiam estas eluzita. |
401 invalid_preimage | La antaŭbildo ne haseas al la pag-hasiĝo de la fakturo. La pago ne estas eluzita. |
401 invalid_payment_credential | La kredencialo estas malformita, estis ŝanĝita post kiam Nymbot eldonis ĝin, aŭ nomas pag-hason por kiu Nymbot neniam eldonis fakturon. Makarono kun limigo kiun Nymbot ne konas, aŭ kun kontradiktaj limigoj, estas rifuzita. |
429 rate_limit_exceeded | Plej ol 30 kredenciais aŭ ŝlosiloj, kiuj malsukcesis verigi, venis de ĉi tiu adreso en unu minuto, aŭ unu rinfunda ŝlosilo estis sendita pli ol 60 fojojn en unu minuto. Atendu por 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"));
Klientoj konstruitaj sur mppx per Lightning-metodo traktu la pagan ĉalendon
mem; direktu ilin al la fino kaj lasu ilin pagi.
Videoj
Pagita POST /videos respondoj 202 simila al ŝlosila, plus a
status_url: GET ĝi sen iu ajn ŝlosilo por sekvi la laboron. Ĝi estas subskribita kaj funkcias dum 24 horoj, tiel longe kiel la laboro estas konservita.
{
"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..."
}
}
Konservu la refund_token el tiu respondo: ĝi estas montrita nur ĉi tie. Ĝi estas malplena dum
la video rindeas (GET /api/v1/l402/refunds respondoj "status": "pending");
se la rendo malsukcesas nefakture, la pago landas sur ĝi. La statuso URL montras
refund_sats por reredita tasko sed neniam la tokenon, do dividi la status-URL ne dividas la rerediton. Kontroli la tokenon ankaŭ finas ne sukcesan taskon, kiun neniu kontrolis.
Refundoj
Se pagita peto malsukcesas kaj la provizanto fakturis Nymbot por la provo, la pagon estas konservata kaj
la eraro diras tion, kun charged_sats, precize kiel por ŝlosila peto. Se ĝi malsukcesas sen esti fakturigita, la eraro portas bonpaga jetono valoras tion, kion vi pagis:
{
"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"
}
}
Neuzataj partoj revenas en la sama maniero: se vi petis du bildojn kaj unu malsukcesis ne fakturite, la sukcesa respondo's nymbot objekto portas refund-tokenon por la mankaĵo;
transkriptaĵo, kies longon ne povis esti legita antaŭe, estas priskribita laŭ la plej longa ebla longo de la dosiero
(neniam pli ol 30 minutoj), kaj la diferenco al la reala longo revenas kiel
refund-tokeno; se ĝi okazas esti pli longa ol 30 minutoj, ĝi estas rifuzata kun 413
kaj la tuta pagado revenas. Embedingoj redonas tion, kion la estimado retenis. Malfelcita video refundigas al la jetono, kiun ĝia submeto redonis.
Refund-token estas hazarda 256-bita kodo. Nymbot konservas nur ĝian haŝon, kaj ĝi eksvalidiĝas post 30 tagoj. Ĝi enhavas sat-saldon, kaj vi povas:
- Pagu per ĝi. Sendi
Authorization: Bearer REFUND-…sur iu ajn de la fino-punktoj supre (OpenAI SDK prenas ĝin kiel sian API-ŝlosilon). La prezo venas el la tokeno kaj tio, kio restas, restas sur ĝi (refund_token_satsen lanymbotobjekto). Tokeno valora malpli ol la peto respondas402refund_insufficient; nefakturita malsukceso metas la satŝojn reen sur la saman tokenon. - Kontrolu ĝin.
GET /api/v1/l402/refundskun la sama ĉeftitolo rezultas{"sats": 237, "status": "open", "expires_at": "..."}. - Unu tokeno povas esti uzata plej multfoje 60 fojojn ene de unu minuto.
- Movu ĝin al nimo. Alglui ĝin en Redemu donacon en la
Nymbot-aplikaĵo, aŭ telefoni
POST /api/v1/l402/refunds/redeemkun unu subskribita peto kaj{"refund_token": "REFUND-...", "balance": "standard"}(aŭ"pro"). La tutaj kreditoj iras al la saldo (10 sats ĉium de standard, 100 sur Pro); sats kiuj ne formis plenan krediton restas sur la token por API petoj.
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"
Respondo
{ "data": { "credited": 23, "tier": "standard", "balance_credits": 123, "remaining_sats": 7 } }