Salá koleka na makambo oyo ezali na kati
Back to Nymbot

Base ya boyebi Miso

Pamba la Pamba la Pamba la 100%

Kofutela nini na na, top-up juu Lightning, top-up otomatiki na wallet na, tanga nini kila misato na, na tanga misato na code.

Kofutela

Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la 100%

GET https://nymbot.ai/api/v1/credits/balance Na na na na na na na na na na POST Na na na na na na na na na na na

balance na na na na na na na na na na na na na na na nanull na na na na na na na na na na na na na na na key makolinhot. makolinhot. makolinhot. makolinhot. makolinhot. makolinhot. makolinhot. makolinhot. makolinhot. makolinhot. makolinhot. makolinhot. makolinhot.

Miso

{
  "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"
  }
}
MisoMiso
401Kofutela ebele, ebele ebele, ebele ebele, ebele ebele.

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

Miso

Na na na na na na na na na na na na na na na na na na na na

GET https://nymbot.ai/api/v1/topup/payment-methods Kofutela

Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba. bulk_bonus makolinhot na mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mikolo mik

Miso

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

Posa Posa Posa

Na na na na na na na na na na na na na na na na na na na Penza Mayi - Mayi - Mayi

POST https://nymbot.ai/api/v1/topup/create/btc-lightning Na na na na na na na na na na

MisoMisoPenzaMiso
amountMisoIyoPenza currency. . . . . .
currencyPenzaMisoSATS [MOKO] USD Miso BTC. Dollars na ya bitcoin price.
tierPenzaMisopro [MOKO] standard: Na na na na na na na na na na

A standard credit is 10 sats and a Pro credit 100 sats, plus any bulk bonus; credits makolinhot

Miso

{
  "invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
  "payment_request": "lnbc100u1p5...",
  "amount_sats": 10000,
  "credits": 115,
  "tier": "pro",
  "expires_at": "2026-09-30T09:27:00Z",
  "status": "pending"
}
MisoMiso
400Sika (unsupported_method(Moko)unsupported_currency) na tier, na minoko, na minoko na minoko (amount_too_small), na 100 000 sats (amount_too_large) na ba mbisi ya Lightning (amount_out_of_range).
429Pamba la Pamba la Pamba la 100%, Pamba la 100%, Pamba la 100%, Pamba la 100%rate_limit_exceededMiso Retry-After).
502Nakanganga (invoice_unavailableMiso 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);

Posa Posa

Na na na na na na na na na na na na na na na na creditedKofutela misato: Kofutela misato misato misato misato misato misato.

GET https://nymbot.ai/api/v1/topup/status/{invoice_id} - pe-po-girl13 - pe-po-girl14

status Miso pending (mimi na na na na) paid (maki, na na na na na na na na na na na) credited [MOKO] expired [Motobaz] Miso Miso Miso

Miso

{
  "invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
  "status": "credited",
  "amount_sats": 10000,
  "credits": 115,
  "tier": "pro",
  "expires_at": null,
  "balance_credits": 523.33,
  "balance_sats": 52333
}
MisoMiso
400ID ya ba 64-character ID ya ba lisa.
404na na na na na na na na na nainvoice_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);

Posa Posa

Penza ya Penza ya Penza ya Penza ya Penza ya Penza ya Penza ya Pisa ya Pisa ya Pisa ya Pisa ya Pisa ya Pisa ya Pisa ya Pisa ya Pisa ya Pisa ya Pisa ya Pisa ya Pisa ya Pisa

GET https://nymbot.ai/api/v1/queries/history — na na na na na na na na na na na Kofutela Na na na na na na na na na na na

MisoMisoPenzaMiso
pagemakolinhotMisoPamba la Pamba la Pamba la 100%, Pamba la 100% 400 invalid_value.
page_countmakolinhotMisoLelo. Lelo. Lelo. Lelo. Lelo.
start_date
end_date
pe-po-girl14MisoISO 8601 (ISO 8601)
modelpe-po-girl14MisoMiso
typepe-po-girl14Misochat, responses, messages, image, video, speech, transcription Miso embedding.
all_keyspe-po-girl14MisoPenza true na na na na na na na na false.
key_idpe-po-girl14MisoNa minoko koleka, na all_keys=true: na na na na na

