Auf dieser Seite
Integrationsleitfaden
Entwicklerdokumentation
Rechnung erstellen, den Kunden zur Zahlungsseite schicken, nach der Zahlung einen signierten Webhook erhalten. Beginnen Sie mit den vier Schritten unten.
Was unterstützt wird
Das Gateway akzeptiert USDT und USDC. Diese Tabelle entspricht GET /v1/services, Stand 4. November 2026. Lesen Sie den aktuellen Katalog, bevor Sie Ihre Auswahl der Zahlungsmethoden bauen.
| Asset | Netzwerk | Bestätigungen |
|---|---|---|
| USDT | Tron | 20 |
| USDT | Ethereum | 12 |
| USDT | Solana | 32 |
| USDT | Polygon | 8 |
| USDT | Arbitrum | 12 |
| USDT | TON | 5 |
| USDC | Ethereum | 12 |
| USDC | Solana | 32 |
| USDC | Polygon | 8 |
| USDC | Base | 12 |
| USDC | Arbitrum | 12 |
Zahlungen sind verwahrt (custodial): Die Mittel gehen auf Adressen ein, die von der Plattform kontrolliert werden. Ihr Händlerguthaben ist der Betrag, den wir Ihnen schulden. Die separate Telegram-Wallet ist selbstverwahrt (non-custodial).
Einschränkungen
- Auszahlungen und Erstattungen sind noch nicht live:
GET /v1/servicesmeldetboundaries.livePayoutsundboundaries.liveRefundsalsfalse. - Eingehende Zahlungen werden nicht von einem KYT-Anbieter geprüft.
- Rechnungen, bei denen die Gebühren 20 % des Betrags übersteigen würden, werden mit
AMOUNT_BELOW_MINIMUMabgelehnt. - Kein vertragliches SLA.
Die Einstiegsgebühr beträgt 0,40 % plus Netzwerkgebühr. Fordern Sie ein Gebührenangebot an, um den Gesamtbetrag und den Mindestbetrag zu erfahren; siehe Preise.
Authentifizierung
Server-zu-Server-Aufrufe verwenden x-api-key. Projektschlüssel gelten nur für ein einzelnes Händlerprojekt. Bewahren Sie sie auf Ihrem Server auf.
Testschlüssel beginnen mit ncp_test_…, Live-Schlüssel mit ncp_live_…. Früher ausgestellte Schlüssel beginnen mit ncp_sandbox_; sie funktionieren weiterhin.
curl -sS "https://api.veilnebu.la/v1/balances" \
-H "x-api-key: $PROJECT_API_KEY"Schreibanfragen signieren
GET-Anfragen benötigen nur x-api-key. Jede mit einem Projektschlüssel authentifizierte POST-, PUT-, PATCH- und DELETE-Anfrage benötigt zusätzlich zwei Header, sonst antwortet die API mit 401 Invalid API signature:
x-ncp-timestamp: ISO-8601, höchstens 5 Minuten von der aktuellen Zeit entfernt.x-ncp-signature:hex(HMAC-SHA256(your API key, "<timestamp>.<METHOD>.<path incl. query>.<raw body>")).
Verwenden Sie Methoden in Großbuchstaben. Signieren Sie genau die Bytes, die Sie senden, einschließlich des Query-Strings im Pfad. Eine Anfrage ohne Body signiert einen leeren String. Die folgenden Helfer benötigen Ihren Projektschlüssel; der Shell-Helfer benötigt Bash, curl und OpenSSL, der Node.js-Helfer verwendet das native fetch.
export API_BASE_URL="https://api.veilnebu.la"
export PROJECT_API_KEY="ncp_test_…"
ncp() {
local method="$1" path="$2" body="" ts sig
shift 2
if [ "$#" -gt 0 ]; then body="$1"; shift; fi
ts=$(date -u +%Y-%m-%dT%H:%M:%S.000Z) || return
sig=$(printf '%s.%s.%s.%s' "$ts" "$method" "$path" "$body" |
openssl dgst -sha256 -hmac "$PROJECT_API_KEY" -hex) || return
sig=${sig##* }
if [ -n "$body" ]; then
curl -sS --request "$method" "$API_BASE_URL$path" \
-H "x-api-key: $PROJECT_API_KEY" \
-H "x-ncp-timestamp: $ts" -H "x-ncp-signature: $sig" \
-H "content-type: application/json" --data-binary "$body" "$@"
else
curl -sS --request "$method" "$API_BASE_URL$path" \
-H "x-api-key: $PROJECT_API_KEY" \
-H "x-ncp-timestamp: $ts" -H "x-ncp-signature: $sig" "$@"
fi
}Erste Rechnung erstellen
Erstellen Sie im Dashboard ein Projekt, kopieren Sie dessen API-Schlüssel und erstellen Sie eine Rechnung. Die Antwort enthält checkoutUrl: Leiten Sie Ihren Kunden dorthin.
ncp POST /v1/payments '{
"amountMinor":"10000",
"currencyCode":"USD",
"settlementAssetCode":"USDT",
"externalId":"order-1001"
}' -H "idempotency-key: order-1001"Auszug aus der Antwort. Die ID wird für jede Rechnung neu erzeugt.
{
"id": "cm3k9x2f40001qz8e7h5v1abc",
"status": "new",
"amountMinor": "10000",
"currencyCode": "USD",
"settlementAssetCode": "USDT",
"checkoutUrl": "https://app.veilnebu.la/checkout/cm3k9x2f40001qz8e7h5v1abc"
}amountMinor ist ein ganzzahliger String in der kleinsten Einheit der Währung: 10000 = 100.00 USD. Das dezimale Feld amount wird nur vom Browser-Endpunkt /v1/public/payments akzeptiert.
Zahlung im Browser und erlaubte Origins
Erstellen Sie im Dashboard einen veröffentlichbaren Schlüssel und tragen Sie die exakten Origins ein, die Ihr Shop verwendet. Browser-Anfragen senden ihn als x-publishable-key an POST /v1/public/payments.
Origin, successUrl und cancelUrl müssen alle auf der Liste der erlaubten Origins des Schlüssels stehen. Ein Origin besteht aus Schema, Host und optionalem Port, ohne Pfad oder Platzhalter. Fehlende oder nicht eingetragene Origins werden abgelehnt.
Der Dezimalbetrag akzeptiert bei Fiatwährungen bis zu zwei Nachkommastellen und bei Kryptowährungen bis zur Anzahl der Dezimalstellen des jeweiligen Assets (USDT und USDC: 6 in allen Netzwerken, die wir derzeit unterstützen).
const response = await fetch('https://api.veilnebu.la/v1/public/payments', {
method: 'POST',
headers: {
'content-type': 'application/json',
'x-publishable-key': 'pk_test_…',
},
body: JSON.stringify({
amount: '100.00',
currencyCode: 'USD',
settlementAssetCode: 'USDT',
successUrl: 'https://shop.example/thanks',
cancelUrl: 'https://shop.example/cart',
}),
});
if (!response.ok) throw new Error(await response.text());
const invoice = await response.json();
window.location.assign(invoice.checkoutUrl);Zahlungsstatus
| Status | Nächster Schritt |
|---|---|
new | Zahlungslink teilen |
pending | Warten auf Zahlung |
confirming | Warten auf Bestätigungen |
paid | Abrechnung bereit |
partially_paid | Kunden bitten, die Zahlung abzuschließen |
overpaid | Gutgeschriebenen Mehrbetrag prüfen |
expired | Neue Rechnung erstellen |
cancelled | Keine Aktion erforderlich |
failed | Details öffnen |
refunded | Keine Aktion erforderlich |
Idempotenzschlüssel
Senden Sie bei der Rechnungserstellung einen stabilen Idempotency-Key, abgeleitet von Ihrer Bestell-ID. Eine Wiederholung mit demselben Schlüssel und Body liefert die ursprüngliche Rechnung zurück. Wird er mit einem anderen Body wiederverwendet, kommt 409 zurück. Lassen Sie Schlüssel und Body unverändert, wenn Sie nach einem Timeout erneut senden.
Die Anfrage finden Sie im Beispiel für die erste Rechnung.
Fehler
Fehler werden als JSON geliefert. message ist ein String oder bei Validierungsfehlern ein Array von Strings.
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Invalid API key"
}| HTTP-Status | Bedeutung und Maßnahme |
|---|---|
400 | Ungültiges Feld; "message" nennt das Feld. Korrigieren Sie es vor einer Wiederholung. |
401 | Invalid API key oder Invalid API signature. Prüfen Sie den Schlüssel, die signierten Bytes und den Zeitstempel. |
404 | Payment invoice not found. Prüfen Sie die ID und das Projekt. |
409 | Derselbe Idempotency-Key mit anderem Body oder Insufficient merchant payable balance. |
429 | Ratenlimit erreicht. Warten Sie vor einer Wiederholung. |
5xx | Mit demselben Idempotency-Key und Body wiederholen. |
Webhooks (HMAC-SHA256)
Jede Zustellung enthält x-nebula-signature: t=<unix>,v1=<hex>. Prüfen Sie den HMAC mit dem Endpunkt-Secret, das Sie beim Anlegen des Endpunkts erhalten haben. Lehnen Sie Zeitstempel ab, die mehr als 300 Sekunden von der aktuellen Zeit abweichen.
Prüfung in Node.js
Der Node.js-Verifier nutzt nur das integrierte crypto-Modul. Übergeben Sie ihm den Signatur-Header, die rohen Body-Bytes und das Endpunkt-Secret.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verify(header, rawBody, secret) {
const parts = {};
for (const piece of (header ?? '').split(',')) {
const separator = piece.indexOf('=');
if (separator <= 0) continue;
parts[piece.slice(0, separator).trim()] = piece.slice(separator + 1).trim();
}
if (!/^[0-9]{1,16}$/.test(parts.t ?? '')) return false;
if (!/^[0-9a-f]{64}$/.test(parts.v1 ?? '')) return false;
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
const expected = createHmac('sha256', secret)
.update(parts.t + '.')
.update(rawBody)
.digest('hex');
if (expected.length !== parts.v1.length) return false;
return timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}Prüfen Sie gegen den rohen Request-Body, vor dem JSON-Parsing. Die Zustellung erfolgt mindestens einmal: Deduplizieren Sie anhand von x-nebula-event-id, der mit eventId im Payload übereinstimmt. Automatische Wiederholungen behalten die Zustell-ID; ein manuelles erneutes Senden erzeugt eine neue Zustell-ID mit derselben Ereignis-ID. Speichern Sie das Ereignis, bevor Sie mit 2xx antworten.
Webhooks lokal testen
Webhook-URLs müssen einen öffentlichen Internet-Host verwenden. Lokale und private Adressen werden abgelehnt. Machen Sie Ihren Empfänger über einen öffentlichen HTTPS-Tunnel erreichbar und registrieren Sie dann dessen URL mit dem Signatur-Helfer.
ncp POST /v1/webhooks/endpoints '{
"url":"https://receiver.example/webhook",
"events":["payment.paid","payment.reorged"]
}'Ersetzen Sie die URL durch Ihren Empfänger. Speichern Sie das beim Anlegen zurückgegebene Endpunkt-Secret.
Ereignistypen
Auszahlungen und Erstattungen sind noch nicht live (GET /v1/services meldet boundaries.livePayouts als false). Bis dahin erfassen Auszahlungen und Auszahlungsstapel die Überweisung nur in Ihrem Guthaben; payout.completed und refund.completed bedeuten nicht, dass Mittel abgeflossen sind.
Der folgende Katalog entspricht GET /v1/services. Ein Katalogeintrag bedeutet nicht, dass die entsprechende Geldbewegung live ist.
| Ereignis | Bedeutung |
|---|---|
webhook. | Eine für einen Webhook-Endpunkt angeforderte Testzustellung. |
payment. | Der Kunde hat eine Zahlungsmethode gewählt; die erste Einzahlung steht aus. |
payment. | Einzahlung erkannt; Warten auf die erforderlichen Bestätigungen. |
payment. | Rechnung vollständig bezahlt und im Ledger verbucht. |
payment. | Weniger als angefordert erhalten; Warten auf den Rest. |
payment. | Mehr als angefordert erhalten; mit der Überzahlung im Ledger verbucht. |
payment. | Rechnung ohne ausreichende Mittel abgelaufen. |
payment. | Rechnung vor der Zahlung storniert. |
payment. | Zahlung wegen eines Chain-, Gebührenrichtlinien- oder Beobachtungsfehlers fehlgeschlagen. |
payment. | Hinweisendes Risikoereignis zu einer bereits gutgeschriebenen Einzahlung. Die KYT-Prüfung eingehender Zahlungen ist nicht live. |
payment. | Eine bestätigte Einzahlung ist durch eine Chain-Reorganisation entfallen; die Rechnung gilt nicht mehr als bezahlt, halten Sie die Auftragsabwicklung daher an oder machen Sie sie rückgängig. |
payment. | Ein nicht unterstützter Token wurde eingezahlt; er wurde nicht gutgeschrieben. |
payout. | Auszahlung in Bearbeitung. Echte Überweisungen sind nicht freigeschaltet. |
payout. | Auszahlung im Guthaben erfasst; das bedeutet nicht, dass Mittel abgeflossen sind. |
payout. | Auszahlung fehlgeschlagen. |
payout. | Auszahlung vor dem Abschluss storniert. |
refund. | Erstattung in Bearbeitung. Echte Erstattungen sind nicht freigeschaltet. |
refund. | Erstattung im Guthaben erfasst; das bedeutet nicht, dass Mittel abgeflossen sind. |
refund. | Erstattung fehlgeschlagen. |
internal_transfer. | Guthabenübertragung zwischen Händlern für den Absender verbucht. |
internal_transfer. | Guthabenübertragung zwischen Händlern dem Empfänger gutgeschrieben. |
static_wallet. | Für einen Kunden wurde eine langlebige Einzahlungsadresse erstellt. |
static_wallet. | Eine statische Wallet wurde gesperrt. |
static_wallet. | Die Sperre einer statischen Wallet wurde aufgehoben. |
static_wallet. | Eine Einzahlung auf eine statische Wallet wurde erkannt und im Ledger verbucht. |
dispute. | Zu einer Rechnung wurde ein Streitfall eröffnet. |
dispute. | Ein Streitfall wurde beigelegt. Die Beilegung allein belegt keine On-Chain-Erstattung. |
dispute. | Ein Streitfall wurde abgelehnt; vom Händler ist nichts zu tun. |
subscription. | Ein Abrechnungszyklus hat eine neue Rechnung erstellt. |
Wiederholungsrichtlinie
Wenn Ihr Endpunkt nicht mit 2xx antwortet, versuchen wir es insgesamt 8-mal: der erste Versuch, dann Wiederholungen nach 1 Minute, 5 Minuten, 30 Minuten, 2 Stunden, 6 Stunden, 12 Stunden und 24 Stunden. Jede Wartezeit beginnt nach dem vorangegangenen fehlgeschlagenen Versuch. Netzwerkfehler und Timeouts zählen ebenfalls als Fehlschläge. Testzustellungen haben einen Versuch.
Nach dem letzten Fehlschlag wird die Zustellung als fehlgeschlagen markiert; senden Sie sie mit POST /v1/webhooks/deliveries/{deliveryId}/resend erneut. Gleichen Sie ersatzweise mit GET /v1/payments/{id} ab.
Auszahlungen und Erstattungen sind noch nicht live (GET /v1/services meldet boundaries.livePayouts als false). Bis dahin erfassen Auszahlungen und Auszahlungsstapel die Überweisung nur in Ihrem Guthaben; payout.completed und refund.completed bedeuten nicht, dass Mittel abgeflossen sind.
Auszahlungsstapel
Ein Stapel fasst Überweisungsdatensätze zusammen. Seine Freigaberichtlinie und die Anzahl der erforderlichen Freigaben werden als approvalPolicy und approvalsRequired zurückgegeben. Bei mehreren Freigebenden kann der Ersteller seinen eigenen Stapel nicht freigeben. Ein einziger berechtigter Operator darf einen in seiner eigenen Sitzung erstellten Stapel freigeben. Geben Sie Stapel im Dashboard mit WebAuthn frei.
export PROJECT_API_KEY="ncp_test_…"
ncp POST /v1/payout-batches '{
"assetCode":"USDT",
"networkCode":"TRON",
"externalId":"batch-1001",
"items":[{
"destinationAddress":"T…",
"amountMinor":"15000000",
"externalRef":"recipient-1001"
}]
}' -H "idempotency-key: batch-1001"Ersetzen Sie das Ziel durch eine gültige Adresse in Ihrem eigenen Testprojekt.
Wiederkehrende Abrechnung
Ein Abonnement erstellt in jedem Abrechnungszyklus eine neue Rechnung und meldet sie mit subscription.invoice_created. Es belastet keine Kunden-Wallet automatisch. Senden Sie dem Kunden die neue URL der Zahlungsseite.
interval: DAY, WEEK, MONTH oder YEAR.
ncp POST /v1/subscriptions '{
"customerRef":"customer-42",
"assetCode":"USDT",
"networkCode":"TRON",
"amountMinor":"9000000",
"interval":"MONTH",
"intervalCount":1
}'Pausieren, fortsetzen oder kündigen Sie mit den Lebenszyklus-Operationen aus der API-Referenz.
Risikoprüfung
Ziele von Auszahlungen und Erstattungen werden vor dem Anlegen der Überweisung mit öffentlichen Sanktionslisten abgeglichen; ein Treffer führt zur Ablehnung der Anfrage. Eingehende Zahlungen werden nicht geprüft.
Telegram-Bot für Händler
@veilnebula_bot arbeitet jeweils mit einem Projekt. Verknüpfen Sie ihn in einem privaten Chat mit dem API-Schlüssel dieses Projekts. Der Bot versucht, Ihre Nachricht zu löschen, und speichert den Schlüssel verschlüsselt. Schlägt das Löschen fehl, widerrufen Sie den Schlüssel und ersetzen Sie ihn. Posten Sie einen Schlüssel niemals in einem gemeinsamen Chat.
Benachrichtigungen gelten für das verknüpfte Projekt und den aktiven Schlüssel. Öffnen Sie das Dashboard, um Auszahlungen freizugeben.
/link <API_KEY>
/balance
/invoices
/notify on
/unlink