Preskoči na vsebino
Nazaj na Nymbot

Baza znanja razvijalci

Ravnovesje, top-ups in ključi

Preverite, kaj imate, nadgradite Lightning, nadgradite samodejno iz lastne denarnice, si oglejte, koliko stane vsaka zahteva in upravljajte ključe iz kode.

Preverjanje ravnotežja

Oba vaša ravnotežja in koliko tega ključa je uporabljeno.

GET https://nymbot.ai/api/v1/credits/balance Potrebujete API ključ. POST Deluje tudi za stranke, ki to pričakujejo.

balance je dva ravnovesja skupaj v dolarjih po trenutni ceni Bitcoin, za orodja, ki pričakujejo eno število (null če se cena ne more prebrati). preostanek je v kreditih in zneskih, kar je način, kako se ravnotežje dejansko ohranja. key Ključ, ki je dosegel svojo mejo, lahko še vedno preveri ravnovesje.

Odgovor

{
  "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"
  }
}
statusaKdaj
401Ključ je manjkajoč, neznan, preklican ali potekel.

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);

Načini plačila

Kako lahko nadgradite, in meje. Lightning je edina metoda.

GET https://nymbot.ai/api/v1/topup/payment-methods Ključ ni potreben.

Top-up je 10 do 1.000.000 sats; Pro top-up mora kupiti vsaj en Pro kredit, zato se začne pri 100 sats. bulk_bonus navaja dodaten kredit na večjih top-upih, enako kot v aplikaciji: 10%, 15% ali 20% več na standardnih top-upih od 500, 1.000 ali 5.000 sats, in na Pro top-upih od 5.000, 10.000 ali 50.000 sats.

Odgovor