Miso

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

Kofutela

Pamba la Pamba la Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100%.

app na na na na na na na na LELO na na na na na na na na na na na na

Kofutela ya ngomba ya Nostr 27235 (NIP-98), pe-po-base64 Authorization pe-po-girl14 Nostr Miso

Miso

{
  "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 is the full URL of the request, query string included, exactly as sent.
  • method Metoda ya http.
  • payload na SHA-256 ya miso ya miso ya miso ya miso, ya miso ya miso ya miso. POST mpe PATCHna na na na na na na na na na na na na na
  • created_at pe-po-girl14
  • na na na na na na na GET makolinhot, mpe o makolinhot na makolinhot nonce makolinhot ya makolinhot ya makolinhot ya makolinhot ya makolinhot ya makolinhot ya makolinhot ya makolinhot
  • The body of a signed request can be at most 64 KB, and a body needs Content-Type: application/json.

Posa Posa 401 missing_nostr_authna na na na na na na na na na na na na na na na invalid_nostr_authNa na na na na na na na na na na nostr_auth_replayed. Kofutela API ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi ya ekomisi 429 Miso Retry-After.

Wikipédia: Nymbot (https://nymbot.ai, https://nymchat.app and their subdomains). A page on any other site gets no CORS headers back, so it cannot read what they return. Scripts and native apps, which send no OriginNa na na na na na

Posa Posa

Pamba la Pamba la Pamba la 100% nsec), na likoki tout: identity na, historia na na na na na na na na na na na na na na na machine na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na

Na na na na na na na na na na na na na na na na na na NOSTR_SECRET_HEXna na na na na na na Penza na na na na na na na na na na na na sha256sum [MOKO] 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");
}

Kofutela

Kokolala ya API ya app-i ya ntuku ya ntuku ya ntuku ya ntuku ya ntuku ya ntuku ya ntuku ya ntuku ya ntuku ya ntuku ya ntuku ya ntuku ya ntuku ya ntuku ya ntuku ya ntuku ya ntuku ya ntuku makolinhot Posa, ya null pe-po-girl13

GET https://nymbot.ai/api/v1/account Penza a Kofutela.

Miso

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

Miso

Kombo na kombo na kombo na kombo na kombo na kombo na kombo na kombo na kombo na kombo KofutelaKokolala nzambe nzambe nzambe nzambe nzambe nzambe nzambe nzambe.

Miso

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

LELO

GET https://nymbot.ai/api/v1/keys Miso

MisoMisoPenzaMiso
include_revokedpe-po-girl14MisoPamba la Pamba la 100% false.

Miso

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

Kofutela

POST https://nymbot.ai/api/v1/keys Posa Posa 201.

MisoMisoPenzaMiso
namePenzaIyo1 to 40 characters, different from your other active keys (ignoring case).
limit_satsMisoMisoNa na na na na na na na na na na na na na na
reset_periodPenzaMisodaily, weekly Miso monthlyMiso limit_satsNa na na na na na na na na na na na na
expire_atpe-po-girl14MisoKofutela: 8601 ko ISO, na milisekundi ya 1970.

Kokomi Sakura (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"
  }
}
MisoMiso
400Na na na na na na na na na na na na naduplicate_name); cap na ba likoti ya 1 na minoko; reset ya ba likoti; futatunoki na minokoti; lingomba ebele (unknown_parameter); na 25 keys tayari (too_many_keys).
429Pamba la Pamba la Pamba la 100%, Pamba la 100%, Pamba la 100%, Pamba la 100%, Pamba la 100% (rate_limit_exceededMiso 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);

makolinhot

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

Miso {"data": {…}} makolinhot 404 key_not_found na na na na na na na na na na na

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

Posa

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

Posa name, limit_sats, reset_period mpe expire_atNa na na na na na na na na na na na null na na na na na na na na na na na na na na400 key_revoked[MOKO] {"data": {…}} makolinhot

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

Posa Posa

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

Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba revoked_at pe-po-girl14 include_revoked=true. Kofutela key na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na na

Miso

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

