Kunnskapsgrunnlag Utviklere
Balanse, top-ups og nøkler
Sjekk hva du har, topp opp over Lightning, topp opp automatisk fra din egen lommebok, se hva hver forespørsel koster, og administrer nøkler fra kode.
Denne siden er maskinoversatt for enkelhets skyld. Den engelske originalen er versjonen som gjelder.
Sjekk balansen
Både dine balanse, og hvor mye av denne nøkkelens kappe er brukt.
GET https://nymbot.ai/api/v1/credits/balance Trenger en API-nøkkel POST Dette gjelder også for kunder som forventer det.
balance er de to saldene sammen i dollar til gjeldende Bitcoin-pris, for verktøy som forventer et enkelt tall (null Resten er i kreditter og satser, som er hvordan saldene faktisk holdes. key En nøkkel som har nådd sin topp, kan fortsatt sjekke balansen.
Svaret
{
"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"
}
}
| Status | Når |
|---|---|
401 | Nøkkelen er savnet, ukjent, tilbakekalt eller utløpt. |
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);
Betalingsmetoder
Hvordan du kan toppe opp, og grensene. Lightning er den eneste metoden.
GET https://nymbot.ai/api/v1/topup/payment-methods Ingen nøkkel nødvendig.
En top-up er 10 til 1.000.000 satser; en Pro top-up må kjøpe minst en Pro-kreditt, så det starter på 100 satser. bulk_bonus Lister opp den ekstra kreditt på større top-ups, det samme som i appen: 10%, 15% eller 20% mer på standard top-ups fra 500, 1000 eller 5000 satser, og på Pro top-ups fra 5000, 10.000 eller 50.000 satser.
Svaret
{
"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);
Høydepunkt over Lightning
Gjør en Lightning faktura som legger til kreditt til nym nøkkelen tilhører. Sjekk det For å få kreditt lagt til.
POST https://nymbot.ai/api/v1/topup/create/btc-lightning Trenger en API-nøkkel
| Feltet | Typen | Krevde | Beskrivelse |
|---|---|---|---|
amount | Antall | Ja | Hvor mye, i currencyEt helt tall for sats. |
currency | Strenge | Nei | SATS (Dette er et forsinkelse) USD eller BTCDollar konverteres til gjeldende Bitcoin-pris. |
tier | Strenge | Nei | pro (default) eller standardHvilken balanse kreditt går til. |
En standard kreditt er 10 satser og en Pro kreditt 100 satser, pluss enhver bulk bonus;
credits Det vil si hva denne rapporten vil legge til.
Svaret
{
"invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
"payment_request": "lnbc100u1p5...",
"amount_sats": 10000,
"credits": 115,
"tier": "pro",
"expires_at": "2026-09-30T09:27:00Z",
"status": "pending"
}
| Status | Når |
|---|---|
400 | En annen metode i veien (unsupported_method, en ukjent valuta (unsupported_currencyEnten det er et lavere beløp, eller det er et lavere beløp.amount_too_smallI tillegg er det over 100 000 (amount_too_large) eller avvist av Lightning lommebok (amount_out_of_range). |
429 | Mer enn 60 fakturaer for denne nym, eller 120 fra denne adressen, på en time (rate_limit_exceeded, med Retry-After). |
502 | Det er foreløpig ikke mulig å sende inn en faktura (invoice_unavailable, med 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);
Sjekk ut top-up
Spør om fakturaen har blitt betalt og, når den har, legger til kreditt. sjekk er hva kreditter det, så etter å ha betalt, sjekk til statusen er creditedÅ sjekke igjen etterpå er trygt: kreditt lander en gang, uansett hvor mange ganger du spør.
GET https://nymbot.ai/api/v1/topup/status/{invoice_id} - trenger en nøkkel fra nym som gjorde fakturaen.
status er pending (Ikke betalt ennå) paid (betalt, men ikke kreditert ennå; sjekk igjen), credited (på din balanse) eller expired (ikke betalt i tide).Balansefeltene er for nivået som fakturaen toppes opp.
Svaret
{
"invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
"status": "credited",
"amount_sats": 10000,
"credits": 115,
"tier": "pro",
"expires_at": null,
"balance_credits": 523.33,
"balance_sats": 52333
}
| Status | Når |
|---|---|
400 | ID-en er ikke 64-karakter-ID-en fra opprettet anrop. |
404 | Ingen faktura ved at id for din 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);
Ønsker historie
En rad per forespørsel: hva det var, hvilken modell, hvor mange tokens og hva det koster. Ingen oppfordringer eller svar holdes, så ingen returneres. Ranger holdes i 90 dager, nyeste først.
GET https://nymbot.ai/api/v1/queries/history - trenger en API-nøkkel, som ser sine egne forespørsler, eller en Signerte forespørsel fra din nym, som ser hver nøkkel.
| Feltet | Typen | Krevde | Beskrivelse |
|---|---|---|---|
page | Nøkkelen er (query) | Nei | Standard 1, maksimalt 1000; en høyere side er 400 invalid_value. |
page_count | Nøkkelen er (query) | Nei | Rader per side. Standard 20, maksimalt 100. |
start_dateend_date | String (forespørsel) | Nei | ISO 8601 datoer og tider. |
model | String (forespørsel) | Nei | Bare denne modellen. |
type | String (forespørsel) | Nei | chat, responses, messages, image, video, speech, transcription eller embedding. |
all_keys | Boolean (forespørsel) | Nei | Med en nøkkel: true Inkluderer alle nøkler av samme nym. false. |
key_id | String (forespørsel) | Nei | Med underskrevet forespørsel, eller med all_keys=trueBare denne nøkkelen. |
Svaret
{
"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);
Signering av konto forespørsler
Laging, endring og tilbakekalling av nøkler, kontooppsummering og automatiske top-ups tar ikke en API-nøkkel.De tar en signatur fra nym, slik at en lekket nøkkel kan bruke opp til sin cap, men kan aldri lage en annen nøkkel eller heve sin egen cap.
Appen gjør dette for deg: alt i sin ild Du trenger bare denne delen for å administrere nøkler fra din egen kode.
Signaturen er en Nostr-hendelse av typen 27235 (NIP-98), sendt base64-kodet i
Authorization Header med ordet Nostr På fronten:
Eventet
{
"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": "..."
}
uer den fullstendige URL-adressen til forespørselen, inkludert forespørselstreng, nøyaktig som sendt.methodDette er HTTP metoden.payloader SHA-256 av den rå forespørselen kroppen, i hex.POSTogPATCH, og kroppen du sender må være byte for byte den du har hashet.created_atDet må være innen 60 sekunder av serverens klokke.- Hver hendelse fungerer én gang, a
GETinkludert, slik at en fanget header ikke kan spilles på nytt. Signer en ny for hver forespørsel.nonceMerk med en tilfeldig verdi, slik at to forespørsler signert i samme sekund fortsatt er forskjellige. - Kroppen til en signert forespørsel kan være maksimalt 64 KB, og en kropp trenger
Content-Type: application/json.
En savnet begivenhet returnerer 401 missing_nostr_authen som er dårlig dannet, dårlig signert, for gammel, eller for en annen URL, metode eller kropp returnerer
invalid_nostr_auth, med årsaken i meldingen; en gjenbrukt en returnerer
nostr_auth_replayedSignaturen sjekkes før kroppen leses, og hver adresse kan feile det 30 ganger i minuttet (en IPv6-adresse teller som sin helhet /64); etter det får den 429 med
Retry-After.
Nettlesere kan bare ringe disse endepunktene fra Nymbots egne nettsteder (https://nymbot.ai,
https://nymchat.app En side på et annet nettsted får ingen CORS-overskrifter tilbake, slik at den ikke kan lese hva de returnerer.
OriginDe er ikke berørt.
Signering trenger din nym's hemmelige nøkkel (den nsec), som styrer alt: din identitet, din historie og din balanse. bare sette den i et skript på en maskin du stoler på, lese den fra miljøet i stedet for å skrive den inn i filen, og foretrekker appen når du kan.
Disse hjelperne bygger overskriften. De senere eksemplene på denne siden bruker dem. De leser hemmelig nøkkel i hex fra NOSTR_SECRET_HEX; cURL en bruker den
Nak kommandolinjeverktøyet, som tar en nsec eller hex-nøkkel, og sha256sum På 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");
}
Kontooppsummering
Hva appens API-ark viser øverst: din offentlige nøkkel, begge balanse, hvor mange nøkler som er aktive (ikke tilbakekalt eller utløpt), og Automatisk top-up innstillinger, eller
null når serveren ikke tilbyr dem.
GET https://nymbot.ai/api/v1/account Trenger a Signerte forespørsel.
Svaret
{
"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());
Styring av nøkler
Endpoengene bak appens nøkkelliste. Alle trenger en Signerte forespørselHver nøkkel returneres i dette skjemaet, med ganger i ISO 8601 og beløp i sats:
Nøkkelobjekt
{
"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 Det er nok å gjenkjenne en nøkkel, men ikke å bruke den.Nøkkelen returneres bare en gang, når den er laget.
Listing av nøkler
GET https://nymbot.ai/api/v1/keys og signerte.
| Feltet | Typen | Krevde | Beskrivelse |
|---|---|---|---|
include_revoked | Boolean (forespørsel) | Nei | Inkluderer tilbakekalt nøkler. false. |
Svaret
{ "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);
Gjør en nøkkel
POST https://nymbot.ai/api/v1/keys Signerer, returnerer 201.
| Feltet | Typen | Krevde | Beskrivelse |
|---|---|---|---|
name | Strenge | Ja | 1 til 40 tegn, forskjellig fra dine andre aktive nøkler (ignoring case). |
limit_sats | Integrert | Nei | Utgiftskapasiteten i sats, minst 1. |
reset_period | Strenge | Nei | daily, weekly eller monthlyBehovet limit_satsLa det gå ut for en kappe som aldri reset. |
expire_at | String eller integer | Nei | Når nøkkelen slutter å fungere: en ISO 8601-tid, eller millisekunder siden 1970. |
Svar på spørsmål (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"
}
}
| Status | Når |
|---|---|
400 | Et manglende eller for langt navn; et navn som allerede er i bruk (duplicate_name); en cap som ikke er et heltall på minst 1; en tilbakestillingsperiode uten cap; en utløpsdato i fortiden; et ukjent felt (unknown_parameter); eller 25 aktive nøkler allerede (too_many_keys). |
429 | Mer enn 60 nøkler laget av denne nym, eller 120 fra denne adressen, på en time (rate_limit_exceeded, med 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);
Å lese en nøkkel
GET https://nymbot.ai/api/v1/keys/{id} og signerte.
Tilbake {"data": {…}} med nøkkelen, eller 404
key_not_found hvis ingen av dine nøkler har dette ID-et.
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);
Endre nøkkel
PATCH https://nymbot.ai/api/v1/keys/{id} og signerte.
Send noen av name, limit_sats, reset_period og
expire_atmed samme regler som når du lager en nøkkel. null renser et felt: ingen cap, ingen reset, ingen utløp. Endring av resetperioden starter en ny periode ved null. En tilbakekalt nøkkel kan ikke endres (400 key_revoked• Tilbake
{"data": {…}} med det oppdaterte nøkkelen objektet.
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);
Åpne en nøkkel
DELETE https://nymbot.ai/api/v1/keys/{id} og signerte.
Stopp nøkkelen på en gang, for godt. Det forblir i listen med revoked_at sett, og kan sees med include_revoked=trueÅ tilbakekalle en nøkkel som allerede er tilbakekalt svarer på samme måte. bare de nyeste 50 tilbakekalt nøkler blir beholdt; eldre blir slettet når en annen nøkkel er tilbakekalt.
Svaret
{ "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 Auto-top-up på vei
Koble en Lightning lommebok med Nostr Wallet Connect og Nymbot toppes opp en balanse av seg selv når API-utgifter kjører det lavt. Signerte forespørsel.
Hvordan det fungerer: Etter at en API-forespørsel er belastet til saldoen du valgte å se, hvis saldoen har falt under terskelen din, lager Nymbot en faktura for ditt toppbeløp, ber lommeboken om å betale det, og legger til kreditt. Det toppes opp maksimalt en gang hvert 5. minutt for hver nym og balanse, slik at et utbrudd av forespørsler ikke kan drenere lommeboken. Utgifter i appene utløser ikke det. Tid og størrelse på den siste toppingen, og den siste feilen, er i innstillingene; hvis en betaling gikk gjennom etter en feil, sjekker fakturaen med Top-up status krediterer dette.
En tilkoblingsstreng lar alle som holder den be lommeboken din om å betale. Nymbot lagrer den kryptert og bruker den bare til å betale sine egne fakturaer, men gjør en tilkobling bare for dette, med et utgiftsbudsjett i lommeboken din, så det mest det noensinne kan betale er et nummer valgt av deg. pay_invoice.
Koble til en lommebok
POST https://nymbot.ai/api/v1/nwc-auto-topup/connect og signerte.
| Feltet | Typen | Krevde | Beskrivelse |
|---|---|---|---|
nwc_url | Strenge | Ja | Forbindelsesstrengen, som starter nostr+walletconnect://Nymbot ber om lommeboken for get_info før du lagrer den, og lagrer den kryptert. |
threshold_sats | Integrert | Ja | Opp når saldoen faller under disse mange satsene. |
topup_sats | Integrert | Ja | Hvor mye å legge til hver gang. 1000 til 1000 000 satser. |
tier | Strenge | Nei | pro (default) eller standard: balansen å se og topp opp. |
Svaret
{
"data": {
"connected": true,
"threshold_sats": 5000,
"topup_sats": 20000,
"tier": "pro",
"last_topup_at": null,
"last_topup_sats": null,
"last_error": null
}
}
| Status | Når |
|---|---|
400 | Ikke en tilkoblingsstreng (invalid_nwc_url(Boken har ikke fått noe svar på spørsmålet)nwc_unreachable) eller nektet å sjekke (nwc_rejected); tilkoblingen kan ikke betale regninger (nwc_missing_permission(eller et beløp utenfor grensene. |
501 | Automatiske topp-ups er ikke slått på for denne serveren (nwc_unavailableDet samme gjelder de to andre terminene. |
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());
Les innstillingene
GET https://nymbot.ai/api/v1/nwc-auto-topup og signerte.
Returnerer det samme objektet som for å koble, med connected: false og de andre feltene
null Når ingen lommebok er koblet til, returneres aldri selve tilkoblingsstrengen.
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());
Disconnecting
DELETE https://nymbot.ai/api/v1/nwc-auto-topup/connection og signerte.
Sletter den lagrede tilkoblingsstrengen. Ingen flere top-ups blir gjort. For å være sikker, kan du også tilbakekalle tilkoblingen i lommeboken.
Svaret
{ "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());
Betal på forespørsel uten nøkkel
De faste prisendepunktene kan betales for én forespørsel om gangen over Lightning, uten nøkkel, ingen konto og ingen saldo: POST /images/generations, POST /images/edits,
POST /videos, POST /audio/speech, POST /audio/transcriptions,
POST /audio/translations og POST /embeddingsChat, svar og meldinger trenger alltid en nøkkel.En forespørsel som bærer en nøkkel faktureres til saldoen som vanlig; betalingsflyten starter bare når ingen nøkkel sendes.
Nymbot snakker to versjoner av den samme ideen, fra en backend: Lightning Labs'
L402 (Også akseptert under sitt gamle navn, LSAT) og IETF utkastet
Betaling HTTP autentisering med lightning Metode og
charge Bruk hva kunden din forstår.
Betaling uten nøkkel er bare på når API_L402_SECRET inneholder minst 32 tilfeldige byter, som hex (64 tegn) eller base64 (44). openssl rand -hex 32En kortere eller gjetningsbar verdi slår av funksjonen og logger hvorfor. API_L402_SECRET_PREVIOUS for en dag: legitimasjoner, status URLer og utfordringer gjort under det fortsette å jobbe til de utløper.
Utfordringen
Send forespørselen med nei Authorization Hvis det er gyldig, kjører ingenting, og du får 402 Payment Required med en faktura for nøyaktig hva den forespørselen koster: samme pris en nøkkel ville betale, konvertert til 10 sats en standard kreditt eller 100 sats en Pro kreditt og avrundet til en hel sat (minst 1 sat, og minst 0.05 kreditt minimum). WWW-Authenticate Utfordringer for samme sak:
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 }
}
Betalingen request Parameteren er base64url JSON:
{"amount":"237","currency":"sat","methodDetails":{"invoice":"lnbc...","network":"mainnet","paymentHash":"..."}}.
En utfordring er knyttet til slutten, til Content-Type (medietypen og, for multipart, grensen) og til SHA-256 av den nøyaktige kroppen bytes du sendte, og varer 15 minutter. identisk Tilbakemelding: Det samme
Content-Type og de samme JSON-bytene, eller for de multiparts endepunktene (/images/edits, /audio/transcriptions, /audio/translationsDe fleste HTTP-biblioteker velger en ny grense hver gang de koder et skjema, så kod den en gang og sender disse bytene to ganger.
Hver adresse kan be om 30 utfordringer per minutt (en IPv6-adresse teller som sin helhet /64). Forespørsler hvis adresse ikke er kjent dele en strengere 10 per minutt, og det er en samlet grense på utfordringene Nymbot problemer over alle adresser; en forespørsel avvist før en utfordring er gjort (for eksempel med en kropp som ikke er gyldig JSON) teller ikke mot det. 429 med Retry-AfterBetalte sluttpunkter kalt uten nøkkel eller legitimasjon teller også mot den generelle grensen på 120 uautentiserte forespørsler per minutt per adresse. Content-Type er ikke application/json (eller
multipart/form-data for uploads) er avvist med 415 og aldri får en faktura.
Embeddings er prissatt fra en estimat av tokens i inngangen, med en 1,5× margin, siden det virkelige antall er kjent bare etterpå. Tilbake til token.
Send betalingen
Betal regningen med hvilken som helst Lightning lommebok. Lommeboken gir deg forbilde, 64 hex tegn. Deretter sende samme forespørsel med en av disse:
| Ordningen | Header |
|---|---|
| L402 | Authorization: L402 <macaroon>:<preimage> (LSAT Fungerer også |
| Betaling | Authorization: Payment <base64url JSON>hvor JSON er {"challenge": {every parameter of the challenge, as sent}, "payload": {"preimage": "<hex>"}} |
En betalt forespørsel svarer akkurat som en som er gjort med en nøkkel, bortsett fra at nymbot
Objektet har ingen balansefelter: {"payment": "l402", "tier": "pro", "paid_sats": 237,
"charged_sats": 237}Og det finnes ikke X-Nymbot-Balance-Sats Header. En forespørsel betalt med betalingsordningen får også en Payment-Receipt header (base64url JSON med utfordring id, betaling hash som reference, status og
timestampBetalte forespørsler er ikke bundet til noen nym, så de vises ikke i spørringshistorikken.
| Status | Når |
|---|---|
402 payment_already_used | Hver betaling betaler for en forespørsel. svaret er en ny utfordring for denne forespørselen, så en klient som cacher sin siste legitimasjon (som lnget Det er bare å lande igjen. |
402 payment_mismatch | Kredensialet ble utstedt for et annet endepunkt, Content-Type eller kropp, eller betale mindre enn denne forespørselen nå koster. En ny utfordring for denne forespørselen kommer med det; hvis betalingen var for liten, kommer det du betalte tilbake som en Tilbake til token (refund_token og refund_sats og i kroppen). |
402 payment_expired | Mer enn 15 minutter har gått siden utfordringen. En ny utfordring kommer med den. Hvis forbilde viser at du betalte, kommer det du betalte tilbake som en Tilbake til token (refund_token og refund_sats i kroppen), en gang; kredensialet blir deretter brukt opp. |
401 invalid_preimage | Forhåndsbilde hashes ikke til fakturaens betaling hash. |
401 invalid_payment_credential | Personvernerklæringen er feilformet, ble endret etter at Nymbot utstedte den, eller navnet på en betalingshash Nymbot aldri utstedte en faktura for. |
429 rate_limit_exceeded | Mer enn 30 legitimasjoner eller nøkler som ikke kunne verifiseres kom fra denne adressen i løpet av et minutt, eller en refusjon token ble sendt mer enn 60 ganger i løpet av et minutt. 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"));
Kundene er bygget på mppx med en Lightning-metode håndtere betalingsutfordringen selv; peke dem på endepunktet og la dem betale.
Videoer
og betalt POST /videos Svarer 202 som en nøkkel, pluss a
status_url: GET Det er signert og fungerer i 24 timer, så lenge jobben holdes.
{
"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..."
}
}
Hold den refund_token I denne artikkelen kan du lese mer om dette, men det er bare en del av videoen (GET /api/v1/l402/refunds Svarer "status": "pending"); hvis gjengivelsen ikke blir fakturert, lander betalingen på den.
refund_sats for en refundert jobb, men aldri token, så deling av status-URL deler ikke refusjonen.
Tilbakebetalinger
Hvis en betalt forespørsel mislykkes og leverandøren fakturerte Nymbot for forsøket, blir betalingen beholdt og feilen sier det, med charged_sats, akkurat som for en nøkkelforespørsel. Hvis den mislykkes uten å bli fakturert, fører feilen til en Tilbake til token Verdt det du betaler:
{
"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"
}
}
Ubrukte deler kommer tilbake på samme måte: Hvis du ba om to bilder og ett mislyktes unfakturert, nymbot objektet bærer en refusjon token for den manglende; en transkripsjon hvis lengde ikke kunne leses opp foran er prissatt for lengst filen kunne være (aldri mer enn 30 minutter), og forskjellen til den faktiske lengden kommer tilbake som en refusjon token; hvis det viser seg å være lengre enn 30 minutter, er det avvist med 413
Innlegg returnerer hva estimatet holdt tilbake.En mislykket video refunderer token innsendingen returnerte.
En refusjon token er en tilfeldig 256-biters kode. Nymbot lagrer bare sin hash, og den utløper etter 30 dager.
- Betal med det. Send oss
Authorization: Bearer REFUND-…Dette er en av de viktigste oppgavene i denne artikkelen, og det er en av de viktigste oppgavene i denne artikkelen. (refund_token_satsI dennymbotEn token verdt mindre enn forespørselen svarer402refund_insufficientEn unbiled feil plasserer satsen tilbake på samme token. - Sjekk det ut.
GET /api/v1/l402/refundsmed samme header returnerer{"sats": 237, "status": "open", "expires_at": "..."}. - En token kan brukes maksimalt 60 ganger i minuttet.
- Flytt den til en nym. Legg den inn Gjør en gave i Nymbot-appen, eller ring
POST /api/v1/l402/refunds/redeemMed a Signerte forespørsel og{"refund_token": "REFUND-...", "balance": "standard"}(eller"pro"Hele kreditter går til saldoen (10 satser hver på standard, 100 på Pro); satser som ikke gjør en hel kreditt opphold på token for API-forespørsler.
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"
Svaret
{ "data": { "credited": 23, "tier": "standard", "balance_credits": 123, "remaining_sats": 7 } }