Преминете към съдържанието
Обратно към Nymbot

База знания Разработчиците

Баланс, върхове и ключове

Проверете какво имате, надхвърлете Lightning, надхвърлете автоматично от собствения си портфейл, вижте колко струва всяко искане и управлявайте ключовете от кода.

Проверка на баланса

И вашите баланси, и колко от капака на този ключ се използва.

GET https://nymbot.ai/api/v1/credits/balance Нуждаете се от API ключ. POST Това важи и за клиентите, които го очакват.

balance е двата баланса заедно в долари на текущата цена на Bitcoin, за инструменти, които очакват едно число (null Останалото е в кредити и ставки, което е начинът, по който балансите всъщност се държат. key Описва ключа, който е поискал.Ключ, който е достигнал своя капак, все още може да провери баланса.

Отговор

{
  "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"
  }
}
статутКога
401Ключът е липсващ, неизвестен, оттеглен или изтекъл.

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

Начини на плащане

Как можете да надхвърлите, и границите. мълния е единственият метод.

GET https://nymbot.ai/api/v1/topup/payment-methods Няма нужда от ключ.

Топ-уп е от 10 до 1 000 000 sats; Pro-top-up трябва да купи най-малко един Pro кредит, така че започва от 100 sats. bulk_bonus изброява допълнителния кредит за по-големите топ-уп, същият като в приложението: 10%, 15% или 20% повече за стандартните топ-уп от 500, 1000 или 5000 sats, и за Pro топ-уп от 5,000, 10,000 или 50,000 sats.

Отговор

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

Нагоре над светкавицата

Създава сметка за светкавицата, която добавя кредит към ключа, към който принадлежи ключът. Проверете го Добавяне на кредита.

POST https://nymbot.ai/api/v1/topup/create/btc-lightning Нуждаете се от API ключ.

полетоТипНеобходимиОписание на
amountбройдаКолко пъти, в currencyЦяло число за залог.
currencyСтрийтнеSATS (В случай на неизпълнение на задължението), USD или BTCДоларите се конвертират на текущата цена на Bitcoin.
tierСтрийтнеpro (в случай на неизпълнение) или standardВ кой баланс се намира кредитът.

Стандартният кредит е 10 стотинки и Pro кредит 100 стотинки, плюс всякакъв бонус; credits Кажи ми какво ще добави тази статия.

Отговор

