API-Dokumentation

Cryptanio mit Ihrer Anwendung verbinden.

Vertrag v1 / 1.0.0 62 / 2026-10-10

Inhalt

Erste Schritte

API für Ihren Server. Zuerst Projekte, Dienste und Adresspools in Account konfigurieren; API führt darin schlüsselberechtigte Aktionen aus.

  1. Konto verifizieren und benötigten Dienst unter Meine Dienste aktivieren.
  2. Einen API-Schlüssel mit minimalen Berechtigungen erstellen und auf Ihrem Server aufbewahren.
  3. Wählen Sie Ihre Aufgabe: Adresse überwachen, Rechnung erstellen oder Ereignisse empfangen.

Beispiele führen echte Aktionen mit Live-Daten aus. Objekte erstellen oder löschen kann Dienstquoten verbrauchen. Schlüssel werden nie eingebettet, sondern aus Umgebungsvariablen gelesen.

Anweisungen für Ihren Agenten

Anweisung in Agentenchat oder Projektregeln einfügen. Sie hilft dem Agenten, Dienste, Preise und Referenz zu verstehen und dann eine REST-API- oder SDK-Integration zu schreiben. Der Agent kann in Ihrer Sprache antworten.

Integrationsanweisungen
Learn how to integrate a server-side application with Cryptanio's public REST API before proposing or writing integration code.

Start here:
- Website: https://cryptanio.com/
- Documentation index: https://cryptanio.com/llms.txt
- Product, services and pricing: https://cryptanio.com/cryptanio.md
- API integration index: https://cryptanio.com/docs/llms.txt
- API guide: https://cryptanio.com/docs.md
- Exact API v1 contract: https://cryptanio.com/openapi.json
- FAQ: https://cryptanio.com/faq/index.md
- SDK setup and examples: https://cryptanio.com/docs.html#sdk

Read the relevant method reference before using it. Use the public API at https://api.cryptanio.com/v1. Do not assume a public sandbox exists.
Use HTTP requests or the documented SDK for the application's language. Match request fields, response schemas and errors to OpenAPI; do not invent endpoints or SDK methods.
Check the actual enabled networks, service, project and API key permissions. Product documentation is not evidence of a live payment, balance or deployment.
Keep API keys in the user's server environment or secret store. Never ask the user to paste a key into chat or put it in a URL, browser bundle or log.
Default to reading. Create, change or delete objects only when the user authorizes the specific task. Explain quota or billing consequences before a write.
Follow the documented confirmation, webhook verification, pagination and retry rules. Reuse an invoice's original Idempotency-Key and request when retrying.
Show the returned chain, asset, address, amount and expiry. Preserve payment_route.kind and its exact string value: destination_tag, memo, comment or reference is mandatory when present. The merchant order reference is a separate field.
For a payment QR use the returned payment_uri when present. A Solana Pay reference is not a wallet memo; do not rebuild its URI or replace it with a plain address. Offer the exact returned checkout_url only to the payer; never construct a checkout URL from an invoice ID. Neither a checkout redirect nor a QR scan confirms payment.
Distinguish pending, confirmed, rolled-back and simulated data. If a fact is unavailable, say so instead of guessing.
Answer the user's questions in their language. If a necessary product decision is not documented, ask instead of inventing it.

Dieser Block enthält keine Schlüssel oder Kontodaten. API-Schlüssel mit minimalen Integrationsrechten nutzen und auf Anwendungsserver halten. Schlüssel nicht im Agentenchat teilen.

API-Referenz

Methoden: 16

Authentifizierung

Authorization: Bearer <API_KEY> von Ihrem Server senden. In Account → API-Schlüssel einen Schlüssel für Live-Daten erstellen, begrenzt auf benötigte Projekte und Aktionen. Derzeit keine öffentliche Sandbox.

Ein Schlüssel kann Lesezugriff, ausgewählte Aktionen, ein Projekt oder einen Dienst und bestimmte IP/CIDR-Bereiche erlauben. Ablauf, Pause und Widerruf beeinflussen ebenfalls den Zugriff. Zur Rotation einen Ersatzschlüssel mit passenden Beschränkungen erstellen, die Integration umstellen und den alten Schlüssel widerrufen. Schlüssel niemals in Browsercode, mobilen Apps oder URLs einbetten.

GeltungsbereichZweck
watchesMonitoring
eventsEreignisse und Zahlungen
invoicesPayments-Rechnungen
webhooksWebhook-Endpunkte
streamSSE

Beschränkungen gelten gemeinsam, nicht alternativ. 401 bedeutet Schlüssel nicht akzeptiert; 403 kann fehlende Rechte oder unzulässige IP bedeuten. Unzugängliche Ressourcen können 404 liefern. Siehe Fehler und Wiederholungen.

SDK: einsatzbereite Clients

Datei für Ihre Sprache herunterladen, auf dem Anwendungsserver speichern und dem Konstruktor Ihren Schlüssel übergeben. Jeder Client deckt alle 16 Methoden dieser Referenz ab. Es gibt kein npm-, PyPI-, Composer- oder crates.io-Paket: Die heruntergeladenen Dateien sind das SDK.

SpracheAnforderungenDatei
Node.jsNode.js 18+cryptanio.mjs
PythonPython 3.10+cryptanio.py
PHPPHP 8.1+ / cURLCryptanio.php
GoGo 1.22+cryptanio.go
RustRust 2021 / reqwest 0.12 / serde_json 1cryptanio.rs

Dateien teilen Release 1.0.0 62. Das Manifest enthält Version, Vertrag und SHA-256 jeder Datei. Zuerst CRYPTANIO_API_KEY und CRYPTANIO_PROJECT_ID in Umgebung setzen. Beispiele lesen nur Ereignisse, greifen aber auf Live-Kontodaten zu.

Node.js

Beispiel als .mjs neben cryptanio.mjs speichern.

Node.js
import { Cryptanio } from './cryptanio.mjs';
const key = process.env.CRYPTANIO_API_KEY;
const project = process.env.CRYPTANIO_PROJECT_ID;
if (!key || !project) throw new Error('Set API key and project ID');
const api = new Cryptanio(key);
const page = await api.listEvents({ project, limit: 25 });
console.log(page);

