Source: https://cryptanio.com/de/docs.html
Contract / release / updated: v1 / 1.0.0 62 / 2026-10-10

# API-Dokumentation

Cryptanio mit Ihrer Anwendung verbinden.

Vertrag v1 / 1.0.0 62 / 2026-10-10

[Markdown](https://cryptanio.com/de/docs.md) [OpenAPI](https://cryptanio.com/openapi.json) [Für KI-Agenten](https://cryptanio.com/docs/llms.txt)

## Erste Schritte

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

- Konto verifizieren und benötigten Dienst unter [Meine Dienste](https://account.cryptanio.com/finance/services) aktivieren.
- Einen [API-Schlüssel](https://account.cryptanio.com/api-keys) mit minimalen Berechtigungen erstellen und auf Ihrem Server aufbewahren.
- Wählen Sie Ihre Aufgabe: [Adresse überwachen](https://cryptanio.com/de/docs.html#quickstart), [Rechnung erstellen](https://cryptanio.com/de/docs.html#invoices) oder [Ereignisse empfangen](https://cryptanio.com/de/docs.html#webhooks).

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.



### Agent instructions

```text
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

### Monitoring-Überwachungen

[POST /v1/watches Monitoring-Überwachung erstellen](https://cryptanio.com/de/docs/reference/create-watch/) [GET /v1/watches Monitoring-Überwachungen auflisten](https://cryptanio.com/de/docs/reference/list-watches/) [GET /v1/watches/{id} Monitoring-Überwachung abrufen](https://cryptanio.com/de/docs/reference/get-watch/) [DELETE /v1/watches/{id} Monitoring-Überwachung löschen](https://cryptanio.com/de/docs/reference/delete-watch/)

### Ereignisse

[GET /v1/events Ereignisse auflisten](https://cryptanio.com/de/docs/reference/list-events/)

### Zahlungen

[GET /v1/payments Payments-Ereignisse auflisten](https://cryptanio.com/de/docs/reference/list-payments/)

### Rechnungen

[POST /v1/invoices Rechnung erstellen](https://cryptanio.com/de/docs/reference/create-invoice/) [GET /v1/invoices Rechnungen auflisten](https://cryptanio.com/de/docs/reference/list-invoices/) [GET /v1/invoices/{id} Rechnung abrufen](https://cryptanio.com/de/docs/reference/get-invoice/) [POST /v1/invoices/{id}/cancel Rechnung stornieren](https://cryptanio.com/de/docs/reference/cancel-invoice/)

### Webhook

[POST /v1/endpoints Webhook-Endpunkt erstellen](https://cryptanio.com/de/docs/reference/create-endpoint/) [GET /v1/endpoints Webhook-Endpunkte auflisten](https://cryptanio.com/de/docs/reference/list-endpoints/) [DELETE /v1/endpoints/{id} Webhook-Endpunkt löschen](https://cryptanio.com/de/docs/reference/delete-endpoint/)

### SSE

[GET /v1/stream Ereignisse streamen](https://cryptanio.com/de/docs/reference/stream-events/)

### API-Zustand

[GET /v1/health API-Zustand abrufen](https://cryptanio.com/de/docs/reference/get-health/)

### Netzwerke

[GET /v1/chains Netzwerke auflisten](https://cryptanio.com/de/docs/reference/list-chains/)

## Authentifizierung

`Authorization: Bearer <API_KEY>` von Ihrem Server senden. In [Account → API-Schlüssel](https://account.cryptanio.com/api-keys) 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.

| Geltungsbereich | Zweck |
| --- | --- |
| `watches` | Monitoring |
| `events` | Ereignisse und Zahlungen |
| `invoices` | Payments-Rechnungen |
| `webhooks` | Webhook-Endpunkte |
| `stream` | SSE |

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](https://cryptanio.com/de/docs.html#errors).

## 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.

| Sprache | Anforderungen | Datei |
| --- | --- | --- |
| Node.js | Node.js 18+ | [cryptanio.mjs](https://cryptanio.com/files/sdk/node/cryptanio.mjs) |
| Python | Python 3.10+ | [cryptanio.py](https://cryptanio.com/files/sdk/python/cryptanio.py) |
| PHP | PHP 8.1+ / cURL | [Cryptanio.php](https://cryptanio.com/files/sdk/php/Cryptanio.php) |
| Go | Go 1.22+ | [cryptanio.go](https://cryptanio.com/files/sdk/go/cryptanio.go) |
| Rust | Rust 2021 / reqwest 0.12 / serde_json 1 | [cryptanio.rs](https://cryptanio.com/files/sdk/rust/cryptanio.rs) |

Dateien teilen Release `1.0.0 62`. Das [Manifest](https://cryptanio.com/files/sdk/manifest.json) 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

```javascript
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

```javascript
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

```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

```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
<?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
<?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

```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

```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

```toml
[dependencies]
reqwest = { version = "=0.12.24", default-features = false, features = ["blocking", "json", "rustls-tls"] }
serde_json = "=1.0.145"
```



 

### Rust

```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

```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](https://cryptanio.com/de/docs.html#reference). 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-Methode | HTTP |
| --- | --- |
| `createWatch` | [POST /v1/watches](https://cryptanio.com/de/docs/reference/create-watch/) |
| `listWatches` | [GET /v1/watches](https://cryptanio.com/de/docs/reference/list-watches/) |
| `getWatch` | [GET /v1/watches/{id}](https://cryptanio.com/de/docs/reference/get-watch/) |
| `deleteWatch` | [DELETE /v1/watches/{id}](https://cryptanio.com/de/docs/reference/delete-watch/) |
| `listEvents` | [GET /v1/events](https://cryptanio.com/de/docs/reference/list-events/) |
| `listPayments` | [GET /v1/payments](https://cryptanio.com/de/docs/reference/list-payments/) |
| `createInvoice` | [POST /v1/invoices](https://cryptanio.com/de/docs/reference/create-invoice/) |
| `listInvoices` | [GET /v1/invoices](https://cryptanio.com/de/docs/reference/list-invoices/) |
| `getInvoice` | [GET /v1/invoices/{id}](https://cryptanio.com/de/docs/reference/get-invoice/) |
| `cancelInvoice` | [POST /v1/invoices/{id}/cancel](https://cryptanio.com/de/docs/reference/cancel-invoice/) |
| `createEndpoint` | [POST /v1/endpoints](https://cryptanio.com/de/docs/reference/create-endpoint/) |
| `listEndpoints` | [GET /v1/endpoints](https://cryptanio.com/de/docs/reference/list-endpoints/) |
| `deleteEndpoint` | [DELETE /v1/endpoints/{id}](https://cryptanio.com/de/docs/reference/delete-endpoint/) |
| `streamEvents` | [GET /v1/stream](https://cryptanio.com/de/docs/reference/stream-events/) |
| `getHealth` | [GET /v1/health](https://cryptanio.com/de/docs/reference/get-health/) |
| `listChains` | [GET /v1/chains](https://cryptanio.com/de/docs/reference/list-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 / Fehler | Felder |
| --- | --- |
| Node.js / Python: ApiError | `status, code, message, retry_after` |
| PHP: CryptanioError | `status, apiCode, getMessage(), retryAfter` |
| Go: *APIError | `Status, Code, Message, RetryAfter` |
| Rust: ApiError | `status: 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](https://cryptanio.com/de/docs.html#stream).

## 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

```bash
#!/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](https://cryptanio.com/de/docs/reference/create-watch/).

## 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

```bash
#!/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.

[POST /v1/invoices Rechnung erstellen](https://cryptanio.com/de/docs/reference/create-invoice/) [GET /v1/invoices Rechnungen auflisten](https://cryptanio.com/de/docs/reference/list-invoices/) [GET /v1/invoices/{id} Rechnung abrufen](https://cryptanio.com/de/docs/reference/get-invoice/) [POST /v1/invoices/{id}/cancel Rechnung stornieren](https://cryptanio.com/de/docs/reference/cancel-invoice/)

### `Customer`

| Feld | Typ | Erforderlich | Beschreibung |
| --- | --- | --- | --- |
| `id` | `string` | Ja | Kundenkennung in Ihrem System.; maxLength: `120` |

### `Product`

| Feld | Typ | Erforderlich | Beschreibung |
| --- | --- | --- | --- |
| `id` | `string` | Nein | Produktkennung in Ihrem System.; maxLength: `120` |
| `name` | `string` | Nein | Produktname.; maxLength: `200` |
| `quantity` | `integer` | Nein | Menge.; minimum: `1`; maximum: `1000000` |

### `Payer`

| Feld | Typ | Erforderlich | Beschreibung |
| --- | --- | --- | --- |
| `comment` | `string` | Ja | Kommentar 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.

[POST /v1/watches Monitoring-Überwachung erstellen](https://cryptanio.com/de/docs/reference/create-watch/) [GET /v1/watches Monitoring-Überwachungen auflisten](https://cryptanio.com/de/docs/reference/list-watches/) [GET /v1/watches/{id} Monitoring-Überwachung abrufen](https://cryptanio.com/de/docs/reference/get-watch/) [DELETE /v1/watches/{id} Monitoring-Überwachung löschen](https://cryptanio.com/de/docs/reference/delete-watch/)

## 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.

[GET /v1/events Ereignisse auflisten](https://cryptanio.com/de/docs/reference/list-events/) [GET /v1/payments Payments-Ereignisse auflisten](https://cryptanio.com/de/docs/reference/list-payments/)

### `Event`

| Feld | Typ | Erforderlich | Beschreibung |
| --- | --- | --- | --- |
| `event_id` | `string` | Ja | Undurchsichtige Kennung; als Zeichenfolge behalten.; minLength: `1` |
| `event_type` | `string` | Ja | Ereignistyp; neue Typen können hinzukommen. |
| `chain` | `string` | Ja | Netzwerkcode. |
| `service` | `string` | Nein | Dienst, falls bekannt. |
| `watch_id` | `string` | Nein | Überwachungs-ID des Projekts, falls zugeordnet.; minLength: `1` |
| `occurred_at` | `string` | Ja | UTC-Datum und -Uhrzeit nach RFC 3339.; `date-time` |
| `payment` | `object \| null` | Ja | Zahlungsdokument oder null bei Nichtzahlungsereignis. GET /events liefert keine contract/notice-Inhalte. |
| `sandbox` | `boolean` | Nein | Testereignis; ohne Angabe false. |

### `EventPayment`

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

| Feld | Typ | Erforderlich | Beschreibung |
| --- | --- | --- | --- |
| `tx_id` | `string` | Nein | Transaktionskennung. |
| `index` | `integer` | Nein | Überweisungsindex innerhalb der Transaktion.; minimum: `0` |
| `height` | `integer` | Nein | Blockhöhe, wenn bekannt.; minimum: `0` |
| `address` | `string` | Nein | Beobachtete Adresse. |
| `asset` | `string` | Nein | REST/SSE-Asset: Zeichenfolgenkennung, nicht das Webhook-Asset-Objekt. |
| `amount_raw` | `string` | Nein | Ganzzahliger Betrag in kleinsten Einheiten als Zeichenfolge.; pattern: `^[0-9]+$` |
| `amount` | `string` | Nein | Exakter Dezimalbetrag als Zeichenfolge; keine Gleitkommazahlen verwenden.; pattern: `^[0-9]+(?:\.[0-9]+)?$` |
| `decimals` | `integer` | Nein | Dezimalstellen.; minimum: `0` |
| `confirmations` | `integer` | Nein | Bestätigungen.; minimum: `0` |
| `revision` | `integer` | Nein | Revision des Überweisungsstatus.; minimum: `0` |
| `direction` | `string` | Nein | Richtung relativ zur beobachteten Adresse.; `in`, `out` |
| `simulated` | `boolean` | Nein | Simuliertes Ereignis. |
| `late` | `boolean` | Nein | Verspätet erkannte Überweisung. |
| `block_hash` | `string` | Nein | Blockhash. |
| `match_key` | `string` | Nein | Zuordnungskennung, sofern vom Netzwerk verwendet. |
| `meta` | `object` | Nein |  |
| `invoice` | `object` | Nein |  |
| `customer` | `object` | Nein |  |
| `product` | `object` | Nein |  |
| `payer` | `object` | Nein |  |
| `metadata` | `object` | Nein |  |

## 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.

| Familie | Inhalt |
| --- | --- |
| payment.pending / confirmed / rolled_back | Eingehende Zahlung |
| debit.pending / confirmed / rolled_back | Ausgehende Zahlung |
| contract.approval / owner_added / owner_removed / threshold_changed / permissions_changed | contract |
| asset.unexpected | contract; Asset wird nicht als akzeptierte Zahlung gutgeschrieben |
| account.notice / account.notification / treasury.alarm / subscription.notice | notice.subject, notice.text |
| webhook.test | Steuerungsereignis 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](https://cryptanio.com/openapi.json).

| Header | Bedeutung |
| --- | --- |
| X-Timestamp | Unix-Sekunden zum Signaturzeitpunkt |
| X-Signature | hex HMAC-SHA256(timestamp + '.' + raw body) |
| X-Event-Id / X-Event-Type | Mit dem signierten Inhalt vergleichen |
| X-Attempt | Versuchsnummer 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 shape example (illustrative)

```json
{
  "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.

| Feld | Typ | Erforderlich | Beschreibung |
| --- | --- | --- | --- |
| `schema_version` | `string` | Ja | Webhook-Inhaltsversion.; `v1` |
| `event_id` | `string` | Ja | Ereignis-ID: unverändert bei Zustellwiederholungen. Verschiedene Zustände können verschiedene event_id haben.; minLength: `1` |
| `event_type` | `string` | Ja | Typ im signierten Inhalt; nach Signaturprüfung verwenden. Neue Typen können hinzukommen. |
| `occurred_at` | `string` | Ja | UTC-Datum und -Uhrzeit nach RFC 3339.; `date-time` |
| `project_id` | `string` | Ja | Undurchsichtige Kennung; als Zeichenfolge behalten.; minLength: `1` |
| `service` | `string` | Nein | Projektdienst, falls zutreffend. |
| `mode` | `string` | Ja | Ereignismodus.; `live`, `test` |
| `sandbox` | `boolean` | Ja | Ausdrückliches Simulationskennzeichen. |
| `payment` | `object` | Nein |  |
| `contract` | `object` | Nein |  |
| `invoice` | `object` | Nein |  |
| `customer` | `object` | Nein |  |
| `product` | `object` | Nein |  |
| `payer` | `object` | Nein |  |
| `metadata` | `object` | Nein |  |
| `notice` | `object` | Nein |  |

### `WebhookPayment`

| Feld | Typ | Erforderlich | Beschreibung |
| --- | --- | --- | --- |
| `chain` | `string` | Ja | Netzwerkcode. |
| `direction` | `string` | Ja | Eingehende Zahlung: in; ausgehende Abbuchung: out.; `in`, `out` |
| `asset` | `object` | Ja |  |
| `address` | `string` | Ja | Beobachtete Adresse. |
| `tx_id` | `string` | Ja | Transaktions-ID. |
| `index` | `integer` | Ja | Überweisungsindex; 0 nicht für jedes Netzwerk voraussetzen.; minimum: `0` |
| `height` | `integer` | Nein | Blockhöhe, falls bekannt.; minimum: `0` |
| `block_hash` | `string` | Nein | Blockhash, falls bekannt. |
| `match_key` | `string` | Nein | Netzwerkspezifische Zuordnungskennung, falls zutreffend. |
| `amount` | `string` | Ja | Exakter Dezimalbetrag als Zeichenfolge; keine Gleitkommazahlen verwenden.; pattern: `^[0-9]+(?:\.[0-9]+)?$` |
| `amount_raw` | `string` | Ja | Ganzzahliger Betrag in kleinsten Einheiten als Zeichenfolge.; pattern: `^[0-9]+$` |
| `decimals` | `integer` | Ja | Dezimalstellen.; minimum: `0` |
| `confirmations` | `integer` | Ja | Bestätigungen.; minimum: `0` |
| `revision` | `integer` | Ja | Revision des Überweisungsstatus. Verschiedene event_id nicht anhand der Transaktionsidentität zusammenfassen.; minimum: `0` |
| `late` | `boolean` | Nein | Verspätet erkannte Überweisung; nicht gleich dem Rechnungsstatus late. |
| `simulated` | `boolean` | Nein | Simulierte Überweisung. |
| `valuation` | `object` | Nein |  |

### `WebhookAsset`

| Feld | Typ | Erforderlich | Beschreibung |
| --- | --- | --- | --- |
| `symbol` | `string` | Nein | Symbol, falls bekannt; reicht nicht zur Tokenidentifizierung. |
| `standard` | `string` | Nein | Tokenstandard, falls bekannt. |
| `contract` | `string` | Nein | Tokenvertrag in seinem Netzwerk, falls zutreffend. |
| `identifier` | `string` | Nein | Andere netzwerkspezifische Tokenkennung. |

### `WebhookContract`

| Feld | Typ | Erforderlich | Beschreibung |
| --- | --- | --- | --- |
| `chain` | `string` | Ja | Netzwerkcode. |
| `address` | `string` | Ja | Beobachtete Adresse oder Vertrag. |
| `tx_id` | `string` | Ja | Transaktions-ID. |
| `index` | `integer` | Ja | Ereignisindex.; minimum: `0` |
| `height` | `integer` | Nein | Blockhöhe.; minimum: `0` |
| `block_hash` | `string` | Nein | Blockhash. |
| `kind` | `string` | Nein | Art der Änderung. |
| `asset` | `string` | Nein | Kennung des betroffenen Assets, falls bekannt. |
| `detail` | `object` | Nein |  |
| `simulated` | `boolean` | Nein | Simuliertes Ereignis. |

### `WebhookInvoice`

| Feld | Typ | Erforderlich | Beschreibung |
| --- | --- | --- | --- |
| `id` | `string` | Ja | Undurchsichtige Kennung; als Zeichenfolge behalten.; minLength: `1` |
| `reference` | `string` | Nein | Bestellreferenz. |
| `status` | `string` | Nein | pending 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` |
| `currency` | `string` | Nein | Währung des Bestellangebots. |
| `amount` | `string` | Nein | Exakter Dezimalbetrag als Zeichenfolge; keine Gleitkommazahlen verwenden.; pattern: `^[0-9]+(?:\.[0-9]+)?$` |

### `Notice`

| Feld | Typ | Erforderlich | Beschreibung |
| --- | --- | --- | --- |
| `subject` | `string` | Ja | Betreff der Mitteilung. |
| `text` | `string` | Ja | Mitteilungstext. |

### `Valuation`

| Feld | Typ | Erforderlich | Beschreibung |
| --- | --- | --- | --- |
| `currency` | `string` | Ja | Bewertungswährung, etwa USD. |
| `amount` | `string` | Ja | Exakter Dezimalbetrag als Zeichenfolge; keine Gleitkommazahlen verwenden.; pattern: `^[0-9]+(?:\.[0-9]+)?$` |
| `rate` | `string` | Ja | Asset-Wechselkurs als Dezimalzeichenfolge.; pattern: `^[0-9]+(?:\.[0-9]+)?$` |
| `rate_at` | `string` | Ja | UTC-Datum und -Uhrzeit nach RFC 3339.; `date-time` |
| `provider` | `string` | Nein | Name 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

```javascript
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](https://cryptanio.com/files/examples/webhook-node.mjs)



### Go

```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](https://cryptanio.com/files/examples/webhook-go.go)

## 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.

[POST /v1/endpoints Webhook-Endpunkt erstellen](https://cryptanio.com/de/docs/reference/create-endpoint/) [GET /v1/endpoints Webhook-Endpunkte auflisten](https://cryptanio.com/de/docs/reference/list-endpoints/) [DELETE /v1/endpoints/{id} Webhook-Endpunkt löschen](https://cryptanio.com/de/docs/reference/delete-endpoint/)

## 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.

[GET /v1/stream Ereignisse streamen](https://cryptanio.com/de/docs/reference/stream-events/)

### `StreamEvent`

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

| Feld | Typ | Erforderlich | Beschreibung |
| --- | --- | --- | --- |
| `event_id` | `string` | Ja | Undurchsichtige Kennung; als Zeichenfolge behalten.; minLength: `1` |
| `event_type` | `string` | Ja | Ereignistyp; neue Typen können hinzukommen. |
| `chain` | `string` | Ja | Netzwerkcode. |
| `service` | `string` | Nein | Dienst, falls bekannt. |
| `watch_id` | `string` | Nein | Überwachungs-ID des Projekts, falls zugeordnet.; minLength: `1` |
| `occurred_at` | `string` | Ja | UTC-Datum und -Uhrzeit nach RFC 3339.; `date-time` |
| `payment` | `object \| null` | Nein | Zahlungsdokument oder null bei Nichtzahlungsereignis. GET /events liefert keine contract/notice-Inhalte. |
| `sandbox` | `boolean` | Nein | Testereignis; ohne Angabe false. |
| `project_id` | `string` | Nein | Undurchsichtige Kennung; als Zeichenfolge behalten.; minLength: `1` |
| `project_name` | `string` | Nein | Projektname. |
| `url` | `string` | Nein | Link zum Ereignis in Account.; `uri` |
| `contract` | `object` | Nein |  |
| `mode` | `string` | Nein | live 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.

| Rechnung | Bedeutung |
| --- | --- |
| pending | Zahlung ausstehend |
| partial | Teil erhalten; Teilzahlungsrichtlinie des Projekts gilt |
| paid | Zahlung akzeptiert |
| underpaid | Unterzahlung erfordert Entscheidung |
| overpaid | Überzahlung erfordert Entscheidung nach geltender Richtlinie |
| late | Zahlung nach Fristablauf erfordert Entscheidung |
| expired | Zahlungsfrist abgelaufen |
| canceled | Rechnung 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

```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.

| HTTP | Aktion |
| --- | --- |
| 400 | JSON, Formate und Parameter korrigieren; nicht unverändert wiederholen |
| 401 | Schlüssel, Ablauf, Pause und Widerruf prüfen |
| 403 | Scopes, Lesen/Schreiben, Projekt, Dienst, IP und Kontoverifizierung prüfen |
| 404 | ID, Schlüsselmodus und Zugriff prüfen; Einschränkungen können die Ressource verbergen |
| 402 | Limit für Monitoring-Überwachungen; Tarif prüfen |
| 409 | Konflikt, inaktiver Dienst, belegter Pool oder Limit; code prüfen |
| 429 | Retry-After beachten; gemeinsame Anfragerate des Kontos reduzieren |
| 500 / 503 | Mit 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](https://cryptanio.com/de/pricing/)

[GET /v1/health API-Zustand abrufen](https://cryptanio.com/de/docs/reference/get-health/) [GET /v1/chains Netzwerke auflisten](https://cryptanio.com/de/docs/reference/list-chains/)

## 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 API | Vertrag |
| --- | --- |
| `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](https://cryptanio.com/openapi.json)

## 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](https://cryptanio.com/de/mcp/). 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.
