Huruw kɔ emu nsɛm no so
San kɔ Nymbot

Nimdeɛ a wɔde gyina so Akanfoɔ a wɔyɛ adwuma a wɔyɛ nneɛma foforɔ

Akonta, m’adɔeɛ ne nneɛma a ɛhia sɛ wɔde ma wo

Hwɛ nea wopɛ, ma owia wɔ Lightning so, ma owia de wo wallet no nso de firi wo nua so, hwɛ sɛnea ɛtɔ sɛ asusuakɔtwe biara, na kã kɔ kwan foforɔ a ɛfiri code mu nso.

Akontaabu mu sika hwɛ

Mo obu mmoa nyinaa, ne sɛnea wɔadi saa kɛseɛ yi anom adidi.

GET https://nymbot.ai/api/v1/credits/balance — hia API key bi. POST ɛyɛ nso, asɛmfɛfoɔ a wɔhwɛ aseɛ no nti.

balance nkyɛn mmienu no nyinaa wura dollars mu wɔ Bitcoin nsuani a ɛwɔ nnɛ yi, ɛde ma ntuo a wɔhwɛ adidi baako (null sɛ ɔtɔ bere no wɔn ntumi nkyerɛwee a. Ne a ɛka no ne credits ne sats, ne ara ne sɛnea wɔ hwɛ akontaabu no so kwan so. key ɛkyerɛw kwan no a ɔbɛtumi afire no. Akwan a ɛahyɛ ne kwan mu no, ɛtumi ahu ne nkyerɛkyerɛmu no bio.

Aboa mu nkyerɛaseɛ

{
  "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"
  }
}
ƐdaeɛƐberɛ bɛn?
401Akwanhyia no awɔ, yɛnni aseɛ nka, wɔasɛe, anaa ɛakɔ ne ntentan.

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

Akɔdeɛ kwan ahorow

Sɛnea wubetumi de sika ahyɛ mu, ne mpanim bi a ɛwɔ so. Lightning ne kwan a ɛtɔ so onipa.

GET https://nymbot.ai/api/v1/topup/payment-methods — kwan biara nni hɔ a ɛhia.

Sika mmoa yɛ 10 kɔsi 1,000,000 sats; Pro mmoa no ɛsɛ sɛ ɛtɔ Pro credit baako anadwo, enti ɛhyɛ aseɛ fi 100 sats. Dollar limit no nteteeɛ no di Bitcoin nkyenkyereɛ akyi. bulk_bonus ɛkyerɛ mpaebɔ deɛ ɛkɔ so wɔ nkyɛdeɛ kɛseɛ no so, sɛnea ɛwɔ app no mu no: 10%, 15% anaa 20% kɔsoro wɔ standard top-ups a ɛfiri 500, 1,000 anaa 5,000 sats no so, na wɔ Pro top-ups no so nso ɛfiri 5,000, 10,000 anaa 50,000 sats no so.

Aboa mu nkyerɛaseɛ

{
  "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 soɔ mpoɔsoɔ

Hye Lightning invoice bi a ɛbɛ de credit hyɛ nym a key no kɔ no mu. Fa any Lightning wallet bi mu bɔ no, na ɛnna hwɛ no sika a ɛwɔ credit no de kɔ sɛ sɛnea ɛbɛyɛ a wɔbɛfa no bɛde to wo mu.

POST https://nymbot.ai/api/v1/topup/create/btc-lightning — hia API key bi.

Akwantuo kwanTwerɛƐsɛ sɛ wɔde di dwumaNkyerɛkyerɛmu
amountnɔbaAaneƐtena sɛn, wɔ currency. Nkontaa kɛse bi ma sats.
currencyntɛntɛnDaabiSATS (nea ɛda hɔ no), USD annaa BTCDɔlaa no wɔde si Bitcoin nnyigyeɛ a ɛwɔ nnɛ yi mu.
tierntɛntɛnDaabipro (deɛ ɛda hɔ no) anase standardƐdeɛn akontaabu mu na kredi no bɛkɔ.

Adeɛ a ɛkyerɛ adan adan nneɛma ne 10 sats na Pro credit no ne 100 sats, ne nneɛma a ɛsɛ sɛ wɔde nnyɛ pii no nso; credits Ɛkyerɛ nea saa akontabuo yi bɛhyɛ mu.

Aboa mu nkyerɛaseɛ

{
  "invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
  "payment_request": "lnbc100u1p5...",
  "amount_sats": 10000,
  "credits": 115,
  "tier": "pro",
  "expires_at": "2026-09-30T09:27:00Z",
  "status": "pending"
}
ƐdaeɛƐberɛ bɛn?
400Akwan foforɔ bi wɔ kwan no mu (unsupported_method), ɔsika a wɔnnyɛ mmɔden kwan bi (unsupported_currency) anaa tier, adeɛ a ɛhia nka, anaa adeɛ a ɛdi minimum no ase (amount_too_small), mmia sata (sats) a ɛdɔɔ so 1,000,000 (amount_too_large) anaa Lightning wallet no ahyɛɛ mu (amount_out_of_range).
429Invoicesee mmienu sɛ mmienu mmaradidi (60) a ɛsen saa nym yi so, anaa nkyerɛkyerɛmu mmienu (120) firi saa kɔmputa adresi yi firi anopa wɔ ahoɔden kronkron (anɔpa) mu (rate_limit_exceeded, ne Retry-After).
502Ɛnyɛ possible sɛ yɛyɛ invoice biara mfitiaseɛ yi (invoice_unavailable, ne 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);

Mefiri ahosɛefoɔ mu adidi bi ho asɛm

Ɛbɛsu sɛ ekyirde no awɔ sɛ wɔapayɛ no anaa, na sɛ wɔapayɛ no a, ɔbɛhyɛ akredit no mu. Sɛ wɔhwɛ a, ɛno na ɛde akredit no ma, enti a wɔapayɛ no a, hwɛ kɔsi sɛ ne bɔne no bɛyɛ dɛɛdeɛ credited. Sɛ wopɛ sɛ wopɛ mmerɛ bi a, wopɛ nanso ɛnyɛ hu: akontaabu no mu sika no ba ne sɛnea wopɛ kɔkɔɔ biara.

GET https://nymbot.ai/api/v1/topup/status/{invoice_id} — ɛsɛ sɛ ɔnya kɛseɛ firi nym a ɔyɛɛ invoice no no.

status ɛyɛ pending (yɛannua da), paid (Ahyɛ no, nanso ɛnnɔ so ase mma no da; hwɛ bio,) credited (wo akonta mu) anaa expired (ɛnnidi wɔ bere mu). Balance beaeɛ no yɛ ma kɔti a invoice no kɔ so ma no no.

Aboa mu nkyerɛaseɛ

{
  "invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
  "status": "credited",
  "amount_sats": 10000,
  "credits": 115,
  "tier": "pro",
  "expires_at": null,
  "balance_credits": 523.33,
  "balance_sats": 52333
}
ƐdaeɛƐberɛ bɛn?
400Id no nyɛ ɔdaeɛ no 64-character id a ɛfiri create call no mu.
404Ɛnyɛ wo din (nym) nti na wo ID no mu nnyɛ invoice bi Ɛ🏾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);