Um die Zahlungsdaten einer bestehenden Rechnung zu lesen, tragen Sie ihre ID in CRYPTANIO_RESOURCE_ID ein. Das Beispiel erhält das erforderliche payment_route, das zurückgegebene payment_uri für den QR-Code und das genaue checkout_url. Übergeben Sie das Ergebnis dem Zahler über Ihre Oberfläche, nicht über öffentliche Protokolle. Beträge bleiben Zeichenketten, fehlende Felder werden ausgelassen.

Node.js
import { Cryptanio } from './cryptanio.mjs';
const key = process.env.CRYPTANIO_API_KEY;
const invoiceID = process.env.CRYPTANIO_RESOURCE_ID;
if (!key || !invoiceID) throw new Error('Set API key and invoice ID');
const api = new Cryptanio(key);
const invoice = await api.getInvoice(invoiceID);
const payment = {
  chain: invoice.chain, asset: invoice.asset, address: invoice.address,
  amount: invoice.amount, expires_at: invoice.expires_at,
  payment_route: invoice.payment_route,
  payment_uri: invoice.payment_uri, checkout_url: invoice.checkout_url,
};
console.log(JSON.stringify(payment, null, 2));
Python

Beispiel als .py neben cryptanio.py speichern.

Python
import os
from cryptanio import Cryptanio
api = Cryptanio(os.environ['CRYPTANIO_API_KEY'])
page = api.list_events({
    'project': os.environ['CRYPTANIO_PROJECT_ID'], 'limit': 25
})
print(page)

Um die Zahlungsdaten einer bestehenden Rechnung zu lesen, tragen Sie ihre ID in CRYPTANIO_RESOURCE_ID ein. Das Beispiel erhält das erforderliche payment_route, das zurückgegebene payment_uri für den QR-Code und das genaue checkout_url. Übergeben Sie das Ergebnis dem Zahler über Ihre Oberfläche, nicht über öffentliche Protokolle. Beträge bleiben Zeichenketten, fehlende Felder werden ausgelassen.

Python
import json
import os
from cryptanio import Cryptanio
api = Cryptanio(os.environ['CRYPTANIO_API_KEY'])
invoice = api.get_invoice(os.environ['CRYPTANIO_RESOURCE_ID'])
payment = {field: invoice[field] for field in (
    'chain', 'asset', 'address', 'amount', 'expires_at',
    'payment_route', 'payment_uri', 'checkout_url'
) if field in invoice}
print(json.dumps(payment, ensure_ascii=False))
PHP

Beispiel als .php neben Cryptanio.php speichern; cURL-Erweiterung aktivieren.

PHP
<?php
require __DIR__ . '/Cryptanio.php';
$key = getenv('CRYPTANIO_API_KEY');
$project = getenv('CRYPTANIO_PROJECT_ID');
if (!$key || !$project) throw new RuntimeException('Set API key and project ID');
$api = new Cryptanio($key);
$page = $api->listEvents(['project' => $project, 'limit' => 25]);
echo json_encode($page, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR);

Um die Zahlungsdaten einer bestehenden Rechnung zu lesen, tragen Sie ihre ID in CRYPTANIO_RESOURCE_ID ein. Das Beispiel erhält das erforderliche payment_route, das zurückgegebene payment_uri für den QR-Code und das genaue checkout_url. Übergeben Sie das Ergebnis dem Zahler über Ihre Oberfläche, nicht über öffentliche Protokolle. Beträge bleiben Zeichenketten, fehlende Felder werden ausgelassen.

PHP
<?php
require __DIR__ . '/Cryptanio.php';
$key = getenv('CRYPTANIO_API_KEY');
$invoiceID = getenv('CRYPTANIO_RESOURCE_ID');
if (!$key || !$invoiceID) throw new RuntimeException('Set API key and invoice ID');
$api = new Cryptanio($key);
$invoice = $api->getInvoice($invoiceID);
$payment = array_intersect_key($invoice, array_fill_keys([
    'chain', 'asset', 'address', 'amount', 'expires_at',
    'payment_route', 'payment_uri', 'checkout_url'
], true));
echo json_encode($payment, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR);
Go

Datei in einem cryptanio/-Verzeichnis Ihres Go-Moduls ablegen. Beispiel nutzt Modul example.local/myapp; Importpfad durch eigenen Modulnamen ersetzen. Keine externen Abhängigkeiten nötig.

Go
package main

import (
    "context"
    "fmt"
    "os"
    "example.local/myapp/cryptanio"
)

func main() {
    key, project := os.Getenv("CRYPTANIO_API_KEY"), os.Getenv("CRYPTANIO_PROJECT_ID")
    if key == "" || project == "" { panic("Set API key and project ID") }
    api, err := cryptanio.New(key, "", 0)
    if err != nil { panic(err) }
    page, err := api.ListEvents(context.Background(), map[string]any{
        "project": project, "limit": 25,
    })
    if err != nil { panic(err) }
    fmt.Println(page)
}

Um die Zahlungsdaten einer bestehenden Rechnung zu lesen, tragen Sie ihre ID in CRYPTANIO_RESOURCE_ID ein. Das Beispiel erhält das erforderliche payment_route, das zurückgegebene payment_uri für den QR-Code und das genaue checkout_url. Übergeben Sie das Ergebnis dem Zahler über Ihre Oberfläche, nicht über öffentliche Protokolle. Beträge bleiben Zeichenketten, fehlende Felder werden ausgelassen.

Go
package main

import (
    "context"
    "encoding/json"
    "os"
    "example.local/myapp/cryptanio"
)

func main() {
    key, invoiceID := os.Getenv("CRYPTANIO_API_KEY"), os.Getenv("CRYPTANIO_RESOURCE_ID")
    if key == "" || invoiceID == "" { panic("Set API key and invoice ID") }
    api, err := cryptanio.New(key, "", 0)
    if err != nil { panic(err) }
    invoice, err := api.GetInvoice(context.Background(), invoiceID)
    if err != nil { panic(err) }
    payment := make(map[string]any)
    for _, field := range []string{
        "chain", "asset", "address", "amount", "expires_at",
        "payment_route", "payment_uri", "checkout_url",
    } {
        if value, ok := invoice[field]; ok { payment[field] = value }
    }
    if err := json.NewEncoder(os.Stdout).Encode(payment); err != nil { panic(err) }
}
Rust

