Langkau ke kandungan
Kembali ke Nymbot

Pangkalan pengetahuan Pengembang

Keseimbangan, top-ups dan kunci

Semak apa yang anda mempunyai, top up atas Lightning, top up secara automatik daripada dompet anda sendiri, lihat berapa kos setiap permintaan, dan menguruskan kunci daripada kod.

Memeriksa keseimbangan

Kedua-dua keseimbangan anda, dan berapa banyak cap kunci ini digunakan.

GET https://nymbot.ai/api/v1/credits/balance Anda memerlukan kunci api. POST Ia juga berfungsi untuk pelanggan yang mengharapkannya.

balance ialah dua keseimbangan bersama dalam dolar pada harga Bitcoin semasa, untuk alat yang mengharapkan nombor tunggal (null jika harga tidak boleh dibaca). sisanya dalam kredit dan sats, yang merupakan cara keseimbangan sebenarnya disimpan. key Kunci yang telah mencapai capnya masih boleh memeriksa baki.

Jawapan

{
  "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"
  }
}
Statusbila
401Kunci hilang, tidak diketahui, dibatalkan atau tamat tempoh.

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

Kaedah Pembayaran

Bagaimana anda boleh top up, dan had. Lightning adalah satu-satunya kaedah.

GET https://nymbot.ai/api/v1/topup/payment-methods Tiada kunci yang diperlukan.

Top-up ialah 10 hingga 1,000,000 sats; top-up Pro mesti membeli sekurang-kurangnya satu kredit Pro, jadi ia bermula pada 100 sats. bulk_bonus senarai kredit tambahan pada top-up yang lebih besar, sama seperti dalam app: 10%, 15% atau 20% lebih pada top-up standard dari 500, 1,000 atau 5,000 sats, dan pada top-up Pro daripada 5,000, 10,000 atau 50,000 sats.

Jawapan

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

Tumping di atas Lightning

Mencipta invois Lightning yang menambah kredit kepada nym yang kunci itu milik. membayarnya dari mana-mana dompet Lightning, kemudian Periksa ia untuk mendapatkan kredit tambahan.

POST https://nymbot.ai/api/v1/topup/create/btc-lightning Anda memerlukan kunci api.

