ข้ามไปที่เนื้อหา
กลับไปที่ Nymbot

ฐานความรู้ ผู้พัฒนา

Balance, top-ups และ keys

ตรวจสอบสิ่งที่คุณมีด้านบนกว่า Lightning ด้านบนโดยอัตโนมัติจากกระเป๋าสตางค์ของคุณเองดูค่าใช้จ่ายของคําขอแต่ละคําขอและจัดการคีย์จากรหัส

ตรวจสอบสมดุล

ทั้งสมดุลของคุณและจํานวนของฝาครอบของคีย์นี้จะใช้

GET https://nymbot.ai/api/v1/credits/balance - ต้องใช้คีย์ API POST ยังทํางานสําหรับลูกค้าที่คาดหวัง

balance เป็นสมดุลทั้งสองด้วยกันในดอลลาร์ในราคา Bitcoin ปัจจุบันสําหรับเครื่องมือที่คาดหวังจํานวนเดียว (null ถ้าราคาไม่สามารถอ่านได้) ส่วนที่เหลือคือในเครดิตและ sats ซึ่งเป็นวิธีที่สมดุลจะถูกเก็บไว้จริง key คําอธิบายคีย์ที่ถาม คีย์ที่ถึงขอบเขตสามารถตรวจสอบสมดุลได้

คําตอบ

{
  "balance": 49.18,
  "balance_sats": 42037,
  "standard": { "credits": 120.4, "sats": 1204 },
  "pro": { "credits": 408.33, "sats": 40833 },
  "key": {
    "id": "4f0c9a1be27d3856",
    "name": "laptop scripts",
    "limit_sats": 20000,
    "period_used_sats": 3412,
    "total_used_sats": 18230,
    "reset_period": "monthly",
    "reset_at": "2026-10-01T00:00:00Z"
  }
}
สถานะเมื่อ
401คีย์ที่หายไปไม่รู้จักถูกลบหรือหมดอายุ

cURL

curl https://nymbot.ai/api/v1/credits/balance \
  -H "Authorization: Bearer $NYMBOT_API_KEY"

Python

import os
import requests

res = requests.get(
    "https://nymbot.ai/api/v1/credits/balance",
    headers={"Authorization": "Bearer " + os.environ["NYMBOT_API_KEY"]},
)
balance = res.json()
print(balance["standard"]["sats"], balance["pro"]["sats"])

JavaScript

const res = await fetch("https://nymbot.ai/api/v1/credits/balance", {
  headers: { "Authorization": "Bearer " + process.env.NYMBOT_API_KEY },
});
const balance = await res.json();
console.log(balance.standard.sats, balance.pro.sats);

วิธีการชําระเงิน

วิธีที่คุณสามารถขึ้นและขีด จํากัด Lightning เป็นวิธีเดียว

GET https://nymbot.ai/api/v1/topup/payment-methods ไม่จําเป็นต้องมีคีย์

Top-up คือ 10 ถึง 1,000,000 sats; a Pro top-up ต้องซื้ออย่างน้อยหนึ่งเครดิต Pro, ดังนั้นมันเริ่มต้นที่ 100 sats. ขีด จํากัด ดอลลาร์ตามราคา Bitcoin. bulk_bonus รายชื่อเครดิตเพิ่มเติมใน Top-ups ขนาดใหญ่เช่นเดียวกับในแอปพลิเคชัน: 10%, 15% หรือ 20% เพิ่มเติมใน Top-ups มาตรฐานจาก 500, 1,000 หรือ 5,000 sats และใน Pro Top-ups จาก 5,000, 10,000 หรือ 50,000 sats

คําตอบ

{
  "supported_methods": [
    {
      "method": "btc-lightning",
      "display_name": "Bitcoin Lightning",
      "supported_currencies": ["SATS", "USD", "BTC"],
      "limits": {
        "SATS": { "min": 10, "max": 1000000 },
        "USD": { "min": 0.02, "max": 1170 },
        "BTC": { "min": 1e-7, "max": 0.01 }
      },
      "tiers": ["standard", "pro"],
      "default_tier": "pro",
      "tier_min_sats": { "standard": 10, "pro": 100 },
      "sats_per_credit": { "standard": 10, "pro": 100 },
      "bulk_bonus": [
        { "bonus": 0.1, "standard_sats": 500, "pro_sats": 5000 },
        { "bonus": 0.15, "standard_sats": 1000, "pro_sats": 10000 },
        { "bonus": 0.2, "standard_sats": 5000, "pro_sats": 50000 }
      ]
    }
  ]
}

cURL

curl https://nymbot.ai/api/v1/topup/payment-methods

Python

import requests

methods = requests.get("https://nymbot.ai/api/v1/topup/payment-methods").json()
print(methods["supported_methods"][0]["limits"])

JavaScript

const methods = await (await fetch("https://nymbot.ai/api/v1/topup/payment-methods")).json();
console.log(methods.supported_methods[0].limits);

ขึ้นอยู่กับ Lightning

สร้างใบแจ้งหนี้ Lightning ที่เพิ่มเครดิตให้กับ nym ที่กุญแจเป็นของ Pay it from any Lightning wallet, then ตรวจสอบ เพื่อให้มีเครดิตเพิ่ม

POST https://nymbot.ai/api/v1/topup/create/btc-lightning - ต้องใช้คีย์ API

พื้นที่ชนิดต้องการคําอธิบาย
amountหมายเลขใช่จํานวนมากใน currencyหมายเลขทั้งหมดสําหรับ sats
currencyสายรัดไม่SATS (ข้อผิดพลาด) USD หรือ BTCดอลลาร์จะถูกแปลงในราคา Bitcoin ปัจจุบัน
tierสายรัดไม่pro (ความผิดพลาด) หรือ standard: ความสมดุลที่เครดิตจะไป

เครดิตมาตรฐานคือ 10 sats และเครดิต Pro 100 sats รวมถึงโบนัสจํานวนมากใด ๆ credits กล่าวว่าสิ่งที่ใบแจ้งหนี้นี้จะเพิ่ม

คําตอบ

{
  "invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
  "payment_request": "lnbc100u1p5...",
  "amount_sats": 10000,
  "credits": 115,
  "tier": "pro",
  "expires_at": "2026-09-30T09:27:00Z",
  "status": "pending"
}
สถานะเมื่อ
400วิธีการอื่น ๆ ในทาง (unsupported_method), สกุลเงินที่ไม่รู้จัก (unsupported_currency) หรือระดับจํานวนเงินที่ขาดหายไปหรือปริมาณต่ํากว่า (amount_too_small), มากกว่า 1,000,000 sats (amount_too_large) หรือปฏิเสธโดยกระเป๋าสตางค์ Lightning (amount_out_of_range).
429มากกว่า 60 บัตรสําหรับนิวเมติกนี้หรือ 120 จากที่อยู่นี้ในชั่วโมง (rate_limit_exceededด้วย Retry-After).
502ไม่สามารถทําบัญชีได้ในขณะนี้ (invoice_unavailableด้วย Retry-After).

cURL

curl https://nymbot.ai/api/v1/topup/create/btc-lightning \
  -H "Authorization: Bearer $NYMBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount": 10000, "currency": "SATS", "tier": "pro"}'

Python

import os
import requests