Datei als src/cryptanio.rs, Beispiel als src/main.rs speichern. Folgende Abhängigkeiten zu Cargo.toml hinzufügen. Synchroner blockierender Client: nicht direkt in asynchronem Worker ausführen.

Cargo.toml
[dependencies]
reqwest = { version = "=0.12.24", default-features = false, features = ["blocking", "json", "rustls-tls"] }
serde_json = "=1.0.145"
Rust
mod cryptanio;
use cryptanio::Cryptanio;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = Cryptanio::new(&std::env::var("CRYPTANIO_API_KEY")?)?;
    let project = std::env::var("CRYPTANIO_PROJECT_ID")?;
    let page = api.list_events(&[("project", &project), ("limit", "25")])?;
    println!("{page}");
    Ok(())
}

Um die Zahlungsdaten einer bestehenden Rechnung zu lesen, tragen Sie ihre ID in CRYPTANIO_RESOURCE_ID ein. Das Beispiel erhält das erforderliche payment_route, das zurückgegebene payment_uri für den QR-Code und das genaue checkout_url. Übergeben Sie das Ergebnis dem Zahler über Ihre Oberfläche, nicht über öffentliche Protokolle. Beträge bleiben Zeichenketten, fehlende Felder werden ausgelassen.

Rust
mod cryptanio;
use cryptanio::Cryptanio;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api = Cryptanio::new(&std::env::var("CRYPTANIO_API_KEY")?)?;
    let invoice = api.get_invoice(&std::env::var("CRYPTANIO_RESOURCE_ID")?)?;
    let mut payment = serde_json::Map::new();
    for field in ["chain", "asset", "address", "amount", "expires_at",
                  "payment_route", "payment_uri", "checkout_url"] {
        if let Some(value) = invoice.get(field) {
            payment.insert(field.to_owned(), value.clone());
        }
    }
    println!("{}", serde_json::Value::Object(payment));
    Ok(())
}

Methoden aufrufen

Node.js und PHP nutzen listEvents, Python und Rust list_events, Go ListEvents. Jede Methode entspricht einer Anfrage in der Referenz. Filter sind Objekt/Map oder in Rust eine Paarliste. Go-Methoden nehmen immer zuerst context.Context. Unbekannte Filter werden vor dem Senden abgelehnt.

Node.js / PHP-MethodeHTTP
createWatchPOST /v1/watches
listWatchesGET /v1/watches
getWatchGET /v1/watches/{id}
deleteWatchDELETE /v1/watches/{id}
listEventsGET /v1/events
listPaymentsGET /v1/payments
createInvoicePOST /v1/invoices
listInvoicesGET /v1/invoices
getInvoiceGET /v1/invoices/{id}
cancelInvoicePOST /v1/invoices/{id}/cancel
createEndpointPOST /v1/endpoints
listEndpointsGET /v1/endpoints
deleteEndpointDELETE /v1/endpoints/{id}
streamEventsGET /v1/stream
getHealthGET /v1/health
listChainsGET /v1/chains

Überwachungs- und Webhook-Erstellung benötigen Anfrageinhalt. Einzelressourcen-Methoden nehmen Zeichenfolgen-ID. createInvoice(body, idempotencyKey) erfordert Schlüssel mit 16–80 ASCII-Zeichen: Buchstaben, Ziffern, Bindestriche oder Unterstriche. Bei Wiederholung gleichen Schlüssel und Inhalt nutzen; SDK erzeugt keine neuen Schlüssel und wiederholt nicht automatisch. Inhalte, Fehler und Rechte je Methodenseite prüfen.

Antworten, Fehler und Streaming

JSON-Antworten behalten Feldnamen; IDs, Beträge und Cursor bleiben Zeichenfolgen. Seitennavigation erfolgt manuell laut Methodenbeschreibung. Fehler liefern HTTP-Status, code, message und Retry-After. Ohne HTTP-Antwort ist status 0 (Rust nutzt None). Keine Weiterleitungen. Reguläre JSON-Antworten sind auf 8 MiB begrenzt. Standard-Timeout: 30 Sekunden, einstellbar bis 300. In Python gilt dies pro Netzwerkaktion; sonst für die gesamte Anfrage einschließlich Streaming. Timeout beweist keine nicht ausgeführte Schreibaktion.

Sprache / FehlerFelder
Node.js / Python: ApiErrorstatus, code, message, retry_after
PHP: CryptanioErrorstatus, apiCode, getMessage(), retryAfter
Go: *APIErrorStatus, Code, Message, RetryAfter
Rust: ApiErrorstatus: Option<u16>, code, message, retry_after

streamEvents liefert rohe SSE-Bytes ohne Wiederverbindung oder Ereignisparsing: Node.js ReadableStream, schließbare Python-HTTP-Antwort, Go io.ReadCloser oder Rust blocking::Response. Stream bei Nichtbedarf freigeben. PHP übergibt Blöcke an Callback; false beendet. Streaming ersetzt Webhooks nicht und garantiert kein Replay; siehe SSE-Regeln.

Ihre erste Überwachung

In Account ein Projekt mit aktivem Monitoring und einen Schlüssel mit watches- und events-Berechtigungen erstellen. Erforderliche Kontoverifizierung abschließen. Projekt-ID aus Einstellungen kopieren; nur tatsächlich gewünschte Adresse hinzufügen.

CRYPTANIO_API_KEY und CRYPTANIO_PROJECT_ID in Serverumgebung setzen. Beispieladresse durch eigene ersetzen. Anfrage legt echte Überwachung an; simuliert keine Transaktion.

