Native REST API
Die native API ist die eigene REST-Schnittstelle von blockwallets: Rechnungen in US-Cent, eine idempotente ref pro Bestellung, statische Einzahlungskonten für alle Netzwerke und mit HMAC-SHA256 signierte Webhooks. Sie erzeugt dieselben Rechnungen auf demselben gehosteten Checkout wie die Cryptomus-kompatible API, mit denselben Gebühren und demselben Guthaben.
Sie erzeugen Ihre Keys selbst im Dashboard unter „Entwickler › Integration & Keys“: einen Live- und einen Test-Key samt Webhook-Signaturgeheimnissen. Jedes wird nur einmal angezeigt; die Liste zeigt nur das Präfix. Ist für Ihr Konto die Zwei-Faktor-Authentifizierung aktiv, verlangt das Erzeugen oder Erneuern eines Live-Keys einen Code. Noch kein Händlerkonto? Zugang anfragen. Sie nutzen bereits Cryptomus? Sehen Sie sich die Cryptomus-kompatible API an (so wählen Sie).
Keys und Anfragen
Base-URL https://blockwallets.io. Anfragen und Antworten sind JSON. Jede Anfrage enthält:
Authorization: Bearer bw_live_…oderBearer bw_test_…: Das Präfix bestimmt den Modus, ein Test-Key sieht also nur Test-Rechnungen und läuft auf TestnetsContent-Type: application/jsonbeiPOST-Anfragen- Bewahren Sie Keys nur auf Ihrem Server auf, nie in einer Webseite oder App; wir speichern nur ihren Hash
Fehler liefern einen HTTP-Status und {"error": {"code": "…", "message": "…"}}: 400 invalid_request (ein Feld fehlt oder ist fehlerhaft), 401 unauthorized (Key fehlt, ist unbekannt oder deaktiviert), 404 not_found, 409 conflict (die Anfrage widerspricht dem aktuellen Zustand der Rechnung), 422 currency_unsupported.
Endpoints
| Endpoint | Was er tut |
|---|---|
GET /v1/networks | Netzwerke, die Sie im Modus dieses Keys gerade annehmen können: Mindestbetrag, Bestätigungen, übliche Ankunftszeit und Gebührenschätzung; bei Coins mit Kurs steht der aktuelle Kurs dabei |
POST /v1/invoices | Eine Rechnung erstellen (201) oder die bestehende zur selben ref zurückgeben (200) |
GET /v1/invoices?ref=… | Eine Rechnung über Ihre ref abfragen |
GET /v1/invoices/:id | Eine Rechnung über die id abfragen |
POST /v1/invoices/:id/network | Das Netzwerk einer Rechnung selbst wählen (White-Label-Checkout): liefert address und pay_amount zur Anzeige |
POST /v1/invoices/:id/close | Eine offene Rechnung schließen, bei der noch keine Überweisung gesehen wurde |
POST /v1/deposit-accounts | Das Einzahlungskonto eines Kunden öffnen (201) oder abrufen (200): eine dauerhafte Adresse in jedem Netzwerk |
GET /v1/deposit-accounts?customer_ref=… | Ein Einzahlungskonto über customer_ref abfragen |
GET /v1/deposit-accounts/:id | Ein Einzahlungskonto über die id abfragen |
GET /v1/deposits | Die Einzahlungen eines Kontos auflisten (account_id oder customer_ref, limit 1–200, Standard 50) |
GET /v1/deposits/:id | Eine Einzahlung abfragen |
GET /v1/events | Webhook-Zustellungen zu einer Rechnung oder Einzahlung (invoice_id oder deposit_id) |
POST /v1/events/:id/redeliver | Einen Webhook erneut senden (202) |
Hängen Sie ?probe=1 an eine Abfrage von Rechnung oder Einzahlungskonto, um dabei die Chain zu prüfen (höchstens alle 10 Sekunden); andernfalls erhalten Sie den letzten Stand unseres Scanners, der jede Minute prüft.
Rechnung erstellen POST /v1/invoices
Rufen Sie POST /v1/invoices auf, wenn der Kunde zur Kasse geht, und leiten Sie ihn auf pay_url aus der Antwort weiter.
curl -X POST https://blockwallets.io/v1/invoices \
-H "Authorization: Bearer $BW_KEY" -H "Content-Type: application/json" \
-d '{"ref":"order_1042","amount":4200,"title":"Order #1042",
"return_url":"https://shop.example/cart","success_url":"https://shop.example/thanks?order=1042",
"meta":{"user_id":42}}'| Feld | Pflicht | Beschreibung |
|---|---|---|
ref | Ja | Ihre Bestellnummer: 1–64 Zeichen aus Buchstaben, Ziffern und _ . : -. Pro Modus eindeutig; dieselbe ref mit denselben Feldern erneut zu senden liefert dieselbe Rechnung, mit anderen Feldern ergibt es 409 |
amount | Ja | Betrag in US-Cent als Ganzzahl: 4200 = $42.00. Nach der Netzwerkwahl nicht unter dem Mindestbetrag des Netzwerks |
title | Ja | Was der Kunde im Checkout sieht, bis zu 64 Zeichen |
return_url | Ja | Wohin „Zurück“ im Checkout führt; muss auf einer Ihrer Website-Domains liegen |
success_url | Nein | Wohin der Kunde nach der Zahlung geht; Standard ist return_url |
network | Nein | Eine Netzwerk-id aus der Netzwerktabelle vorauswählen; weglassen, damit der Kunde im Checkout wählt |
customer_ref | Nein | Ihre Kunden-id, bis zu 64 Zeichen, wird unverändert zurückgegeben |
lifetime | Nein | Lebensdauer in Sekunden, 600 – 43200, Standard 3600 |
amount_rule | Nein | "any" = alles gutschreiben, was ankommt (Aufladungen): paid, sobald bestätigt. Weggelassen gilt die „Betragsregel“ unter „Einstellungen › Zahlungsregeln & Gebühren“ im Dashboard |
accuracy_percent | Nein | Wie viel Unterzahlung noch als bezahlt gilt, 0 – 5 (Prozent), Standard 0 |
subtract_percent | Nein | Anteil der Plattformgebühr, den der Kunde zahlt, 0 – 100 (Prozent), wird zu pay_amount addiert; weggelassen gilt der Dashboard-Standard |
payment_multiple | Nein | Ob eine Unterzahlung an dieselbe Adresse nachgezahlt werden kann; Standard aus dem Dashboard (an, solange Sie es nicht geändert haben). false: Die erste zu geringe Überweisung endet als wrong_amount |
meta | Nein | Ein beliebiges JSON-Objekt bis 2 KB, wird in Abfragen und Webhooks unverändert zurückgegeben |
currency | Nein | Nur USD (Standard); alles andere ergibt 422 |
Jede URL muss auf einer Ihrer Website-Domains liegen (Dashboard → „Entwickler › Integration & Keys“). Die Antwort ist das unten beschriebene Rechnungsobjekt; network, address und pay_amount werden gefüllt, sobald ein Netzwerk gewählt ist.
Das Rechnungsobjekt
Ids beginnen mit inv_. amount ist in US-Cent; pay_amount und paid_amount sind Coin-Mengen als Dezimal-Strings im gewählten Netzwerk.
{
"id": "inv_01J8…",
"ref": "order_1042",
"mode": "live",
"status": "pending",
"amount": 4200,
"currency": "USD",
"title": "Order #1042",
"meta": { "user_id": 42 },
"network": null,
"address": null,
"pay_amount": null,
"paid_amount": null,
"payments": [],
"pay_url": "https://blockwallets.io/pay/inv_01J8…",
"return_url": "https://shop.example/cart",
"success_url": "https://shop.example/thanks?order=1042",
"created_at": "2026-11-03T08:00:00.000Z",
"expires_at": "2026-11-03T09:00:00.000Z",
"paid_at": null,
"closed_at": null
}| status | Bedeutung | Was Sie tun |
|---|---|---|
pending | Wartet auf Zahlung | — |
confirming | Eine Überweisung wurde gesehen und wird bestätigt, oder sie kam zu niedrig an und kann noch aufgestockt werden | — |
paid | Bezahlt | Bestellung versenden / gutschreiben |
paid_over | Bezahlt und überzahlt | Dasselbe; der Überschuss liegt in Ihrem Guthaben |
wrong_amount | Mit weniger als dem vollen Betrag beendet (bei Ablauf oder bei der ersten zu geringen Überweisung, wenn payment_multiple false ist) | Aufladungsgeschäfte können gutschreiben, was angekommen ist (paid_amount; bei Coins mit Kurs zusätzlich paid_cents); Shops bitten den Kunden, den Rest zu zahlen |
closed | Abgelaufen, ohne dass etwas eingegangen ist, oder von Ihnen geschlossen | — (später eingehendes Geld wird trotzdem gutgeschrieben und gemeldet) |
Weitere Felder: pay_url (der gehostete Checkout), payments (jede Überweisung mit txid, amount, confirmations und confirmed), expires_at, paid_at, closed_at; BTC, LTC, DOGE, BCH und native Coins haben außerdem rate (US-Dollar pro Coin, 30 Minuten fest), rate_locked_until und paid_cents (bisher eingegangen, in US-Cent).
Netzwerke
Übergeben Sie die id als network. GET /v1/networks liefert die in Ihrem Modus gerade offenen Netzwerke; ein Netzwerk kann pausiert sein, lesen Sie die Liste also lieber aus, statt Werte fest einzutragen.
| network | Coin | Chain | Minimum |
|---|---|---|---|
USDT_TRC20 | USDT | TRON | $1 |
USDT_BEP20 | USDT | BNB Chain | $1 |
USDC_BEP20 | USDC | BNB Chain | $1 |
USDT_ERC20 | USDT | Ethereum | $5 |
USDC_ERC20 | USDC | Ethereum | $5 |
USDC_BASE | USDC | Base | $1 |
USDT_POLYGON | USDT | Polygon | $1 |
USDC_POLYGON | USDC | Polygon | $1 |
USDT_ARBITRUM | USDT | Arbitrum | $1 |
USDC_ARBITRUM | USDC | Arbitrum | $1 |
USDT_OPTIMISM | USDT | Optimism | $1 |
USDC_OPTIMISM | USDC | Optimism | $1 |
USDT_AVALANCHE | USDT | Avalanche | $1 |
USDC_AVALANCHE | USDC | Avalanche | $1 |
USDT_XLAYER | USDT | X Layer | $1 |
USDC_XLAYER | USDC | X Layer | $1 |
USD1_BEP20 | USD1 | BNB Chain | $1 |
FDUSD_BEP20 | FDUSD | BNB Chain | $1 |
DAI_ERC20 | DAI | Ethereum | $5 |
DAI_ARBITRUM | DAI | Arbitrum | $1 |
DAI_BASE | DAI | Base | $1 |
BTC | BTC | Bitcoin | $5 |
LTC | LTC | Litecoin | $1 |
DOGE | DOGE | Dogecoin | $1 |
BCH | BCH | Bitcoin Cash | $1 |
TRX | TRX | TRON | $1 |
BNB | BNB | BNB Chain | $1 |
ETH | ETH | Ethereum | $5 |
ETH_BASE | ETH | Base | $1 |
ETH_ARBITRUM | ETH | Arbitrum | $1 |
ETH_OPTIMISM | ETH | Optimism | $1 |
POL | POL | Polygon | $1 |
AVAX | AVAX | Avalanche | $1 |
OKB | OKB | X Layer | $1 |
USDT_SOL | USDT | Solana | $1 |
USDC_SOL | USDC | Solana | $1 |
SOL | SOL | Solana | $1 |
USDT_TON | USDT | TON | $1 |
TON | TON | TON | $1 |
Einzahlungskonten (statische Adressen) POST /v1/deposit-accounts
POST /v1/deposit-accounts mit {"customer_ref": "user_42"} gibt diesem Kunden eine dauerhafte Adresse in jedem Netzwerk (alle EVM-Chains teilen sich eine Adresse). Alles, was er sendet, wird in US-Dollar gutgeschrieben, mit einem Webhook deposit.credited pro Überweisung.
curl -X POST https://blockwallets.io/v1/deposit-accounts \
-H "Authorization: Bearer $BW_KEY" -H "Content-Type: application/json" \
-d '{"customer_ref":"user_42"}'{
"id": "dac_01J8…",
"mode": "live",
"customer_ref": "user_42",
"deposit_url": "https://blockwallets.io/deposit/dac_01J8…",
"min_amount": 100,
"currency": "USD",
"networks": [
{ "id": "USDT_TRC20", "chain": "tron", "token": "USDT", "address": "TXy4…8kQ2", "min_amount": 100, "confirmations": 1, … },
{ "id": "USDC_BASE", "chain": "base", "token": "USDC", "address": "0x5aE1…", "min_amount": 100, "confirmations": 20, … }
]
}customer_ref: 1–128 Zeichen aus Buchstaben, Ziffern und_ . : @ -; derselbe Wert liefert immer dasselbe Konto. Optionalreturn_urlauf Ihren Domains- Die Antwort enthält
deposit_url(eine gehostete Seite mit Adressen, QR-Codes und letzten Einzahlungen) undnetworks(je Netzwerkid,address,min_amount,confirmations) - Einzahlungs-ids beginnen mit
dep_;amountsind US-Cent,amount_tokendie Coin-Menge, und Coins mit Kurs tragen den verwendetenrate
Überweisungen unter dem Mindestbetrag (meist $1, BTC $5) werden als below_min erfasst und nicht automatisch gutgeschrieben; kontaktieren Sie uns, damit sie gutgeschrieben werden.
Webhooks
Wir senden JSON per POST an die Webhook-URL im Dashboard („Entwickler › Integration & Keys“; Live und Test haben jeweils eigene URL und eigenes Secret). Der Body ist das Event:
POST /your/webhook
X-BW-Event: ev_01J8…
X-BW-Delivery: 1
X-BW-Signature: t=1793693052,v1=5f0c9b…
{"id":"ev_01J8…","type":"invoice.paid","created_at":"2026-11-03T08:04:12.000Z","invoice":{"id":"inv_01J8…","ref":"order_1042","status":"paid","amount":4200,…}}X-BW-Signature:t=<unix seconds>,v1=<hex>, wobeiv1= HMAC-SHA256(Webhook-Secret dieses Modus,t+.+ roher Body)X-BW-Event: die Event-id (ev_…); deduplizieren Sie darüberX-BW-Delivery: die Nummer des Versuchs, beginnend bei 1
| Event | Wann |
|---|---|
invoice.paid | Die Rechnung wurde paid oder paid_over (einschließlich Geld, das nach Ablauf ankam) |
invoice.wrong_amount | Die Rechnung endete als wrong_amount |
invoice.closed | Die Rechnung ist abgelaufen, ohne dass etwas einging, oder Sie haben sie geschlossen |
deposit.credited | Eine Überweisung an ein Einzahlungskonto wurde gutgeschrieben |
Prüfen Sie gegen den rohen Body, bevor Sie ihn parsen, lehnen Sie ein t ab, das mehr als 300 Sekunden von Ihrer Uhr abweicht, und vergleichen Sie in konstanter Zeit. invoice / deposit im Body ist dasselbe Objekt, das eine Abfrage liefert.
import crypto from "node:crypto";
// rawBody: the request body exactly as received (a string), header: X-BW-Signature
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.trim().split("=")));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return typeof parts.v1 === "string" && parts.v1.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}Eine 2xx-Antwort gilt als zugestellt; andernfalls wiederholen wir nach 1 Minute, 5 Minuten, 30 Minuten, 2 Stunden, 12 Stunden, 24 Stunden und 24 Stunden (insgesamt 8 Versuche).
Events und erneute Zustellung
GET /v1/events?invoice_id=inv_… (oder deposit_id=dep_…) listet die Webhooks einer Rechnung oder Einzahlung mit state, attempts, last_status und last_error. POST /v1/events/ev_…/redeliver reiht ihn sofort neu ein, zum Beispiel nachdem Sie Ihren Endpoint repariert haben. Die Seite „Entwickler › Webhook-Protokoll“ im Dashboard zeigt jeden Versuch mit Anfrage und Antwort.
Testmodus
Mit einem bw_test_-Key erstellte Rechnungen laufen auf Testnets und berühren nie echtes Geld. Der gehostete Checkout zeigt eine Schaltfläche „Zahlung simulieren“ (voll / halb / überzahlt), sodass Sie Status und Webhooks sehen, ohne Testnet-Coins zu besorgen.