{
  "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);

Spuščanje nad Lightning

Ustvarja Račun Lightning, ki dodaja kredit k nimmu, ki mu pripada ključ. Plačajte ga iz katere koli denarnice Lightning, nato Preverite ga Za dodajanje kredita.

POST https://nymbot.ai/api/v1/topup/create/btc-lightning Potrebujete API ključ.

poljeVrstaPotrebnoOpis
amountštevilojaKoliko je, v currencyCelotno število za stavo.
currencyStringneSATS (v primeru nepravilnosti) USD ali BTCDolarji se pretvorijo po trenutni ceni Bitcoin.
tierStringnepro (odvisno od dolžnosti) ali standard: v katero bilanco gre kredit.

Standardni kredit je 10 sats in Pro kredit 100 sats, plus kateri koli bonus v razsutem stanju; credits Povejte, kaj bo dodal ta članek.

Odgovor

{
  "invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
  "payment_request": "lnbc100u1p5...",
  "amount_sats": 10000,
  "credits": 115,
  "tier": "pro",
  "expires_at": "2026-09-30T09:27:00Z",
  "status": "pending"
}
statusaKdaj
400Druga metoda na poti (unsupported_method), neznana valuta (unsupported_currency) ali ravni, manjkajoči znesek ali znesek pod najmanjšo vrednostjo (amount_too_small(več kot 1 milijon dolarjev)amount_too_large) ali zavrnjen s svetlobno denarnico (amount_out_of_range).
429Več kot 60 računov za to nimm, ali 120 iz tega naslova, v eni uri (rate_limit_exceeded, z Retry-After).
502Trenutno ni mogoče izvesti nobenega računa (invoice_unavailable, z 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);

Preverjanje top-up

Vpraša, ali je bil račun plačan in, ko je, dodaja kredit. Preverjanje je tisto, kar ga kreditira, zato po plačilu preverite, dokler stanje ni creditedPonovno preverjanje pozneje je varno: kredit pristane enkrat, ne glede na to, kolikokrat vprašate.

GET https://nymbot.ai/api/v1/topup/status/{invoice_id} - potrebuje ključ od nimma, ki je naredil račun.

status je pending (za zdaj še ni plačana) paid (plačano, vendar še ni kreditirano; preverite še enkrat), credited (na vašem ravnovesju) ali expired (ni plačano pravočasno). polja ravnovesja so za raven, na kateri se obračuna račun.

Odgovor

{
  "invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
  "status": "credited",
  "amount_sats": 10000,
  "credits": 115,
  "tier": "pro",
  "expires_at": null,
  "balance_credits": 523.33,
  "balance_sats": 52333
}
statusaKdaj
400ID ni 64-mestni ID iz klica za ustvarjanje.
404Nihče ne ve, kje se nahaja tvoja hiša (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);

Želi zgodovino

Ena vrstica na zahtevo: kaj je bilo, kateri model, koliko žetonov in koliko stane. Ni opozoril ali odgovorov, zato noben ni vrnjen. Vrstice so shranjene 90 dni, najprej najnovejše. Ključ, ki je dosegel svojo mejo, lahko še vedno prebere svojo zgodovino.

GET https://nymbot.ai/api/v1/queries/history — potrebuje API ključ, ki vidi lastne zahteve, ali Podpisana zahteva iz vašega nimma, ki vidi vsak ključ.

poljeVrstaPotrebnoOpis
pagePovpraševanje (vključno z vprašanjem)nePrivzeto 1, največ 1000; višja stran je 400 invalid_value.
page_countPovpraševanje (vključno z vprašanjem)neVrstice na stran. Privzeto 20, največ 100.
start_date
end_date
String (poizvedba)neISO 8601 datumi in časi.
modelString (poizvedba)neSamo ta model.
typeString (poizvedba)nechat, responses, messages, image, video, speech, transcription ali embedding.
all_keysBoolean (poizvedba)neZ enim ključem: true vključuje vsak ključ istega nimma. privzeto false.
key_idString (poizvedba)neS podpisano zahtevo ali s all_keys=trueSamo ta ključ.

Odgovor

{
  "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);

Podpis računskih zahtevkov

Ustvarjanje, spreminjanje in preklic ključev, povzetek računa in samodejni top-up ne vzamejo API ključa. Vzamejo podpis iz vašega nimma, tako da lahko ujet ključ porabi do svoje meje, vendar nikoli ne more narediti drugega ključa ali dvigniti lastne meje.

Aplikacija to počne za vas: vse v svoji ogenj Ta odsek potrebujete le za upravljanje ključev iz lastne kode.

Podpis je dogodek Nostr vrste 27235 (NIP-98), ki je bil poslan s kodiranjem base64 v Authorization Header z besedo Nostr Na sprednji strani:

Dogodek

{
  "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 je celoten URL zahteve, vključen niz poizvedb, točno tako, kot je bil poslan.
  • method To je HTTP metoda.
  • payload je SHA-256 surovega zahtevnega telesa, v hex. POST in PATCH, in telo, ki ga pošljete, mora biti bajt za bajt, ki ste ga hashed.
  • created_at mora biti v 60 sekundah od ure strežnika.
  • Vsak dogodek deluje enkrat, a GET vključena, tako da zajetega glave ni mogoče predvajati. Podpišite novega za vsako zahtevo. nonce označite z naključno vrednostjo, tako da se dve zahtevi, podpisani v isti sekundi, še vedno razlikujeta.
  • Telo podpisane zahteve je lahko največ 64 KB, telo pa potrebuje Content-Type: application/json.

Manjkajoči dogodek se vrača 401 missing_nostr_auth; ena, ki je slabo oblikovana, slabo podpisana, preveč stara ali za drugačen URL, metodo ali telo vrne invalid_nostr_auth, z razlogom v sporočilu; ponovno uporabljen se vrne nostr_auth_replayedPodpis se preveri, preden se telo prebere, in vsak naslov lahko ne uspe 30 krat na minuto (IPv6 naslov šteje kot celoto /64); potem dobi 429 s Retry-After.

Brskalniki lahko te končne točke pokličejo samo iz lastnih spletnih mest Nymbota (https://nymbot.ai, https://nymchat.app Stran na katerem koli drugem mestu ne dobi nobenih naslovov CORS nazaj, zato ne more prebrati tega, kar vrnejo. Originin niso prizadeti.

Vaš skrivni ključ

Podpis potrebuje skrivni ključ vašega nimma (na nsec), ki nadzoruje vse: vašo identiteto, vašo zgodovino in vašo bilanco. Samo ga postavite v skript na stroju, ki mu zaupate, ga preberite iz okolja, namesto da bi ga zapisali v datoteko, in raje uporabite aplikacijo, ko lahko.

Ti pomočniki ustvarijo glavo. Kasnejši primeri na tej strani jih uporabljajo. Preberejo skrivni ključ v šestnem formatu iz NOSTR_SECRET_HEX; cURL ena uporablja Nak orodje ukazne vrstice, ki vzame nsec ali hex ključ, in sha256sum za 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");
}

Povzetek računa

Kaj aplikacija API list prikazuje na vrhu: vaš javni ključ, oba ravnotežja, koliko ključev so aktivni (ni preklican ali potekel), in Samodejni top-up nastavitve ali null če jih strežnik ne ponuja.

GET https://nymbot.ai/api/v1/account Potrebujejo a Podpisana zahteva.

Odgovor

{
  "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());

Upravljanje ključev

Končne točke za seznamom ključev aplikacije. Vsi potrebujejo Podpisana zahtevaVsak ključ se vrne v tej obliki, s časi v ISO 8601 in zneski v sats:

Ključni predmet

{
  "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 To je dovolj, da prepoznate ključ, vendar ga ne uporabite.Samo ključ se vrne le enkrat, ko je ustvarjen.

Seznam ključev

GET https://nymbot.ai/api/v1/keys je podpisal

poljeVrstaPotrebnoOpis
include_revokedBoolean (poizvedba)neVključuje preklicane ključe. privzeto false.

Odgovor

{ "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);

Izdelava ključa

POST https://nymbot.ai/api/v1/keys Podpis, vrnitev 201.

poljeVrstaPotrebnoOpis
nameStringja1 do 40 znakov, ki se razlikujejo od drugih aktivnih ključev (ne upoštevajte primera).
limit_satsintegerneIzdatki v plačilnem načrtu, vsaj 1. pustite ga brez plačila.
reset_periodStringnedaily, weekly ali monthlyPotrebe limit_satsPustite ga ven za pokrov, ki se nikoli ne ponastavi.
expire_atString ali integerneKo ključ preneha delovati: ISO 8601 čas, ali milisekund od leta 1970.

Odgovori na vprašanja (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"
  }
}
statusaKdaj
400Manjkajoče ali preveliko ime; že uporabljeno ime (duplicate_name); omejitev, ki ni celo število vsaj 1; obdobje ponastavitve brez omejitve; iztekanje v preteklosti; neznano polje (unknown_parameter); ali 25 aktivnih ključev že (too_many_keys).
429Več kot 60 ključev, ki jih ta nimm, ali 120 iz tega naslova, v eni uri (rate_limit_exceeded, z 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);

branje enega ključa

GET https://nymbot.ai/api/v1/keys/{id} je podpisal

Vrnitev {"data": {…}} s ključnim predmetom, ali 404 key_not_found če vaš ključ nima tega ID-ja.

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);

Spreminjanje ključa

PATCH https://nymbot.ai/api/v1/keys/{id} je podpisal

Pošljite katerokoli name, limit_sats, reset_period in expire_at, z enakimi pravili kot pri izdelavi ključa. null Počisti polje: brez omejitve, brez ponastavitve, brez poteka. Če spremenite obdobje ponastavitve, se novo obdobje začne z ničlo.400 key_revoked• Vrnitev {"data": {…}} z posodobljenim ključnim predmetom.

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);

Preklic ključa

DELETE https://nymbot.ai/api/v1/keys/{id} je podpisal

Zaustavite ključ naenkrat, za dobro. To ostane na seznamu s revoked_at postavljen, in ga je mogoče videti z include_revoked=truePreklic ključa, ki je že preklican, odgovori na enak način. Le zadnjih 50 preklicanih ključev je ohranjenih; starejši ključi so izbrisani, ko je preklican še en ključ.

Odgovor

{ "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 avto-top-up predvajanje

Povežite denarnico Lightning z aplikacijo Nostr Wallet Connect in Nymbot vzpostavi ravnovesje sam po sebi, ko poraba API teče nizko. Podpisana zahteva.

Kako deluje: ko se zahteva API zaračuna na stanje, ki ste ga izbrali za gledanje, če je to stanje padlo pod prag, Nymbot izda račun za vaš znesek, prosi vašo denarnico, da ga plača, in doda kredit. To se poveča največ enkrat vsakih 5 minut za vsak nim in ravnotežje, tako da izbruh zahtev ne more izprazniti denarnice. Poraba v aplikacijah ga ne sproži. Čas in velikost zadnjega top-up in zadnje napake sta v nastavitvah; če je plačilo šlo skozi po napaki, preverite svoj račun z Stanje top-up kreditov za to.

Preden povežete denarnico

Nymbot shranjuje šifrirano in jo uporablja samo za plačilo lastnih računov, vendar vzpostavi povezavo samo za to, s proračunom za porabo v denarnici, tako da je največ, kar bi lahko kdaj plačal, številka, ki ste jo izbrali. denarnica mora podpirati pay_invoice.

Povežite denarnico

POST https://nymbot.ai/api/v1/nwc-auto-topup/connect je podpisal

poljeVrstaPotrebnoOpis
nwc_urlStringjaVtičnica za povezavo, ki se začne nostr+walletconnect://Nymbot prosi za denarnico get_info preden ga shranite in shranite šifrirano.
threshold_satsintegerjaNa vrhu, ko je ravnovesje padlo pod te številne cene.
topup_satsintegerjaKoliko je treba vsakič dodati. 1000 do 1.000.000 sats.
tierStringnepro (odvisno od dolžnosti) ali standard: ravnovesje za opazovanje in zgoraj.

Odgovor

{
  "data": {
    "connected": true,
    "threshold_sats": 5000,
    "topup_sats": 20000,
    "tier": "pro",
    "last_topup_at": null,
    "last_topup_sats": null,
    "last_error": null
  }
}
statusaKdaj
400Ni povezave vrstice (invalid_nwc_url); denarnica ni odgovorila na svoj prenos (nwc_unreachable) ali zavrnil preverjanje (nwc_rejected); povezava ne more plačati računov (nwc_missing_permissionali znesek, ki presega omejitve.
501Za ta strežnik niso vklopljeni samodejni top-ups (nwc_unavailableEnako velja za druge dve končni točki.

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());

branje nastavitev

GET https://nymbot.ai/api/v1/nwc-auto-topup je podpisal

Vrne isti predmet kot povezavo, z connected: false in druga polja null ko ni povezanega denarnice. Povezava sama ni nikoli vrnjena.

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());

odklonitev

DELETE https://nymbot.ai/api/v1/nwc-auto-topup/connection je podpisal

Izbriše shranjeno vrstico povezave. Ni več top-upov. Da bi bili prepričani, lahko preklicate tudi povezavo v denarnici.

Odgovor

{ "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());

Plačilo na zahtevo brez ključa

Končne točke s fiksno ceno lahko plačate za eno zahtevo naenkrat preko Lightning, brez ključa, brez računa in brez ravnotežja: POST /images/generations, POST /images/edits, POST /videos, POST /audio/speech, POST /audio/transcriptions, POST /audio/translations in POST /embeddingsKlepet, Odgovori in Sporočila vedno potrebujejo ključ. Zahteva, ki nosi ključ, se obračuna na stanje kot običajno; pretok plačil se začne le, če ni poslan ključ.

Nymbot govori dve različici iste ideje, iz enega backend: Lightning Labs' š402 (tudi pod njegovim starim imenom, LSAT) in osnutek IETF plačilo HTTP preverjanje pristnosti s lightning Metoda in charge Uporabite vse, kar vaš kupec razume.

Upravljanje lastnega strežnika

Plačilo brez ključa je na voljo le, če API_L402_SECRET vsebuje vsaj 32 naključnih bajtov, kot je hex (64 znakov) ali base64 (44). openssl rand -hex 32Krajša ali ugibljiva vrednost izklopi funkcijo in zabeleži, zakaj. API_L402_SECRET_PREVIOUS za en dan: poverilnice, URL-ji stanja in izzivi, opravljeni pod njim, še naprej delujejo, dokler ne potečejo.

Izziv

Pošljite zahtevo z NE Authorization če je veljavna, se nič ne izvaja in dobite 402 Payment Required z računom za točno tisto, kar zahteva stroške: enako ceno bi ključ plačal, pretvoril na 10 sats standardni kredit ali 100 sats Pro kredit in zaokrožil do celotnega sat (vsaj 1 sat, in vsaj 0.05 kreditni minimum). WWW-Authenticate Izzivi za isti račun:

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 }
}

plačila request parameter je base64url JSON: {"amount":"237","currency":"sat","methodDetails":{"invoice":"lnbc...","network":"mainnet","paymentHash":"..."}}.

Izziv je vezan na končno točko, na Content-Type (njegov tip medija in, za več delov, njegova meja) in na SHA-256 točnega telesa bajtov, ki ste jih poslali, in traja 15 minut. identična Ponovno vprašanje: enako Content-Type in enake JSON bajte ali za večdelne končne točke (/images/edits, /audio/transcriptions, /audio/translationsVečina knjižnic HTTP izbere novo mejo vsakič, ko kodirajo obrazec, zato ga enkrat kodirajte in pošljite te bajte dvakrat.

Vsak naslov lahko zahteva 30 izzivov na minuto (IPv6 naslov šteje kot celoten /64). Zahteve, katerih naslov ni znan, delijo strožje 10 na minuto, in obstaja splošna omejitev na izzive Nymbot težave na vseh naslovih; zahteva zavrnjena pred izzivom (na primer s telesom, ki ni veljaven JSON) ne šteje proti njej. 429 s Retry-AfterPlačane končne točke, ki se kličejo brez ključa ali pooblastila, štejejo tudi do splošne omejitve 120 nepooblaščenih zahtevkov na minuto na naslov. Content-Type Ni pa application/json (ali pa multipart/form-data za naložbe) je zavrnjen z 415 Nikoli ne dobiš računa.

Vdelave so cenjene na podlagi ocene žetonov v vnosu, z 1,5-kratno maržo, saj je dejansko število znano šele pozneje. Vrnite token.

Pošiljanje plačila

Plačajte račun s katerim koli Lightning denarnico. Denarnica vam daje predogled, 64 šesterih znakov. Nato pošljite isto zahtevo z enim od teh:

shemeHeaderji
š402Authorization: L402 <macaroon>:<preimage> (LSAT deluje tudi
plačiloAuthorization: Payment <base64url JSON>, kjer je JSON {"challenge": {every parameter of the challenge, as sent}, "payload": {"preimage": "<hex>"}}

Plačano povpraševanje odgovarja točno tako, kot je odgovorjeno s ključem, razen, da nymbot Objekt nima polja ravnotežja: {"payment": "l402", "tier": "pro", "paid_sats": 237, "charged_sats": 237}In ni nobenega X-Nymbot-Balance-Sats zahtevo, plačano s plačilno shemo, prejme tudi Payment-Receipt glavo (base64url JSON z id izziv, plačilni hash kot reference, status in timestampPlačane zahteve niso vezane na noben nim, zato se ne pojavijo v zgodovini poizvedb.

statusaKdaj
402 payment_already_usedVsako plačilo plača za eno zahtevo. odgovor je nov izziv za to zahtevo, tako da stranka, ki predpomni svoje zadnje poverilnice (kot lnget Pa še enkrat, samo še enkrat.
402 payment_mismatchIzdajalec je bil dodeljen za drugo končno točko, Content-Type ali telo, ali plača manj, kot je ta zahteva zdaj stane. nov izziv za to zahtevo prihaja z njim; če je bilo plačilo premajhno, se tisto, kar ste plačali, vrne kot Vrnite token (refund_token in refund_sats v svojem telesu).
402 payment_expiredOd izziva je minilo več kot 15 minut. Z njim prihaja nov izziv. Če predogled prikazuje, da ste plačali, se to, kar ste plačali, vrne kot izziv. Vrnite token (refund_token in refund_sats v telesu), enkrat; potem se kredencial uporabi.
401 invalid_preimagePredogled ne hash na plačilni hash računa. plačilo se ne porabi.
401 invalid_payment_credentialPoverilnica je nepravilno oblikovana, je bila spremenjena po tem, ko jo je izdal Nymbot, ali imenuje plačilni hash Nymbot ni nikoli izdal računa.
429 rate_limit_exceededVeč kot 30 poverilnic ali ključev, ki jih ni bilo mogoče preveriti, je prišlo s tega naslova v eni minuti, ali pa je bil en token za vračilo poslan več kot 60-krat v eni minuti. 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"));

Stranke so zgrajene na mppx z metodo Lightning sami obravnavajo izziv Plačila; pokažite jih na končno točko in pustite, da plačajo.

Video posnetki

Plačana je POST /videos Odgovori 202 kot ključavnica, plus a status_url: GET To je podpisano in deluje 24 ur, dokler je delo ohranjeno.

{
  "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..."
  }
}

Ohranite jih refund_token iz tega odgovora: prikazano je samo tukaj. To je prazno, medtem ko je videoposnetek prikazan (GET /api/v1/l402/refunds Odgovori "status": "pending"); če prikaz ne uspe brez obračuna, plačilo pristane na njem. refund_sats za povrnjeno delo, vendar nikoli žetona, tako da skupna raba URL stanja ne deli povračila.

Povračilo

Če plačana zahteva ne uspe in ponudnik zaračuna Nymbot za poskus, se plačilo ohrani in napaka pravi tako, z charged_sats, točno tako kot za ključno zahtevo. Če ne uspe brez zaračunavanja, napaka prinaša Vrnite token Vredno je, kar ste plačali:

{
  "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"
  }
}

Neuporabljeni deli se vrnejo na enak način: če ste zahtevali dve sliki in ena ni bila obračunana, je uspešen odgovor nymbot predmet nosi token za vračilo za manjkajočega; transkripcija, katere dolžine ni bilo mogoče predhodno prebrati, je cenjena za najdaljšo datoteko (nikoli več kot 30 minut), in razlika do dejanske dolžine se vrne kot token za vračilo; če se izkaže, da je daljša od 30 minut, se zavrne z 413 in celotno plačilo se vrne. Vdelave vrnejo tisto, kar je ocena zadržala. Neuspešen videoposnetek vrne žeton, ki ga je poslala.

Token za vračilo denarja je naključna 256-bitna koda. Nymbot shrani samo svoj hash in poteče po 30 dneh.

  • Plačajte z njim. Pošlji Authorization: Bearer REFUND-… na kateri koli od zgoraj navedenih končnih točk (OpenAI SDK jo vzame kot API ključ).refund_token_sats V na nymbot predmet). žeton, ki je vreden manj kot odgovor na zahtevo 402 refund_insufficientNeizpolnjena napaka postavi sats nazaj na isti žeton.
  • Preverite ga GET /api/v1/l402/refunds z istim naslovom se vrne {"sats": 237, "status": "open", "expires_at": "..."}.
  • En token se lahko uporabi največ 60 krat na minuto.
  • Premaknite ga v nym. Vstavite ga v Privoščite darilo v aplikaciji Nymbot ali klic POST /api/v1/l402/refunds/redeem z a Podpisana zahteva in {"refund_token": "REFUND-...", "balance": "standard"} (ali pa "pro"Celotni krediti gredo v stanje (10 sats vsak na standard, 100 na Pro); stave, ki ne naredijo celotnega kredita na žetonu za zahteve 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"

Odgovor

{ "data": { "credited": 23, "tier": "standard", "balance_credits": 123, "remaining_sats": 7 } }