Shell / cURL
#!/usr/bin/env bash
set -euo pipefail
: "${CRYPTANIO_API_KEY:?Set CRYPTANIO_API_KEY}"
: "${CRYPTANIO_PROJECT_ID:?Set CRYPTANIO_PROJECT_ID}"
json_string() {
  local text="$1" char code index output='"'
  for ((index=0; index<${#text}; index++)); do
    char="${text:index:1}"
    case "$char" in
      '"'|'\') output+="\\$char" ;;
      *) printf -v code '%d' "'$char"
         if ((code < 32)); then printf -v char '\\u%04x' "$code"; fi
         output+="$char" ;;
    esac
  done
  printf '%s"' "$output"
}
response_file="$(mktemp)"
trap 'rm -f "$response_file"' EXIT
transfer_status=0
http_status="$(curl \
  --silent --show-error --max-time 30 --request POST \
  --header "Authorization: Bearer $CRYPTANIO_API_KEY" \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data-binary '{"project":'"$(json_string "$CRYPTANIO_PROJECT_ID")"',"chain":"ethereum","address":"0x52908400098527886E0F7030069857D2E4169EE7","asset":"native","label":"Treasury"}' \
  "https://api.cryptanio.com/v1/watches" \
  --output "$response_file" --write-out '%{http_code}')" || transfer_status=$?
if [[ "$http_status" == 2?? ]]; then
  cat "$response_file"
  exit "$transfer_status"
fi
printf 'HTTP %s\n' "$http_status" >&2
cat "$response_file" >&2
exit 1

Eine erfolgreiche Antwort enthält id: speichern Sie diesen Wert. GET /v1/watches/{id} liefert die Überwachung und Einstellungen, keine Zahlungen. Erkannte Aktivitäten mit GET /v1/events, gefiltert nach watch_id, abrufen. Eine leere Liste vor der Transaktionserkennung ist normal. Antwort, Fehler und Beispiele in anderen Sprachen.

Payments-Rechnungen

Payments für Ihr Projekt aktivieren und unterstützte Adressen in Account zum Pool hinzufügen. project ausdrücklich senden, statt die Standardprojektauswahl zu nutzen. amount ist eine Zeichenfolge in Kryptoasset-Einheiten; invoice_currency/invoice_amount beschreiben separat den Angebotspreis Ihrer Bestellung.

CRYPTANIO_PROJECT_ID auf Payments-Projekt und CRYPTANIO_API_KEY auf Schlüssel mit invoices-Recht setzen. CRYPTANIO_OPERATION_ID muss für neue Bestellung eindeutig sein; bei derselben Aktion wiederverwenden. Rechnung wird in Live-Daten erstellt.

Shell / cURL
#!/usr/bin/env bash
set -euo pipefail
: "${CRYPTANIO_API_KEY:?Set CRYPTANIO_API_KEY}"
: "${CRYPTANIO_OPERATION_ID:?Set CRYPTANIO_OPERATION_ID}"
: "${CRYPTANIO_PROJECT_ID:?Set CRYPTANIO_PROJECT_ID}"
json_string() {
  local text="$1" char code index output='"'
  for ((index=0; index<${#text}; index++)); do
    char="${text:index:1}"
    case "$char" in
      '"'|'\') output+="\\$char" ;;
      *) printf -v code '%d' "'$char"
         if ((code < 32)); then printf -v char '\\u%04x' "$code"; fi
         output+="$char" ;;
    esac
  done
  printf '%s"' "$output"
}
response_file="$(mktemp)"
trap 'rm -f "$response_file"' EXIT
transfer_status=0
http_status="$(curl \
  --silent --show-error --max-time 30 --request POST \
  --header "Authorization: Bearer $CRYPTANIO_API_KEY" \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header "Idempotency-Key: $CRYPTANIO_OPERATION_ID" \
  --data-binary '{"project":'"$(json_string "$CRYPTANIO_PROJECT_ID")"',"invoice_currency":"USD","invoice_amount":"12.50","reference":"order-42"}' \
  "https://api.cryptanio.com/v1/invoices" \
  --output "$response_file" --write-out '%{http_code}')" || transfer_status=$?
if [[ "$http_status" == 2?? ]]; then
  cat "$response_file"
  exit "$transfer_status"
fi
printf 'HTTP %s\n' "$http_status" >&2
cat "$response_file" >&2
exit 1

Schlüssel muss invoices und Payments erlauben; Monitoring-Beispielschlüssel kann auf anderen Dienst begrenzt sein. Idempotency-Key enthält 16-80 ASCII-Buchstaben, Ziffern, - und _. Dieselbe normalisierte Anfrage mit gleichem Schlüssel liefert vorhandene Rechnung mit 201; geänderter Inhalt liefert 409 conflict. Aktionsschlüssel gelten kontoweit. reference ersetzt sie nicht.

Zeigen Sie dem Käufer das zurückgegebene Netzwerk, den Vermögenswert, die Adresse, amount und die Frist. Wenn payment_route vorhanden ist, übergeben Sie dessen kind und den genauen Zeichenkettenwert value: destination_tag, memo, comment oder reference ist nötig, um die Zahlung dieser Rechnung zuzuordnen. Das Bestellfeld reference ist davon getrennt.

Verwenden Sie das zurückgegebene payment_uri für den Zahlungs-QR-Code, falls vorhanden. Eine Solana-Pay-Referenz ist kein Wallet-Memo: Ersetzen Sie die URI nicht durch eine einfache Adresse und setzen Sie sie nicht neu zusammen. Kann die Wallet das erforderliche Zuordnungsmerkmal nicht übermitteln, bieten Sie dem Zahler checkout_url oder eine kompatible Wallet an.

checkout_url ist die gehostete Zahlungsseite für neue Rechnungen. Geben Sie nur die genau zurückgegebene URL an den Zahler weiter; bilden Sie sie nicht aus der ID. Der Link zeigt Zahlungsdetails und Status und gehört nicht in öffentliche Protokolle. Fehlt er, zeigen Sie die vollständigen Zahlungsdaten. Eine Browserweiterleitung bestätigt keine Zahlung: Prüfen Sie die API oder einen verifizierten Webhook.

asked kann zur Unterscheidung von Bestellungen von amount abweichen. Gleichen Sie mit amount_raw als Ganzzahl beliebiger Genauigkeit ab. Die Standard-TTL beträgt 60 Minuten, maximal 10080 Minuten. Rechnungslisten akzeptieren before, liefern aber kein next_before: Verwenden Sie die ID des letzten Elements und beenden Sie bei einer leeren Seite.

Customer

FeldTypErforderlichBeschreibung
idstringJaKundenkennung in Ihrem System.
maxLength: 120
Product

FeldTypErforderlichBeschreibung
idstringNeinProduktkennung in Ihrem System.
maxLength: 120
namestringNeinProduktname.
maxLength: 200
quantityintegerNeinMenge.
minimum: 1; maximum: 1000000
Payer

FeldTypErforderlichBeschreibung
commentstringJaKommentar des Zahlenden.
maxLength: 500
InvoiceMetadata

Bis zu 20 Paare, höchstens 8192 JSON-Bytes. Keine Geheimnisse einschließen.

object Bis zu 20 Paare, höchstens 8192 JSON-Bytes. Keine Geheimnisse einschließen.

Monitoring-Überwachungen

Eine Überwachung gehört zu einem Monitoring-Projekt. Dieselbe Adresse lässt sich in mehreren Projekten mit eigenen Richtungs- und Asset-Regeln verwenden. Adressbuchlisten und Address Sources in Account verbinden; diese REST API stellt deren Verwaltungsbefehle nicht bereit.

Liste nach absteigender ID. Falls next_before vorhanden, in nächster Anfrage als before senden, Projekt und Filter beibehalten. limit standardmäßig 50, höchstens 200. IDs als Zeichenfolgen speichern. Entfernte Überwachungen verlassen aktive Liste; Adresse bleibt in anderen Projekten und Adressbuch.

Ereignisse und Verlauf

/v1/events liefert dienstübergreifend für Schlüssel verfügbare Ereignisse; /v1/payments ist auf Payments begrenzt. Filter: project, address, chain, type, watch_id, tx_id. before ist ID-Cursor, kein Datum; kein from/to-Filter. next_before ruft nächste Seite ab.

Erkannte Ereignisse sind bis zu 30 Tage verfügbar. Dies ist kein Archiv aller zugestellten Nachrichten: notice und webhook.test sind darüber nicht garantiert wiederherstellbar. REST Event hat ein eigenes, von Webhooks getrenntes Schema; innerhalb von v1 können Felder hinzukommen.

Event

FeldTypErforderlichBeschreibung
event_idstringJaUndurchsichtige Kennung; als Zeichenfolge behalten.
minLength: 1
event_typestringJaEreignistyp; neue Typen können hinzukommen.
chainstringJaNetzwerkcode.
servicestringNeinDienst, falls bekannt.
watch_idstringNeinÜberwachungs-ID des Projekts, falls zugeordnet.
minLength: 1
occurred_atstringJaUTC-Datum und -Uhrzeit nach RFC 3339.
date-time
paymentobject | nullJaZahlungsdokument oder null bei Nichtzahlungsereignis. GET /events liefert keine contract/notice-Inhalte.
sandboxbooleanNeinTestereignis; ohne Angabe false.
EventPayment

REST/SSE-Zahlungsdokument. Felder hängen von Ereignis und Netzwerk ab; nicht das normalisierte Webhook-v1-Format.

FeldTypErforderlichBeschreibung
tx_idstringNeinTransaktionskennung.
indexintegerNeinÜberweisungsindex innerhalb der Transaktion.
minimum: 0
heightintegerNeinBlockhöhe, wenn bekannt.
minimum: 0
addressstringNeinBeobachtete Adresse.
assetstringNeinREST/SSE-Asset: Zeichenfolgenkennung, nicht das Webhook-Asset-Objekt.
amount_rawstringNeinGanzzahliger Betrag in kleinsten Einheiten als Zeichenfolge.
pattern: ^[0-9]+$
amountstringNeinExakter Dezimalbetrag als Zeichenfolge; keine Gleitkommazahlen verwenden.
pattern: ^[0-9]+(?:\.[0-9]+)?$
decimalsintegerNeinDezimalstellen.
minimum: 0
confirmationsintegerNeinBestätigungen.
minimum: 0
revisionintegerNeinRevision des Überweisungsstatus.
minimum: 0
directionstringNeinRichtung relativ zur beobachteten Adresse.
in, out
simulatedbooleanNeinSimuliertes Ereignis.
latebooleanNeinVerspätet erkannte Überweisung.
block_hashstringNeinBlockhash.
match_keystringNeinZuordnungskennung, sofern vom Netzwerk verwendet.
metaobjectNein
invoiceobjectNein
customerobjectNein
productobjectNein
payerobjectNein
metadataobjectNein

Webhook-Ereignisse

Zustellung erfolgt mindestens einmal: Ereignisse können mehrfach ankommen. Nach Signaturprüfung innerhalb der Integration anhand von event_id deduplizieren. Verarbeitung und Geschäftsänderung in einer Datenbanktransaktion speichern. tx_id/address/asset ersetzt event_id nicht: Dieser Schlüssel fasst verschiedene Übergänge, Richtungen und Projekte zusammen.

event_type und event_id aus dem signierten Inhalt lesen. X-Event-Type/X-Event-Id-Header sind nicht im HMAC enthalten; bei Nutzung mit Inhalt vergleichen. Beim Aktualisieren project_id, direction und payment.revision berücksichtigen. Zustellreihenfolge nicht voraussetzen; unbekannte Typen sicher ignorieren und zur Diagnose behalten.

FamilieInhalt
payment.pending / confirmed / rolled_backEingehende Zahlung
debit.pending / confirmed / rolled_backAusgehende Zahlung
contract.approval / owner_added / owner_removed / threshold_changed / permissions_changedcontract
asset.unexpectedcontract; Asset wird nicht als akzeptierte Zahlung gutgeschrieben
account.notice / account.notification / treasury.alarm / subscription.noticenotice.subject, notice.text
webhook.testSteuerungsereignis ohne Zahlung

schema_version: v1 enthält je nach Ereignistyp payment, contract oder notice; webhook.test nichts davon. IDs und Beträge sind Zeichenfolgen. amount_raw enthält kleinste Einheiten; amount eine Dezimaldarstellung. Netzwerke und Assets über chains prüfen. Vollständige Objektschemata in OpenAPI.

HeaderBedeutung
X-TimestampUnix-Sekunden zum Signaturzeitpunkt
X-Signaturehex HMAC-SHA256(timestamp + '.' + raw body)
X-Event-Id / X-Event-TypeMit dem signierten Inhalt vergleichen
X-AttemptVersuchsnummer ab 1

Nach dauerhafter Ereignisannahme 2xx zurückgeben. Versuchstimeout: 10 Sekunden. Netzwerkfehler, 408, 425, 429 und 5xx werden bis zu 24 Stunden wiederholt, mit Verzögerungen von 2 Sekunden bis 15 Minuten und Zufallsstreuung; Retry-After beachten. Keine Weiterleitungen. Andere 3xx/4xx beenden Zustellung; 410 deaktiviert Ziel und Rückstau.

Webhook-Formatbeispiel (illustrativ)
{
  "schema_version": "v1",
  "event_id": "2300",
  "event_type": "payment.confirmed",
  "occurred_at": "2026-10-06T10:00:00Z",
  "project_id": "1002",
  "service": "monitoring",
  "mode": "test",
  "sandbox": true,
  "payment": {
    "chain": "ethereum",
    "direction": "in",
    "asset": {
      "symbol": "ETH"
    },
    "address": "0x52908400098527886E0F7030069857D2E4169EE7",
    "tx_id": "simulated_2300",
    "index": 0,
    "amount": "1.000000000000000000",
    "amount_raw": "1000000000000000000",
    "decimals": 18,
    "confirmations": 0,
    "revision": 1,
    "simulated": true
  }
}
Webhook

Öffentlicher signierter Webhook-v1-Inhalt. payment.* und debit.* enthalten payment; contract.* und asset.unexpected enthalten contract; webhook.test hat keine Geschäftsdaten; account.notice, account.notification, treasury.alarm und subscription.notice enthalten notice. Zustellwiederholungen über event_id deduplizieren.

FeldTypErforderlichBeschreibung
schema_versionstringJaWebhook-Inhaltsversion.
v1
event_idstringJaEreignis-ID: unverändert bei Zustellwiederholungen. Verschiedene Zustände können verschiedene event_id haben.
minLength: 1
event_typestringJaTyp im signierten Inhalt; nach Signaturprüfung verwenden. Neue Typen können hinzukommen.
occurred_atstringJaUTC-Datum und -Uhrzeit nach RFC 3339.
date-time
project_idstringJaUndurchsichtige Kennung; als Zeichenfolge behalten.
minLength: 1
servicestringNeinProjektdienst, falls zutreffend.
modestringJaEreignismodus.
live, test
sandboxbooleanJaAusdrückliches Simulationskennzeichen.
paymentobjectNein
contractobjectNein
invoiceobjectNein
customerobjectNein
productobjectNein
payerobjectNein
metadataobjectNein
noticeobjectNein
WebhookPayment

FeldTypErforderlichBeschreibung
chainstringJaNetzwerkcode.
directionstringJaEingehende Zahlung: in; ausgehende Abbuchung: out.
in, out
assetobjectJa
addressstringJaBeobachtete Adresse.
tx_idstringJaTransaktions-ID.
indexintegerJaÜberweisungsindex; 0 nicht für jedes Netzwerk voraussetzen.
minimum: 0
heightintegerNeinBlockhöhe, falls bekannt.
minimum: 0
block_hashstringNeinBlockhash, falls bekannt.
match_keystringNeinNetzwerkspezifische Zuordnungskennung, falls zutreffend.
amountstringJaExakter Dezimalbetrag als Zeichenfolge; keine Gleitkommazahlen verwenden.
pattern: ^[0-9]+(?:\.[0-9]+)?$
amount_rawstringJaGanzzahliger Betrag in kleinsten Einheiten als Zeichenfolge.
pattern: ^[0-9]+$
decimalsintegerJaDezimalstellen.
minimum: 0
confirmationsintegerJaBestätigungen.
minimum: 0
revisionintegerJaRevision des Überweisungsstatus. Verschiedene event_id nicht anhand der Transaktionsidentität zusammenfassen.
minimum: 0
latebooleanNeinVerspätet erkannte Überweisung; nicht gleich dem Rechnungsstatus late.
simulatedbooleanNeinSimulierte Überweisung.
valuationobjectNein
WebhookAsset

FeldTypErforderlichBeschreibung
symbolstringNeinSymbol, falls bekannt; reicht nicht zur Tokenidentifizierung.
standardstringNeinTokenstandard, falls bekannt.
contractstringNeinTokenvertrag in seinem Netzwerk, falls zutreffend.
identifierstringNeinAndere netzwerkspezifische Tokenkennung.
WebhookContract

FeldTypErforderlichBeschreibung
chainstringJaNetzwerkcode.
addressstringJaBeobachtete Adresse oder Vertrag.
tx_idstringJaTransaktions-ID.
indexintegerJaEreignisindex.
minimum: 0
heightintegerNeinBlockhöhe.
minimum: 0
block_hashstringNeinBlockhash.
kindstringNeinArt der Änderung.
assetstringNeinKennung des betroffenen Assets, falls bekannt.
detailobjectNein
simulatedbooleanNeinSimuliertes Ereignis.
WebhookInvoice

FeldTypErforderlichBeschreibung
idstringJaUndurchsichtige Kennung; als Zeichenfolge behalten.
minLength: 1
referencestringNeinBestellreferenz.
statusstringNeinpending wartet auf Zahlung; seen erkannt; partial teilweise bezahlt; paid beglichen; underpaid/overpaid/late erfordern Entscheidung; expired Frist abgelaufen; canceled storniert.
pending, seen, paid, underpaid, partial, overpaid, expired, late, canceled
currencystringNeinWährung des Bestellangebots.
amountstringNeinExakter Dezimalbetrag als Zeichenfolge; keine Gleitkommazahlen verwenden.
pattern: ^[0-9]+(?:\.[0-9]+)?$
Notice

FeldTypErforderlichBeschreibung
subjectstringJaBetreff der Mitteilung.
textstringJaMitteilungstext.
Valuation

FeldTypErforderlichBeschreibung
currencystringJaBewertungswährung, etwa USD.
amountstringJaExakter Dezimalbetrag als Zeichenfolge; keine Gleitkommazahlen verwenden.
pattern: ^[0-9]+(?:\.[0-9]+)?$
ratestringJaAsset-Wechselkurs als Dezimalzeichenfolge.
pattern: ^[0-9]+(?:\.[0-9]+)?$
rate_atstringJaUTC-Datum und -Uhrzeit nach RFC 3339.
date-time
providerstringNeinName der Kursquelle, falls bekannt.

Signaturen prüfen

HMAC vor JSON-Parsing über ursprüngliche Inhaltsbytes einschließlich Leerzeichen und Zeilenumbrüchen prüfen. Frischeprüfung begrenzt Replay, ersetzt aber keine dauerhafte event_id-Deduplizierung. Beispiele akzeptieren nur Hexsignaturen mit 64 Zeichen und Zeitstempel innerhalb von 300 Sekunden der Serverzeit. Geheimnis des konkreten Webhook-Ziels nutzen.

Node.js
import { createHmac, timingSafeEqual } from "node:crypto";
import { TextDecoder } from "node:util";

// rawBody is the original HTTP request Buffer, before JSON.parse or serialization.
export function verifyWebhook(secret, timestamp, rawBody, signature, nowSeconds = Math.floor(Date.now() / 1000)) {
  if (typeof secret !== "string" || secret.length === 0 || !Buffer.isBuffer(rawBody) || rawBody.length === 0 ||
      typeof timestamp !== "string" || !/^(0|[1-9][0-9]*)$/.test(timestamp) ||
      typeof signature !== "string" || !/^[0-9a-f]{64}$/i.test(signature) ||
      !Number.isSafeInteger(nowSeconds) || nowSeconds < 0) return false;

  const signedAt = Number(timestamp);
  if (!Number.isSafeInteger(signedAt) || Math.abs(nowSeconds - signedAt) > 300) return false;

  const expected = createHmac("sha256", secret).update(timestamp).update(".").update(rawBody).digest();
  return timingSafeEqual(expected, Buffer.from(signature, "hex"));
}

// headers is Node.js request.headers (lowercase names). Optional X-Event-Id/Type
// headers are not signed separately; compare them with the verified body.
export function readSignedWebhook(secret, timestamp, rawBody, signature, headers = {}, nowSeconds) {
  if (!verifyWebhook(secret, timestamp, rawBody, signature, nowSeconds) ||
      headers === null || typeof headers !== "object" || Array.isArray(headers)) return null;

  let event;
  try {
    event = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(rawBody));
  } catch {
    return null;
  }
  if (event === null || typeof event !== "object" || Array.isArray(event) || event.schema_version !== "v1" ||
      typeof event.event_id !== "string" || event.event_id.length === 0 ||
      typeof event.event_type !== "string" || event.event_type.length === 0) return null;

  for (const [header, field] of [["x-event-id", "event_id"], ["x-event-type", "event_type"]]) {
    if (headers[header] !== undefined && headers[header] !== event[field]) return null;
  }
  return event;
}

Node.js-Beispiel herunterladen

Go
package webhook

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"strconv"
	"time"
	"unicode/utf8"
)