res = requests.post(
    "https://nymbot.ai/api/v1/topup/create/btc-lightning",
    headers={"Authorization": "Bearer " + os.environ["NYMBOT_API_KEY"]},
    json={"amount": 10000, "currency": "SATS", "tier": "pro"},
)
invoice = res.json()
print(invoice["payment_request"])

JavaScript

const res = await fetch("https://nymbot.ai/api/v1/topup/create/btc-lightning", {
  method: "POST",
  headers: {
    "Authorization": "Bearer " + process.env.NYMBOT_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ amount: 10000, currency: "SATS", tier: "pro" }),
});
const invoice = await res.json();
console.log(invoice.payment_request);

ตรวจสอบ top-up

สอบถามว่าใบแจ้งหนี้ได้รับการชําระเงินหรือไม่และเมื่อมีการเพิ่มเครดิต ตรวจสอบคืออะไรเครดิตมันดังนั้นหลังจากชําระเงินตรวจสอบจนกว่าสถานะจะ creditedตรวจสอบอีกครั้งหลังจากนั้นมีความปลอดภัย: การเชื่อมโยงไปยังประเทศหนึ่งครั้งไม่ว่าคุณจะถามหลายครั้ง

GET https://nymbot.ai/api/v1/topup/status/{invoice_id} - ต้องใช้กุญแจจากนิมที่ทําบัญชี

status เป็น pending (ยังไม่ได้ชําระเงิน) paid (จ่าย แต่ยังไม่ได้รับการเชื่อมโยง; ตรวจสอบอีกครั้ง) credited (ในสมดุลของคุณ) หรือ expired (ไม่มีการชําระเงินในเวลา) พื้นที่สมดุลเป็นสําหรับระดับที่ใบแจ้งหนี้สูงสุด

คําตอบ

{
  "invoice_id": "b7d41e0c95a2f38e6c1d0e9a4b7f2c61d3e8a05f9b2c4d7e1a6f3b8c0d5e2a9f4",
  "status": "credited",
  "amount_sats": 10000,
  "credits": 115,
  "tier": "pro",
  "expires_at": null,
  "balance_credits": 523.33,
  "balance_sats": 52333
}
สถานะเมื่อ
400id ไม่ใช่ id 64-character จากการสร้างการโทร
404ไม่มีใบแจ้งหนี้โดย id ของคุณ (invoice_not_found).

cURL

curl https://nymbot.ai/api/v1/topup/status/$INVOICE_ID \
  -H "Authorization: Bearer $NYMBOT_API_KEY"

Python

import os, time
import requests

headers = {"Authorization": "Bearer " + os.environ["NYMBOT_API_KEY"]}
url = "https://nymbot.ai/api/v1/topup/status/" + invoice["invoice_id"]

while True:
    status = requests.get(url, headers=headers).json()["status"]
    if status in ("credited", "expired"):
        break
    time.sleep(3)
print(status)

JavaScript

const headers = { "Authorization": "Bearer " + process.env.NYMBOT_API_KEY };
const url = "https://nymbot.ai/api/v1/topup/status/" + invoice.invoice_id;

let status;
do {
  await new Promise((r) => setTimeout(r, 3000));
  status = (await (await fetch(url, { headers })).json()).status;
} while (status !== "credited" && status !== "expired");
console.log(status);

ชอบประวัติศาสตร์

หนึ่งบรรทัดต่อคําขอ: มันคืออะไรรูปแบบใดจํานวนโทเค็นและค่าใช้จ่ายใด ไม่มีคําแนะนําหรือคําตอบจะถูกเก็บไว้ดังนั้นไม่มีคําตอบจะถูกส่งกลับ หนึ่งบรรทัดจะถูกเก็บไว้เป็นเวลา 90 วันใหม่ครั้งแรก คีย์ที่ถึงขอบเขตสามารถอ่านประวัติของมันได้

GET https://nymbot.ai/api/v1/queries/history — ต้องใช้คีย์ API ซึ่งจะเห็นคําขอของตัวเองหรือ ใบสมัครที่ลงนาม จากนิมของคุณซึ่งเห็นทุกกุญแจ

พื้นที่ชนิดต้องการคําอธิบาย
pageหมายเลขรุ่น (query)ไม่หน้าเริ่มต้น 1, สูงสุด 1,000; หน้าที่สูงกว่าคือ 400 invalid_value.
page_countหมายเลขรุ่น (query)ไม่รอบต่อหน้า หมายเลขเริ่มต้น 20, สูงสุด 100
start_date
end_date
สกรู (query)ไม่ISO 8601 วันที่หรือเวลา
modelสกรู (query)ไม่รูปแบบนี้เท่านั้น
typeสกรู (query)ไม่chat, responses, messages, image, video, speech, transcription หรือ embedding.
all_keysบูเลียน (คําถาม)ไม่ด้วยคีย์: true ประกอบด้วยคีย์แต่ละคีย์ของ nym เดียวกัน false.
key_idสกรู (query)ไม่ด้วยใบสมัครที่ลงนามหรือ all_keys=true: เท่านั้นคีย์นี้

คําตอบ

{
  "data": [
    {
      "id": "q_71c4e9a0",
      "timestamp": "2026-09-30T08:12:00Z",
      "model": "anthropic/claude-sonnet-5",
      "type": "chat",
      "input_tokens": 1240,
      "output_tokens": 380,
      "cached_tokens": 0,
      "cost_sats": 16.2,
      "cost_usd": 0.01895,
      "balance": "pro",
      "key_id": "4f0c9a1be27d3856",
      "web_search": false,
      "status": "ok"
    }
  ],
  "pagination": { "page": 1, "page_count": 20, "total": 311, "total_pages": 16 }
}

cURL

curl "https://nymbot.ai/api/v1/queries/history?page_count=50&type=chat" \
  -H "Authorization: Bearer $NYMBOT_API_KEY"

Python

import os
import requests

res = requests.get(
    "https://nymbot.ai/api/v1/queries/history",
    headers={"Authorization": "Bearer " + os.environ["NYMBOT_API_KEY"]},
    params={"page_count": 50, "type": "chat"},
)
for row in res.json()["data"]:
    print(row["timestamp"], row["model"], row["cost_sats"])

JavaScript

const res = await fetch("https://nymbot.ai/api/v1/queries/history?page_count=50&type=chat", {
  headers: { "Authorization": "Bearer " + process.env.NYMBOT_API_KEY },
});
for (const row of (await res.json()).data) console.log(row.timestamp, row.model, row.cost_sats);

การลงนามคําขอบัญชี

การสร้างการเปลี่ยนแปลงและการยกเลิกคีย์สรุปบัญชีและอัตโนมัติ top-ups ไม่ใช้คีย์ API พวกเขาใช้การลงนามจาก nym ของคุณดังนั้นคีย์ที่รั่วไหลสามารถใช้ได้จนถึงแคป แต่ไม่สามารถทําคีย์อื่นหรือเพิ่มแคปของตัวเอง

แอปพลิเคชันทําสิ่งนี้สําหรับคุณ: ทุกอย่างใน ไฟ sheet ใช้จุดสิ้นสุดเหล่านี้ คุณเพียงต้องการส่วนนี้เพื่อจัดการคีย์จากรหัสของคุณเอง