Nsɛmuesɛtɔ nkyerɛkyerɛmu

Kɔmɔ biako kɔmɔ biako: nea ɛyɛɛ no, mɔde bɛn, nkyerɛwee (tokens) bɛn, ne nea ɛtee nkwantuoɔ. Nkyerɛkyerɛmu anaa nkyerɛaseɛ biara ntetee, enti obiara nnye bi. Kɔmɔ no wɔ hɔ wɔ nnɔkra aduasa (90 days) mu, nea ɛdi kan ne nea ɛdi akyi. Akwan a ɛahyɛ ne nneyɛe mu mu no, ɛtumi ahu ne nkyerɛkyerɛmu no.

GET https://nymbot.ai/api/v1/queries/history — API key kwan bi na ɛhia, a ɛhwɛ ne nea ɛhwɛ ne ho mpaebɔ no, anaa a asɛm a wɔahyɛ nkyerɛwee wɔ mu efiri wo din no mu, a ɛhwɛ ɔpon kwan biara.

Akwantuo kwanTwerɛƐsɛ sɛ wɔde di dwumaNkyerɛkyerɛmu
pageinteger (asɛmbiɛ)DaabiƐnyinsɛm 1, ɛnyɛ kɔ a ɛrebɛkɔ sɛ mfonini 1,000; ɛkyɛn saa nkyekyɛmu yi nso ne 400 invalid_value.
page_countinteger (asɛmbiɛ)DaabiNkyekyɛmu a ɛwɔ afeɛ bi wɔ asɛmhyɛ mu. Ne nkyekyɛmu ne 20, ɛtɔ mmata 100.
start_date
end_date
string (asɛm asɛ:")DaabiISO 8601 da an anɔpa.
modelstring (asɛm asɛ:")DaabiƐde saa model yi nkoaa.
typestring (asɛm asɛ:")Daabichat, responses, messages, image, video, speech, transcription annaa embedding.
all_keysboolean (asɛm bi a ɛwɔ mfeɛ mu)DaabiNe adeɛ a ɛtwa ɔpo: true ɛkyerɛ nnyinasoɔ biara a ɛwɔ nkyerɛkyerɛmu a ɛdi kan no mu. Default false.
key_idstring (asɛm asɛ:")DaabiNe nkyerɛkyerɛmu a wɔate aseɛ no, anaa ne... all_keys=trueKɛsi yi nkoaa.

Aboa mu nkyerɛaseɛ

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

Akonta nkyerɛkyerɛmu a wɔrehyɛ aseɛ

Ɛyɛ key anom, asɛm sesa, ne kɔm nkyerɛkyerɛmu ne deɛ ɛyɛ deɛ ɛyɛ deɛ ɛka kɔm nkyerɛkyerɛmu no nyinaa, ɛhia API key biara. Wɔhia w'anym (nym) nkyerɛkyerɛmu (signature), enti sɛ key bi bue a, ɛtumi di dwumadie a ɛda ne nkyerɛkyerɛmu so no, nanso ɛntumi mma no kwan sɛ ɛbɛyɛ kɔm key foforɔ anaa ɛbɛma ne nkyerɛkyerɛmu kɔ so.

App yi yɛ eyi ama wo: biribiara wɔ ne mu API sheet di dwumadie bɔn yi dwuma. Wo nkoaa hia saa kɔmputa da yi sɛnea wubɛtumi adi wo code mu nkyɛdeɛ akyerɛ.

Nnyigye yi yɛ Nostr event a ɛyɛ kind 27235 (NIP-98), a wɔasɛe no wɔ base64-encoded mu wɔ Authorization ti mu nkyerɛkyerɛmu a ɔwɔ asɛmfua no Nostr anim:

Asɛm no

{
  "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 ɛyɛ request no URL kɔmɔ no nyinaa, asɛm a wɔde hyɛɛ mu nso, ɛyɛ ne sɛnea wɔde hyɛɛ no kɔmɔ no exactly.
  • method ɛno ne HTTP kwan no.
  • payload ɛno ne raw request body no SHA-256, wɔ hex mu. Yɛhia no wɔ POST ne PATCH, na nea wofiri no mu ne wo nnam no ɛsɛ sɛ ɛyɛ nea ɛyɛɛ no nea woyɛɛ ne kɔm (hash) no mma biara nnyɛ foforɔ.
  • created_at Ɛsɛ sɛ ɛbɛyɛ mmiɛnsa nante (60 seconds) a ɛbɛkɔ mpo sɛ server no nante.
  • Adeɛ biara yɛ adwuma birĩ, a GET wɔde hyɛ mu, enti header a wɔafa no nnyɛ a obi bɛtumi de agye ne ho a. Sian mu nsɛm foforɔ ma request biara. Fa bi addow nonce fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea ɛnyɛ nea ɛwɔ hɔ no nkyɛnfa de fa nkyɛnkyɛn nea
  • A nkyerɛwee a wɔasɛn no mu bɛtumi ayɛ 64 KB kɛseɛ bi, na nkyerɛwee no hia... Content-Type: application/json.

Asɛm a ɛkɔɔ bi de ba 401 missing_nostr_auth; nea ɛyɛ mpaa, nea ɛnyɛ nokware, nea ɛda hɔ dodoɔ, anaa nea ɛyɛ URL, method anaa body foforɔ bi nti de ama invalid_nostr_auth, ne nkyerɛkyerɛmu no wɔ mpaboa no mu; nea wɔ de hyɛɛ no bio no ba bio nostr_auth_replayedAPI key a wɔatuma hyɛ saa endpoints yi mu no, wɔanya no. Wɔhwɛ signature no ansa na wɔanante body no ase, na ala adresi biara bɛtumi ayɛ nneɛma a ɛyɛ mpan (fail) 30 wɔ minit mu (IPv6 ala adresi biara kɔ mpaako /64 mu); ɛda saa a, ɛgye 429 ne ho Retry-After.

Abawafoɔ (Browsers) bɛtumi afa saa endpoints yi dwumadie fi Nymbot nkyerɛwee sɛnea ɛteɛ no nko ara (https://nymbot.ai, https://nymchat.app (ne wɔn subdomains nso). Wɔ afe biara a ɛwɔ afa bi foforɔ so no, CORS headers biara nni hɔ a ɛbɛba, enti ɛntumi mmu nea wɔde ba no. Scripts ne native apps, a wɔntumi ntu Origin, ɛnyɛ wɔn ho asɛm.

Wo anomye kwan

Akyerɛkyerɛmu no nnya wo nym ne kɔm kɔm mfonini (ɛno) nsec), a ɛhyɛ biara a ɛwɔ mu: wo din, wo amammere ne wo sika a ɛwɔ wo nsa mu. Fa nkɔmmɔbɔ (script) a wopɛ wɔ kɔmputa a wopɛ ne ho akyerɛ, fa fie (environment) fi kɔmputa no mu na ɛnyɛ sɛ wode to no file mu, na fa app no dwene kɛseɛ bere biara a wubetumi adi.

Ssɛnfoɔ yi si header no ano. Adeɛ a ɛreba mfatoho biara wɔ saa asɛm yi ase no de wɔn adi. Wɔhia secret key a ɛyɛ hex no firi NOSTR_SECRET_HEX; cURL no deɛ uży Ɛ nka komputɛ bɔteneɛ kwan, a ɛfa nsec anaa hex key, na ne... sha256sum (Wɔ macOS so, 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");
}

Akonta mmuaeɛ no

API sheet no mpanim no wɔ app no mu: wo public key, akɔm mmienu no nyinaa, nka sɛ key bɛn na ɛwɔ anim (a wɔankasɛe anaa bi nnwu), ne... deɛ ɛyɛ nokwafoɔ mmerɛ a wɔde mpanin bɔ ho anaa mpanin nnyimpa nkyerɛkyerɛmu ayɛbea no, anaa null sɛ server no annye wɔn.

GET https://nymbot.ai/api/v1/account — hia mmerɛ bi asɛm a wɔahyɛ nkyerɛwee wɔ mu.

Aboa mu nkyerɛaseɛ

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

Kɔti hwɛ ne ho

App key list no a ɛhyɛ app no anim no endpoints nyinaa. Wɔtwe nyinaa hia ne a Mpaebɔ a wɔatow nkyerɛwee bi wɔn so. Key biara hyɛ saa fã yi mu, ne bere a ɛwɔ ISO 8601 mu ne nkaano a ɛwɔ sats mu:

Akwanya adeɛ

{
  "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 Ɛyɛ enough sɛ wuhunu kɔfɛ bi, nanso wode nnyɛ adwuma. Kɔfɛ no ara wɔde hyɛ wo ma mmerɛ koro, sɛ wɔayɛ no.

Kɛseɛ a ɛwɔ kɛseɛ mu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no nkyerɛkyerɛmu no

GET https://nymbot.ai/api/v1/keys — bɔɔ dwumadie.

Akwantuo kwanTwerɛƐsɛ sɛ wɔde di dwumaNkyerɛkyerɛmu
include_revokedboolean (asɛm bi a ɛwɔ mfeɛ mu)DaabiFa kɔm bɔ mmiɛnsa nkyɛn a wɔahyɛ wɔn mu. Default false.

Aboa mu nkyerɛaseɛ

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

Kɔm fura mpanimmu kɛseɛ bi wɔtwa

POST https://nymbot.ai/api/v1/keys — bɔɔ nkyerɛwee. Nnuaeɛ 201.

Akwantuo kwanTwerɛƐsɛ sɛ wɔde di dwumaNkyerɛkyerɛmu
namentɛntɛnAaneNkyerɛkyerɛmu 1 kɔsi 40, ɛnyɛ wo deɛ ɛwɔ wo akwan foforɔ mu (sɛ ɛnyɛ nkyerɛkyerɛmu a ɛwɔ hɔ no) (sɛ ɛnyɛ nkyerɛkyerɛmu a ɛyɛ kɛse anaa ketewa no).
limit_satsnamba a ɛnyɛ nanteɛ nambaDaabiSika a wotumi de twaa no wɔ sats mu, ɛkam sɛ ɛnyɛ baako. Ma ɛnyɛ hwee sɛ ɛnyɛ ɛnyɛ kwan a ɛnyɛ hwee.
reset_periodntɛntɛnDaabidaily, weekly annaa monthly.ɔheneɛ nneɛma limit_satsƐyɛ mmerɛ sɛ ɛbɛtena hɔ ma kɛsetɛ a ɛnyɛ mmerɛ biara.
expire_atstring anaa integerDaabiBerɛ a kɔte no bɛyɛ adwuma ase anka: ISO 8601 bere, anaa millisecond a ɛrekɔ so fi afe 1970 no mu.

Aboafo (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"
  }
}
ƐdaeɛƐberɛ bɛn?
400Din a ɛhia anaa din a ɛyɛ tenten; din a wadi dwumadie ansa na ɛreba (duplicate_name); akannifoɔ a ɛnyɛ namba a ɛnyɛ nkyɛn a ɛnyɛ koraa sɛ baako; asɛm a wɔbɛsɛe no a ɛnyɛ akannifoɔ; awieɛ a ɛdi kan no; asɛm a yɛnni nimdeɛ (unknown_parameter); anaa kwan mmienu a ɛwɔ hɔ a ɛyɛ anadwo (too_many_keys).
429Nkyɛn mmiensa (60) kɛseɛn a saa din yi yɛɛ no, anaa nkyɛn mmienu (120) fi saa kɔmputa dwumadie yi mu, wɔ nnɔnhwere bi mu (rate_limit_exceeded, ne 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);

Akɔnten baako anom nkyerɛkyerɛmu bi a ɛkyerɛ kwan

GET https://nymbot.ai/api/v1/keys/{id} — bɔɔ dwumadie.

Nnuaba a ɛsan no {"data": {…}} ɔde kɔteɛ no, anaa 404 key_not_found Sɛ wo kɛyi biara nni saa ID no a.

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

Sɛnea wɔsesa nkyɛn bi

PATCH https://nymbot.ai/api/v1/keys/{id} — bɔɔ dwumadie.

Fa biako wɔ biako mu akyiri name, limit_sats, reset_period ne expire_at, ne kwan a wode yɛ adeɛ bi kɛseɛ no so kwan no so. null εpɛ kwan bi field: ɛnyɛ kɛseɛ, ɛnyɛ reset, ɛnyɛ ɛda adi. Sɛ wode reset berɛ no si kɔ asofoɔ bi a, ɛhyɛ berɛ foforɔ ase fi zero. Sɛ wate key bi ase a, woyɛ no asɛm biara (400 key_revoked). Sɛ nea ɛba no {"data": {…}} ɔde nkyerɛkyerɛmu foforɔ no.

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

Akae kooko bi tewi

DELETE https://nymbot.ai/api/v1/keys/{id} — bɔɔ dwumadie.

Kyerɛ kwan no ntɛm, ɛketewa. Ɛtena list no mu ne revoked_at hyɛ, na wɔn nso bɛhu wɔ include_revoked=trueSɛ wotu key a watoom aseɛ no a, n'asɛm no yɛ saa ara. Key ansi a ɛnkɔ so kɛseɛ no nko na wɔhwɛ; nketewa a ɛda ansa no wɔtu wɔn sɛ wotu key foforo bi.

Aboa mu nkyerɛaseɛ

{ "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 nnyinasoɔ mu nnyinasoɔɔ

Hyɛ Lightning wallet bi ne Nostr Wallet Connect ano kókóɛ, na Nymbot bɛkyerɛ mu adeɛ ne ne ho mpaebɔ dɔm wɔ sɛ API dwumadi no bɛyɛ mmerɛ bi a. App no API sheet no wɔ saa nneyɛeɛ yi ara; ɛne endpoints a ɛwɔ ne ase no. Wɔ nyinaa hyɛ aseɛ... asɛm a wɔahyɛ nkyerɛwee wɔ mu.

Sɛnea ɛyɛ: ɛda API kɔkɔɔ a wɔde de to woahyɛɛ sika mu nkyɛmu so a, sɛ nea ɛwɔ saa sika mu no ayɛ kɛseɛ sene wo mpaebo no a, Nymbot yɛ invoice ma woahyɛɛ sika no, kɔpɛ wo wallet sɛ ɛbɛtɔ so, na ɛde credit no hyɛ mu. Ɛhyɛ sika mu mmerɛ biara mma da biara mu mmiɛnsa anadwo mmienu (5 minutes) mma nym biara ne sika mu nkyɛmu biara, enti sɛ kɔkɔɔ pii ba a, ɛbɛtumi ammu wo wallet mu nyinaa. Sika a wode di dwuma wɔ app mu no nnyɛ saa. Berɛ ne sɛnea ɛyɛɛ mmerɛ a wode sika hyɛɛ mu bio no, ne nkyɛmu a ɛhyɛɛ aseɛ no, ne error a ɛhyɛɛ aseɛ no, ɛwɔ settings mu; sɛ sika tɔɔ mu a ɛda error bi a so no, hwɛ ne invoice no wɔ Sika a wɔatow mu asɛm Ɛkyerɛ ɛno ho.

Ansa woahyia wallet bi

Connection string bi ma obi a ɔwura bi wɔ no tumi ka wo wallet sɛ ɛbɛtodɔ adeɛ. Nymbot gye no de hyɛ mmoa mu na ɛkɔm hyɛ mu, na ɛde kɛkɛ na ɛtodɔ ne nkwagye mfonini no, nanso ma connection bi kɛkɛ ma saa adeɛ yi, na ɛwɔ wo wallet mu mfonini a ɛbɛtumi akyɛ, na sɛ ɛbɛtodɔ adeɛ a ɛbɛtumi akyɛ no ne nea woahyɛɛ no kɛkɛ. Wallet no nnye saa adeɛ yi so. pay_invoice.

Sɛnea wɔhyɛ wallet bi nsa so

POST https://nymbot.ai/api/v1/nwc-auto-topup/connect — bɔɔ dwumadie.

Akwantuo kwanTwerɛƐsɛ sɛ wɔde di dwumaNkyerɛkyerɛmu
nwc_urlntɛntɛnAaneConnection string no, rehyɛ aseɛ nostr+walletconnect://. Nymbot ɛbɛhia wallet no nneɛma sɛ get_info ase sɛ ɔde to mu ansa na ɔde kura no ɛsɛ sɛ ɛyɛ adidi a wɔahyɛ mu.
threshold_satsnamba a ɛnyɛ nanteɛ nambaAaneMa mmoa bere a ne mmoa no bɛnyɛ saa sats yi akyi no. Kom sɛ sats 1,000.
topup_satsnamba a ɛnyɛ nanteɛ nambaAaneƐde sɛn na ɛsɛ sɛ yɛde hyɛ biara. 1,000 kɔsi 1,000,000 sats.
tierntɛntɛnDaabipro (deɛ ɛda hɔ no) anase standard: akonta a ɛsɛ sɛ whwɛ na wode to so.

Aboa mu nkyerɛaseɛ

{
  "data": {
    "connected": true,
    "threshold_sats": 5000,
    "topup_sats": 20000,
    "tier": "pro",
    "last_topup_at": null,
    "last_topup_sats": null,
    "last_error": null
  }
}
ƐdaeɛƐberɛ bɛn?
400Ɛnyɛ connection string (invalid_nwc_url); wallet noaanya nni mmuae wɔ ne relay so (nwc_unreachable) anaa asɛe check no (nwc_rejected); kɔnɛktɛn no ntumi nkyɛ invoice no (nwc_missing_permission); anom kyɛn kwan no anaa sika a ɛdi kan no a ɛdi kɛseɛ anaa ɛyɛ kɛseɛ.
501Woatɔ nneɛma de ɛhyɛ mfomsoɔ (automatic top-ups) mu wɔ saa server yi so (nwc_unavailable). Saa ara na ɛfa ɛbia mmienu a ɛdi so no ho.

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

Mefiri nkyerɛkyerɛmu no ase reading

GET https://nymbot.ai/api/v1/nwc-auto-topup — bɔɔ dwumadie.

Ɛde adeɛ a ɛfiri connecting no ara na ɛde kɔ, ne sɛ, connected: false na afɔre a ɛbɔ mfeɛ no nso null sɛ wallet biara nni hɔ a akyerɛkyerɛ mu nnuane biara ntena hɔ. Ɛnyɛ connection string no ara na wɔde ma.

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

Aka nkyɛn wɔn

DELETE https://nymbot.ai/api/v1/nwc-auto-topup/connection — bɔɔ dwumadie.

Ɛsesa connection string a wɔasie no. Wɔnnye mmoa (top-ups) biara bio. Sɛ wopɛ sɛ wopue nea ɛda hɔ no a, wubetumi asɛe connection no wɔ wo wallet mu.

Aboa mu nkyerɛaseɛ

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

Wosika sika koro koro anaa? Wanhwɛ key biara a.

Wobɛtumi afa nnyigyeɛ a ɔde nnuaeɛ biara nnuaeɛ a ɛnyɛ mmerɛ no so afa Lightning so, wɔ nkyɛdeɛ biara a ɛnni hɔ, akɔmɔ biara nni hɔ na sika biara nni hɔ: POST /images/generations, POST /images/edits, POST /videos, POST /audio/speech, POST /audio/transcriptions, POST /audio/translations ne POST /embeddings. Chat, nsɛm a wɔde bue mu ne Messages nyinaa hyɛ kɔm (key) nti. Sɛ asɛm bi kɔ so ne kɔm (key) a ɛtena mu a, wɔfa ne nsie (balance) no so bɔ sɛnea ɛyɛ kwan no; adeɛ no bɔ sɛnea ɛteɛ no hyɛ aseɛ nko ara sɛ kɔm (key) biara nni hɔ a.

Nymbot ka nkyerɛwee mmienu a ɛyɛ adeɛ baako no, fi backend baako: Lightning Labs' L402 (na wɔataa no wɔ ne din foforɔ no ase, LSAT) ne IETF draft no Nnyidie HTTP authentication scheme ne saa no lightning ɔnea ne charge ɔtee. Fa nea wo klientte ase no fa.

W'akora server bi ho dwuma

Sika bɔn a wode mframa biara nni mu no, ɛyɛ kwan a ɛwɔ no nko ara sɛ API_L402_SECRET ɛwɔ kɔmɔ kɔmɔ nketewa mmiɛnsa ananomi (32) a ɛnyɛ nea ɛwɔ hɔ biara, sɛ hex (akoraa nkyerɛwee 64) anaa base64 (44). Yɛde bi bɛyɛ openssl rand -hex 32. A nketewa anaa nea wɔbɛtumi ahyia value bi ma ɛde saa ade no si komm na ɛkyerɛw kwan a ɛde maa ɛyɛɛ saa. Sɛ wopɛ sɛ wosenya foforɔ a, fa nea ɛwɔ hɔ no kɔ API_L402_SECRET_PREVIOUS Daako: credentials, status URL ne nnɔbae a wɔayɛ wɔ hɔ ase bɛtena so kɔsi sɛ ɛbɛpa.

Ɔhwɛsɛ no

Ma asɛm no a ɛnni Authorization header. Sɛ ɛyɛ nokware a, biribiara nnye ase, na wobɛnya 402 Payment Required ɛfiri invoice bi a ɛkyerɛ sɛnea saa asɛmpeɛ no tɔ: adeyɛ no ara a key bɛtɔ, a wɔahyɛ no sɛ 10 sats wɔ standard credit biara anaa 100 sats wɔ Pro credit biara na wɔayɛ no kɔ so kɔ sɛ sat kɔtɔ (atɛn sɛnea ɛbɛyɛ a ɛbɛyɛ sat 1, na ɛnyɛ kɔsi 0.05 credit minimum no so). Mmuaeɛ no kura nneɛma mmiɛnsa WWW-Authenticate Nsɛnnennen ma invoice no ara:

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

Ɔdwom no request parameter no yɛ base64url JSON: {"amount":"237","currency":"sat","methodDetails":{"invoice":"lnbc...","network":"mainnet","paymentHash":"..."}}.

Asɛm bi ahyɛ ne ho so wɔ awieeɛ no, kɔ... Content-Type (ne media type na, sɛ ɛyɛ multipart a, ne boundary) na ne SHA-256 a ɛfa ne body bytes a woyɛde too no ho pɛpɛɛpɛ, na ɛbɛtena miniti du ne mmienu (15) mu. Sɛ watae a, tu... teɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛ sɛre bio: ɛno ara Content-Type na JSON bytes no nso, anaa ɛpono a ɛwɔ multipart mu noho bi (/images/edits, /audio/transcriptions, /audio/translations) multipart body a ɛhia no ne boundary a ɛda so no ara. HTTP library pii de boundary foforo kɔtɔ bere biara a wɔrekyerɛ form, enti kyerɛ no ɛkaa na tumi de saa bytes no nnyɛ dua mmienu.

Abantenten biara bɛtumi akyerɛhwɛ asɛm mmiɛnsa wɔ minit bi mu (IPv6 address biara yɛ ne /64 nyinaa). Akyerɛhwɛ a ne abantenten nte ase nni no, wɔde kɛseɛ kɛseɛ anane mmiɛnsa wɔ minit bi mu, na ɛwom kɛseɛ bi wɔ Nymbot de ma abantenten nyinaa; sɛ wobɛtumi anyɛ asɛm bi ansa na asɛm no afiri mu (te sɛ ne mu ne JSON a ɛnyɛ nokware) a, ɛnyɛ ne de kɔ ade no. Ɛno akyi no, mmuaeɛ no ne 429 ne ho Retry-After, wɔahyɛ no ansa na wɔatumi akenkan nwoma no. Sɛ wɔfrɛ endpoints a wɔantumi nkyerɛ wɔn kwan anaa nea ɛkyerɛ wɔn asɛm no a, ɛregye ne din wɔ nkanhyɛ a ɛwɔ mmerɛ biako mu wɔ adresi biara mu, ɛno yɛ nkan a ɛdidi dwuma mmerɛ 120 wɔ mmerɛ biako mu. Wɔhwɛ nea ɛkyerɛ wɔn asɛm ansa na wɔatumi akenkan nwoma no, na ɛfrɛ nka a Content-Type ɛnyɛ application/json (anɔpa multipart/form-data adeɛ a wɔde hyɛ mu no yɛato no ano ne 415 na ɔntumi nnya invoice biara.

Embeddings boɔ nnuaeɛ firi tokens a ɛwɔ mu mu, ne 1.5× nnuaeɛ mu nti, efisɛ ɛdaeɛ nti na yɛhu nokorɛ no, Wopɛ sɛ wopɛ tokens a wɔadi dwuma no nkoaa, na sika a ɛnyɛ dwuma no nso de ba wo nkyɛn sɛ sika nkyɛm nkwatiba.

Merekɔ adeɛ no so

Fa any Lightning wallet to togye invoice no. Wallet no bɛma wo preimage no, ɛyɛ hex characters 64. Afei fa ɛmɔɔ nea ɛyɛ yi biako dwetie:

NhyehyɛeTi dwumadie
L402Authorization: L402 <macaroon>:<preimage> (LSAT ɛyɛ nso)
NnyidieAuthorization: Payment <base64url JSON>, ɛhɔ a JSON no wɔ {"challenge": {every parameter of the challenge, as sent}, "payload": {"preimage": "<hex>"}}

Asɛm a wɔatɔ sika wɔho bɛyɛ ne te sɛ neaa wɔde kɛsɛe yɛɛ no, mmom... nymbot adeɛ no mu nni muasuo nkyerɛkyerɛmu bi: {"payment": "l402", "tier": "pro", "paid_sats": 237, "charged_sats": 237}, na nni hɔ X-Nymbot-Balance-Sats header. A akyerew a wɔdeedee Akwankyerɛ kwan no so no, ɔnya Payment-Receipt header (base64url JSON ne challenge id no, akɔdeɛ hash no sɛ reference, status ne timestamp). Awtewɔ aduane a wɔtɔ no nnye nnyina anyɛ nnyina biara ho, enti wɔn nnyɛ wɔn wɔ query history mu.

ƐdaeɛƐberɛ bɛn?
402 payment_already_usedƆbɔdeɛ biara hyɛ adeɛ bi a ɛfata asɛm bi a wɔbɛpa. Ɛdeɛ a ɛba no yɛ nnɔbae foforɔ ma saa asɛm yi, enti ɔtamfo a ɔde ne nneɛma a ɔde hyɛɛ aseɛ no kura (te sɛ lnget ɔno nkoaa na ɔbɔ sɛ ɔbɛhyɛ aseɛ bio.
402 payment_mismatchAkwanneɛ deɛ wɔde hyɛɛ deɛ ɛkɔ so bi foforɔ no ho, Content-Type anomɔdeɛ anaa ɔde sika kɔɔ nsuo mu, anaa ɔde sika kɔɔ nsuo mu annye de. Nkwagyeɛ foforɔ bi ba saa asɛm yi ne nti; sɛ sika no yɛɔn kɛseɛ a, nea wode hyɛɛ no de ba ne Ɛ sika nkyɛm nkwatiba (refund_token ne refund_sats wɔ nna mu).
402 payment_expiredMfitiɛ minit du ne mmienu (15) a ɛtwam mfiaseɛ challenge no bi. Ahoti foforɔ bi ba ne ho. Sɛ preimage no kyerɛ sɛ woasee a, nea woasee no sɔ kɔ sɛ a sika nkyɛm nkwatiba (refund_token ne refund_sats wɔ mu no), berɛ a; credential no bɛdi mu.
401 invalid_preimagePreimage no yi nnyɛ invoice no akwankyerɛ (payment hash) no mu hash no. Akwankyerɛ no nti nni mu nsuo a wɔadi dwuma bi.
401 invalid_payment_credentialKyerɛwdeɛ no nkyerɛwee bi wɔ mu, anaa wɔsesa no Nymbot ahyɛɛ aseɛ no akyi, anaa ɛkyerɛ payment hash a Nymbot annye invoice bi adi wɔ ne ho. Macaroon a ɛwɔ caveat a Nymbot nnim, anaa ɛwɔ caveat a ɛyɛ korɔkorɔ, wɔanya no.
429 rate_limit_exceededNneɛma kɛseɛ sɛ aduonu (30) a wɔanyɛ wɔn adwuma yie ɛfiri saa kwan yi mu wɔ minit bi mu, anaa refund token baako wɔatuma no nnɔn wɔ aduonu (60) kɛseɛ sɛ ɛda wɔ minit bi mu. Te... 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"));

Klient a wɔahyia wɔn so mppx fa Lightning kwan so ma wɔn nkyɛn mpaeɛ no; kyerɛ wɔn kwan a ɛkɔ endpoint no so na ɛgye wɔn adeɛ.

Nvideo

Akyɛdeɛ a wɔatua POST /videos nsɛmmisa 202 Sɛ obi a ɔwɔ kɛyi te sɛ no, ne nea ɛreba bi status_url: GET ɛnyɛ biara kwan koro a ɛbɛma woatumi asɔ adwuma no. Wɔahyɛ aseɛ na ɛbɛyɛ nnɔnman hɔ, sɛnea adwuma no bɛtena so bi.

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

Gyina mu refund_token fi saa nkyerɛaseɛ no mu: ɛhɔ nko ara na wɔhunu. Ɛyɛ hɔ aka mpo berɛ a video no reyɛ adwuma (GET /api/v1/l402/refunds nsɛmmisa "status": "pending"); sɛ render no anni nkyɛaseɛ a wɔanɔ aka bi a, ahwɛdom no mu ahwɛfoɔ de adeɛ no hyɛ ne so. Status URL no kyerɛ refund_sats adeɛ a wɔatwɛ nsesaeɛ ma adwuma bi nanso wɔannidi token no, enti sɛ wopɛ status URL no a ɛkyerɛ nsesaeɛ no nni hɔ. Sɛ wowɔ token no nso a ɛboa ma adwuma a ɛhyɛɛ aseɛ a obiara ampaeɛ no kɔ tiawa.

Sika a wɔde de hyɛ wo nsa mfeɛ

Sɛ adeɛ a wɔbɔ wo sika no nyɛ yie na nnyimpa no nso de Nymbot sika no fa n'adwuma no ho a, wɔde sika no tena hɔ na errɔ no nso kyerɛ saa, ne sɛ, charged_sats, sɛnea ɛyɛ sɛ ɛyɛ adeɛ a wɔahyɛ nkyerɛkyerɛmu a ɛwɔ nkyerɛkyerɛmu mu no exactly. Sɛ ɛnyɛ hɔ a wɔatɔ sika no a, mberɛ a ɛyɛ komm no, ɔhaw no wɔ... sika nkyɛm nkwatiba nea wo too sɛn de bɔɔ no nhyira:

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

Nneɛma a wɔadi nnyɛ bi de ba kɔ mmara kɔ mu koro te sɛnea ɛyɛɛ no ansa: sɛ wopɛɛ mfonini mmienu na biara nnyɛ no wɔ nnuae a wɔnnyɛ nkyɛdeɛ, ne nkyerɛkyerɛmu a ɛyɛ adwuma no sɛ nymbot nkitaho no wɔ to mfitiaseɛ mu a ɛpɛ deɛ wɔahyɛ no nkyɛdeɛ nkyɛdeɛ no nti; transcription a wɔntumi nnkasa ne ne nkyɛn mu mfeɛ ansa na wɔahwɛ no no, wɔbɔ no sɛ ne nkyɛn mu mfeɛ a ɛtɔɔdɔɔ no (ɛnyɛ mfeɛ 30 a ɛtɔɔdɔɔ no), na ɛda bi a ɛbɛyɛ dɛɛ mfeɛ 30 a ɛtɔɔdɔɔ no nkyɛdeɛ nkyɛdeɛ no bɛba; sɛ ɛbɛyɛ sɛ ɛtɔɔdɔɔ mfeɛ 30 a ɛtɔɔdɔɔ no a, wɔbɛrefuse no wɔ 413 na ahwɛadeɛ nyinaa san kɔ. Embeddings de nea nkyerɛkyerɛmu no nanteɛ no san ma. Video a ɛanteɛ ma ne token no san kɔ ne nkyerɛkyerɛmu a ɛsan ma no.

Refund token yɛ random 256-bit code bi. Nymbot ne ne hash nko ara na ɔto so, na ɛma n'ani ɛwɔ nnɔnkɔsa 30 akyi. Ɛwɔ sat balance bi, na wopɛ sɛ woyɛ:

  • Fa ɛno to sɛɛ. Tu Authorization: Bearer REFUND-… wɔ ɛpon nokwaara bi a ɛwɔ ɛhɔ no윗 (OpenAI SDK no deɛ no sɛ ne API key). Agyapadeɛ no fi token no mu na nea ɛtena mu no nea ɛtena wɔ hɔ (refund_token_sats wɔ no mu nymbot ɔhunu). Token a ɛho hia yɛ kɛseɛ sene asɛm no mu nnyigyeɛ. 402 refund_insufficient; nnaadaa a wɔannkyɛ aka no, ɛma sats no san kɔ ɛno ara so token no so.
  • Hwɛ no. GET /api/v1/l402/refunds ɛde header no ara hyɛ nsa {"sats": 237, "status": "open", "expires_at": "..."}.
  • Token bi wɔde too no ɛtɔ sɛ mfa anankeso wɔ minit bi mu.
  • Fa kɔ nym bi ho. Hyɛ mu kɔ Fa abowura bi di dwuma wɔ Nymbot app no mu, anaa frɛ POST /api/v1/l402/refunds/redeem ne bi Ɛna asɛm a wɔahyɛ nkyerɛwee wɔ mu ne {"refund_token": "REFUND-...", "balance": "standard"} (anɔpa "pro"). Akonta nyinaa kɔ akonta no mu (sats 10 biara wɔ standard so, 100 wɔ Pro so); sats a ɛnyɛ akonta kɛseɛ ara no tete wɔ token no so ma API requests.

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"

Aboa mu nkyerɛaseɛ

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