// VerifyWebhook checks the original HTTP body bytes before parsing JSON.
// Optional nowSeconds is used only for deterministic tests.
func VerifyWebhook(secret, timestamp string, rawBody []byte, signature string, nowSeconds ...int64) bool {
	if secret == "" || len(rawBody) == 0 || len(signature) != 64 || len(nowSeconds) > 1 {
		return false
	}
	signedAt, err := strconv.ParseInt(timestamp, 10, 64)
	if err != nil || signedAt < 0 || strconv.FormatInt(signedAt, 10) != timestamp {
		return false
	}
	now := time.Now().Unix()
	if len(nowSeconds) == 1 {
		now = nowSeconds[0]
	}
	if now < 0 || now-signedAt < -300 || now-signedAt > 300 {
		return false
	}
	provided, err := hex.DecodeString(signature)
	if err != nil || len(provided) != sha256.Size {
		return false
	}
	mac := hmac.New(sha256.New, []byte(secret))
	mac.Write([]byte(timestamp))
	mac.Write([]byte("."))
	mac.Write(rawBody)
	return hmac.Equal(mac.Sum(nil), provided)
}

// WebhookEvent contains only routing fields. Parse other fields from rawBody
// after ReadSignedWebhook succeeds; unknown fields are allowed.
type WebhookEvent struct {
	SchemaVersion string `json:"schema_version"`
	EventID       string `json:"event_id"`
	EventType     string `json:"event_type"`
}