สัญญาณนี้เป็นเหตุการณ์ของ Nostr ประเภท 27235 (NIP-98), ส่งโดย base64-encoded ใน Authorization header กับคํา Nostr ด้านหน้า :

เหตุการณ์

{
  "kind": 27235,
  "created_at": 1790726400,
  "tags": [
    ["u", "https://nymbot.ai/api/v1/keys"],
    ["method", "POST"],
    ["nonce", "9c4e21f07a3b...16 random bytes in hex"],
    ["payload", "3f1a0d7c8e2b...sha256 of the exact request body in hex"]
  ],
  "content": "",
  "pubkey": "your public key in hex",
  "id": "...",
  "sig": "..."
}
  • u เป็น URL เต็มของคําขอซึ่งรวมถึงลําดับคําถามเช่นเดียวกับที่ส่ง
  • method เป็นวิธีการ HTTP
  • payload เป็น SHA-256 ของ ร่างกายคําขอดิบ ใน hex. It is required on POST และ PATCH, และร่างกายที่คุณส่งต้องเป็นบิตต่อบิตที่คุณ hashed
  • created_at ควรอยู่ในช่วงเวลา 60 วินาทีของเซิร์ฟเวอร์
  • ทุกกิจกรรมทํางานครั้งเดียว a GET รวมดังนั้นหัวที่จับได้ไม่สามารถเล่นซ้ําได้ สัญญาณใหม่สําหรับทุกคําขอ เพิ่มหัวที่จับได้ nonce แท็กด้วยค่าสุ่มเพื่อให้สองคําขอที่ลงนามในวินาทีเดียวกันยังคงแตกต่างกัน
  • ร่างกายของคําขอที่ลงนามสามารถมีขนาดสูงสุด 64 กิโลไบต์และจําเป็นต้องใช้ Content-Type: application/json.

เหตุการณ์ที่หายไปกลับมา 401 missing_nostr_auth; หนึ่งที่ถูกสร้างขึ้นไม่ดีลงนามไม่ดี เก่าเกินไปหรือสําหรับ URL ทางวิธีการหรือร่างกายที่แตกต่างกันกลับ invalid_nostr_auth, ด้วยเหตุผลในข้อความ; a reused one returns nostr_auth_replayedคีย์ API ที่ส่งไปยังจุดสิ้นสุดเหล่านี้จะถูกปฏิเสธ การลงนามจะถูกตรวจสอบก่อนที่จะอ่านร่างกายและแต่ละที่อยู่สามารถล้มเหลวได้ 30 ครั้งต่อนาที (ที่อยู่ IPv6 หมายถึง /64) หลังจากนั้นจะได้รับ 429 ด้วย Retry-After.

