Перейти к содержимому
Вернуться в Nymbot

База знаний Разработчики

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

Проверьте, что у вас есть, переверните Lightning, автоматически переверните свой собственный кошелек, посмотрите, сколько стоит каждый запрос, и управляйте ключами из кода.

Проверить баланс

Как ваши балансы, так и то, сколько используется крышки этого ключа.

GET https://nymbot.ai/api/v1/credits/balance Нужен ключ API. POST Работает и для клиентов, которые этого ожидают.

balance это два баланса вместе в долларах по текущей цене Биткойна, для инструментов, которые ожидают единого числа (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 топ-упы от 5000, 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);

Вверх над молнией

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

POST https://nymbot.ai/api/v1/topup/create/btc-lightning Нужен ключ API.

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

Стандартный кредит составляет 10 sats и Pro кредит 100 sats, плюс любая масса бонуса; 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) или отклоненный молниеносным кошельком (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);

Хочется истории

Один ряд на запрос: что это было, какая модель, сколько токенов и сколько это стоило. Никаких запросов или ответов не сохраняется, поэтому никто не возвращается.

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
String (требование)НетISO 8601 Даты и времена.
modelString (требование)НетТолько эта модель.
typeString (требование)Нетchat, responses, messages, image, video, speech, transcription или embedding.
all_keysБоулиан (поискНетС одним ключом: true включает все ключи одного и того же нюма. false.
key_idString (требование)Нетс подписанным заявлением или с 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. Они берут подпись от вашего nym, так что утерянный ключ может потратить до своего предела, но никогда не может сделать другой ключ или повысить свой собственный.

Приложение делает это для вас: все в своем Огонь Sheet использует эти конечные точки. Вам нужен только этот раздел для управления ключами из собственного кода.

Подпись является событием Nostr типа 27235 (NIP-98), отправленным с кодировкой base64 в Authorization Header с словом 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 КБ, а тело нуждается в 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Боулиан (поискНетВключить отменяемые ключи. по умолчанию 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_satsintegerНетКапитал расходов в 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 минут для каждого нима и баланса, так что всплеск запросов не может вытащить кошелек. Расходы в приложениях не запускают его. Время и размер последней суммы, и последняя ошибка, находятся в настройках; если оплата прошла после ошибки, проверяйте свой счет с Статус Top-Up Кредит на это.

Прежде чем подключить кошелек

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

Подключение кошелька

POST https://nymbot.ai/api/v1/nwc-auto-topup/connect — Вы подписали

ПолеТипТребуетсяОписание
nwc_urlСтрингДаСхема соединения, начинающаяся nostr+walletconnect://Nymbot запрашивает кошелек для get_info перед тем, как сохранить его, и хранить его зашифрованным.
threshold_satsintegerДаВверх, когда баланс падает ниже этих многочисленных ставок.
topup_satsintegerДаСколько добавлять каждый раз. от 1000 до 1000 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 говорит о двух версиях одной и той же идеи, из одного фонаря: Lightning Labs Л402 (также принято под своим старым именем, LSAT) и проект IETF платеж Система аутентификации HTTP с помощью lightning Метод и charge Используйте то, что понимает ваш клиент.

Запуск собственного сервера

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

вызов

Отправить запрос с No 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 шестизначных символов. Затем отправить тот же запрос с одним из этих:

схемаHeader
Л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 с методом молнии справляться с платежным вызовом сами; указать их на конечную точку и позволить им заплатить.

Видео

Оплачивается 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-… в любой из вышеуказанных конечных точек (OpenAI SDK принимает его в качестве ключа API). цена исходит от токена и что остается на нем (refund_token_sats В НА nymbot Токен, который стоит меньше, чем ответы на запросы 402 refund_insufficientНесчетная неудача возвращает ставку на тот же токен.
  • Проверьте это 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 } }