// ReadSignedWebhook extracts event_id/type only from the verified body.
// X-Event-Id/Type are not signed separately; nonempty values must match the body.
func ReadSignedWebhook(secret, timestamp string, rawBody []byte, signature, eventIDHeader, eventTypeHeader string,
	nowSeconds ...int64) (*WebhookEvent, error) {
	if !VerifyWebhook(secret, timestamp, rawBody, signature, nowSeconds...) {
		return nil, errors.New("invalid webhook signature or timestamp")
	}
	var event WebhookEvent
	if !utf8.Valid(rawBody) || json.Unmarshal(rawBody, &event) != nil || event.SchemaVersion != "v1" ||
		event.EventID == "" || event.EventType == "" {
		return nil, errors.New("invalid webhook body")
	}
	if eventIDHeader != "" && eventIDHeader != event.EventID || eventTypeHeader != "" && eventTypeHeader != event.EventType {
		return nil, errors.New("webhook headers do not match the signed body")
	}
	return &event, nil
}

Go-Beispiel herunterladen

Webhook-Endpunkte

Eine öffentliche HTTPS-URL auf Port 443 für ein bestimmtes Projekt hinzufügen. Zugangsdaten, Fragmente, Weiterleitungen und nicht öffentliche Ziele sind unzulässig. Bis zu 20 Endpunkte pro Konto. Jeder hat ein eigenes Geheimnis, das nur bei der ersten Erstellung ausgegeben wird; auf Ihrem Server speichern.

