Vidensgrundlag Udviklere
Balance, top-ups og nøgler
Tjek, hvad du har, top op over Lightning, top op automatisk fra din egen tegnebog, se, hvad hver anmodning koster, og administrer nøgler fra kode.
Denne side er maskinoversat for nemheds skyld. Den engelske original er den version, der gælder.
Tjek balancen
Både dine balancer, og hvor meget af denne nøgles cap bruges.
GET https://nymbot.ai/api/v1/credits/balance Det kræver en API-nøgle. POST Det gælder også for de kunder, der forventer det.
balance er de to saldi sammen i dollars ved den nuværende Bitcoin pris, for værktøjer, der forventer et enkelt tal (null Resten er i kreditter og satser, hvilket er, hvordan balancerne rent faktisk holdes. key En nøgle, der har nået sin grænse, kan stadig tjekke balancen.
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 er | Når |
|---|---|
401 | Nøglen er manglende, ukendt, tilbagekaldt eller udløbet. |
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 op, og grænserne. Lightning er den eneste metode.
GET https://nymbot.ai/api/v1/topup/payment-methods Ingen nøgle kræves.
En top-up er 10 til 1.000.000 sats; en Pro top-up skal købe mindst en Pro kredit, så det starter på 100 sats. bulk_bonus Lister den ekstra kredit på større top-ups, det samme som i appen: 10%, 15% eller 20% mere på standard top-ups fra 500, 1.000 eller 5.000 satser, og på Pro top-ups fra 5.000, 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);
Løber op over lyn
Opret en Lightning faktura, der tilføjer kredit til nym nøglen tilhører. betale det fra enhver Lightning tegnebog, så Tjek det For at få kreditten tilføjet.
POST https://nymbot.ai/api/v1/topup/create/btc-lightning Det kræver en API-nøgle.
| Feltet | Type af | Kræves | Beskrivelse af |
|---|---|---|---|
amount | Nummeret | Ja | Hvor meget, i currencyEt helt tal for sats. |
currency | Strenge | Nej ikke | SATS (Det er et underskud) USD eller BTCDollars konverteres til den nuværende Bitcoin pris. |
tier | Strenge | Nej ikke | pro (den forældede) eller standardHvilken balance kreditten går til. |
En standard kredit er 10 satser og en Pro kredit 100 satser, plus enhver bulk bonus;
credits Det vil sige, hvad denne faktura vil tilføje.
Svaret
{
"invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
"payment_request": "lnbc100u1p5...",
"amount_sats": 10000,
"credits": 115,
"tier": "pro",
"expires_at": "2026-09-30T09:27:00Z",
"status": "pending"
}
| Status er | Når |
|---|---|
400 | En anden metode på vejen (unsupported_method) en ukendt valuta (unsupported_currencyeller et beløb, der mangler, eller et beløb under minimumsbeløbet (amount_too_small) over 1.000.000 satser (amount_too_large) eller afvises af Lightning wallet (amount_out_of_range). |
429 | Mere end 60 fakturaer for denne nym, eller 120 fra denne adresse, på en time (rate_limit_exceeded, med Retry-After). |
502 | Der kan ikke indgives en faktura i øjeblikket (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);
Tjek en top-up
Spørger, om regningen er blevet betalt, og når den er, tilføjer den kredit. Tjek er, hvad kreditter det, så efter at have betalt, tjek, indtil status er creditedTjek igen efterfølgende er sikkert: kredit lander én gang, uanset hvor mange gange du spørger.
GET https://nymbot.ai/api/v1/topup/status/{invoice_id} - har brug for en nøgle fra nym, der lavede fakturaen.
status er pending (Det er ikke betalt endnu) paid (betalt, men endnu ikke krediteret; tjek igen), credited (på din balance) eller expired (ikke betalt i tide).Balancefelterne er for det niveau, som fakturaen topper op.
Svaret
{
"invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
"status": "credited",
"amount_sats": 10000,
"credits": 115,
"tier": "pro",
"expires_at": null,
"balance_credits": 523.33,
"balance_sats": 52333
}
| Status er | Når |
|---|---|
400 | Id'et er ikke det 64-tegns id fra oprettelsesopkaldet. |
404 | Ingen faktura af denne 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 række pr. anmodning: hvad det var, hvilken model, hvor mange tokens og hvad det kostede. Ingen opfordringer eller svar opbevares, så ingen returneres. Rækker opbevares i 90 dage, nyeste først. En nøgle, der har nået sin grænse, kan stadig læse sin historie.
GET https://nymbot.ai/api/v1/queries/history - har brug for en API-nøgle, som kan se sine egne anmodninger, eller en Underskrevet anmodning af din nym, som ser hver nøgles.
| Feltet | Type af | Kræves | Beskrivelse af |
|---|---|---|---|
page | Det er et spørgsmål (query) | Nej ikke | Standard 1, højst 1000; en højere side er 400 invalid_value. |
page_count | Det er et spørgsmål (query) | Nej ikke | Rækker pr. side. Standard 20, højst 100. |
start_dateend_date | String (Kørsel) | Nej ikke | ISO 8601 datoer og tider. |
model | String (Kørsel) | Nej ikke | Kun denne model. |
type | String (Kørsel) | Nej ikke | chat, responses, messages, image, video, speech, transcription eller embedding. |
all_keys | af Boolean (Query) | Nej ikke | Med en nøgle: true Indeholder alle nøgler af samme nym. false. |
key_id | String (Kørsel) | Nej ikke | Med en underskrevet ansøgning, eller med all_keys=trueKun denne nøgle. |
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 af kontoanmodninger
Oprettelse, ændring og tilbagekaldelse af nøgler, kontooversigt og automatiske top-ups tager ikke en API-nøgle.De tager en signatur fra din nym, så en lækket nøgle kan bruge op til sin cap, men kan aldrig lave en anden nøgle eller hæve sin egen cap.
App'en gør dette for dig: alt i sin ild Du har kun brug for denne sektion til at administrere nøgler fra din egen kode.
Signaturen er en Nostr-begivenhed af typen 27235 (NIP-98), sendt base64-kodet i
Authorization Header med ordet Nostr På forsiden:
Begivenheden
{
"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 fulde URL-adresse for anmodningen, herunder forespørgselsstrengen, nøjagtigt som sendt.methodDet er HTTP metoden.payloader SHA-256 af den rå anmodning krop, i hex. Det kræves påPOSTogPATCH, og den krop, du sender, skal være byte for byte den du hashede.created_atDet skal være inden for 60 sekunder af serverens klokke.- Hver begivenhed fungerer én gang, a
GETinkluderet, så en fanget overskrift ikke kan afspilles igen. Underskrive en ny for hver anmodning.noncetag med en tilfældig værdi, så to anmodninger, der er underskrevet i samme sekund, stadig er forskellige. - Kroppen af en underskrevet anmodning kan højst være 64 KB, og en krop skal
Content-Type: application/json.
En manglende begivenhed vender tilbage 401 missing_nostr_authen, der er dårligt dannet, dårligt underskrevet, for gammel eller til en anden URL, metode eller krop returnerer
invalid_nostr_auth, med årsagen i meddelelsen; en genbrugt en returnerer
nostr_auth_replayedEn API-nøgle sendt til disse endpoints afvises. underskriften kontrolleres, før kroppen læses, og hver adresse kan fejle det 30 gange i minuttet (en IPv6-adresse tæller som sin helhed /64); derefter får den 429 med
Retry-After.
Browsere kan kun kalde disse slutpunkter fra Nymbots egne websteder (https://nymbot.ai,
https://nymchat.app En side på et andet websted får ingen CORS-overskrifter tilbage, så den ikke kan læse, hvad de returnerer.
OriginDe er ikke berørt.
Signering kræver din nym's hemmelige nøgle (den nsec), som styrer alt: din identitet, din historie og din balance. Kun sætte det i et script på en maskine, du stoler på, læse det fra miljøet i stedet for at skrive det i filen, og foretrækker appen, når du kan.
Disse hjælpere bygger overskriften. De senere eksempler på denne side bruger dem. De læser den hemmelige nøgle i hex fra NOSTR_SECRET_HEX; cURL en bruger den
Nak kommandolinjeværktøj, der tager en nsec eller hex-nøgle, 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");
}
Konto sammenfatning
Hvad appens API-ark viser øverst: din offentlige nøgle, begge balancer, hvor mange nøgler der er aktive (ikke tilbagekaldt eller udløbet), og Automatisk top-up indstillinger, eller
null når serveren ikke tilbyder dem.
GET https://nymbot.ai/api/v1/account Har brug for a Underskrevet anmodning.
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 af nøgler
Endpunkterne bag app'ens nøgleliste. Alle har brug for en Underskrevet anmodningHver nøgle returneres i denne form, med tider i ISO 8601 og beløb i sats:
Nøgleobjekt
{
"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 at genkende en nøgle, men ikke at bruge den.Nøglen returneres kun én gang, når den er lavet.
Liste over nøgler
GET https://nymbot.ai/api/v1/keys og underskrevet.
| Feltet | Type af | Kræves | Beskrivelse af |
|---|---|---|---|
include_revoked | af Boolean (Query) | Nej ikke | Inkluderer tilbagekaldte nøgler. 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);
Gør en nøgle
POST https://nymbot.ai/api/v1/keys Underskrevet - vender tilbage 201.
| Feltet | Type af | Kræves | Beskrivelse af |
|---|---|---|---|
name | Strenge | Ja | 1 til 40 tegn, der adskiller sig fra dine andre aktive nøgler (ignorerende tilfælde). |
limit_sats | Integer | Nej ikke | Indtjeningskapaciteten i sats, mindst 1. |
reset_period | Strenge | Nej ikke | daily, weekly eller monthlyBehovet limit_satsLæg det ud for en hætte, der aldrig genopretter. |
expire_at | String eller integer | Nej ikke | Når nøglen stopper med at arbejde: en ISO 8601-tid, eller millisekunder siden 1970. |
Svar på spørgsmå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 er | Når |
|---|---|
400 | Et manglende eller for langt navn; et navn, der allerede er i brug (duplicate_name); en cap, der ikke er et helt tal på mindst 1; en reset periode uden cap; en udløb i fortiden; et ukendt felt (unknown_parameter); eller 25 aktive nøgler allerede (too_many_keys). |
429 | Mere end 60 nøgler lavet af denne nym, eller 120 fra denne adresse, 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);
Læs en nøgle
GET https://nymbot.ai/api/v1/keys/{id} og underskrevet.
Tilbage {"data": {…}} med nøgleobjektet, eller 404
key_not_found Hvis ingen af dine nøgler har dette id.
cURL
URL=https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856
curl "$URL" -H "Authorization: $(nostr_auth GET "$URL")"
Python
import requests
url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856"
print(requests.get(url, headers={"Authorization": nostr_auth("GET", url)}).json()["data"])
JavaScript
const url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856";
console.log((await (await fetch(url, { headers: { "Authorization": nostrAuth("GET", url) } })).json()).data);
Ændring af nøgle
PATCH https://nymbot.ai/api/v1/keys/{id} og underskrevet.
Send en af name, limit_sats, reset_period og
expire_atmed de samme regler som når man laver en nøgle. null fjerne et felt: ingen cap, ingen reset, ingen udløb. Ændring af resetperioden starter en ny periode ved nul. En tilbagekaldt nøgle kan ikke ændres (400 key_revoked) vender tilbage
{"data": {…}} med det opdaterede nøgleobjekt.
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);
Tilbagekaldelse af nøgle
DELETE https://nymbot.ai/api/v1/keys/{id} og underskrevet.
Stopper nøglen med det samme, for godt. Det forbliver på listen med revoked_at set, og kan ses med include_revoked=trueTilbagekaldelse af en nøgle, der allerede er tilbagekaldt, svarer på samme måde.Kun de nyeste 50 tilbagekaldte nøgler bevares; ældre nøgler slettes, når en anden nøgle tilbagekaldes.
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());
Næste Næste indlæg: NWC Auto-top-up
Tilslut en Lightning tegnebog med Nostr Wallet Connect og Nymbot topper en balance af sig selv, når API-udgifter kører det lavt. Appens API-ark har de samme indstillinger; disse er slutpunkterne bag det. Underskrevet anmodning.
Hvordan det virker: Efter en API-anmodning er opkrævet til den balance, du valgte at se, hvis den balance er faldet under din tærskel, laver Nymbot en faktura for dit top-up beløb, beder din tegnebog om at betale det, og tilføjer kredit. Det topper op højst en gang hvert 5. minut for hver nym og balance, så et udbrud af anmodninger ikke kan dræne tegnebogen. Udgifter i apps udløser det ikke. Tid og størrelse på den sidste top-up, og den sidste fejl, er i indstillingerne; hvis en betaling gik igennem efter en fejl, tjekke sin faktura med Top-up status krediterer det.
Nymbot gemmer det krypteret og kun nogensinde bruger det til at betale sine egne top-up fakturaer, men gøre en forbindelse bare for dette, med et udgiftsbudget i din tegnebog, så det mest det nogensinde kunne betale er et nummer valgte dig. pay_invoice.
Tilslutning af en tegnebog
POST https://nymbot.ai/api/v1/nwc-auto-topup/connect og underskrevet.
| Feltet | Type af | Kræves | Beskrivelse af |
|---|---|---|---|
nwc_url | Strenge | Ja | Forbindelsesstrengen, der starter med nostr+walletconnect://Nymbot beder om en tegnebog get_info før du gemmer det, og gemmer det krypteret. |
threshold_sats | Integer | Ja | Top op, når saldoen falder under disse mange sats. |
topup_sats | Integer | Ja | Hvor meget skal du tilføje hver gang. 1.000 til 1.000.000 satser. |
tier | Strenge | Nej ikke | pro (den forældede) eller standardBalancen til at se og top op. |
Svaret
{
"data": {
"connected": true,
"threshold_sats": 5000,
"topup_sats": 20000,
"tier": "pro",
"last_topup_at": null,
"last_topup_sats": null,
"last_error": null
}
}
| Status er | Når |
|---|---|
400 | Der er ikke tale om en linje (invalid_nwc_url); tegnebogen svarede ikke på sin relæ (nwc_unreachable) eller afviste kontrollen (nwc_rejected); forbindelsen kan ikke betale fakturaer (nwc_missing_permissioneller et beløb uden for grænserne. |
501 | De automatiske top-ups er ikke tændt for denne server (nwc_unavailableDet samme gælder for de to andre slutpunkter. |
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());
Læs indstillingerne
GET https://nymbot.ai/api/v1/nwc-auto-topup og underskrevet.
Returnerer det samme objekt som forbinder, med connected: false og de øvrige felter
null Når der ikke er tilsluttet en tegnebog, returneres forbindelsesstrengen aldrig.
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());
Afbrydelse af
DELETE https://nymbot.ai/api/v1/nwc-auto-topup/connection og underskrevet.
Sletter den gemte forbindelsesstreng. Der oprettes ikke flere top-ups. For at være sikker kan du også tilbagekalde forbindelsen i din tegnebog.
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 efter anmodning uden nøgle
De faste pris-endpoint kan betales for én anmodning ad gangen over Lightning, uden nøgle, uden konto og uden balance: POST /images/generations, POST /images/edits,
POST /videos, POST /audio/speech, POST /audio/transcriptions,
POST /audio/translations og POST /embeddingsChat, svar og beskeder har altid brug for en nøgle.En anmodning, der bærer en nøgle, faktureres til saldoen som sædvanlig; betalingsstrømmen starter kun, når ingen nøgle sendes.
Nymbot taler to versioner af den samme idé, fra en backend: Lightning Labs'
K402 (Også accepteret under sit gamle navn, LSAT) og IETF-udkastet
Betaling af HTTP-godkendelsesordningen med den lightning Metode og
charge Brug, hvad din kunde forstår.
Betaling uden nøgle er kun aktiveret, når API_L402_SECRET indeholder mindst 32 tilfældige byte, som hex (64 tegn) eller base64 (44). openssl rand -hex 32En kortere eller gættelig værdi slukker funktionen og logger hvorfor. API_L402_SECRET_PREVIOUS for en dag: legitimationsoplysninger, status URL'er og udfordringer lavet under det fortsætter med at arbejde, indtil de udløber.
Udfordringen
Send forespørgslen med nej Authorization header. Hvis det er gyldigt, kører intet, og du får 402 Payment Required med en faktura for præcis, hvad den anmodning koster: den samme pris en nøgle ville betale, konverteret til 10 sats en standard kredit eller 100 sats en Pro kredit og afrundet til en hel sat (mindst 1 sat, og mindst 0.05 kredit minimum). WWW-Authenticate Udfordringer for samme ansøgning:
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 En af de vigtigste parametre er base64url JSON:
{"amount":"237","currency":"sat","methodDetails":{"invoice":"lnbc...","network":"mainnet","paymentHash":"..."}}.
En udfordring er knyttet til slutpunktet, til Content-Type (deres medie type og, for multipart, dens grænse) og til SHA-256 af den nøjagtige krop bytes du sendte, og varer 15 minutter. identisk Forespørgsel: Det samme
Content-Type og de samme JSON bytes, eller for de multiparts endpoint (/images/edits, /audio/transcriptions, /audio/translationsDe fleste HTTP-biblioteker vælger en ny grænse hver gang de koder en formular, så kod den en gang og send disse bytes to gange.
Hver adresse kan anmode om 30 udfordringer pr. minut (en IPv6-adresse tæller som sin helhed /64). Anmodninger, hvis adresse ikke er kendt, deler en strengere 10 pr. minut, og der er en samlet grænse for udfordringerne Nymbot problemer på tværs af alle adresser; en anmodning afvist før en udfordring er lavet (for eksempel med en krop, der ikke er gyldig JSON) tæller ikke mod det. 429 med Retry-AfterBetalte slutpunkter, der kaldes uden en nøgle eller credential, tæller også mod den generelle grænse på 120 uautentiserede anmodninger pr. minut pr. adresse. Content-Type Er ikke application/json (eller
multipart/form-data for uploads) er nægtet med 415 Og får aldrig en faktura.
Embeddings prissættes ud fra en estimering af tokens i input, med en margin på 1,5 gange, da det faktiske antal kun kendes bagefter. Tilbagebetaling af token.
Send betalingen
Betal regningen med enhver Lightning tegnebog. tegnebogen giver dig forbilledet, 64 hex tegn. Så send den samme anmodning med en af disse:
| Skemaet | Header |
|---|---|
| K402 | Authorization: L402 <macaroon>:<preimage> (LSAT Det virker også) |
| Betaling af | Authorization: Payment <base64url JSON>Hvor JSON er placeret {"challenge": {every parameter of the challenge, as sent}, "payload": {"preimage": "<hex>"}} |
En betalt anmodning svarer nøjagtigt som en, der er lavet med en nøgle, bortset fra at nymbot
Objektet har ingen balancefelter: {"payment": "l402", "tier": "pro", "paid_sats": 237,
"charged_sats": 237}Og der er ikke X-Nymbot-Balance-Sats En anmodning betalt med betalingsordningen modtager også en Payment-Receipt header (base64url JSON med udfordring id, betaling hash som reference, status og
timestampBetalte forespørgsler er ikke bundet til nogen nym, så de vises ikke i forespørgselshistorikken.
| Status er | Når |
|---|---|
402 payment_already_used | Hver betaling betaler for en anmodning. svaret er en ny udfordring for denne anmodning, så en klient, der cacher sin sidste credential (som lnget Det er simpelthen land igen. |
402 payment_mismatch | Opgaven blev udstedt for et andet endpoint. Content-Type eller krop, eller betale mindre end denne anmodning nu koster. En ny udfordring for denne anmodning kommer med det; hvis betalingen var for lille, hvad du betalte kommer tilbage som en Tilbagebetaling af token (refund_token og refund_sats i den indre krop). |
402 payment_expired | Mere end 15 minutter er gået siden udfordringen. En ny udfordring kommer med den. Hvis forbilledet viser, at du har betalt, kommer det, du har betalt, tilbage som en Tilbagebetaling af token (refund_token og refund_sats i kroppen), en gang; credentialen bliver derefter brugt op. |
401 invalid_preimage | Forbilledet hashes ikke til fakturaens betalingshash. |
401 invalid_payment_credential | Oplysningerne er misdannede, blev ændret, efter at Nymbot udstedte dem, eller navngav en betalingshash, som Nymbot aldrig udstedte en faktura for. |
429 rate_limit_exceeded | Mere end 30 legitimationsoplysninger eller nøgler, der ikke kunne verificeres, kom fra denne adresse på et minut, eller en refunderingstoken blev sendt mere end 60 gange i et minut. 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"));
Kunderne er bygget på mppx med en Lightning-metode håndtere betalingsudfordringen selv; peg dem på slutpunktet og lad dem betale.
Videoer
En betalt POST /videos Svarer 202 som en nøgle, plus a
status_url: GET Det er underskrevet og fungerer i 24 timer, så længe jobbet 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 Det er kun her, der vises svaret. Det er tomt, mens videoen gengiver (GET /api/v1/l402/refunds Svarer "status": "pending"); hvis renderingen ikke er faktureret, lander betalingen på den.
refund_sats for et refunderet job, men aldrig token, så deling af status-URL'en deler ikke refusionen.
Tilbagebetaling
Hvis en betalt anmodning mislykkes, og udbyderen fakturerede Nymbot for forsøget, opbevares betalingen, og fejlen siger det, med charged_sats, præcis som for en nøgleforespørgsel. Hvis den mislykkes uden at blive faktureret, medfører fejlen en Tilbagebetaling af token Værd hvad du har betalt:
{
"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"
}
}
Ubrugte dele returneres på samme måde: Hvis du har bedt om to billeder, og et af dem mislykkedes, lykkes svaret. nymbot objekt bærer en refundering token for den manglende; en transkription, hvis længde ikke kunne læses op forud, prissættes for den længste fil kunne være (aldrig mere end 30 minutter), og forskellen til den faktiske længde kommer tilbage som en refundering token; hvis det viser sig at være længere end 30 minutter, er det afvist med 413
Embeddings returnerer, hvad estimatet holdt tilbage. En mislykket video refunderer den token, dens indsendelse returnerede.
Et refunderingstoken er en tilfældig 256-bit kode. Nymbot gemmer kun sin hash, og den udløber efter 30 dage.
- Betal med det. Send mig
Authorization: Bearer REFUND-…På den ene side er der en afdeling, hvor der er tale om en afdeling, og på den anden side er der en afdeling, hvor der er tale om en afdeling, hvor der er tale om en afdeling (refund_token_satsI dennymbotEn token, der er mindre værd end svarene på anmodningen402refund_insufficientEn mislykket fejl sætter satsen tilbage på samme token. - Tjek det
GET /api/v1/l402/refundsmed samme header returnerer{"sats": 237, "status": "open", "expires_at": "..."}. - En token kan bruges op til 60 gange i minuttet.
- Flyt den til en nym. Sæt den i Giv en gave i Nymbot-appen, eller ringe
POST /api/v1/l402/refunds/redeemmed a Underskrevet anmodning og{"refund_token": "REFUND-...", "balance": "standard"}(eller"pro"Hele kreditter går til saldoen (10 satser hver på standard, 100 på Pro); satser, der ikke gør en hel kredit ophold på token for API-forespørgsler.
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 } }