{
  "invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
  "payment_request": "lnbc100u1p5...",
  "amount_sats": 10000,
  "credits": 115,
  "tier": "pro",
  "expires_at": "2026-09-30T09:27:00Z",
  "status": "pending"
}
статутКога
400Друг метод на пътя (unsupported_method, неизвестна валута (unsupported_currencyв) минимална стойност или минимална стойност или минимална стойност (amount_too_small, над 1 000 000 стотинки (amount_too_large) или отхвърлени от портфейла на Lightning (amount_out_of_range).
429Повече от 60 фактури за този нюм, или 120 от този адрес, в един час (rate_limit_exceeded, с Retry-After).
502В момента не може да се направи фактура (invoice_unavailable, с 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);

Проверка на върха

Пита дали фактурата е платена и, след като има, добавя кредита. Проверка е това, което го кредитира, така че след плащане, проверете, докато състоянието е creditedПроверката отново след това е безопасна: кредитът се приземява веднъж, независимо колко пъти питате.

GET https://nymbot.ai/api/v1/topup/status/{invoice_id} — се нуждае от ключ от ним, който е направил фактурата.

status е pending (все още не е платен) paid (платено, но все още не е кредитирано; проверете отново), credited (на вашия баланс) или expired (не се плаща навреме). Полетата на баланса са за нивото, на което се изчислява фактурата.

Отговор

{
  "invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
  "status": "credited",
  "amount_sats": 10000,
  "credits": 115,
  "tier": "pro",
  "expires_at": null,
  "balance_credits": 523.33,
  "balance_sats": 52333
}
статутКога
400Идентификаторът не е 64-цифровият идентификатор от повикването за създаване.
404Нито един от тях не може да се похвали с това име (вж.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);

Искам история

Един ред на заявка: какво е било, какъв модел, колко токени и колко струва. Не се съхраняват обаждания или отговори, така че никой не се връща. Редове се съхраняват в продължение на 90 дни, най-новото първо. Ключ, който е достигнал своя таван, все още може да прочете своята история.

GET https://nymbot.ai/api/v1/queries/history — се нуждае от API ключ, който вижда собствените си искания, или Подписано искане от твоята нима, която вижда всеки ключ.

полетоТипНеобходимиОписание на
pageСъвпадение за: QueryнеПо подразбиране 1, най-много 1000; по-висока страница е 400 invalid_value.
page_countСъвпадение за: QueryнеРедове на страница. По подразбиране 20, най-много 100.
start_date
end_date
Стрийт (поискане на търсене)неISO 8601 дати или часове.
modelСтрийт (поискане на търсене)неСамо този модел.
typeСтрийт (поискане на търсене)неchat, responses, messages, image, video, speech, transcription или embedding.
all_keysБоулиан (на английски език) QueryнеС един ключ: true включва всеки ключ от един и същ нюм. false.
key_idСтрийт (поискане на търсене)нес подписано искане, или с all_keys=trueСамо този ключ.

Отговор

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

Подписване на заявки за сметка

Създаването, промяната и оттеглянето на ключове, резюмето на сметката и автоматичните надстройки не вземат API ключ. Те вземат подпис от вашия нюм, така че изтеклият ключ може да изразходва до своя капак, но никога не може да направи друг ключ или да повиши собствения си капак.

Приложението прави това за вас: всичко в него Огънят Този раздел ви е необходим само за да управлявате ключовете от собствения си код.

Подписът е събитие Nostr от типа 27235 (NIP-98), изпратено base64-кодирано в Authorization Хедър с думата Nostr На преден план:

Събитието

{
  "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 е пълен URL адрес на заявката, включващ низ от заявки, точно както е изпратен.
  • method Това е HTTP методът.
  • payload е SHA-256 на тялото на суровото искане, в хекса. POST и PATCH, и тялото, което изпращате, трябва да бъде байт за байт този, който хаширате.
  • created_at трябва да е в рамките на 60 секунди от часа на сървъра.
  • Всяко събитие работи веднъж, а GET включени, така че заснетата заглавие не може да бъде възпроизведена отново. Подпишете нова за всяка заявка. nonce етикет с случайна стойност, така че две заявки, подписани в една и съща секунда, все още се различават.
  • Тялото на подписано искане може да бъде най-много 64 KB, а тялото се нуждае от Content-Type: application/json.

Изчезнало събитие се завръща 401 missing_nostr_auth; един, който е лошо оформен, лошо подписан, твърде стар, или за различен URL, метод или тяло връща invalid_nostr_auth, с причината в съобщението; един повторно използван се връща nostr_auth_replayedПодписът се проверява преди тялото да бъде прочетено и всеки адрес може да се провали 30 пъти в минута (IPv6 адресът се брои като цяло /64); след това получава 429 с Retry-After.

Браузърите могат да извикват тези крайни точки само от собствените сайтове на Nymbot (https://nymbot.ai, https://nymchat.app Страница на всеки друг сайт не получава CORS заглавия обратно, така че не може да чете това, което те връщат. OriginТе не са засегнати.

Вашият таен ключ

Подписването се нуждае от тайния ключ на вашия ним (на nsec), който контролира всичко: вашата самоличност, историята и баланса ви. Само го поставете в скрипт на машина, на която се доверявате, прочетете го от околната среда, вместо да го напишете в файла, и предпочитате приложението, когато можете.

Тези помощници изграждат заглавието. По-късните примери на тази страница ги използват. Те четат тайния ключ в хекса от NOSTR_SECRET_HEX; cURL един използва НОК инструмент за командния ред, който взема nsec или хекс ключ, и sha256sum за 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");
}

Резюме на сметката

Какво показва API листът на приложението в горната част: вашият публичен ключ, двата баланса, колко ключа са активни (не са отменени или изтекли) и Автоматично натоварване настройки или null когато сървърът не ги предлага.

GET https://nymbot.ai/api/v1/account Нуждае се от Подписано искане.

Отговор

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

Управление на ключове

Крайните точки зад списъка с ключове на приложението. Всички те се нуждаят от Подписано исканеВсеки ключ се връща в следната форма, с времена в ISO 8601 и суми в sats:

Ключови обекти

{
  "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 Достатъчно е да разпознаете ключ, но не и да го използвате.Самият ключ се връща само веднъж, когато е направен.

Списък на ключовете

GET https://nymbot.ai/api/v1/keys — Аз съм подписал.

полетоТипНеобходимиОписание на
include_revokedБоулиан (на английски език) QueryнеВключва отменени ключове. по подразбиране false.

Отговор

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

Създаване на ключ

POST https://nymbot.ai/api/v1/keys Връщане - връщане 201.

полетоТипНеобходимиОписание на
nameСтрийтда1 до 40 знака, различни от останалите ви активни ключове (игнориране на случая).
limit_satsинтегритетнеКапацитетът на разходите в sats, най-малко 1.
reset_periodСтрийтнеdaily, weekly или monthlyнуждите limit_satsОставете го за капачка, която никога не се възстановява.
expire_atstring или integerнеКогато ключът спре да работи: ISO 8601 време, или милисекунди от 1970 година.

Отговор на въпроса (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"
  }
}
статутКога
400Липсващо или твърде дълго име; вече използвано име (duplicate_name); таван, който не е цяло число от най-малко 1; период на нулиране без таван; изтичане в миналото; неизвестно поле (unknown_parameter); или 25 активни ключове вече (too_many_keys).
429Повече от 60 ключа, направени от този ним, или 120 от този адрес, в един час (rate_limit_exceeded, с 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);

Четене на ключ

GET https://nymbot.ai/api/v1/keys/{id} — Аз съм подписал.

Връщане {"data": {…}} с ключовия обект, или 404 key_not_found Ако вашият ключ няма този идентификатор.

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

Смяна на ключ

PATCH https://nymbot.ai/api/v1/keys/{id} — Аз съм подписал.

Изпратете някой от name, limit_sats, reset_period и expire_atсъщите правила, както при създаването на ключ. null Изчиства поле: няма капаци, няма нулиране, няма изтичане. Промяната на периода на нулиране започва нов период от нула.400 key_revoked• Връщане {"data": {…}} с актуализирания ключов обект.

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

Отмяна на ключ

DELETE https://nymbot.ai/api/v1/keys/{id} — Аз съм подписал.

Спира ключа веднага, за добро. Той остава в списъка с revoked_at Намерени са и могат да се видят include_revoked=trueОттеглянето на ключ, който вече е оттеглен, отговаря по същия начин. Само най-новите 50 оттеглени ключа се запазват; по-старите се изтриват, когато се оттегли друг ключ.

Отговор

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

Свържете портфейла на Lightning с Nostr Wallet Connect и Nymbot ще постави баланса сам по себе си, когато разходите за API го изпълняват ниско. Подписано искане.

Как работи: След като заявката за API се таксува на баланса, който сте избрали да гледате, ако този баланс е паднал под прага ви, Nymbot издава фактура за сумата ви, пита портфейла ви да я плати и добавя кредита. Той се натрупва най-много веднъж на всеки 5 минути за всеки нюм и баланс, така че избухването на искания не може да изтегли портфейла. Изразходването в приложенията не го задейства. Времето и размерът на последната надстройка и последната грешка са в настройките; ако плащането е минало след грешка, проверете фактурата си с Статусът на върха Кредитирай го

Преди да свържете портфейл

Nymbot го съхранява шифровано и само някога го използва, за да плати собствените си фактури, но направете връзка само за това, с бюджет за разходи в портфейла си, така че най-много, което някога може да плати, е номер, който сте избрали. pay_invoice.

Свързване на портфейл

POST https://nymbot.ai/api/v1/nwc-auto-topup/connect — Аз съм подписал.

полетоТипНеобходимиОписание на
nwc_urlСтрийтдаВръзката, започвайки от nostr+walletconnect://Nymbot пита портфейла за get_info преди да го съхранява и го съхранява криптирано.
threshold_satsинтегритетдаНагоре, когато балансът падне под тези много sats. най-малко 1000.
topup_satsинтегритетдаКолко да добавя всеки път. 1000 до 1 000 000 sats.
tierСтрийтнеpro (в случай на неизпълнение) или standard: балансът да се наблюдава и да се издига.

Отговор

{
  "data": {
    "connected": true,
    "threshold_sats": 5000,
    "topup_sats": 20000,
    "tier": "pro",
    "last_topup_at": null,
    "last_topup_sats": null,
    "last_error": null
  }
}
статутКога
400не е свързан с връзката (invalid_nwc_url(Възможно ли е да не се отговори на въпроса за разпределението)nwc_unreachable) или се отказва от проверката (nwc_rejected); връзката не може да плати фактури (nwc_missing_permissionили сума, която е извън границите.
501Автоматичните надстройки не са включени за този сървър (nwc_unavailableСъщото се отнася и за останалите две крайни точки.

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

Прочетете настройките

GET https://nymbot.ai/api/v1/nwc-auto-topup — Аз съм подписал.

Връща същия обект като свързване, с connected: false и други полета null когато няма свързан портфейл. самата връзка никога не се връща.

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

Откъсване

DELETE https://nymbot.ai/api/v1/nwc-auto-topup/connection — Аз съм подписал.

Изтрива съхранената връзка. Не се правят повече надстройки. За да сте сигурни, можете също да оттеглите връзката в портфейла си.

Отговор

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

Плащане по заявка без ключ

Крайните точки с фиксирана цена могат да бъдат платени за едно искане наведнъж през Lightning, без ключ, без сметка и без баланс: POST /images/generations, POST /images/edits, POST /videos, POST /audio/speech, POST /audio/transcriptions, POST /audio/translations и POST /embeddingsЧат, отговори и съобщения винаги се нуждаят от ключ. Заявка, която носи ключ, се начислява към баланса както обикновено; потокът от плащания започва само когато няма ключ.

Nymbot говори две версии на една и съща идея, от един backend: Lightning Labs Е402 (също приети под старото си име, LSAT) и проекта на IETF Плащането Схема за HTTP аутентификация с lightning Метод и charge Използвайте това, което клиентът ви разбира.

Изграждане на собствен сървър

Плащането без ключ е само когато API_L402_SECRET съдържа най-малко 32 случайни байта, като шестоъгълник (64 знака) или base64 (44). openssl rand -hex 32По-кратка или предположима стойност изключва функцията и регистрира защо.За да я завъртите, преместете старата стойност на API_L402_SECRET_PREVIOUS за един ден: поверителностите, URL адресите на състоянието и предизвикателствата, направени по него, продължават да работят, докато изтекат.

Предизвикателството

Изпратете заявката с не Authorization ако е валидна, нищо не работи и получавате 402 Payment Required с фактура за точно това, което искането струва: същата цена, която ключът би платил, конвертиран на 10 sats стандартен кредит или 100 sats Pro кредит и закръглено до цял sat (най-малко 1 sat, и най-малко 0.05 кредитен минимум). WWW-Authenticate Предизвикателства за една и съща сметка:

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

Плащането request Параметърът е base64url JSON: {"amount":"237","currency":"sat","methodDetails":{"invoice":"lnbc...","network":"mainnet","paymentHash":"..."}}.

Едно предизвикателство е свързано с крайната точка, с Content-Type (видът на медията и, за многочасти, границата му) и на SHA-256 на точните байтове на тялото, които сте изпратили, и трае 15 минути. идентични Отново искане: същото Content-Type и същите JSON байтове, или за множество крайни точки (/images/edits, /audio/transcriptions, /audio/translationsПовечето HTTP библиотеки избират нова граница всеки път, когато кодират формуляр, така че кодирайте го веднъж и изпращайте тези байтове два пъти.

Всеки адрес може да поиска 30 предизвикателства на минута (IPv6 адрес се брои като цяло /64). Заявления, чийто адрес не е известен, споделят по-строг 10 на минута, и има обща граница за предизвикателствата Nymbot проблеми във всички адреси; искане, отхвърлено преди да бъде направено предизвикателство (например с тяло, което не е валидно JSON) не се брои към него. 429 с Retry-AfterПлатени крайни точки, които се обаждат без ключ или поверителност, също се броят към общия лимит от 120 неоторизирани искания в минута на адрес. Content-Type Не е application/json (или multipart/form-data за изтегляне) се отхвърля с 415 Никога не получава фактура.

Вгражданията се оценяват въз основа на оценка на токените в входа, с марж от 1.5 пъти, тъй като действителният брой е известен само след това. Възстановяване на токен.

Изпращане на плащането

Платете сметката с всеки портфейл на Lightning. Портфейлът ви дава предварителното изображение, 64 шестоъгълни знака. След това изпратете същото искане с едно от тези:

схематаХедър
Е402Authorization: L402 <macaroon>:<preimage> (LSAT работи също)
ПлащанетоAuthorization: Payment <base64url JSON>Къде е JSON {"challenge": {every parameter of the challenge, as sent}, "payload": {"preimage": "<hex>"}}

Платената заявка отговаря точно като тази, направена с ключ, с изключение на това, че nymbot Обектът няма полета за баланс: {"payment": "l402", "tier": "pro", "paid_sats": 237, "charged_sats": 237}И там няма X-Nymbot-Balance-Sats Заявка, платена с схемата за плащане, също получава Payment-Receipt header (base64url JSON с ID за предизвикателство, плащане хаш като reference, status и timestampПлатените заявки не са обвързани с нима, така че те не се появяват в историята на заявките.

статутКога
402 payment_already_usedВсяко плащане плаща за едно искане.Отговорът е ново предизвикателство за това искане, така че клиентът, който кешира последната си поверителност (като lnget Отново просто се върна.
402 payment_mismatchКредитът е издаден за друга крайна точка, Content-Type или тялото, или плаща по-малко от това искане сега струва. ново предизвикателство за това искане идва с него; ако плащането е твърде малко, това, което сте платили, се връща като Възстановяване на токен (refund_token и refund_sats в рамките на тялото).
402 payment_expiredПовече от 15 минути са минали от предизвикателството.Ново предизвикателство идва с него.Ако предварителното изображение показва, че сте платили, това, което сте платили, се връща като Възстановяване на токен (refund_token и refund_sats в тялото), веднъж; след това се използва доверието.
401 invalid_preimageПредварителното изображение не хашира платежния хаш на фактурата.
401 invalid_payment_credentialУдостоверението е дефектно, е променено, след като Nymbot го е издал, или имената на плащане хаш Nymbot никога не е издавал фактура за.
429 rate_limit_exceededПовече от 30 идентификационни данни или ключове, които не успяха да се потвърдят, дойдоха от този адрес в рамките на минута, или един токен за възстановяване беше изпратен повече от 60 пъти в минута. 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"));

Клиентите са изградени на mppx С помощта на метода Lightning се справяте сами с предизвикателството за плащане; насочете ги към крайната точка и ги оставете да платят.

Видеото

Платени са POST /videos отговори 202 като ключова една, плюс а status_url: GET Той е подписан и работи в продължение на 24 часа, докато работата е запазена.

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

Дръжте го refund_token от този отговор: той се показва само тук. Той е празен, докато видеотоGET /api/v1/l402/refunds отговори "status": "pending"); ако възпроизвеждането се провали без фактуриране, плащането се приземява върху него. refund_sats за възстановена работа, но никога токена, така че споделянето на URL адреса на състоянието не споделя възстановяването.

възстановяване

Ако платеното искане се провали и доставчикът е таксувал Nymbot за опита, плащането се запазва и грешката казва така, с charged_sats, точно както за ключово искане. Ако той се провали, без да бъде фактуриран, грешката носи Възстановяване на токен Заслужава си това, което сте платили:

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

Неизползваните части се връщат по същия начин: ако сте поискали две снимки и едното не е разчитано, отговорът на успеха nymbot обектът носи токен за възстановяване за липсващия; транскрипция, чиято дължина не може да бъде прочетена предварително, се цени за най-дългата, която може да бъде файла (никога не повече от 30 минути), а разликата с реалната дължина се връща като токен за възстановяване; ако се окаже, че е по-дълга от 30 минути, тя се отхвърля с 413 Вгражданията връщат това, което е задържано от оценката.Неуспешното видео връща токена, който е върнато от подаденото.

Токенът за възстановяване е случайно 256-битов код. Nymbot съхранява само своя хеш и изтича след 30 дни.

  • Платете с него. Изпрати Authorization: Bearer REFUND-… За да се отървете от този проблем, е необходимо да се избягва използването на антибиотици, като се вземат под внимание всички фактори, които причиняват възпаление (refund_token_sats В на nymbot Токен, който струва по-малко от отговора на заявката 402 refund_insufficientНеизчислена грешка поставя sats обратно на същия токен.
  • Проверете го GET /api/v1/l402/refunds със същия хедър се връща {"sats": 237, "status": "open", "expires_at": "..."}.
  • Един токен може да се използва най-много 60 пъти в минута.
  • Преместете го в нюанс. Поставете го в Подарете си подарък в приложението Nymbot, или повикване POST /api/v1/l402/refunds/redeem с а Подписано искане и {"refund_token": "REFUND-...", "balance": "standard"} (или "pro"Цели кредити отиват в баланса (10 sats всеки на стандарт, 100 на Pro); ставки, които не правят цял кредит остават на токена за API заявки.

cURL

URL=https://nymbot.ai/api/v1/l402/refunds/redeem
BODY='{"refund_token":"REFUND-...","balance":"standard"}'
curl "$URL" \
  -H "Authorization: $(nostr_auth POST "$URL" "$BODY")" \
  -H "Content-Type: application/json" \
  -d "$BODY"

Отговор

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