เบราว์เซอร์สามารถเรียกจุดสิ้นสุดเหล่านี้ได้เฉพาะจากเว็บไซต์ของ Nymbot (https://nymbot.ai, https://nymchat.app และโดเมนย่อยของพวกเขา) หน้าในเว็บไซต์อื่น ๆ จะไม่ได้รับหัว CORS กลับไปดังนั้นจึงไม่สามารถอ่านสิ่งที่พวกเขาคืนได้ สคริปต์และแอปพลิเคชันพื้นฐานซึ่งส่งไม่มี Originไม่ได้รับผลกระทบ

คีย์ลับของคุณ

การลงนามต้องมีคีย์ความลับของ nym ของคุณ (the nsec), ซึ่งควบคุมทุกอย่าง: ตัวตนของคุณประวัติและสมดุลของคุณ เพียงใส่ในสคริปต์บนเครื่องที่คุณไว้วางใจอ่านจากสภาพแวดล้อมแทนที่จะเขียนลงในไฟล์และชอบแอพเมื่อคุณสามารถ

ผู้ช่วยเหล่านี้สร้างหัวฉบับ ตัวอย่างต่อไปนี้ในหน้านี้ใช้พวกเขา พวกเขาอ่านคีย์ความลับใน hex จาก NOSTR_SECRET_HEX; cURL หนึ่งใช้ ทารก เครื่องมือบรรทัดคําสั่งซึ่งใช้คีย์ nsec หรือ hex และ sha256sum (ใน macOS shasum -a 256).

cURL

nostr_auth() {
  method="$1"; url="$2"; body="$3"
  nonce=$(openssl rand -hex 16)
  if [ -n "$body" ]; then
    hash=$(printf '%s' "$body" | sha256sum | cut -d' ' -f1)
    event=$(nak event --sec "$NOSTR_SECRET_HEX" -k 27235 -t "u=$url" -t "method=$method" -t "nonce=$nonce" -t "payload=$hash")
  else
    event=$(nak event --sec "$NOSTR_SECRET_HEX" -k 27235 -t "u=$url" -t "method=$method" -t "nonce=$nonce")
  fi
  printf 'Nostr %s' "$(printf '%s' "$event" | base64 | tr -d '\n')"
}

Python

# pip install coincurve requests
import base64, hashlib, json, os, time
from coincurve import PrivateKey, PublicKeyXOnly

SECRET = bytes.fromhex(os.environ["NOSTR_SECRET_HEX"])

def nostr_auth(method, url, body=b""):
    pubkey = PublicKeyXOnly.from_secret(SECRET).format().hex()
    tags = [["u", url], ["method", method], ["nonce", os.urandom(16).hex()]]
    if body:
        tags.append(["payload", hashlib.sha256(body).hexdigest()])
    created_at = int(time.time())
    serialized = json.dumps([0, pubkey, created_at, 27235, tags, ""], separators=(",", ":"), ensure_ascii=False)
    event_id = hashlib.sha256(serialized.encode()).digest()
    event = {
        "id": event_id.hex(),
        "pubkey": pubkey,
        "created_at": created_at,
        "kind": 27235,
        "tags": tags,
        "content": "",
        "sig": PrivateKey(SECRET).sign_schnorr(event_id).hex(),
    }
    return "Nostr " + base64.b64encode(json.dumps(event).encode()).decode()

JavaScript

// npm install nostr-tools
import { createHash, randomBytes } from "node:crypto";
import { finalizeEvent } from "nostr-tools/pure";

const secret = Buffer.from(process.env.NOSTR_SECRET_HEX, "hex");

export function nostrAuth(method, url, body = "") {
  const tags = [["u", url], ["method", method], ["nonce", randomBytes(16).toString("hex")]];
  if (body) tags.push(["payload", createHash("sha256").update(body).digest("hex")]);
  const event = finalizeEvent(
    { kind: 27235, created_at: Math.floor(Date.now() / 1000), tags, content: "" },
    secret,
  );
  return "Nostr " + Buffer.from(JSON.stringify(event)).toString("base64");
}

บัญชีสรุป

สิ่งที่แผ่น API ของแอพแสดงให้เห็นด้านบน: คีย์สาธารณะของคุณทั้งสองสมดุลจํานวนคีย์ที่ใช้งานอยู่ (ไม่ถูกลบหรือหมดอายุ) และ อัตโนมัติ Top-up การตั้งค่าหรือ null เมื่อเซิร์ฟเวอร์ไม่ให้พวกเขา

GET https://nymbot.ai/api/v1/account ต้องการ a ใบสมัครที่ลงนาม.

คําตอบ

{
  "data": {
    "pubkey": "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d",
    "balances": {
      "standard": { "credits": 120.4, "sats": 1204 },
      "pro": { "credits": 408.33, "sats": 40833 }
    },
    "keys_active": 3,
    "nwc_auto_topup": {
      "connected": true, "threshold_sats": 5000, "topup_sats": 20000, "tier": "pro",
      "last_topup_at": null, "last_topup_sats": null, "last_error": null
    }
  }
}

cURL

URL=https://nymbot.ai/api/v1/account
curl "$URL" -H "Authorization: $(nostr_auth GET "$URL")"

Python

import requests

url = "https://nymbot.ai/api/v1/account"
print(requests.get(url, headers={"Authorization": nostr_auth("GET", url)}).json())

JavaScript

const url = "https://nymbot.ai/api/v1/account";
const res = await fetch(url, { headers: { "Authorization": nostrAuth("GET", url) } });
console.log(await res.json());

การจัดการคีย์

จุดสิ้นสุดที่อยู่เบื้องหลังรายการกุญแจของแอพ พวกเขาทุกคนต้องการ ใบสมัครที่ลงนามแต่ละคีย์จะถูกส่งกลับในรูปแบบนี้ด้วยเวลาใน ISO 8601 และจํานวนใน sats:

วัตถุสําคัญ

{
  "id": "4f0c9a1be27d3856",
  "name": "laptop scripts",
  "hint": "sk-nymbot-Qm7x…c2Lw",
  "limit_sats": 20000,
  "reset_period": "monthly",
  "reset_at": "2026-10-01T00:00:00Z",
  "expire_at": null,
  "period_used_sats": 3412,
  "total_used_sats": 18230,
  "created_at": "2026-08-14T09:21:07Z",
  "updated_at": "2026-09-02T17:40:55Z",
  "last_used_at": "2026-09-30T08:12:00Z",
  "revoked_at": null
}

hint มันเพียงพอที่จะรับรู้คีย์ แต่ไม่ใช้มัน คีย์เองจะถูกส่งกลับเพียงครั้งเดียวเมื่อทํา

รายการคีย์

GET https://nymbot.ai/api/v1/keys ใบสมัคร

พื้นที่ชนิดต้องการคําอธิบาย
include_revokedบูเลียน (คําถาม)ไม่รวมถึงคีย์ที่ถูกลบ. Default false.

คําตอบ

{ "data": [ { "id": "4f0c9a1be27d3856", "name": "laptop scripts", "hint": "sk-nymbot-Qm7x…c2Lw", "...": "..." } ] }

cURL

URL=https://nymbot.ai/api/v1/keys
curl "$URL" -H "Authorization: $(nostr_auth GET "$URL")"

Python

import requests

url = "https://nymbot.ai/api/v1/keys"
for key in requests.get(url, headers={"Authorization": nostr_auth("GET", url)}).json()["data"]:
    print(key["id"], key["name"], key["period_used_sats"], key["limit_sats"])

JavaScript

const url = "https://nymbot.ai/api/v1/keys";
const { data } = await (await fetch(url, { headers: { "Authorization": nostrAuth("GET", url) } })).json();
for (const key of data) console.log(key.id, key.name, key.period_used_sats, key.limit_sats);

สร้างกุญแจ

POST https://nymbot.ai/api/v1/keys หมายเลขรุ่น: Return 201.

พื้นที่ชนิดต้องการคําอธิบาย
nameสายรัดใช่1 ถึง 40 ตัวอักษรที่แตกต่างจากคีย์ที่ใช้งานอื่น ๆ ของคุณ (ลืมกรณี)
limit_satsอินเทอร์ไม่ปริมาณค่าใช้จ่ายใน sats อย่างน้อย 1. ให้มันออกสําหรับไม่มี cap.
reset_periodสายรัดไม่daily, weekly หรือ monthlyความต้องการ limit_satsปล่อยให้ออกสําหรับหมวกที่ไม่เคยรีเซ็ต
expire_atstring หรือ integerไม่เมื่อคีย์หยุดทํางาน: เวลา ISO 8601 หรือมิลลิสวินาทีตั้งแต่ 1970

คําตอบ (201)

{
  "data": {
    "id": "4f0c9a1be27d3856",
    "name": "laptop scripts",
    "hint": "sk-nymbot-Qm7x…c2Lw",
    "limit_sats": 20000,
    "reset_period": "monthly",
    "key": "sk-nymbot-Qm7x...c2Lw",
    "...": "the rest of the key object"
  }
}
สถานะเมื่อ
400ชื่อที่หายไปหรือยาวเกินไป ชื่อที่ใช้แล้ว (duplicate_name); cap ที่ไม่ได้เป็นตัวเลขทั้งหมดอย่างน้อย 1; ระยะเวลาการรีเซ็ตโดยไม่มี cap; การหมดอายุในอดีต; ฟิลด์ที่ไม่รู้จัก (unknown_parameter) หรือ 25 คีย์ที่ใช้งานอยู่แล้ว (too_many_keys).
429มากกว่า 60 คีย์ที่ทําโดย nym นี้หรือ 120 จากที่อยู่นี้ในหนึ่งชั่วโมง (rate_limit_exceededด้วย Retry-After).

cURL

URL=https://nymbot.ai/api/v1/keys
BODY='{"name":"laptop scripts","limit_sats":20000,"reset_period":"monthly"}'
curl "$URL" \
  -H "Authorization: $(nostr_auth POST "$URL" "$BODY")" \
  -H "Content-Type: application/json" \
  -d "$BODY"

Python

import json
import requests

url = "https://nymbot.ai/api/v1/keys"
body = json.dumps({"name": "laptop scripts", "limit_sats": 20000, "reset_period": "monthly"}).encode()
res = requests.post(
    url,
    data=body,
    headers={"Authorization": nostr_auth("POST", url, body), "Content-Type": "application/json"},
)
print(res.json()["data"]["key"])

JavaScript

const url = "https://nymbot.ai/api/v1/keys";
const body = JSON.stringify({ name: "laptop scripts", limit_sats: 20000, reset_period: "monthly" });
const res = await fetch(url, {
  method: "POST",
  headers: { "Authorization": nostrAuth("POST", url, body), "Content-Type": "application/json" },
  body,
});
console.log((await res.json()).data.key);

อ่านหนึ่งกุญแจ

GET https://nymbot.ai/api/v1/keys/{id} ใบสมัคร

กลับ {"data": {…}} กับวัตถุที่สําคัญหรือ 404 key_not_found ถ้าไม่มีคีย์ของคุณมี ID ที่

cURL

URL=https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856
curl "$URL" -H "Authorization: $(nostr_auth GET "$URL")"

Python

import requests

url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856"
print(requests.get(url, headers={"Authorization": nostr_auth("GET", url)}).json()["data"])

JavaScript

const url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856";
console.log((await (await fetch(url, { headers: { "Authorization": nostrAuth("GET", url) } })).json()).data);

เปลี่ยนกุญแจ

PATCH https://nymbot.ai/api/v1/keys/{id} ใบสมัคร

ส่งใด ๆ ของ name, limit_sats, reset_period และ expire_at, ตามกฎเดียวกันเช่นเดียวกับเมื่อทํากุญแจ null ทําความสะอาดฟิลด์: ไม่มีการปิดกั้นไม่มีการรีเซ็ตไม่มีการหมดอายุ การเปลี่ยนแปลงระยะเวลาการรีเซ็ตเริ่มต้นระยะเวลาใหม่ที่ 0 คีย์ที่ยกเลิกไม่สามารถเปลี่ยนได้ (400 key_revoked) กลับ {"data": {…}} กับวัตถุกุญแจที่อัปเดต

cURL

URL=https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856
BODY='{"limit_sats":50000,"expire_at":null}'
curl -X PATCH "$URL" \
  -H "Authorization: $(nostr_auth PATCH "$URL" "$BODY")" \
  -H "Content-Type: application/json" \
  -d "$BODY"

Python

import json
import requests

url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856"
body = json.dumps({"limit_sats": 50000, "expire_at": None}).encode()
res = requests.patch(
    url,
    data=body,
    headers={"Authorization": nostr_auth("PATCH", url, body), "Content-Type": "application/json"},
)
print(res.json()["data"])

JavaScript

const url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856";
const body = JSON.stringify({ limit_sats: 50000, expire_at: null });
const res = await fetch(url, {
  method: "PATCH",
  headers: { "Authorization": nostrAuth("PATCH", url, body), "Content-Type": "application/json" },
  body,
});
console.log((await res.json()).data);

การยกเลิกกุญแจ

DELETE https://nymbot.ai/api/v1/keys/{id} ใบสมัคร

ปิดคีย์ในครั้งเดียวสําหรับดี มันยังคงอยู่ในรายการที่มี revoked_at ตั้งและสามารถมองเห็นได้ด้วย include_revoked=trueการยกเลิกคีย์ที่ยกเลิกแล้วตอบแบบเดียวกันเท่านั้น 50 คีย์ที่ยกเลิกล่าสุดจะถูกเก็บไว้; คีย์เก่าจะถูกลบเมื่อยกเลิกคีย์อื่น

คําตอบ

{ "data": { "id": "4f0c9a1be27d3856", "revoked": true } }

cURL

URL=https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856
curl -X DELETE "$URL" -H "Authorization: $(nostr_auth DELETE "$URL")"

Python

import requests

url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856"
print(requests.delete(url, headers={"Authorization": nostr_auth("DELETE", url)}).json())

JavaScript

const url = "https://nymbot.ai/api/v1/keys/4f0c9a1be27d3856";
const res = await fetch(url, { method: "DELETE", headers: { "Authorization": nostrAuth("DELETE", url) } });
console.log(await res.json());

NWC อัตโนมัติ Top-Up

เชื่อมต่อกระเป๋าสตางค์ Lightning กับ Nostr Wallet Connect และ Nymbot เก็บสมดุลด้วยตัวเองเมื่อใช้จ่าย API ทํางานต่ํา แผ่น API ของแอปมีการตั้งค่าเดียวกัน นี่คือจุดสิ้นสุดที่อยู่เบื้องหลัง ทั้งหมดพวกเขาต้องการ ใบสมัครที่ลงนาม.

วิธีการทํางาน: หลังจากที่คําขอ API จะถูกเรียกเก็บค่าใช้จ่ายไปยังสมดุลที่คุณเลือกที่จะดูหากสมดุลนั้นลดลงภายใต้ขอบเขตของคุณ Nymbot จะเรียกเก็บค่าธรรมเนียมสําหรับจํานวนเงินสูงสุดของคุณขอให้กระเป๋าสตางค์ของคุณจ่ายและเพิ่มเครดิต มันจะเพิ่มขึ้นมากที่สุดหนึ่งครั้งทุก 5 นาทีสําหรับแต่ละนิมและสมดุลดังนั้นการระเบิดของคําขอไม่สามารถทิ้งกระเป๋าสตางค์ การใช้จ่ายในแอปพลิเคชันไม่ได้เปิดใช้งานเวลาและขนาดของยอดนิยมล่าสุดและข้อผิดพลาดล่าสุดอยู่ในการตั้งค่า หากการชําระเงินผ่านไปหลังจากเกิดข้อผิดพลาดตรวจสอบใบแจ้งหนี้ด้วย สถานะ Top-Up เครดิตมัน

ก่อนที่จะเชื่อมต่อกระเป๋าสตางค์

เชือกการเชื่อมต่อช่วยให้ผู้ที่ถือมันขอให้กระเป๋าสตางค์ของคุณชําระเงิน Nymbot เก็บมันเข้ารหัสและใช้มันเพียงครั้งเดียวเพื่อชําระค่าธรรมเนียมด้านบนของตัวเอง แต่สร้างการเชื่อมต่อเพื่อทําเช่นนี้ด้วยงบประมาณการใช้จ่ายในกระเป๋าสตางค์ของคุณเพื่อให้มากที่สุดที่มันสามารถจ่ายคือหมายเลขที่คุณเลือก กระเป๋าสตางค์ต้องสนับสนุน pay_invoice.

การเชื่อมต่อกระเป๋าสตางค์

POST https://nymbot.ai/api/v1/nwc-auto-topup/connect ใบสมัคร

พื้นที่ชนิดต้องการคําอธิบาย
nwc_urlสายรัดใช่การเชื่อมต่อ string เริ่มต้น nostr+walletconnect://Nymbot สอบถามกระเป๋าสตางค์สําหรับ get_info ก่อนที่จะบันทึกและจัดเก็บที่เข้ารหัส
threshold_satsอินเทอร์ใช่ด้านบนขึ้นเมื่อสมดุลลดลงภายใต้จํานวนมากของ sats น้อยกว่า 1,000
topup_satsอินเทอร์ใช่จํานวนมากที่จะเพิ่มแต่ละครั้ง. 1,000 ถึง 1,000,000 sats.
tierสายรัดไม่pro (ความผิดพลาด) หรือ standard: ความสมดุลที่จะสังเกตและขึ้น

คําตอบ

{
  "data": {
    "connected": true,
    "threshold_sats": 5000,
    "topup_sats": 20000,
    "tier": "pro",
    "last_topup_at": null,
    "last_topup_sats": null,
    "last_error": null
  }
}
สถานะเมื่อ
400ไม่มีการเชื่อมต่อ string (invalid_nwc_url); กระเป๋าสตางค์ไม่ตอบกลับเกี่ยวกับการส่งต่อ (nwc_unreachable) หรือปฏิเสธการตรวจสอบ (nwc_rejected); การเชื่อมต่อไม่สามารถชําระค่าธรรมเนียมได้ (nwc_missing_permission) หรือจํานวนเงินที่เกินขีด จํากัด
501การอัพโหลดอัตโนมัติไม่เปิดใช้งานสําหรับเซิร์ฟเวอร์นี้ (nwc_unavailable) เช่นเดียวกับสองจุดปลายทางอื่น ๆ

cURL

URL=https://nymbot.ai/api/v1/nwc-auto-topup/connect
BODY='{"nwc_url":"nostr+walletconnect://...","threshold_sats":5000,"topup_sats":20000,"tier":"pro"}'
curl "$URL" \
  -H "Authorization: $(nostr_auth POST "$URL" "$BODY")" \
  -H "Content-Type: application/json" \
  -d "$BODY"

Python

import json, os
import requests

url = "https://nymbot.ai/api/v1/nwc-auto-topup/connect"
body = json.dumps({
    "nwc_url": os.environ["NWC_URL"],
    "threshold_sats": 5000,
    "topup_sats": 20000,
    "tier": "pro",
}).encode()
res = requests.post(
    url,
    data=body,
    headers={"Authorization": nostr_auth("POST", url, body), "Content-Type": "application/json"},
)
print(res.json())

JavaScript

const url = "https://nymbot.ai/api/v1/nwc-auto-topup/connect";
const body = JSON.stringify({
  nwc_url: process.env.NWC_URL,
  threshold_sats: 5000,
  topup_sats: 20000,
  tier: "pro",
});
const res = await fetch(url, {
  method: "POST",
  headers: { "Authorization": nostrAuth("POST", url, body), "Content-Type": "application/json" },
  body,
});
console.log(await res.json());

อ่านการตั้งค่า

GET https://nymbot.ai/api/v1/nwc-auto-topup ใบสมัคร

ส่งกลับวัตถุเดียวกันกับการเชื่อมต่อด้วย connected: false และสาขาอื่น ๆ null เมื่อไม่มีกระเป๋าสตางค์ที่เชื่อมต่อ เชือกการเชื่อมต่อเองจะไม่ถอนคืน

cURL

URL=https://nymbot.ai/api/v1/nwc-auto-topup
curl "$URL" -H "Authorization: $(nostr_auth GET "$URL")"

Python

import requests

url = "https://nymbot.ai/api/v1/nwc-auto-topup"
print(requests.get(url, headers={"Authorization": nostr_auth("GET", url)}).json())

JavaScript

const url = "https://nymbot.ai/api/v1/nwc-auto-topup";
console.log(await (await fetch(url, { headers: { "Authorization": nostrAuth("GET", url) } })).json());

ปิดการเชื่อมต่อ

DELETE https://nymbot.ai/api/v1/nwc-auto-topup/connection ใบสมัคร

ลบลําดับการเชื่อมต่อที่บันทึกไว้ ไม่มีการเพิ่มขึ้นอีกต่อไป เพื่อให้แน่ใจคุณยังสามารถยกเลิกการเชื่อมต่อในกระเป๋าสตางค์ของคุณ

คําตอบ

{ "data": { "connected": false, "threshold_sats": null, "topup_sats": null, "tier": null, "last_topup_at": null, "last_topup_sats": null, "last_error": null } }

cURL

URL=https://nymbot.ai/api/v1/nwc-auto-topup/connection
curl -X DELETE "$URL" -H "Authorization: $(nostr_auth DELETE "$URL")"

Python

import requests

url = "https://nymbot.ai/api/v1/nwc-auto-topup/connection"
print(requests.delete(url, headers={"Authorization": nostr_auth("DELETE", url)}).json())

JavaScript

const url = "https://nymbot.ai/api/v1/nwc-auto-topup/connection";
const res = await fetch(url, { method: "DELETE", headers: { "Authorization": nostrAuth("DELETE", url) } });
console.log(await res.json());

การชําระเงินตามคําขอโดยไม่มีกุญแจ

จุดสิ้นสุดราคาคงที่สามารถจ่ายได้สําหรับคําขอหนึ่งครั้งตลอดเวลาโดยไม่มีกุญแจไม่มีบัญชีและไม่มีสมดุล: POST /images/generations, POST /images/edits, POST /videos, POST /audio/speech, POST /audio/transcriptions, POST /audio/translations และ POST /embeddingsแชท คําตอบ และข้อความต้องมีกุญแจเสมอ คําขอที่มีกุญแจจะถูกเรียกเก็บเงินเข้าสู่สมดุลตามปกติ กระแสการชําระเงินจะเริ่มเมื่อไม่มีกุญแจที่ถูกส่ง

Nymbot พูดสองรุ่นของความคิดเดียวกันจากด้านหลังหนึ่ง: Lightning Labs ล402 (ยังยอมรับภายใต้ชื่อเก่าของมัน LSAT) และโครงการ IETF การชําระเงิน แผนการรับรอง HTTP กับ lightning วิธีการและ charge intention. ใช้สิ่งที่ลูกค้าเข้าใจ

ดําเนินเซิร์ฟเวอร์ของคุณเอง

การชําระเงินโดยไม่มีกุญแจจะเปิดเฉพาะเมื่อ API_L402_SECRET มีอย่างน้อย 32 บิตแบบสุ่มเช่น hex (64 ตัวอักษร) หรือ base64 openssl rand -hex 32หมายเลขที่สั้นหรือคาดเดาได้ปิดฟังก์ชั่นและบันทึกเหตุผล เพื่อหมุนคุณสามารถย้ายค่าเก่าไปยัง API_L402_SECRET_PREVIOUS สําหรับหนึ่งวัน: ใบรับรอง URL สถานะและท้าทายที่ทําภายใต้มันยังคงทํางานจนกว่าจะหมดอายุ

ความท้าทาย

ส่งคําขอด้วย No Authorization header หากถูกต้องไม่มีอะไรทํางานและคุณจะได้รับ 402 Payment Required ด้วยใบแจ้งหนี้สําหรับค่าใช้จ่ายที่ร้องขอ: ราคาเดียวกันที่กุญแจจะจ่ายแปลงที่ 10 sats เครดิตมาตรฐานหรือ 100 sats เครดิต Pro และกลมกลมขึ้นไปทั้ง sat (อย่างน้อย 1 sat และอย่างน้อย 0.05 เครดิตต่ําสุด) คําตอบมีสาม WWW-Authenticate ความท้าทายสําหรับบัญชีเดียวกัน:

HTTP/1.1 402 Payment Required
Content-Type: application/problem+json; charset=utf-8
Cache-Control: no-store
WWW-Authenticate: L402 macaroon="AgJC...", invoice="lnbc2370n1..."
WWW-Authenticate: LSAT macaroon="AgJC...", invoice="lnbc2370n1..."
WWW-Authenticate: Payment id="kM9x...", realm="nymbot", method="lightning", intent="charge",
    request="eyJhbW91bnQiOiIyMzciLC...", description="Nymbot API POST /images/generations (237 sats)",
    digest="sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:", expires="2026-09-30T12:15:00.000Z",
    opaque="eyJlbmRwb2ludCI6IlBPU1QgL2ltYWdlcy9nZW5lcmF0aW9ucyJ9"

{
  "type": "https://paymentauth.org/problems/payment-required",
  "title": "Payment Required",
  "status": 402,
  "detail": "This request costs 237 sats. Pay the Lightning invoice, then send the identical request again ...",
  "challengeId": "kM9x...",
  "amount_sats": 237,
  "invoice": "lnbc2370n1...",
  "payment_hash": "9db1370f...",
  "expires_at": "2026-09-30T12:15:00.000Z",
  "error": { "message": "This request costs 237 sats. ...", "type": "payment_required", "code": "payment_required", "param": null }
}

การชําระเงิน request พารามิเตอร์ base64url JSON: {"amount":"237","currency":"sat","methodDetails":{"invoice":"lnbc...","network":"mainnet","paymentHash":"..."}}.

ความท้าทายที่เชื่อมโยงกับจุดสิ้นสุด Content-Type (ประเภทสื่อและสําหรับหลายส่วนขอบเขตของมัน) และไปยัง SHA-256 ของตัวอักษรร่างกายที่แน่นอนที่คุณส่งและใช้เวลา 15 นาที หลังจากชําระเงินส่ง เคล็ดลับ คําขออีกครั้ง: เดียวกัน Content-Type และตัวอักษร JSON เดียวกันหรือสําหรับจุดปลายส่วนหลายส่วน (/images/edits, /audio/transcriptions, /audio/translations) ร่างกายหลายส่วนเดียวกันที่มีขอบเขตเดียวกัน ส่วนใหญ่ห้องสมุด HTTP เลือกขอบเขตใหม่ทุกครั้งที่พวกเขาเข้ารหัสแบบฟอร์มดังนั้นเข้ารหัสครั้งเดียวและส่งตัวอักษรเหล่านี้สองครั้ง

Each address can ask for 30 challenges per minute (an IPv6 address counts as its whole /64). Requests whose address is not known share a stricter 10 per minute, and there is a overall cap on the challenges Nymbot issues across all addresses; a request rejected before a challenge is made (ตัวอย่างเช่น with a body that is not valid JSON) does not count towards it. Beyond that the answer is 429 ด้วย Retry-After, ส่งก่อนที่ร่างกายจะถูกอ่าน จุดสิ้นสุดที่ชําระเงินที่เรียกร้องโดยไม่มีกุญแจหรือใบรับรองยังคํานึงถึงขีด จํากัด โดยทั่วไปของ 120 คําขอที่ไม่ได้รับการรับรองความถูกต้องต่อนาทีต่อที่อยู่ การรับรองจะถูกตรวจสอบก่อนที่ร่างกายจะถูกอ่านและคําขอที่ Content-Type ไม่ใช่ application/json (หรือ multipart/form-data สําหรับ uploads) ถูกปฏิเสธด้วย 415 และไม่เคยได้รับบัญชี

การบูรณาการจะถูกกําหนดราคาจากประมาณของโทเค็นในการป้อนข้อมูลด้วย margin 1.5 ครั้งเนื่องจากจํานวนจริงจะรู้จักหลังจากนั้น คุณจ่ายสําหรับโทเค็นที่ใช้แล้วและส่วนที่ไม่ได้ใช้ของการชําระเงินจะกลับมาเป็น การคืนเงิน token.

ส่งการชําระเงิน

จ่ายบัญชีด้วยกระเป๋าสตางค์ Lightning ใด ๆ กระเป๋าสตางค์ให้ภาพล่วงหน้า 64 ตัวอักษรหกเหลี่ยม จากนั้นส่งคําขอเดียวกันด้วยหนึ่งในเหล่านี้:

แผนหัวหน้า
ล402Authorization: L402 <macaroon>:<preimage> (LSAT ทํางานเช่นกัน)
การชําระเงินAuthorization: Payment <base64url JSON>ที่ JSON คือ {"challenge": {every parameter of the challenge, as sent}, "payload": {"preimage": "<hex>"}}

คําขอชําระเงินตอบอย่างแม่นยําเช่นเดียวกับคําขอที่ทําด้วยกุญแจ nymbot Object ไม่มีฟิลด์สมดุล: {"payment": "l402", "tier": "pro", "paid_sats": 237, "charged_sats": 237}และไม่มี X-Nymbot-Balance-Sats header. คําขอที่ชําระโดยใช้แผนการชําระเงินยังได้รับ Payment-Receipt header (base64url JSON กับ challenge id, การชําระเงิน hash as reference, status และ timestamp). คําขอชําระเงินไม่ได้เชื่อมโยงกับ nym ใด ๆ ดังนั้นพวกเขาจะไม่ปรากฏในประวัติการสอบถาม

สถานะเมื่อ
402 payment_already_usedการชําระเงินแต่ละครั้งมีค่าใช้จ่ายสําหรับคําขอหนึ่งคําตอบคือความท้าทายใหม่สําหรับคําขอนี้ดังนั้นลูกค้าที่แคชใบรับรองล่าสุด (เช่น lnget ทํา) เพียงแค่พืชอีกครั้ง
402 payment_mismatchcredential ได้รับการเผยแพร่สําหรับจุดปลายทางอื่น Content-Type หรือค่าใช้จ่ายน้อยกว่าคําขอนี้ตอนนี้ค่าใช้จ่าย การท้าทายใหม่สําหรับคําขอนี้มาพร้อมกับมัน; ถ้าการชําระเงินเล็กเกินไปสิ่งที่คุณจ่ายจะกลับมาเป็น การคืนเงิน token (refund_token และ refund_sats ในร่างกาย)
402 payment_expiredมากกว่า 15 นาทีผ่านไปตั้งแต่ความท้าทาย มีความท้าทายใหม่มาพร้อมกับมัน หากภาพล่วงหน้าแสดงให้เห็นว่าคุณจ่ายเงินแล้วสิ่งที่คุณจ่ายจะกลับมาเป็น การคืนเงิน token (refund_token และ refund_sats ในร่างกาย) หนึ่งครั้ง; การเชื่อมโยงจะถูกใช้แล้ว
401 invalid_preimageภาพล่วงหน้าไม่แฮชกับแฮชการชําระเงินของใบแจ้งหนี้ การชําระเงินไม่ได้ใช้จ่าย
401 invalid_payment_credentialใบรับรองผิดปกติถูกเปลี่ยนแปลงหลังจาก Nymbot ได้ออกหรือชื่อ hash การชําระเงิน Nymbot ไม่ได้ออกใบแจ้งหนี้ สําหรับ Macaron ที่มีคําเตือน Nymbot ไม่ทราบหรือมีคําเตือนที่ขัดแย้งจะถูกปฏิเสธ
429 rate_limit_exceededมากกว่า 30 ใบรับรองหรือคีย์ที่ไม่ได้รับการตรวจสอบมาจากที่อยู่อีเมลนี้ภายในหนึ่งนาทีหรือ token การคืนเงินหนึ่งครั้งถูกส่งมามากกว่า 60 ครั้งในนาที Retry-After.

cURL

BODY='{"model":"nano-banana","prompt":"a lighthouse at dusk","response_format":"b64_json"}'
URL=https://nymbot.ai/api/v1/images/generations

# 1. Get the challenge
CH=$(curl -s -D - -o /dev/null "$URL" -H "Content-Type: application/json" -d "$BODY" | grep -i '^www-authenticate: L402')
MAC=$(echo "$CH" | sed -E 's/.*macaroon="([^"]+)".*/\1/')
INVOICE=$(echo "$CH" | sed -E 's/.*invoice="([^"]+)".*/\1/')

# 2. Pay $INVOICE with your wallet and copy the preimage
PREIMAGE=...

# 3. Send the identical request with the credential
curl "$URL" -H "Content-Type: application/json" -H "Authorization: L402 $MAC:$PREIMAGE" -d "$BODY"

lnget

# lnget (Lightning Labs) pays L402 challenges from your own lnd node and retries for you
lnget -X POST -H "Content-Type: application/json" \
  -d '{"model":"nano-banana","prompt":"a lighthouse at dusk","response_format":"b64_json"}' \
  https://nymbot.ai/api/v1/images/generations

Python

import base64, json, re
import requests

url = "https://nymbot.ai/api/v1/images/generations"
body = json.dumps({"model": "nano-banana", "prompt": "a lighthouse at dusk", "response_format": "b64_json"}).encode()
headers = {"Content-Type": "application/json"}

challenge = requests.post(url, data=body, headers=headers)
assert challenge.status_code == 402
info = challenge.json()
print("Pay", info["amount_sats"], "sats:", info["invoice"])

preimage = pay_with_your_wallet(info["invoice"])  # 64 hex characters

# L402
mac = re.search(r'L402 macaroon="([^"]+)"', challenge.headers["WWW-Authenticate"]).group(1)
res = requests.post(url, data=body, headers={**headers, "Authorization": f"L402 {mac}:{preimage}"})
print(res.json()["nymbot"])

JavaScript

const url = "https://nymbot.ai/api/v1/images/generations";
const body = JSON.stringify({ model: "nano-banana", prompt: "a lighthouse at dusk", response_format: "b64_json" });
const headers = { "Content-Type": "application/json" };

const challenge = await fetch(url, { method: "POST", headers, body });
const www = challenge.headers.get("www-authenticate");

// The Payment scheme: echo every challenge parameter back with the preimage
const start = www.indexOf("Payment ");
const params = Object.fromEntries([...www.slice(start + 8).matchAll(/(\w+)="((?:[^"\\]|\\.)*)"/g)].map((m) => [m[1], m[2]]));
const { invoice } = JSON.parse(Buffer.from(params.request, "base64url").toString()).methodDetails;
const preimage = await payWithYourWallet(invoice);

const credential = Buffer.from(JSON.stringify({ challenge: params, payload: { preimage } })).toString("base64url");
const res = await fetch(url, { method: "POST", headers: { ...headers, Authorization: `Payment ${credential}` }, body });
console.log((await res.json()).nymbot, res.headers.get("payment-receipt"));

ลูกค้าสร้างขึ้นบน mppx ด้วยวิธีการ Lightning จะจัดการกับความท้าทายการชําระเงินด้วยตัวเอง แสดงให้เห็นถึงจุดสิ้นสุดและปล่อยให้พวกเขาจ่าย

วิดีโอ

การชําระเงิน POST /videos คําตอบ 202 เช่นเดียวกับ keyed one, plus a status_url: GET มันไม่มีกุญแจใด ๆ เพื่อติดตามงาน มันลงนามและทํางานเป็นเวลา 24 ชั่วโมงจนกว่างานจะถูกเก็บไว้

{
  "id": "vid_...",
  "status": "in_progress",
  "status_url": "https://nymbot.ai/api/v1/videos/vid_...?exp=1790000000&sig=...",
  "nymbot": {
    "payment": "l402", "tier": "pro", "paid_sats": 4800, "charged_sats": 4800,
    "refund_token": "REFUND-5E0B..."
  }
}

เก็บ refund_token จากคําตอบนี้: มันแสดงเฉพาะที่นี่ มันว่างเปล่าในขณะที่วิดีโอแสดง (GET /api/v1/l402/refunds คําตอบ "status": "pending"); หากการแสดงผลไม่ได้เรียกเก็บเงินแล้วการชําระเงินจะถูกวางไว้บนมัน URL สถานะจะแสดง refund_sats สําหรับงานที่ได้รับการคืนเงิน แต่ไม่เคย token ดังนั้นการแบ่งปัน URL สถานะไม่แบ่งปันการคืนเงิน การตรวจสอบ token ยังแก้ไขงานที่ไม่ประสบความสําเร็จที่ไม่มีใครสํารวจ

การคืนเงิน

หากคําขอชําระเงินล้มเหลวและผู้ให้บริการเรียกเก็บเงิน Nymbot สําหรับความพยายามการชําระเงินจะถูกเก็บไว้และข้อผิดพลาดกล่าวว่าเช่นนั้น charged_sats, เช่นเดียวกับคําขอที่คีย์ หากไม่ได้รับการเรียกเก็บเงินข้อผิดพลาดจะนําไปสู่ การคืนเงิน token ค่าใช้จ่ายที่คุณจ่าย:

{
  "error": {
    "message": "The image generator failed. Nothing was charged. Please try again. The 237 sats you paid are on refund token REFUND-...",
    "type": "api_error",
    "code": "upstream_error",
    "refund_token": "REFUND-0C15DBED145D59131BA70298A413ADEB3D9B9AB082C476EA70A5BD38FCA5DE6D",
    "refund_sats": 237,
    "refund_expires_at": "2026-10-30T12:00:00.000Z"
  }
}

ชิ้นส่วนที่ไม่ได้ใช้กลับไปในลักษณะเดียวกัน: ถ้าคุณขอภาพสองภาพและหนึ่งไม่สามารถเรียกเก็บเงินได้คําตอบที่ประสบความสําเร็จ nymbot วัตถุมีรหัสคืนเงินสําหรับสิ่งที่หายไป; การคัดลอกความยาวที่ไม่สามารถอ่านได้ก่อนจะถูกกําหนดราคาเป็นเวลานานที่สุดที่ไฟล์อาจเป็น (ไม่เกิน 30 นาที) และความแตกต่างกับความยาวที่แท้จริงจะกลับมาเป็นรหัสคืนเงิน; ถ้ามันกลายเป็นเวลานานกว่า 30 นาทีมันจะถูกปฏิเสธด้วย 413 และการชําระเงินทั้งหมดจะกลับมา การแทรกซ้อนกลับค่าใช้จ่ายที่คํานวณถือไว้แล้ว วิดีโอที่ล้มเหลวจะคืนค่าใช้จ่ายไปยัง token ของการส่งกลับ

รหัสคืนเงินเป็นรหัส 256 บิตแบบสุ่ม Nymbot เก็บฮับเท่านั้นและหมดอายุหลังจาก 30 วัน มันถือสมดุล sat และคุณสามารถ:

  • จ่ายด้วยมัน ส่ง Authorization: Bearer REFUND-… ในจุดสิ้นสุดใด ๆ ด้านบน ( SDK OpenAI ใช้มันเป็นคีย์ API ของมัน) ราคามาจาก token และสิ่งที่เหลือยังคงอยู่บนมัน (refund_token_sats ใน the nymbot วัตถุ) สัญลักษณ์ที่มีมูลค่าน้อยกว่าคําตอบที่ร้องขอ 402 refund_insufficient; การล้มเหลวที่ไม่ได้รับการเรียกเก็บเงินจะวาง sats กลับไปที่ token เดียวกัน
  • ตรวจสอบ GET /api/v1/l402/refunds ด้วย header เดียวกันกลับ {"sats": 237, "status": "open", "expires_at": "..."}.
  • หนึ่ง token สามารถใช้ได้สูงสุด 60 ครั้งต่อนาที
  • เปลี่ยนเป็น nym ป้อนมันลงใน แปลงของขวัญ ในแอป Nymbot หรือโทร POST /api/v1/l402/refunds/redeem ด้วย A ใบสมัครที่ลงนาม และ {"refund_token": "REFUND-...", "balance": "standard"} (หรือ "pro"). เครดิตทั้งหมดไปในสมดุล (10 sats แต่ละบนมาตรฐาน, 100 บน Pro); sats ที่ไม่ได้ทําให้เครดิตทั้งหมดอยู่บนโตเกนสําหรับคําขอ API

cURL

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

คําตอบ

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