Dieselbe URL für dasselbe Projekt und denselben Modus erneut erstellen liefert 200 und den vorhandenen Endpunkt ohne Geheimnis. Ein neuer Endpunkt liefert 201. DELETE liefert 200 mit id und deleted: true, auch bei sicherer Wiederholung. Ein Schlüssel sieht nur seinen Modus und erlaubte Projekte; Zustellung folgt den Projekteinstellungen.

SSE-Stream

SSE dient serverseitiger Integration und Live-Anzeige; keine Garantie für Zustellung oder Nachholung. Serverseitigen HTTP-Client mit Bearer-Header nutzen. Browser-EventSource kann diesen nicht senden; API-Schlüssel nicht in Browsercode oder Querystring setzen.

Nachrichten nutzen event: payment und eigenes StreamEvent-Format, nicht webhook v1 oder REST Event. Kommentare beginnen mit Doppelpunkt; Heartbeats etwa alle 20 Sekunden. retry: 5000 ist ein Wiederverbindungshinweis. Nach Trennung verfügbare Blockchain-Ereignishistorie über events abrufen.

StreamEvent

JSON in SSE data; unterscheidet sich von webhook v1. Nichtzahlungsereignisse lassen payment weg und können contract enthalten.

FeldTypErforderlichBeschreibung
event_idstringJaUndurchsichtige Kennung; als Zeichenfolge behalten.
minLength: 1
event_typestringJaEreignistyp; neue Typen können hinzukommen.
chainstringJaNetzwerkcode.
servicestringNeinDienst, falls bekannt.
watch_idstringNeinÜberwachungs-ID des Projekts, falls zugeordnet.
minLength: 1
occurred_atstringJaUTC-Datum und -Uhrzeit nach RFC 3339.
date-time
paymentobject | nullNeinZahlungsdokument oder null bei Nichtzahlungsereignis. GET /events liefert keine contract/notice-Inhalte.
sandboxbooleanNeinTestereignis; ohne Angabe false.
project_idstringNeinUndurchsichtige Kennung; als Zeichenfolge behalten.
minLength: 1
project_namestringNeinProjektname.
urlstringNeinLink zum Ereignis in Account.
uri
contractobjectNein
modestringNeinlive oder test.
live, test

