Base de conhecimento Desenvolvedores
Balanço, top-ups e chaves
Verifique o que você tem, top up sobre o Lightning, top up automaticamente a partir de sua própria carteira, veja o que cada pedido custa e gerencie chaves a partir de código.
Esta página foi traduzida automaticamente por conveniência. O original em inglês é a versão aplicável.
Verificar o equilíbrio
Ambos os seus saldos, e quanto da tampa desta chave é usada.
GET https://nymbot.ai/api/v1/credits/balance Precisa de uma chave de fogo. POST Também funciona, para clientes que o esperam.
balance é os dois saldos juntos em dólares no preço atual do Bitcoin, para ferramentas que esperam um único número (null O resto é em créditos e sats, que é como os saldos são realmente mantidos. key Uma chave que atingiu seu limite ainda pode verificar o saldo.
Resposta
{
"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"
}
}
| Estatuto | Quando |
|---|---|
401 | A chave está faltando, desconhecida, revogada ou expirada. |
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);
Métodos de pagamento
Como você pode subir, e os limites. relâmpago é o único método.
GET https://nymbot.ai/api/v1/topup/payment-methods Nenhuma chave necessária.
Um top-up é de 10 a 1.000.000 sats; um top-up Pro tem que comprar pelo menos um crédito Pro, então ele começa em 100 sats. bulk_bonus lista o crédito extra em top-ups maiores, o mesmo que no aplicativo: 10%, 15% ou 20% mais em top-ups padrão de 500, 1.000 ou 5.000 sats, e em top-ups Pro de 5.000, 10.000 ou 50.000 sats.
Resposta
{
"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);
Subiu sobre o relâmpago
Faça uma fatura de relâmpago que adiciona crédito ao nim que a chave pertence. Verifique o para ter o crédito acrescentado.
POST https://nymbot.ai/api/v1/topup/create/btc-lightning Precisa de uma chave de fogo.
| Campo | Tipo | Requerido | Descrição |
|---|---|---|---|
amount | Número | Sim | Quanto tempo, em currencyUm número inteiro para a aposta. |
currency | string | Não | SATS (O que é o defeito) USD ou BTCOs dólares são convertidos ao preço atual do Bitcoin. |
tier | string | Não | pro (o defeito) ou standard• Qual é o balanço para o qual o crédito vai. |
Um crédito padrão é 10 sats e um crédito Pro 100 sats, mais qualquer bônus em massa;
credits diz o que esta fatura vai acrescentar.
Resposta
{
"invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
"payment_request": "lnbc100u1p5...",
"amount_sats": 10000,
"credits": 115,
"tier": "pro",
"expires_at": "2026-09-30T09:27:00Z",
"status": "pending"
}
| Estatuto | Quando |
|---|---|
400 | Outro método no caminho (unsupported_method, uma moeda desconhecida (unsupported_currency) ou nível, um montante faltante, ou um montante abaixo do mínimo (amount_too_small, acima de 1 milhão de vagas (amount_too_large) ou rejeitado pela carteira de relâmpago (amount_out_of_range). |
429 | Mais de 60 faturas para este nim, ou 120 a partir deste endereço, em uma hora (rate_limit_exceeded, com Retry-After). |
502 | Nenhuma fatura pode ser feita no momento (invoice_unavailable, com 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);
Verificar um top-up
Pergunta se a fatura foi paga e, uma vez que tem, adiciona o crédito. Checking é o que créditos, então depois de pagar, verifique até o status é creditedVerificar novamente depois é seguro: o crédito chega uma vez, não importa quantas vezes você pedir.
GET https://nymbot.ai/api/v1/topup/status/{invoice_id} - Precisa de uma chave do nim que fez a fatura.
status É pending (ainda não foi pago) paid (Pago, mas ainda não creditado; verifique novamente), credited (no seu equilíbrio) ou expired (Não pago a tempo).Os campos do saldo são para o nível que a fatura sobe.
Resposta
{
"invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
"status": "credited",
"amount_sats": 10000,
"credits": 115,
"tier": "pro",
"expires_at": null,
"balance_credits": 523.33,
"balance_sats": 52333
}
| Estatuto | Quando |
|---|---|
400 | O id não é o id de 64 caracteres da chamada criada. |
404 | Nenhuma fatura por esse id para o seu nym (invoice_not_found). |
cURL
curl https://nymbot.ai/api/v1/topup/status/$INVOICE_ID \
-H "Authorization: Bearer $NYMBOT_API_KEY"
Python
import os, time
import requests
headers = {"Authorization": "Bearer " + os.environ["NYMBOT_API_KEY"]}
url = "https://nymbot.ai/api/v1/topup/status/" + invoice["invoice_id"]
while True:
status = requests.get(url, headers=headers).json()["status"]
if status in ("credited", "expired"):
break
time.sleep(3)
print(status)
JavaScript
const headers = { "Authorization": "Bearer " + process.env.NYMBOT_API_KEY };
const url = "https://nymbot.ai/api/v1/topup/status/" + invoice.invoice_id;
let status;
do {
await new Promise((r) => setTimeout(r, 3000));
status = (await (await fetch(url, { headers })).json()).status;
} while (status !== "credited" && status !== "expired");
console.log(status);
Queremos História
Uma linha por solicitação: o que era, que modelo, quantos tokens e quanto custa. Não são mantidos pedidos ou respostas, então nenhuma é devolvida. As fileiras são mantidas por 90 dias, o mais recente primeiro. Uma chave que atingiu seu limite ainda pode ler seu histórico.
GET https://nymbot.ai/api/v1/queries/history necessita de uma chave da API, que veja as suas próprias solicitações, ou Solicitação assinada do seu ninho, que vê cada chave.
| Campo | Tipo | Requerido | Descrição |
|---|---|---|---|
page | Nome completo (query) | Não | Padrão 1, no máximo 1000; uma página mais alta é 400 invalid_value. |
page_count | Nome completo (query) | Não | Linhas por página. 20 por padrão, no máximo 100. |
start_dateend_date | Redação de Query (String) | Não | ISO 8601 datas ou horas. |
model | Redação de Query (String) | Não | Só esse modelo. |
type | Redação de Query (String) | Não | chat, responses, messages, image, video, speech, transcription ou embedding. |
all_keys | Booleão (query) | Não | Com uma chave: true inclui todas as chaves do mesmo nym. false. |
key_id | Redação de Query (String) | Não | Com uma solicitação assinada, ou com all_keys=trueApenas essa chave. |
Resposta
{
"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);
Assinar solicitações de conta
Criar, alterar e revogar chaves, o resumo da conta e os top-ups automáticos não tomam uma chave da API. Eles tomam uma assinatura do seu nim, de modo que uma chave vazada pode gastar até seu cap, mas nunca pode fazer outra chave ou aumentar seu próprio cap.
O aplicativo faz isso por você: tudo em sua Fogo Você só precisa desta seção para gerenciar chaves de seu próprio código.
A assinatura é um evento Nostr do tipo 27235 (NIP-98), enviado base64-codificado na
Authorization Header com a palavra Nostr Na sua frente:
O Evento
{
"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é o URL completo da solicitação, incluindo a cadeia de consulta, exatamente como enviado.methodÉ o método HTTP.payloadé o SHA-256 do corpo do pedido bruto, em hex.POSTePATCH, e o corpo que você envia deve ser byte por byte o que você hashou.created_atdeve estar dentro de 60 segundos do relógio do servidor.- Cada evento funciona uma vez, a
GETincluído, para que um cabeçalho capturado não possa ser reproduzido. Assine um novo cabeçalho para cada solicitação.noncemarcar com um valor aleatório para que dois pedidos assinados no mesmo segundo ainda sejam diferentes. - O corpo de uma solicitação assinada pode ser de no máximo 64 KB, e um corpo precisa
Content-Type: application/json.
Um evento perdido retorna 401 missing_nostr_auth; um que é mal formado, mal assinado, muito antigo, ou para um URL, método ou corpo diferente retorna
invalid_nostr_auth, com a razão na mensagem; um reutilizado retorna
nostr_auth_replayedA assinatura é verificada antes que o corpo seja lido, e cada endereço pode falhar 30 vezes por minuto (um endereço IPv6 conta como seu todo /64); depois disso, ele recebe 429 com
Retry-After.
Os navegadores podem chamar esses endpoints apenas a partir dos sites próprios do Nymbot (https://nymbot.ai,
https://nymchat.app Uma página em qualquer outro site não recebe cabeçalhos CORS de volta, então não pode ler o que eles retornam.
Originnão são afetados.
A assinatura precisa da chave secreta do seu nim (a nsec), que controla tudo: sua identidade, seu histórico e seu saldo.Só coloque-o em um script em uma máquina em que você confia, leia-o do ambiente em vez de escrevê-lo no arquivo, e prefira o aplicativo quando você puder.
Estes ajudantes criam o cabeçalho. Os exemplos posteriores nesta página usam-no. Eles lêem a chave secreta em hexágono de NOSTR_SECRET_HEX; o cURL um usa o
NÃO ferramenta de linha de comando, que leva uma chave nsec ou hex, e sha256sum Para os 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");
}
Resumo da Contabilidade
O que a folha da API do aplicativo mostra na parte superior: sua chave pública, ambos os balanços, quantas chaves estão ativas (não revogadas ou expiradas), e o número de chaves que você tem. Top-up automático configurações, ou
null quando o servidor não os oferece.
GET https://nymbot.ai/api/v1/account Precisa de a Solicitação assinada.
Resposta
{
"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());
Gerenciamento de chaves
Os endpoints por trás da lista de chaves do aplicativo. Todos eles precisam de um Solicitação assinadaCada chave é devolvida neste formulário, com tempos na ISO 8601 e somas em sats:
Objeto chave
{
"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 É suficiente para reconhecer uma chave, mas não para usá-la.A chave em si é devolvida apenas uma vez, quando é feita.
Lista de chaves
GET https://nymbot.ai/api/v1/keys e assinado .
| Campo | Tipo | Requerido | Descrição |
|---|---|---|---|
include_revoked | Booleão (query) | Não | Incluir chaves revogadas. padrão false. |
Resposta
{ "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);
Fazendo uma chave
POST https://nymbot.ai/api/v1/keys Assinado - Retorno 201.
| Campo | Tipo | Requerido | Descrição |
|---|---|---|---|
name | string | Sim | 1 a 40 caracteres, diferentes das suas outras chaves ativas (ignorando o caso). |
limit_sats | inteiro | Não | O limite de gastos em sats, pelo menos 1. deixe-o para fora sem cap. |
reset_period | string | Não | daily, weekly ou monthlyNecessidades limit_satsDeixe-o para fora para um capô que nunca se restaura. |
expire_at | String ou inteiro | Não | Quando a chave pára de funcionar: uma ISO 8601 vezes, ou milissegundos desde 1970. |
Reações (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"
}
}
| Estatuto | Quando |
|---|---|
400 | Um nome perdido ou muito longo; um nome já em uso (duplicate_name); um cap que não é um número inteiro de pelo menos 1; um período de reset sem um cap; uma expiração no passado; um campo desconhecido (unknown_parameter); ou 25 chaves ativas já (too_many_keys). |
429 | Mais de 60 chaves feitas por este nim, ou 120 deste endereço, em uma hora (rate_limit_exceeded, com 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);
Leia uma chave
GET https://nymbot.ai/api/v1/keys/{id} e assinado .
regressão {"data": {…}} com o objeto chave, ou 404
key_not_found Se a sua chave não tiver esse ID.
cURL
URL=https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856
curl "$URL" -H "Authorization: $(nostr_auth GET "$URL")"
Python
import requests
url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856"
print(requests.get(url, headers={"Authorization": nostr_auth("GET", url)}).json()["data"])
JavaScript
const url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856";
console.log((await (await fetch(url, { headers: { "Authorization": nostrAuth("GET", url) } })).json()).data);
Mudar uma chave
PATCH https://nymbot.ai/api/v1/keys/{id} e assinado .
Envie qualquer um name, limit_sats, reset_period e
expire_atcom as mesmas regras que quando se faz uma chave. null Não é possível alterar o período de validade, não é possível alterar o período de validade, não é possível alterar o período de validade (400 key_revoked• Retorno
{"data": {…}} com o objeto chave atualizado.
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);
Revogar uma chave
DELETE https://nymbot.ai/api/v1/keys/{id} e assinado .
Parar a chave de uma vez, para sempre. Ele permanece na lista com revoked_at Acompanhe e pode ser visto com include_revoked=trueRevogar uma chave que já foi revogada responde da mesma forma.Apenas as mais recentes 50 chaves revogadas são mantidas; as mais antigas são excluídas quando outra chave é revogada.
Resposta
{ "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 em São Paulo
Conecte uma carteira Lightning com o Nostr Wallet Connect e o Nymbot coloca um equilíbrio por si só quando o gasto com a API é baixo.A folha da API do aplicativo tem as mesmas configurações; estes são os endpoints por trás dela. Solicitação assinada.
Como funciona: depois que um pedido de API é cobrado para o saldo que você escolheu para assistir, se esse saldo caiu abaixo do seu limiar, o Nymbot faz uma fatura para o seu montante superior, pede à sua carteira para pagá-lo e adiciona o crédito. Ele sobe no máximo uma vez a cada 5 minutos para cada nim e saldo, de modo que uma explosão de pedidos não pode drenar a carteira. Gastar nos aplicativos não o desencadeia. O tempo e o tamanho do último top-up, e o último erro, estão nas configurações; se um pagamento passou após um erro, verifique sua fatura com O status top-up Crédito para isso.
Uma cadeia de conexão permite que quem a detém peça à sua carteira para pagar.Nymbot o armazena criptografado e só o usa para pagar suas próprias faturas, mas faça uma conexão apenas para isso, com um orçamento de gastos em sua carteira, de modo que o mais que poderia pagar é um número escolhido por você. pay_invoice.
Conectando uma carteira
POST https://nymbot.ai/api/v1/nwc-auto-topup/connect e assinado .
| Campo | Tipo | Requerido | Descrição |
|---|---|---|---|
nwc_url | string | Sim | A cadeia de conexão, começando nostr+walletconnect://Nymbot pede a carteira para get_info antes de guardá-lo e armazená-lo criptografado. |
threshold_sats | inteiro | Sim | Top up quando o saldo cai abaixo dessas muitas sats. |
topup_sats | inteiro | Sim | Quanto adicionar cada vez. 1.000 a 1.000.000 sats. |
tier | string | Não | pro (o defeito) ou standardO equilíbrio para olhar e subir. |
Resposta
{
"data": {
"connected": true,
"threshold_sats": 5000,
"topup_sats": 20000,
"tier": "pro",
"last_topup_at": null,
"last_topup_sats": null,
"last_error": null
}
}
| Estatuto | Quando |
|---|---|
400 | Não é uma cadeia de conexão (invalid_nwc_url); a carteira não respondeu sobre o seu releio (nwc_unreachable) ou recusou a verificação (nwc_rejected); a conexão não pode pagar faturas (nwc_missing_permission(ou uma quantia fora dos limites. |
501 | Não é permitida a utilização de suporte automático para este servidor (nwc_unavailableO mesmo se aplica aos outros dois endpoints. |
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());
Leia as configurações
GET https://nymbot.ai/api/v1/nwc-auto-topup e assinado .
Retorna o mesmo objeto que a conexão, com connected: false E os outros campos
null Quando nenhuma carteira está conectada, a própria cadeia de conexão nunca é devolvida.
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());
Desconectando
DELETE https://nymbot.ai/api/v1/nwc-auto-topup/connection e assinado .
Elimina a cadeia de conexão armazenada.Não são feitos mais top-ups.Para ter certeza, você também pode revogar a conexão em sua carteira.
Resposta
{ "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());
Pagamento por solicitação sem chave
Os endpoints de preço fixo podem ser pagos por um pedido de cada vez durante o Lightning, sem chave, sem conta e sem saldo: POST /images/generations, POST /images/edits,
POST /videos, POST /audio/speech, POST /audio/transcriptions,
POST /audio/translations e POST /embeddingsChat, Respostas e Mensagens sempre precisam de uma chave. Uma solicitação que carrega uma chave é faturada ao saldo como de costume; o fluxo de pagamento só começa quando nenhuma chave é enviada.
Nymbot fala duas versões da mesma ideia, de um backend: Lightning Labs'
C402 (também aceito sob seu antigo nome, LSAT) e o projeto IETF
Pagamento O sistema de autenticação HTTP com o lightning Método e
charge Use o que seu cliente entende.
Pagar sem chave é só quando API_L402_SECRET possui pelo menos 32 bytes aleatórios, como hex (64 caracteres) ou base64 (44). openssl rand -hex 32Um valor mais curto ou razoável desliga o recurso e registra o porquê. Para girá-lo, mova o valor antigo para API_L402_SECRET_PREVIOUS por um dia: credenciais, URLs de status e desafios feitos sob ele continuam a funcionar até que expiram.
O desafio
Envie a solicitação com não Authorization se for válido, nada é executado e você 402 Payment Required com uma fatura para exatamente o que esse pedido custa: o mesmo preço que uma chave pagaria, convertido em 10 sats um crédito padrão ou 100 sats um crédito Pro e arredondado até um sat inteiro (pelo menos 1 sat, e pelo menos o mínimo de crédito 0,05). WWW-Authenticate Dificuldades para a mesma fatura:
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 }
}
O pagamento request O parâmetro é base64url JSON:
{"amount":"237","currency":"sat","methodDetails":{"invoice":"lnbc...","network":"mainnet","paymentHash":"..."}}.
Um desafio está ligado ao ponto final, ao Content-Type (o seu tipo de mídia e, para multipartes, o seu limite) e para o SHA-256 do corpo exato de bytes que você enviou, e dura 15 minutos. idêntico Mais uma vez: o mesmo
Content-Type e os mesmos bytes JSON, ou para os pontos finais multipartes (/images/edits, /audio/transcriptions, /audio/translationsA maioria das bibliotecas HTTP escolhe um novo limite cada vez que codificar um formulário, então codifique-o uma vez e envie esses bytes duas vezes.
Cada endereço pode pedir 30 desafios por minuto (um endereço IPv6 conta como seu /64 inteiro). Solicitações cujo endereço não é conhecido compartilham um 10 mais rigoroso por minuto, e há um limite geral sobre os desafios Nymbot problemas em todos os endereços; um pedido recusado antes de um desafio é feito (por exemplo, com um corpo que não é válido JSON) não conta para ele. 429 com Retry-AfterOs endpoints pagos chamados sem uma chave ou credencial também contam para o limite geral de 120 solicitações não autenticadas por minuto por endereço. Content-Type Não é application/json (ou
multipart/form-data Porém, para os recusados, 415 Nunca recebe uma fatura.
As incorporações são avaliadas a partir de uma estimativa dos tokens na entrada, com uma margem de 1,5 vezes, uma vez que a contagem real só é conhecida depois. Reembolso de token.
Enviar o pagamento
Pague a fatura com qualquer carteira Lightning. A carteira dá-lhe a pré-imagem, 64 caracteres hexagonais. Em seguida, envie a mesma solicitação com um destes:
| esquema | cabeçalho |
|---|---|
| C402 | Authorization: L402 <macaroon>:<preimage> (LSAT também trabalha) |
| Pagamento | Authorization: Payment <base64url JSON>Onde está o JSON {"challenge": {every parameter of the challenge, as sent}, "payload": {"preimage": "<hex>"}} |
Um pedido pago responde exatamente como um pedido feito com uma chave, exceto que o nymbot
O objeto não tem campos de equilíbrio: {"payment": "l402", "tier": "pro", "paid_sats": 237,
"charged_sats": 237}E há não há X-Nymbot-Balance-Sats Um pedido pago com o esquema de Pagamento também recebe um Payment-Receipt header (base64url JSON com o ID de desafio, o hash de pagamento como reference, status e
timestampAs solicitações pagas não estão vinculadas a nenhum nim, por isso não aparecem no histórico da consulta.
| Estatuto | Quando |
|---|---|
402 payment_already_used | Cada pagamento paga por uma solicitação.A resposta é um novo desafio para essa solicitação, de modo que um cliente que cache sua última credencial (como lnget Simplesmente o país de novo. |
402 payment_mismatch | A credencial foi emitida para outro ponto final, Content-Type ou corpo, ou paga menos do que este pedido agora custa. Um novo desafio para este pedido vem com ele; se o pagamento foi muito pequeno, o que você pagou retorna como um Reembolso de token (refund_token e refund_sats no seu corpo). |
402 payment_expired | Mais de 15 minutos se passaram desde o desafio. Um novo desafio vem com ele. Se a pré-imagem mostra que você pagou, o que você pagou retorna como um Reembolso de token (refund_token e refund_sats no corpo), uma vez; a credencial é então usada. |
401 invalid_preimage | A pré-imagem não hash para o hash de pagamento da fatura. |
401 invalid_payment_credential | A credencial está mal formada, foi alterada depois que o Nymbot a emitiu, ou nomea um hash de pagamento que o Nymbot nunca emitiu uma fatura. |
429 rate_limit_exceeded | Mais de 30 credenciais ou chaves que falharam em verificar vieram deste endereço em um minuto, ou um token de reembolso foi enviado mais de 60 vezes em um minuto. 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"));
Clientes construídos em mppx com um método de relâmpago lidar com o desafio de pagamento eles mesmos; apontá-los para o ponto final e deixá-los pagar.
Vídeo
e pagos POST /videos respostas 202 como uma chave, mais a
status_url: GET Ele é assinado e funciona por 24 horas, desde que o trabalho seja mantido.
{
"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..."
}
}
Mantenha o refund_token a partir desta resposta: é mostrado apenas aqui. É vazio enquanto o vídeo renderiza (GET /api/v1/l402/refunds respostas "status": "pending"); se o render falhar sem faturamento, o pagamento aterrissará nele.
refund_sats Para um trabalho reembolsado, mas nunca o token, então compartilhar o URL de status não compartilha o reembolso.
Reembolso
Se um pedido pago falhar e o provedor cobrar Nymbot pela tentativa, o pagamento é mantido e o erro diz que é, com charged_sats, exatamente como para um pedido chaveado. Se ele falhar sem ser cobrado, o erro carrega uma Reembolso de token Vale o que você pagou:
{
"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"
}
}
As peças não usadas retornam da mesma forma: se você pediu duas fotos e uma falhou sem cobrar, a resposta de sucesso nymbot O objeto carrega um token de reembolso para o que falta; uma transcrição cujo comprimento não pudesse ser lido antes é preenchido pelo mais longo que o arquivo poderia ser (nunca mais do que 30 minutos), e a diferença para o comprimento real vem de volta como um token de reembolso; se for mais longo do que 30 minutos, é recusado com 413
Os embeddings retornam o que a estimativa manteve de volta. Um vídeo falhado devolve o token de sua submissão devolvido.
Um token de reembolso é um código aleatório de 256 bits. Nymbot armazena apenas seu hash, e expira após 30 dias.
- Pague com isso. Enviar
Authorization: Bearer REFUND-…Em qualquer um dos pontos finais acima (um SDK OpenAI leva-o como sua chave API).O preço vem do token e o que fica fica nele (refund_token_satsEm OnymbotUm token vale menos do que as respostas da solicitação402refund_insufficientUma falha não contabilizada coloca a taxa de volta no mesmo token. - Verifique isso .
GET /api/v1/l402/refundscom o mesmo header retorna{"sats": 237, "status": "open", "expires_at": "..."}. - Um token pode ser usado no máximo 60 vezes por minuto.
- Mova-o para um nym. Coloque-o em Faça um presente no aplicativo Nymbot, ou ligue
POST /api/v1/l402/refunds/redeemcom a Solicitação assinada e{"refund_token": "REFUND-...", "balance": "standard"}(ou"pro"Os créditos inteiros vão para o saldo (10 centavos cada no padrão, 100 no Pro); centavos que não fazem um crédito inteiro ficar no token para solicitações de 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"
Resposta
{ "data": { "credited": 23, "tier": "standard", "balance_credits": 123, "remaining_sats": 7 } }