LapanganJenisdiperlukanPenerangan
amountNomboryaBerapa banyak, dalam currencySatu nombor penuh untuk tarikh.
currencyString yangTidakSATS (Dalam hal yang demikian, USD atau BTCDolar ditukar pada harga Bitcoin semasa.
tierString yangTidakpro (Perkara yang telah ditetapkan) atau standard: mana keseimbangan kredit akan pergi.

Kredit standard ialah 10 sats dan kredit Pro 100 sats, ditambah bonus bulk apa-apa; credits menyatakan apa yang akan ditambahkan dalam akaun ini.

Jawapan

{
  "invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
  "payment_request": "lnbc100u1p5...",
  "amount_sats": 10000,
  "credits": 115,
  "tier": "pro",
  "expires_at": "2026-09-30T09:27:00Z",
  "status": "pending"
}
Statusbila
400Kaedah-kaedah lain dalam jalan (unsupported_method, sebuah mata wang yang tidak diketahui (unsupported_currency(b) jumlah yang kurang atau jumlah yang lebih rendah daripada jumlah minimum)amount_too_small(dalam jumlah yang lebih daripada 100,000 orang)amount_too_large) atau ditolak oleh dompet Lightning (amount_out_of_range).
429Lebih daripada 60 faktur untuk nym ini, atau 120 dari alamat ini, dalam satu jam (rate_limit_exceeded, dengan Retry-After).
502Tiada akaun boleh dibuat pada masa ini (invoice_unavailable, dengan 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);

Melakukan pemeriksaan top-up

Menanyakan sama ada invois telah dibayar dan, sebaik sahaja ia telah, menambah kredit. pemeriksaan adalah apa kreditnya, jadi selepas membayar, semak sehingga status creditedSemak semula selepas itu selamat: kredit mendarat sekali, tidak kira berapa kali anda meminta.

GET https://nymbot.ai/api/v1/topup/status/{invoice_id} - memerlukan kunci daripada nym yang membuat invoice.

status ialah pending (Tidak dibayar sehingga kini) paid (Dibayar tetapi belum dikreditkan; semak semula), credited (dalam pertukaran anda) atau expired (tidak dibayar pada masanya). medan keseimbangan adalah untuk peringkat yang invoice top up.

Jawapan

{
  "invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
  "status": "credited",
  "amount_sats": 10000,
  "credits": 115,
  "tier": "pro",
  "expires_at": null,
  "balance_credits": 523.33,
  "balance_sats": 52333
}
Statusbila
400ID bukan 64-karakter id daripada panggilan cipta.
404Tiada akaun oleh id itu untuk nym anda (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);

mahu sejarah

Satu baris setiap permintaan: apa itu, model mana, berapa banyak token dan apa kosnya. Tiada prompts atau jawapan disimpan, jadi tiada yang dikembalikan. Barisan disimpan selama 90 hari, terkini pertama. Kunci yang telah mencapai capnya masih boleh membaca sejarahnya.

GET https://nymbot.ai/api/v1/queries/history memerlukan kunci API, yang melihat permintaan sendiri, atau Permintaan ditandatangani daripada nym anda, yang melihat setiap kunci.

LapanganJenisdiperlukanPenerangan
pagePenyelesaian (query)TidakDefault 1, sehingga 1,000; halaman yang lebih tinggi ialah 400 invalid_value.
page_countPenyelesaian (query)TidakBaris per halaman. Default 20, pada maksimum 100.
start_date
end_date
Penyelesaian (Query)TidakISO 8601 tarikh atau masa.
modelPenyelesaian (Query)TidakHanya model ini sahaja.
typePenyelesaian (Query)Tidakchat, responses, messages, image, video, speech, transcription atau embedding.
all_keysMelayu kepada Melayu (query)TidakDengan satu kunci: true mengandungi setiap kunci yang sama.Default false.
key_idPenyelesaian (Query)TidakDengan permintaan yang ditandatangani, atau dengan all_keys=trueHanya kunci ini sahaja.

Jawapan

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

Menandatangani permintaan akaun

Mencipta, mengubah dan membatalkan kunci, ringkasan akaun dan top-up automatik tidak mengambil kunci API.Mereka mengambil tanda tangan daripada nym anda, jadi kunci yang bocor boleh menghabiskan sehingga capnya tetapi tidak boleh membuat kunci lain atau menaikkan capnya sendiri.

Aplikasi ini buat untuk anda: segala-galanya dalam Kebakaran sheet menggunakan titik akhir ini. Anda hanya memerlukan seksyen ini untuk menguruskan kunci daripada kod anda sendiri.

Tanda tangan ini ialah peristiwa Nostr jenis 27235 (NIP-98), dihantar dengan kod base64 dalam Authorization Header dengan perkataan Nostr Di hadapan :

peristiwa

{
  "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 adalah URL penuh permintaan, string pertanyaan termasuk, persis seperti yang dihantar.
  • method Ini ialah kaedah HTTP.
  • payload ialah SHA-256 badan permintaan mentah, dalam hex. POST dan PATCH, dan badan yang anda hantar mesti byte untuk byte yang anda hashed.
  • created_at Ia mesti berada dalam masa 60 saat daripada jam pelayan.
  • Setiap peristiwa berlaku sekali, a GET termasuk, supaya tajuk yang ditangkap tidak boleh diputar semula. Tandatangani tajuk baru untuk setiap permintaan. Tambah nonce tag dengan nilai rawak supaya dua permintaan yang ditandatangani pada saat yang sama masih berbeza.
  • Badan permintaan yang ditandatangani boleh mempunyai maksimum 64 KB, dan badan memerlukan Content-Type: application/json.

Peristiwa yang hilang kembali 401 missing_nostr_authsatu yang terbentuk buruk, ditandatangani buruk, terlalu lama, atau untuk URL, kaedah atau badan yang berbeza mengembalikan invalid_nostr_authOleh yang demikian, al-Quran mengingatkan kepada orang yang kembali kepada Al-Quran. nostr_auth_replayedKunci API yang dihantar ke titik akhir ini ditolak. tanda tangan disemak sebelum badan dibaca, dan setiap alamat boleh gagal 30 kali setiap minit (sebuah alamat IPv6 dihitung sebagai keseluruhan /64); selepas itu ia mendapat 429 dengan Retry-After.

Pelayar boleh memanggil titik akhir ini hanya dari laman web Nymbot sendiri (https://nymbot.ai, https://nymchat.app dan subdomain mereka). halaman di mana-mana laman lain tidak mendapat tajuk CORS kembali, jadi ia tidak boleh membaca apa yang mereka kembalikan. skrip dan aplikasi asli, yang menghantar tiada OriginMereka tidak terpengaruh.

Kunci Rahsia Anda

Menandatangani memerlukan kunci rahsia nym anda (yang nsec), yang mengawal segala-galanya: identiti anda, sejarah anda dan keseimbangan anda. hanya meletakkannya dalam skrip pada mesin yang anda percayai, baca dari persekitaran bukannya menulisnya ke dalam fail, dan lebih suka aplikasi apabila anda boleh.

Penolong-penolong ini membina tajuk. contoh-contoh yang kemudian di halaman ini menggunakan mereka. Mereka membaca kunci rahsia dalam hex daripada NOSTR_SECRET_HEX; cURL satu menggunakan nak alat baris perintah, yang mengambil kunci nsec atau hex, dan sha256sum Pada 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");
}

Akaun ringkasan

Apa lembaran API aplikasi menunjukkan di bahagian atas: kunci awam anda, kedua-dua keseimbangan, berapa banyak kunci yang aktif (tidak dibatalkan atau tamat tempoh), dan automatik top-up pengaturan, atau null apabila pelayan tidak menawarkan.

GET https://nymbot.ai/api/v1/account memerlukan a Permintaan ditandatangani.

Jawapan

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

Pengurusan Kunci

Titik akhir di sebalik senarai kunci aplikasi. semua mereka memerlukan Permintaan ditandatanganiSetiap kunci dikembalikan dalam bentuk ini, dengan masa dalam ISO 8601 dan jumlah dalam sats:

objek utama

{
  "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 hanya cukup untuk mengenali kunci tetapi tidak untuk menggunakannya. kunci itu sendiri hanya dikembalikan sekali, apabila ia dibuat.

Senarai Kunci

GET https://nymbot.ai/api/v1/keys telah ditandatangani.

LapanganJenisdiperlukanPenerangan
include_revokedMelayu kepada Melayu (query)TidakTermasuk kunci yang dibatalkan. Default false.

Jawapan

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

Membuat Kunci

POST https://nymbot.ai/api/v1/keys telah ditandatangani. kembali 201.

LapanganJenisdiperlukanPenerangan
nameString yangya1 hingga 40 watak, berbeza daripada kunci aktif anda yang lain (mengabaikan kes).
limit_satsIntegraTidakPengeluaran cap dalam sats, sekurang-kurangnya 1. biarkan ia keluar tanpa cap.
reset_periodString yangTidakdaily, weekly atau monthlykeperluan limit_satsTinggalkan untuk cap yang tidak pernah reset.
expire_atstring atau integerTidakApabila kunci berhenti berfungsi: masa ISO 8601, atau milisekunder sejak 1970.

Penyelesaian (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"
  }
}
Statusbila
400Nama yang hilang atau terlalu panjang; nama yang sudah digunakan (duplicate_name); cap yang bukan nombor keseluruhan sekurang-kurangnya 1; tempoh reset tanpa cap; tamat tempoh di masa lalu; medan yang tidak diketahui (unknown_parameter); atau 25 kunci aktif sudah (too_many_keys).
429Lebih daripada 60 kunci yang dibuat oleh nym ini, atau 120 dari alamat ini, dalam satu jam (rate_limit_exceeded, dengan 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);

Membaca satu kunci

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

Kembali {"data": {…}} dengan objek utama, atau 404 key_not_found jika tiada kunci anda mempunyai id itu.

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

Menukar Kunci

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

Hantar mana-mana daripada name, limit_sats, reset_period dan expire_at, dengan peraturan yang sama seperti apabila membuat kunci. null Mengubah tempoh reset memulakan tempoh baru pada nol. kunci yang dibatalkan tidak boleh diubah (400 key_revoked) Kembali {"data": {…}} dengan objek kunci yang dikemas kini.

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

Membatalkan Kunci

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

Menghentikan kunci pada bila-bila masa, untuk kebaikan. ia kekal dalam senarai dengan revoked_at ditubuhkan, dan boleh dilihat dengan include_revoked=trueMembatalkan kunci yang telah dibatalkan menjawab dengan cara yang sama.Satu-satunya 50 kunci yang telah dibatalkan terkini disimpan; yang lebih tua dipadamkan apabila kunci lain dibatalkan.

Jawapan

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

Perkhidmatan NWC Auto-top-up

Menghubungkan dompet Lightning dengan Nostr Wallet Connect dan Nymbot menampung keseimbangan dengan sendirinya apabila pengeluaran API berjalan rendah. Permintaan ditandatangani.

Bagaimana ia berfungsi: selepas permintaan API dikenakan bayaran kepada baki yang anda pilih untuk menonton, jika baki itu telah jatuh di bawah ambang anda, Nymbot membuat invois untuk jumlah top-up anda, meminta dompet anda untuk membayarnya, dan menambah kredit. Ia melebihi maksimum sekali setiap 5 minit untuk setiap nym dan baki, jadi letupan permintaan tidak boleh mengosongkan dompet. Menghabiskan dalam aplikasi tidak memicu ia. Masa dan saiz top-up terakhir, dan kesilapan terakhir, berada dalam tetapan; jika pembayaran berlaku selepas kesilapan, semak invoisnya dengan Status Top-Up kredit kepada mereka.

Sebelum anda menyambungkan dompet

Rantaian sambungan membolehkan sesiapa yang memegangnya meminta dompet anda untuk membayar.Nymbot menyimpannya disulitkan dan hanya pernah menggunakannya untuk membayar invois top-up sendiri, tetapi buat sambungan hanya untuk ini, dengan bajet pengeluaran dalam dompet anda, jadi yang paling ia boleh membayar adalah nombor yang dipilih anda. pay_invoice.

Menghubungkan Dompet

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

LapanganJenisdiperlukanPenerangan
nwc_urlString yangyaRangkaian sambungan, bermula nostr+walletconnect://Nymbot meminta dompet untuk get_info sebelum disimpan, dan menyimpan ia tersembunyi.
threshold_satsIntegrayaTop up apabila baki jatuh di bawah ini banyak sats. sekurang-kurangnya 1,000.
topup_satsIntegrayaBerapa banyak untuk menambah setiap kali. 1,000 hingga 1,000,000 sats.
tierString yangTidakpro (Perkara yang telah ditetapkan) atau standard: keseimbangan untuk melihat dan top up.

Jawapan

{
  "data": {
    "connected": true,
    "threshold_sats": 5000,
    "topup_sats": 20000,
    "tier": "pro",
    "last_topup_at": null,
    "last_topup_sats": null,
    "last_error": null
  }
}
Statusbila
400Tiada rangkaian rangkaian (invalid_nwc_url(Baca juga: Perbincangan di atas tidak boleh dijawab)nwc_unreachable) atau menolak cek (nwc_rejected); sambungan tidak boleh membayar invois (nwc_missing_permission); atau jumlah di luar had.
501Perkhidmatan ini tidak boleh diakses secara automatik (nwc_unavailable) Sama berlaku untuk kedua-dua titik akhir yang lain.

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

Membaca tetapan

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

Mengembalikan objek yang sama seperti menyambung, dengan connected: false dan bidang-bidang lain null apabila tiada dompet yang disambungkan. rantaian sambungan itu sendiri tidak dikembalikan.

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

Penyelesaian

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

Menghapuskan string sambungan yang disimpan. Tiada lagi top-up dibuat. Untuk memastikan, anda juga boleh membatalkan sambungan dalam dompet anda.

Jawapan

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

Pembayaran Permintaan Tanpa Kunci

Titik akhir harga tetap boleh dibayar untuk satu permintaan pada satu masa sepanjang Lightning, tanpa kunci, tiada akaun dan tiada baki: POST /images/generations, POST /images/edits, POST /videos, POST /audio/speech, POST /audio/transcriptions, POST /audio/translations dan POST /embeddingsChat, Jawapan dan Mesej sentiasa memerlukan kunci. permintaan yang membawa kunci dikira ke baki seperti biasa; aliran pembayaran hanya bermula apabila tiada kunci dihantar.

Nymbot berbicara dua versi idea yang sama, daripada satu latar belakang: Lightning Labs S402 (juga diterima di bawah nama lama, LSAT) dan rancangan IETF Pembayaran Skim pengesahan HTTP dengan lightning kaedah dan charge Gunakan apa sahaja yang pelanggan anda faham.

Menjalankan pelayan anda sendiri

Bayar tanpa kunci hanya pada apabila API_L402_SECRET mempunyai sekurang-kurangnya 32 byte acak, seperti hex (64 watak) atau base64 (44). openssl rand -hex 32Nilai yang lebih pendek atau boleh ditebak mematikan ciri dan mencatat mengapa. API_L402_SECRET_PREVIOUS untuk satu hari: credentials, status URL dan cabaran yang dibuat di bawahnya terus berfungsi sehingga kedaluwarsa.

cabaran

Hantar permintaan dengan tidak Authorization header. jika ia sah, tiada apa-apa berjalan, dan anda mendapat 402 Payment Required dengan invois untuk apa yang kos permintaan itu: harga yang sama kunci akan membayar, ditukar kepada 10 sats kredit standard atau 100 sats kredit Pro dan disegerakkan sehingga keseluruhan sat (sekurang-kurangnya 1 sat, dan sekurang-kurangnya 0.05 minimum kredit). WWW-Authenticate Soalan-soalan untuk akaun yang sama:

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

Pembayaran request parameter ini ialah base64url JSON: {"amount":"237","currency":"sat","methodDetails":{"invoice":"lnbc...","network":"mainnet","paymentHash":"..."}}.

Tindakan ini dikaitkan dengan titik akhir, kepada Content-Type (tipe media dan, untuk pelbagai bahagian, sempadan) dan kepada SHA-256 daripada bajet badan yang tepat yang anda hantar, dan berlangsung selama 15 minit. identik Soalan lain : sama Content-Type dan sama byte JSON, atau untuk pelbagai titik akhir bahagian (/images/edits, /audio/transcriptions, /audio/translationsKebanyakan pustaka HTTP memilih sempadan baru setiap kali mereka mengkodkan borang, jadi mengkodnya sekali dan menghantar bajet itu dua kali.

Setiap alamat boleh meminta 30 cabaran setiap minit (sebuah alamat IPv6 dihitung sebagai keseluruhan /64). Permintaan yang alamat yang tidak diketahui berkongsi 10 yang lebih ketat setiap minit, dan terdapat cap keseluruhan pada cabaran Nymbot masalah di semua alamat; permintaan yang ditolak sebelum cabaran dibuat (contohnya dengan badan yang tidak sah JSON) tidak dihitung ke arahnya. 429 dengan Retry-After, dihantar sebelum badan dibaca. titik akhir dibayar yang dipanggil tanpa kunci atau credential juga dihitung ke arah had umum 120 permintaan yang tidak disahkan per minit setiap alamat. Content-Type Bukan application/json ( atau multipart/form-data Oleh yang demikian, ia telah ditolak oleh 415 dan tidak pernah menerima akaun.

Embeddings dinilai daripada anggaran token dalam input, dengan 1.5× margin, kerana bilangan sebenar hanya dikenali selepas itu. Kembalikan Token.

Menghantar Pembayaran

Bayar invois dengan mana-mana dompet Lightning. Dompet memberi anda imej pra, 64 watak hex. Kemudian hantar permintaan yang sama dengan salah satu daripada ini:

RancanganHeader yang
S402Authorization: L402 <macaroon>:<preimage> (LSAT juga boleh bekerja)
PembayaranAuthorization: Payment <base64url JSON>Di mana JSON ialah {"challenge": {every parameter of the challenge, as sent}, "payload": {"preimage": "<hex>"}}

Permintaan berbayar menjawab persis seperti yang dibuat dengan kunci, kecuali bahawa nymbot objek tidak mempunyai medan keseimbangan: {"payment": "l402", "tier": "pro", "paid_sats": 237, "charged_sats": 237}Dan terdapat tidak X-Nymbot-Balance-Sats permohonan yang dibayar dengan skim Pembayaran juga menerima Payment-Receipt header (base64url JSON dengan id cabaran, hash pembayaran sebagai reference, status dan timestampPermintaan berbayar tidak dikaitkan dengan sebarang nym, jadi mereka tidak muncul dalam sejarah pertanyaan.

Statusbila
402 payment_already_usedSetiap bayaran membayar untuk satu permintaan. jawapan adalah cabaran baru untuk permintaan ini, jadi pelanggan yang memadamkan credential terakhir (seperti lnget (Sebenarnya, ia hanya berlaku sekali lagi.
402 payment_mismatchPendaftaran telah dikeluarkan untuk titik akhir yang lain, Content-Type atau badan, atau membayar kurang daripada permintaan ini sekarang kos. cabaran baru untuk permintaan ini datang dengan ia; jika bayaran terlalu kecil, apa yang anda bayar kembali sebagai Kembalikan Token (refund_token dan refund_sats dalam badan yang lain).
402 payment_expiredLebih daripada 15 minit telah berlalu sejak cabaran. cabaran baru datang dengan itu. Jika gambar pra menunjukkan anda telah dibayar, apa yang anda telah dibayar kembali sebagai Kembalikan Token (refund_token dan refund_sats dalam badan), sekali; kredensial kemudian digunakan.
401 invalid_preimagePreimage tidak hash kepada hash pembayaran invoice.
401 invalid_payment_credentialKredensial itu disalah bentuk, telah diubah selepas Nymbot mengeluarkan, atau nama hash pembayaran Nymbot tidak pernah mengeluarkan invoice untuk.
429 rate_limit_exceededLebih daripada 30 credentials atau kunci yang gagal untuk mengesahkan datang dari alamat ini dalam satu minit, atau satu token bayaran balik dihantar lebih daripada 60 kali dalam satu minit. 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"));

Pelanggan yang dibina mppx dengan kaedah Lightning menangani cabaran Pembayaran sendiri; tunjukkan mereka di titik akhir dan biarkan mereka membayar.

Video yang

yang dibayar POST /videos Jawapan 202 seperti sebuah kunci, plus a status_url: GET ia tanpa sebarang kunci untuk mengikuti kerja. ia ditandatangani dan berfungsi selama 24 jam, selagi kerja disimpan.

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

simpanlah refund_token daripada jawapan ini: ia dipaparkan hanya di sini. Ia kosong sementara videoGET /api/v1/l402/refunds Jawapan "status": "pending"); jika render gagal dibayar, bayaran mendarat di atasnya. URL status menunjukkan refund_sats untuk kerja yang dikembalikan tetapi tidak pernah token, jadi berkongsi URL status tidak berkongsi pengembalian.

Pengembalian

Jika permintaan berbayar gagal dan pembekal dikenakan bayaran kepada Nymbot untuk percubaan, bayaran disimpan dan kesilapan berkata demikian, dengan charged_sats, sama seperti permintaan kunci.Jika ia gagal tanpa dikira, kesilapan membawa Kembalikan Token Berharga apa yang anda bayar:

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

Bahagian-bahagian yang tidak digunakan kembali dengan cara yang sama: jika anda meminta dua imej dan satu gagal dibebankan, jawapan kejayaan nymbot objek membawa token pengembalian wang untuk yang hilang; transkrip yang panjangnya tidak boleh dibaca di hadapan harga untuk yang paling lama fail boleh (tidak lebih daripada 30 minit), dan perbezaan kepada panjang sebenar kembali sebagai token pengembalian wang; jika ia ternyata lebih lama daripada 30 minit, ia ditolak dengan 413 dan semua bayaran dikembalikan. embeddings mengembalikan apa yang dikehendaki. video yang gagal mengembalikan token yang dikembalikan.

Token pengembalian wang adalah kod 256-bit acak. Nymbot hanya menyimpan hashnya, dan ia tamat tempoh selepas 30 hari. Ia memegang baki sat, dan anda boleh:

  • Bayarlah dengan itu. hantar Authorization: Bearer REFUND-… Perbezaan di antara kedua-duanya ialah di mana-mana kawasan yang mempunyai kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang mempunyai kawasan-kawasan yang berlainan.refund_token_sats Di dalam nymbot objek). token bernilai kurang daripada jawapan permintaan 402 refund_insufficient; kegagalan yang tidak dikira meletakkan sats kembali pada token yang sama.
  • Periksa ia GET /api/v1/l402/refunds dengan header yang sama kembali {"sats": 237, "status": "open", "expires_at": "..."}.
  • Satu token boleh digunakan sehingga 60 kali setiap minit.
  • Masukkan ke dalam nym. Masukkan ke dalam Kembalikan hadiah dalam aplikasi Nymbot, atau panggilan POST /api/v1/l402/refunds/redeem Dengan a Permintaan ditandatangani dan {"refund_token": "REFUND-...", "balance": "standard"} ( atau "pro"Semua kredit pergi ke baki (10 sats masing-masing pada standard, 100 pada Pro); sats yang tidak membuat keseluruhan kredit tinggal pada token untuk permintaan 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"

Jawapan

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