Connect a Lightning wallet with Nostr Wallet Connect and Nymbot tops up a balance by itself when API spending runs it low. The app's API sheet has the same settings; these are the endpoints behind it. All of them need a Kofutela.

How it works: after an API request is charged to the balance you chose to watch, if that balance has fallen below your threshold, Nymbot makes an invoice for your top-up amount, asks your wallet to pay it, and adds the credit. It tops up at most once every 5 minutes for each nym and balance, so a burst of requests cannot drain the wallet. Spending in the apps does not trigger it. The time and size of the last top-up, and the last error, are in the settings; if a payment went through after an error, checking its invoice with Posa Posa Kofutela

Kofutela wallet

A connection string lets whoever holds it ask your wallet to pay. Nymbot stores it encrypted and only ever uses it to pay its own top-up invoices, but make a connection just for this, with a spending budget in your wallet, so the most it could ever pay is a number you chose. The wallet has to support pay_invoice.

Posa Posa

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

MisoMisoPenzaMiso
nwc_urlPenzaIyoPamba la Pamba la Pamba la 100% nostr+walletconnect://. Nymbot na na wallet na get_info na na na na na na na na na na
threshold_satsMisoIyoPamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba
topup_satsMisoIyoNa na na na na na na na na na na na na na na
tierPenzaMisopro [MOKO] standard: balanse ya mayi na mayi na mayi.

Miso

{
  "data": {
    "connected": true,
    "threshold_sats": 5000,
    "topup_sats": 20000,
    "tier": "pro",
    "last_topup_at": null,
    "last_topup_sats": null,
    "last_error": null
  }
}
MisoMiso
400Sika (invalid_nwc_urlTango ya libosó (nwc_unreachable) na na na na (nwc_rejected); ba na ba na na na na na na na na (nwc_missing_permission); Na minoko na minoko.
501Lelo (Lelo)nwc_unavailable[MOKO] Eko ya mayi pe-po-girl13

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

Miso

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

Na na na na na na na na na connected: false Na minoko koleka null na na na na na na na na na na

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

Kofutela

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

Na na na na na na na na na na na na na na na na na na na na

Miso

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

Nakanganga

Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la: POST /images/generations, POST /images/edits, POST /videos, POST /audio/speech, POST /audio/transcriptions, POST /audio/translations mpe POST /embeddings. Chat, Responses and Messages always need a key. A request that carries a key is billed to the balance as usual; the payment flow only starts when no key is sent.

Nymbot na na na na na na na na na na na na na na na na na ETENI YA 40 (mimi na na na na na na na) LSAT) na draft ya IETF Miso Pamba la Pamba la Pamba la 100% lightning ETENI YA charge Na na na na na na na na na na na na

Posa Posa Posa

Na na na na na na na na na API_L402_SECRET na na na na na na na na na na na na openssl rand -hex 32. Kofutela ya nzambe ya nzambe ya nzambe ya nzambe ya nzambe ya nzambe ya nzambe ya nzambe ya nzambe ya nzambe ya nzambe ya nzambe ya nzambe. API_L402_SECRET_PREVIOUS po: credentials, status URLs na mbisi mbisi mbisi mbisi mbisi mbisi mbisi mbisi mbisi mbisi mbisi mbisi.

Posa

Send the request with no Authorization pe-po-girl14 402 Payment Required na faktura na esengo na miso ya miso: ekomisi ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya miso ya mis WWW-Authenticate ETENI YA 10

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

Miso request pe-po-girl14 {"amount":"237","currency":"sat","methodDetails":{"invoice":"lnbc...","network":"mainnet","paymentHash":"..."}}.

Penza ya Posa Posa Posa Content-Type (misi ya media na, na multipart, ya bordi) na SHA-256 ya bautisi ya mwili na bautisi na bautisi na bautisi na bautisi na bautisi na bautisi na bautisi na bautisi na bautisi na bautisi na bautisi na bautisi na bautisi na bautisi na bautisi na bautisi na bautisi). Miso ETENI YA 10 Content-Type na na na na na na na na na/images/edits, /audio/transcriptions, /audio/translations(HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP) (HTTP)

