콘텐츠로 건너뛰기
Nymbot로 돌아가기

지식 기반 개발자

균형, top-ups 및 keys

당신이 가지고있는 것을 확인하고, 번개를 넘어, 자동으로 자신의 지갑에서, 각 요청의 비용을 확인하고, 코드에서 키를 관리합니다.

균형을 확인하기

당신의 균형, 그리고이 키의 캡이 얼마나 사용되는지.

GET https://nymbot.ai/api/v1/credits/balance API 키가 필요합니다. POST 그것은 또한 그것을 기대하는 고객을 위해 작동합니다.

balance 현재 비트코인 가격에서 달러로 두 잔액이 함께 균형을 이루어지며, 단일 숫자를 기대하는 도구의 경우 (null 가격이 읽을 수없는 경우) 나머지는 크레딧과 sats로 이루어집니다.This is how the balances are actually kept. key 요청한 키를 설명합니다.cap에 도달한 키는 여전히 균형을 확인할 수 있습니다.A key that has reached its cap can still check the balance.

대답

{
  "balance": 49.18,
  "balance_sats": 42037,
  "standard": { "credits": 120.4, "sats": 1204 },
  "pro": { "credits": 408.33, "sats": 40833 },
  "key": {
    "id": "4f0c9a1be27d3856",
    "name": "laptop scripts",
    "limit_sats": 20000,
    "period_used_sats": 3412,
    "total_used_sats": 18230,
    "reset_period": "monthly",
    "reset_at": "2026-10-01T00:00:00Z"
  }
}
상태언제
401키가 누락되거나, 알려지지 않거나, 취소되거나 만료되었습니다.

cURL

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

Python

import os
import requests

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

JavaScript

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

지불 방법

어떻게 상승할 수 있는지, 그리고 한계.불빛은 유일한 방법이다.

GET https://nymbot.ai/api/v1/topup/payment-methods 열쇠가 필요하지 않습니다.

탑업은 10 ~ 1,000,000 sats입니다; Pro 탑업은 적어도 하나의 Pro 크레딧을 구입해야하므로 100 sats에서 시작됩니다. bulk_bonus 더 큰 탑업에 대한 추가 크레딧은 앱과 동일합니다 : 500, 1,000 또는 5,000 sats에서 표준 탑업에서 10%, 15% 또는 20% 더, 5,000, 10,000 또는 50,000 sats에서 Pro 탑업에서.

대답