Zahlungs- und Rechnungszustände

Blockchain-Zahlungsstatus und Bestellstatus unterscheiden sich. payment.pending bezeichnet Erkennung vor ausreichender Bestätigung; payment.confirmed bedeutet, dass die Bestätigungsregel des Netzwerks/Projekts erfüllt ist; payment.rolled_back meldet eine Rücknahme. Bestellungen nicht bei pending, ausgehenden Abbuchungen oder simulierten Ereignissen erfüllen.

RechnungBedeutung
pendingZahlung ausstehend
partialTeil erhalten; Teilzahlungsrichtlinie des Projekts gilt
paidZahlung akzeptiert
underpaidUnterzahlung erfordert Entscheidung
overpaidÜberzahlung erfordert Entscheidung nach geltender Richtlinie
lateZahlung nach Fristablauf erfordert Entscheidung
expiredZahlungsfrist abgelaufen
canceledRechnung storniert; Datensatz bleibt lesbar

needs_decision ist bei underpaid, overpaid und late vorhanden. In Account lösen. Reorg und erneute Aufnahme können neue Übergänge und neue payment.revision erzeugen; confirmed ist keine bedingungslose Garantie gegen künftige Änderungen.

Fehler und sichere Wiederholungen

application/json
{"error":{"code":"forbidden","message":"this API key is read-only"}}

HTTP-Status und error.code für Logik nutzen, message für Diagnose. Erfolgreiche Listen enthalten data; einzelne Objekte werden direkt geliefert. Health nutzt eigenes status/version-Schema, auch bei 503. Nicht auf exakten Nachrichtentext verlassen.

HTTPAktion
400JSON, Formate und Parameter korrigieren; nicht unverändert wiederholen
401Schlüssel, Ablauf, Pause und Widerruf prüfen
403Scopes, Lesen/Schreiben, Projekt, Dienst, IP und Kontoverifizierung prüfen
404ID, Schlüsselmodus und Zugriff prüfen; Einschränkungen können die Ressource verbergen
402Limit für Monitoring-Überwachungen; Tarif prüfen
409Konflikt, inaktiver Dienst, belegter Pool oder Limit; code prüfen
429Retry-After beachten; gemeinsame Anfragerate des Kontos reduzieren
500 / 503Mit begrenztem Backoff wiederholen; Rechnungserstellung nur mit ursprünglichem Idempotency-Key

Ein Timeout bedeutet nicht, dass die Aktion nicht ausgeführt wurde. Den Aktionsschlüssel einer Rechnung beim Wiederholen nicht ändern. Bei Methoden ohne Duplikatschutz zuerst den Zustand lesen; nicht jeder POST ist idempotent.

Netzwerke und Limits

chains auf gewähltem API-Host für Netzwerk-, Asset-, Funktions- und Bestätigungskatalog nutzen. Eintrag im allgemeinen Katalog garantiert weder Aktivierung in dieser Umgebung noch alle Aktionen. Dienstquoten und Budget in Account prüfen; Preise stehen unter Preise.

Authentifizierte REST-Quote pro Konto: 10 Anfragen/s ohne kostenpflichtigen Dienst, 50 mit kostenpflichtigem Dienst; kurzfristiger Burst: 20/100. Alle Kontoschlüssel und Modi teilen die Quote. Überschreitung liefert 429 mit Retry-After. Dienstquoten und API-Ratenlimits gelten separat.

Dienstpreise und Quoten

API-Versionen

Referenz beschreibt v1 in Release 1.0.0 62; aktualisiert 2026-10-10. Vor neuen Funktionen installiertes Release über GET /v1/health prüfen. Dokumentationsversion bestätigt kein Deployment.

Öffentliche APIVertrag
https://api.cryptanio.com/v1

/v1 für stabile Integrationen nutzen. Unversionierter Pfad wählt aktuellen stabilen Vertrag der Umgebung; unbekanntes /vN liefert 404. X-API-Version bezeichnet den Vertrag; X-Server-Version und health.version das Produktrelease, keinen anderen API-Vertrag.

OpenAPI 3.1 herunterladen

API-Änderungen

Release 1.0.0 62 enthält SDK-Downloads für Node.js, Python, PHP, Go und Rust sowie lokalen MCP für KI-Agenten. Referenz, Markdown und rohe HTTP-Beispiele bleiben separat verfügbar. Keine öffentliche Sandbox. API-Verhalten unverändert.

In v1 sollen Clients zusätzliche Antwortfelder tolerieren. Unbekannten Ereignistyp akzeptieren bedeutet keine Bestellerfüllung oder Zahlungsgutschrift. Änderungen vor Nutzung mit Version der gewählten Umgebung abgleichen.