Each address can ask for 30 challenges a minute (an IPv6 address counts as its whole /64). Requests whose address is not known share a stricter 10 a minute, and there is an overall cap on the challenges Nymbot issues across all addresses; a request refused before a challenge is made (for example with a body that is not valid JSON) does not count toward it. Beyond that the answer is 429 Miso Retry-AfterPamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba Content-Type Miso application/json [MOKO] multipart/form-data pe-po-girl14 415 na na na na na na na na

Na na na na na na na na na na na na na na na na na na na na na na na na Posa Posa.

Nakanganga

Na na na na na na na na na na na na na na na na na na na na na na na na na na na na

MisoMiso
ETENI YA 40Authorization: L402 <macaroon>:<preimage> (LSAT [MOKO]
MisoAuthorization: Payment <base64url JSON>na na na na na na {"challenge": {every parameter of the challenge, as sent}, "payload": {"preimage": "<hex>"}}

Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la 100% nymbot ETENI YA 6 {"payment": "l402", "tier": "pro", "paid_sats": 237, "charged_sats": 237}Na na na na na na X-Nymbot-Balance-Sats makolinhot. Makolinhot ya makolinhot Payment-Receipt makolinhot (base64url JSON na challenge id, makolinhot na makolinhot reference, status mpe timestamp(Payed requests) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

MisoMiso
402 payment_already_usedKokolala nzala nzala nzala nzala nzala nzala nzala nzala nzala nzala nzala lnget na na na na na na na
402 payment_mismatchPamba la Pamba la Pamba la 100% Content-Type na na na na na na na na na na na na na na na na na na na na na na na na Posa Posa (refund_token mpe refund_sats Lelo)
402 payment_expiredNa minoko mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi mingi. Posa Posa (refund_token mpe refund_sats lingomba ya libosó ya libosó ya libosó ya libosó ya libosó ya libosó ya libosó ya libosó ya libosó
401 invalid_preimagePamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba ya Pamba
401 invalid_payment_credentialThe credential is malformed, was changed after Nymbot issued it, or names a payment hash Nymbot never issued an invoice for. A macaroon with a caveat Nymbot does not know, or with conflicting caveats, is refused.
429 rate_limit_exceededPamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la Pamba la 100% 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"));

Miso mppx na Lightning mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula mbula

Miso

Miso POST /videos Miso 202 pe-po-girl14 status_url: GET na na na na na na na na na na na na na na

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

Penza refund_token pe-po-girl13 pe-po-girl14GET /api/v1/l402/refunds Miso "status": "pending"); sanza likota likota likota likota likota likota likota refund_sats na na na na na na na na na na na na na na na na na na na na na

Miso

If a paid request fails and the provider billed Nymbot for the attempt, the payment is kept and the error says so, with charged_sats. . . . . . . . . . . . . . . . . . . . . . . . . . . Posa Posa Na na na na na na na

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

Pamba la Pamba la Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba la 100% ya Pamba nymbot object carries a refund token for the missing one; a transcription whose length could not be read up front is priced for the longest the file could be (never more than 30 minutes), and the difference to the real length comes back as a refund token; if it turns out to be longer than 30 minutes, it is refused with 413 na na na na na na na na na na na na na na na na na na na na

Kofutela token na ye 256-bit na ye. Nymbot na ye na ye, na ye na ye, na ye na ye.

  • Nakanganga Miso Authorization: Bearer REFUND-… Penza ya Penza ya Penza ya Penza ya Penza ya Penza ya Penza ya Penza ya Penza (refund_token_sats Miso nymbot . . . . . . . . . . . . . . . . 402 refund_insufficient. . . . . . . . . . . . . . . . . . . .
  • Penza GET /api/v1/l402/refunds makolinhot {"sats": 237, "status": "open", "expires_at": "..."}.
  • Token na likoti na 60 ya minoko.
  • Posa na nym. Posa Posa Posa na Nymbot app, na POST /api/v1/l402/refunds/redeem Miso Kofutela mpe {"refund_token": "REFUND-...", "balance": "standard"} [MOKO] "pro"). Kokolala nzambe (kokolala nzambe 10 nzambe, 100 nzambe Pro); nzambe na asali na asali na token na API nzambe.

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"

Miso

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