{
  "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 위에 올라가기

열쇠가 소유하고있는 nym에 크레딧을 추가하는 Lightning 청구서를 만듭니다. 확인해 보세요 크레딧을 추가할 수 있습니다.

POST https://nymbot.ai/api/v1/topup/create/btc-lightning API 키가 필요합니다.

필드타입필요성설명서
amount숫자예얼마나 많은지, in currency전체 숫자로 값을 지불합니다.
currencyString아니오SATS (아무래도 부족한 부분은 USD 또는 BTC달러는 현재 Bitcoin 가격으로 변환됩니다.
tierString아니오pro (Default) 또는 standard: 어떤 균형으로 신용이 가는지.

표준 크레딧은 10 sats, 프로 크레딧은 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_small1억원 이상의 수익률(amount_too_large) 또는 Lightning 지갑에 의해 거부 (amount_out_of_range).
429이 주소에서 60 개 이상의 요금 청구서 또는 120 개 이상의 요금 청구서가 1 시간에 (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} - 청구서를 만든 nym에서 열쇠가 필요합니다.

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는 생성 호출의 64자 ID가 아닙니다.The id is not the 64-character ID from the create call.
404니가 니가 니가 니가 니가 니가 니가 니가 (invoice_not_found).

cURL

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

Python

import os, time
import requests

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

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

JavaScript

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

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

원하는 역사

요청 당 한 행 : 그것이 무엇이었는지, 어떤 모델이었는지, 얼마나 많은 토큰이 있고 비용이 얼마나 들었는지. 인스턴스 또는 응답이 보관되지 않으므로 아무것도 반환되지 않습니다. 라인은 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바이올린 (Query)아니오하나의 열쇠 : true 동일한 nym의 모든 키를 포함합니다.Default 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);

계좌 서명 요청

키 만들기, 변경 및 취소, 계정 요약 및 자동 탑업은 API 키를 가져 오지 않습니다.그들은 귀하의 nym에서 서명을 가져옵니다, 그래서 유출 된 키는 캡까지 지출 할 수 있지만 결코 다른 키를 만들거나 자신의 캡을 올릴 수 없습니다.

앱은 당신을 위해 이것을합니다 : 모든 것이 화재 Sheet은 이러한 엔드포인트를 사용합니다.당신은 자신의 코드에서 키를 관리하기 위해 이 섹션만 필요합니다.

서명은 유형 27235 (NIP-98)의 Nostr 이벤트이며, base64로 인코딩된 메시지로 전송됩니다. Authorization Header with the Word에 대한 리뷰 보기 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, 전송된 것과 동일합니다. is the full URL of the request, query string included, exactly as sent.
  • method 이것은 HTTP 방법입니다.
  • payload is the SHA-256 of the raw request body, in hex. 그것은 원본 요청체의 SHA-256입니다. POST 그리고 PATCH, 그리고 당신이 보내는 몸은 당신이 해시 한 것에 대하여 바이트가되어야합니다.
  • created_at 서버 시계의 60초 이내에 있어야 합니다.
  • 모든 이벤트는 한 번, a GET 캡처된 헤더를 재생할 수 없도록 포함되어 있습니다. 각 요청에 대해 새 헤더를 서명합니다. nonce 무작위 값으로 태그하여 동일한 초에 서명된 두 개의 요청이 여전히 다릅니다.
  • 서명된 요청의 몸체는 최대 64KB가 될 수 있으며, 몸체는 Content-Type: application/json.

실종된 이벤트가 돌아옵니다. 401 missing_nostr_auth나쁘게 형성된, 나쁘게 서명된, 너무 오래된, 또는 다른 URL, 방법 또는 신체를 반환하는 invalid_nostr_auth메시지에 있는 이유와 함께, 재사용한 하나는 반환한다. nostr_auth_replayed이 엔드포인트로 보낸 API 키는 거부됩니다.자체가 읽기 전에 서명은 확인되며 각 주소는 분당 30번 실패할 수 있습니다(IPv6 주소는 전체 /64로 계산됩니다). 429 와 Retry-After.

브라우저는 Nymbot의 자신의 사이트에서만 이러한 엔드포인트를 호출할 수 있습니다 (https://nymbot.ai, https://nymchat.app 다른 사이트의 페이지는 CORS 헤더를 다시 받지 않으므로 그들이 반환하는 것을 읽을 수 없습니다. Origin그들은 영향을 받지 않는다.

당신의 비밀 열쇠

서명은 귀하의 nym의 비밀 키 (the secret key)가 필요합니다. nsec모든 것을 제어 : 귀하의 정체성, 귀하의 역사 및 귀하의 균형.당신이 신뢰하는 기계에 스크립트에 그것을 넣어, 파일에 쓰기보다는 환경에서 그것을 읽고, 당신이 할 수있을 때 앱을 선호.

이 도우미는 헤더를 구축합니다.이 페이지의 나중 예제는 그들을 사용합니다.그들은 hex에서 비밀 키를 읽습니다. NOSTR_SECRET_HEXcURL one 를 사용하여 나이키 명령줄 도구는 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());

키 관리

응용 프로그램의 키 목록 뒤에 있는 엔드포인트.All of them need a 서명 요청각 키는 이 양식으로 반환되며, 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바이올린 (Query)아니오삭제된 키를 포함합니다.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 서명, 반환 201.

필드타입필요성설명서
nameString예1 ~ 40 문자, 다른 활성 키와 다릅니다 (무시 케이스).
limit_sats통합아니오지출 캡은 sats에, 적어도 1. cap을 위해 그것을 밖으로 두십시오.
reset_periodString아니오daily, weekly 또는 monthly필요성 limit_sats결코 재설정되지 않는 캡을 위해 그것을 남겨 두십시오.
expire_atstring 또는 integer아니오키가 작동 중지될 때: ISO 8601 시간 또는 1970년 이후의 밀리초.

대답하기 (201)

{
  "data": {
    "id": "4f0c9a1be27d3856",
    "name": "laptop scripts",
    "hint": "sk-nymbot-Qm7x…c2Lw",
    "limit_sats": 20000,
    "reset_period": "monthly",
    "key": "sk-nymbot-Qm7x...c2Lw",
    "...": "the rest of the key object"
  }
}
상태언제
400잃어버린 또는 너무 긴 이름; 이미 사용 중인 이름 (duplicate_name(최소 1의 전체 숫자가 아닌 캡; 캡이없는 재설정 기간; 과거에 만료; 알 수없는 필드)unknown_parameter); 또는 이미 25 개의 활성 키 (too_many_keys).
42960개 이상의 키가 이 니머에 의해 만들어졌거나 120개 이상의 키가 이 주소에서 1시간 만에 만들어졌습니다(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);

1 키 읽기

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 Auto-Top-Up 부근의 호텔

라이트닝 지갑을 Nostr Wallet Connect와 연결하면 API 지출이 낮을 때 Nymbot가 스스로 균형을 유지합니다. 서명 요청.

그것이 작동하는 방법 : API 요청이 시청하기로 선택한 잔액에 부과 된 후, 그 잔액이 당신의 한계 아래로 떨어졌을 경우, Nymbot은 당신의 상승 금액에 대한 청구서를 만듭니다, 지갑에 그것을 지불하도록 요청하고 신용을 추가합니다. 그것은 각 짐과 잔액에 대해 최대 5 분마다 한 번씩 상승합니다, 그래서 요청의 폭발이 지갑을 낭비 할 수 없습니다. 앱에서 지출하는 것은 그것을 유발하지 않습니다. 마지막 상승의 시간과 크기, 그리고 마지막 오류는 설정에 있습니다. TOP-UP 상태 그것을 신용합니다.

지갑을 연결하기 전에

Nymbot는 그것을 암호화로 저장하고 자신의 상단 청구서를 지불하기 위해 그것을 사용하지만 지갑에 지출 예산이 있으므로 가장 많이 지불 할 수있는 숫자가 당신을 선택합니다. pay_invoice.

지갑 연결하기

POST https://nymbot.ai/api/v1/nwc-auto-topup/connect 그리고 서명했다.

필드타입필요성설명서
nwc_urlString예연결 문자열, 시작 nostr+walletconnect://Nymbot은 지갑을 요청합니다.Nymbot asks the wallet for get_info 그것을 저장하기 전에, 그리고 그것을 암호화 저장합니다.
threshold_sats통합예잔액이 이 많은 sats 아래로 떨어지면 최소 1,000.
topup_sats통합예매번 얼마를 추가해야합니까? 1,000 ~ 1,000,000 sats.
tierString아니오pro (Default) 또는 standard: 균형을 지켜보고 탑을 올립니다.

대답

{
  "data": {
    "connected": true,
    "threshold_sats": 5000,
    "topup_sats": 20000,
    "tier": "pro",
    "last_topup_at": null,
    "last_topup_sats": null,
    "last_error": null
  }
}
상태언제
400링크 링크 링크 (invalid_nwc_url(그러나 그들은 그들의 지갑에 대해 대답하지 않았습니다.)nwc_unreachable) 또는 체크를 거부 (nwc_rejected(인터넷을 통해서 지불할 수 없음)nwc_missing_permission(또는 제한된 금액을 넘어서는 금액입니다.
501이 서버에서 자동 톱 업이 켜지지 않습니다 (nwc_unavailable) 다른 두 개의 끝점에 대해서도 마찬가지입니다.

cURL

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

Python

import json, os
import requests

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

JavaScript

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

Settings 읽기

GET https://nymbot.ai/api/v1/nwc-auto-topup 그리고 서명했다.

연결하는 것과 동일한 개체를 반환합니다.Returns the same object as connecting, with 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());

disconnect하기

DELETE https://nymbot.ai/api/v1/nwc-auto-topup/connection 그리고 서명했다.

저장된 연결 문자열을 삭제합니다.더 이상 탑업이 이루어지지 않습니다. 확실히, 당신은 또한 당신의 지갑에 연결을 취소할 수 있습니다.

대답

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

cURL

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

Python

import requests

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

JavaScript

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

열쇠 없이 요청에 따라 지불

고정 가격 엔드포인트는 Lightning를 통해 한 번에 한 번의 요청에 대해 열쇠, 계정 및 잔액없이 지불 할 수 있습니다. POST /images/generations, POST /images/edits, POST /videos, POST /audio/speech, POST /audio/transcriptions, POST /audio/translations 그리고 POST /embeddings채팅, 응답 및 메시지는 항상 열쇠를 필요로 합니다. 열쇠가 있는 요청은 평소처럼 잔액에 청구됩니다; 지불 흐름은 열쇠가 전송되지 않은 경우에만 시작됩니다.

Nymbot은 하나의 백엔드에서 같은 아이디어의 두 가지 버전을 말합니다 : 라이트닝 랩 L402 (또한 이전의 이름으로 받아들여진, LSAT) 및 IETF 프로젝트 지불 HTTP Authentication Scheme with the lightning 방법 및 charge 당신의 고객이 이해하는 것을 사용하십시오.

당신의 자신의 서버를 실행

키 없이 지불하는 것은 열릴 때만 가능합니다. API_L402_SECRET 최소 32 개의 무작위 바이트(64 문자) 또는 base64 (44)를 포함합니다. openssl rand -hex 32짧거나 추측할 수 있는 값이 기능을 끄고 이유를 로그인합니다. rotating it, move the old value to API_L402_SECRET_PREVIOUS 하루 동안 : 인증서, 상태 URL 및 그 아래에서 만든 도전은 만료 될 때까지 계속 작동합니다.

도전

No 요청을 보내기 Authorization header.If it is valid, nothing runs, and you get 402 Payment Required 그 요청 비용에 대한 청구서로 : 키가 지불 할 수있는 동일한 가격, 표준 크레딧 또는 프로 크레딧의 100 sats로 변환하고 전체 sat (적어도 1 sat, 적어도 0.05 크레딧 최소)로 둥글어집니다. WWW-Authenticate 동일한 계좌에 대한 도전 :

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

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

지불 request 예를 들어 base64url JSON은 다음과 같습니다. {"amount":"237","currency":"sat","methodDetails":{"invoice":"lnbc...","network":"mainnet","paymentHash":"..."}}.

도전은 최종점에 묶여 있으며, Content-Type (그의 미디어 유형과, 다중 부분의 경우, 그 경계) 그리고 SHA-256에 당신이 보낸 정확한 몸 바이트, 그리고 15 분 지속됩니다. 동일한 다시 요청 : 동일한 Content-Type 동일한 JSON 바이트, 또는 다중 부분 엔드포인트 (/images/edits, /audio/transcriptions, /audio/translations대부분의 HTTP 라이브러리는 양식을 인코딩할 때마다 새로운 경계를 선택하므로 한 번 인코딩하고 그 바이트를 두 번 보내십시오.

각 주소는 분당 30개의 도전을 요청할 수 있습니다 (IPv6 주소는 전체 /64로 계산됩니다). 주소가 알려지지 않은 요청은 분당 10개를 더 엄격하게 공유하며, 모든 주소에 걸쳐 Nymbot 문제에 대한 전반적인 제한이 있습니다. 429 와 Retry-After지불된 엔드포인트는 키나 자격 증명 없이 호출되며 또한 주소 당 1분당 120건의 일반 제한으로 계산됩니다. Content-Type 아니 아니야 application/json (또는 multipart/form-data 부정하는 자는 부정하는 자 415 그리고 결코 청구서를 받지 않는다.

삽입물은 입력에 있는 토큰의 예상으로, 실제 계산이 나중에 알 수 있기 때문에 1.5× 마진으로 가격을 설정합니다.You pay for the tokens actually used, and the unused part of the payment comes back as a 토큰 반환.

지불을 보내기

모든 라이트닝 지갑으로 청구서를 지불합니다. 지갑은 64 개의 헥스 캐릭터의 사전 이미지를 제공합니다.

계획헤더
L402Authorization: L402 <macaroon>:<preimage> (LSAT 또한 작동합니다)
지불Authorization: Payment <base64url JSON>JSON이 있는 곳 {"challenge": {every parameter of the challenge, as sent}, "payload": {"preimage": "<hex>"}}

유료 요청은 열쇠로 만든 요청과 마찬가지로 응답합니다.A paid request answers exactly like one made with a key, except that the nymbot Object에는 균형 필드가 없습니다: {"payment": "l402", "tier": "pro", "paid_sats": 237, "charged_sats": 237}, and there is no X-Nymbot-Balance-Sats header.A request paid with the Payment scheme also receives a Payment-Receipt 헤더 (base64url JSON with the challenge id, the payment hash as) reference, status 그리고 timestamp지불 요청은 어떤 nym에 묶여 있지 않으므로 쿼리 기록에 나타나지 않습니다.Paid requests are not tied to any nym, so they do not appear in the query history.

상태언제
402 payment_already_used각 지불은 하나의 요청에 대해 지불합니다.The response is a new challenge for this request, so a client that caches its last credential (as) lnget 단순히 다시 땅을
402 payment_mismatch다른 종료점에 대한 인증서가 발행되었으며, Content-Type 이 요청에 대한 새로운 도전은 그것과 함께 제공됩니다; 지불이 너무 작았다면, 당신이 지불 한 것은 반환됩니다. 토큰 반환 (refund_token 그리고 refund_sats 몸 안에 있음)
402 payment_expired도전 이후 15분이 넘는 시간이 흘렀습니다.새로운 도전이 함께 제공됩니다. 미리 이미지가 당신이 지불 한 것을 보여주면, 당신이 지불 한 것이 반환됩니다. 토큰 반환 (refund_token 그리고 refund_sats 한 번, 한 번; 그 후에 신용이 사용됩니다.
401 invalid_preimage사전 이미지는 청구서의 지불 해시에 해시되지 않습니다.
401 invalid_payment_credential신분증이 잘못 형성되었거나 Nymbot가 발행 한 후 변경되었거나 지불 해시 Nymbot가 청구서를 발행 한 적이없는 이름입니다.A macaroon with a caveat Nymbot does not know, or with conflicting caveats, is refused.
429 rate_limit_exceeded확인하지 못한 30개 이상의 인증서 또는 키가 1분 이내에 이 주소에서 나왔거나 1분 이내에 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 번개 방법을 사용하여 지불 도전을 스스로 처리하십시오; 그들을 최종 지점에 지시하고 지불하십시오.

비디오

A 지불 POST /videos 대답 202 마치 열쇠 하나처럼, 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..."
  }
}

유지하기 The refund_token 이 게시물을 즐겨찾기로 설정 9월 14일 (WEB 이 게시물을 즐겨찾기로 설정 9월 15일 (WEB 이 게시물을 즐겨찾기로 설정 9월 15일 (WEB 이 게시물을 즐겨찾기로 설정 9월 15일 (WEB 이 게시물을 즐겨찾기로 설정 9월 15일 (WEBGET /api/v1/l402/refunds 대답 "status": "pending"); 렌더링이 청구되지 않으면 지불이 그 위에 착륙합니다. refund_sats 환불된 작업을 위해, 그러나 토큰을 결코 공유하지 않으므로 상태 URL을 공유하면 환불이 공유되지 않습니다.

환불

지불 요청이 실패하고 공급자가 시도에 대해 Nymbot을 청구하면 지불이 유지되고 오류가 그렇게 말합니다. charged_sats실패하면 청구되지 않고 오류가 발생합니다.If it fails without being billed, the error carries a 토큰 반환 당신이 지불 한 가치 :

{
  "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 분을 초과하지 않음)에 대해 가격을 부과하고 실제 길이의 차이는 환불 토큰으로 반환됩니다. 413 그리고 전체 지불이 반환됩니다.Inbeddings는 예상치 않은 것을 반환합니다.A failed video refunds to the token its submission returned.

환불 토큰은 무작위 256-비트 코드입니다. Nymbot은 해시만 저장하고 30일 후에 만료됩니다.

  • 그것으로 지불하십시오. 보내기 Authorization: Bearer REFUND-… 위의 엔드포인트 중 어느 것이든 (OpenAI SDK는 이를 API 키로 사용합니다). 가격은 토큰에서 차감되며, 남은 금액은 토큰에 유지됩니다 (refund_token_sats 에서 The nymbot object).A token worth less than the request answers( 요청에 대한 응답보다 적은 가치가 있는 토큰) 402 refund_insufficient부정된 실패는 동일한 토큰에 sats를 다시 넣습니다.
  • 그것을 확인하라 GET /api/v1/l402/refunds 동일한 header로 반환 {"sats": 237, "status": "open", "expires_at": "..."}.
  • 1분에 최대 60번의 토큰을 사용할 수 있습니다.
  • 그것을 NIM로 옮기십시오. 그것을 넣어 넣어 선물 다시보기 Nymbot 앱에서, 또는 전화 POST /api/v1/l402/refunds/redeem 와 A 서명 요청 그리고 {"refund_token": "REFUND-...", "balance": "standard"} (또는 "pro"전체 크레딧은 잔액으로 이동합니다 (10 개의 스케이트 각 표준, 100 개의 프로); 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 } }