API ドキュメント
Cryptanio をアプリケーションに接続しましょう。
契約 v1 / 1.0.0 62 / 2026-10-10
目次
始める
API はサーバー向けです。先に Account でプロジェクト、サービス、アドレスプールを設定してください。API はその中で、キーが許可する操作を実行します。
- アカウントを確認し、マイサービスで必要なサービスを有効にしてください。
- 最小限の権限で API キーを作成し、サーバーに保管してください。
- 目的を選択してください:アドレスを監視、請求書を作成、またはイベントを受信。
サンプルは実データに対して実際の操作を行います。オブジェクトの作成や削除でサービスの割当量を消費する場合があります。キーはサンプルに埋め込まず、環境変数から読み取ります。
エージェントへの指示
この指示をエージェントのチャットまたはプロジェクトのルールに貼り付けてください。エージェントがサービス、料金、リファレンスを理解し、REST API または SDK を使ったアプリケーション連携を実装するのに役立ちます。エージェントはあなたの言語で回答できます。
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.このブロックにキーやアカウントデータは含まれていません。連携に必要な最小限の権限を持つ API キーを使用し、アプリケーションサーバーで保管してください。エージェントのチャットでキーを共有しないでください。
API リファレンス
メソッド:16
Monitoring の監視
請求書
Webhook
API の稼働状況
ネットワーク
認証
サーバーから Authorization: Bearer <API_KEY> を送信してください。Account → API キーで実データ用のキーを作成し、必要なプロジェクトと操作に制限してください。公開サンドボックスは現在提供していません。
キーには読み取り専用、特定の操作、単一のプロジェクトやサービス、指定した IP/CIDR 範囲のアクセスを許可できます。有効期限、一時停止、失効もアクセスに影響します。キーを更新するには、適切な制限を持つ新しいキーを作成し、連携を切り替えてから古いキーを失効させてください。ブラウザーのコード、モバイルアプリ、URL にキーを埋め込まないでください。
| 範囲 | 目的 |
|---|---|
watches | Monitoring |
events | イベントと支払い |
invoices | Payments の請求書 |
webhooks | Webhook エンドポイント |
stream | SSE |
制限は互いに置き換わるのではなく、同時に適用されます。401 はキーが受け入れられなかったことを示し、403 は権限不足または許可されていない IP を示す場合があります。アクセスできないリソースは 404 を返す場合があります。エラーと再試行を参照してください。
SDK:すぐに使えるクライアント
使用する言語のファイルをダウンロードし、アプリケーションサーバーに保存して、コンストラクターにキーを渡してください。各クライアントはこのリファレンスの全 16 メソッドに対応しています。インストールする npm、PyPI、Composer、crates.io のパッケージはなく、ダウンロードしたファイルが SDK です。
| 言語 | 要件 | ファイル |
|---|---|---|
| Node.js | Node.js 18+ | cryptanio.mjs |
| Python | Python 3.10+ | cryptanio.py |
| PHP | PHP 8.1+ / cURL | Cryptanio.php |
| Go | Go 1.22+ | cryptanio.go |
| Rust | Rust 2021 / reqwest 0.12 / serde_json 1 | cryptanio.rs |
これらのファイルはリリース 1.0.0 62 に属します。マニフェストには、バージョン、契約、各ファイルの SHA-256 が記載されています。先に環境変数へ CRYPTANIO_API_KEY と CRYPTANIO_PROJECT_ID を設定してください。これらの例はイベントの読み取りのみを行いますが、実際のアカウントデータにアクセスします。
Node.js
例を .mjs ファイルとして cryptanio.mjs と同じ場所に保存してください。
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);既存インボイスの支払い案内を読み取るには、そのIDをCRYPTANIO_RESOURCE_IDに設定します。次の例は必須のpayment_route、QR用に返されたpayment_uri、正確なcheckout_urlを保持します。結果は自分の画面を通じて支払者に渡し、公開ログには記録しないでください。金額は文字列のまま保持され、存在しないフィールドは省略されます。
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
例を .py ファイルとして cryptanio.py と同じ場所に保存してください。
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)既存インボイスの支払い案内を読み取るには、そのIDをCRYPTANIO_RESOURCE_IDに設定します。次の例は必須のpayment_route、QR用に返されたpayment_uri、正確なcheckout_urlを保持します。結果は自分の画面を通じて支払者に渡し、公開ログには記録しないでください。金額は文字列のまま保持され、存在しないフィールドは省略されます。
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
例を .php ファイルとして Cryptanio.php と同じ場所に保存し、cURL 拡張機能を有効にしてください。
<?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);既存インボイスの支払い案内を読み取るには、そのIDをCRYPTANIO_RESOURCE_IDに設定します。次の例は必須のpayment_route、QR用に返されたpayment_uri、正確なcheckout_urlを保持します。結果は自分の画面を通じて支払者に渡し、公開ログには記録しないでください。金額は文字列のまま保持され、存在しないフィールドは省略されます。
<?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
Go モジュール内の cryptanio/ ディレクトリにファイルを配置してください。この例ではモジュール example.local/myapp を使用しています。インポートパスを自分のモジュール名に置き換えてください。外部依存関係は不要です。
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)
}既存インボイスの支払い案内を読み取るには、そのIDをCRYPTANIO_RESOURCE_IDに設定します。次の例は必須のpayment_route、QR用に返されたpayment_uri、正確なcheckout_urlを保持します。結果は自分の画面を通じて支払者に渡し、公開ログには記録しないでください。金額は文字列のまま保持され、存在しないフィールドは省略されます。
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
ファイルを src/cryptanio.rs、例を src/main.rs として保存してください。以下の依存関係を Cargo.toml に追加します。これは同期的に処理を待機するクライアントです。非同期ワーカー上で直接実行しないでください。
[dependencies]
reqwest = { version = "=0.12.24", default-features = false, features = ["blocking", "json", "rustls-tls"] }
serde_json = "=1.0.145"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(())
}既存インボイスの支払い案内を読み取るには、そのIDをCRYPTANIO_RESOURCE_IDに設定します。次の例は必須のpayment_route、QR用に返されたpayment_uri、正確なcheckout_urlを保持します。結果は自分の画面を通じて支払者に渡し、公開ログには記録しないでください。金額は文字列のまま保持され、存在しないフィールドは省略されます。
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(())
}メソッドの呼び出し
Node.js と PHP は listEvents、Python と Rust は list_events、Go は ListEvents を使用します。各メソッドはリファレンスの一つのリクエストに対応します。フィルターはオブジェクト/マップで、Rust ではペアのリストです。Go のメソッドは常に context.Context を最初の引数に取ります。未知のフィルターは送信前に拒否されます。
| Node.js / PHP メソッド | HTTP |
|---|---|
createWatch | POST /v1/watches |
listWatches | GET /v1/watches |
getWatch | GET /v1/watches/{id} |
deleteWatch | DELETE /v1/watches/{id} |
listEvents | GET /v1/events |
listPayments | GET /v1/payments |
createInvoice | POST /v1/invoices |
listInvoices | GET /v1/invoices |
getInvoice | GET /v1/invoices/{id} |
cancelInvoice | POST /v1/invoices/{id}/cancel |
createEndpoint | POST /v1/endpoints |
listEndpoints | GET /v1/endpoints |
deleteEndpoint | DELETE /v1/endpoints/{id} |
streamEvents | GET /v1/stream |
getHealth | GET /v1/health |
listChains | GET /v1/chains |
監視対象と Webhook の作成ではリクエスト本文を渡します。単一リソースの操作では文字列の ID を渡します。createInvoice(body, idempotencyKey) では、ASCII の英字、数字、ハイフン、アンダースコアからなる 16~80 文字のキーが必要です。再試行では同じキーと本文を再利用してください。SDK は新しいキーを生成せず、自動再試行も行いません。本文、エラー、権限は各メソッドのページを参照してください。
応答、エラー、ストリーミング
JSON 応答はフィールド名を保持し、ID、金額、カーソルは文字列のままです。ページ取得は各メソッドの説明に従い手動で行います。エラーは HTTP ステータス、code、message、Retry-After を示します。HTTP 応答がない場合のステータスは 0 です(Rust は None)。リダイレクトは追跡しません。通常の JSON 応答は 8 MiB までです。既定のタイムアウトは 30 秒で、最大 300 秒に設定できます。Python ではネットワーク操作に、他のクライアントではストリーミングを含むリクエスト全体に適用されます。タイムアウトは書き込みが実行されなかった証明にはなりません。
| 言語/エラー | フィールド |
|---|---|
| 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 は、再接続やイベント解析を行わずに SSE の未処理バイト列を提供します。Node.js の ReadableStream、閉じることのできる Python HTTP 応答、Go の io.ReadCloser、Rust の blocking::Response です。不要になったストリームは解放してください。PHP はデータ片をコールバックに渡し、false を返すと停止します。ストリーミングは Webhook の代わりにはならず、履歴の再送も保証しません。SSE のルールを参照してください。
最初の監視対象
Account で有効な Monitoring サービスを持つプロジェクトと、watches・events 権限を持つキーを作成します。必要な場合はアカウント認証を完了してください。設定からプロジェクト ID をコピーし、実際に監視したいアドレスだけを追加します。
サーバーの環境変数に CRYPTANIO_API_KEY と CRYPTANIO_PROJECT_ID を設定してください。例のアドレスを自分のアドレスに置き換えます。このリクエストは実際の監視対象を追加し、取引をシミュレーションしません。
#!/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
成功応答には id が含まれます。保存してください。GET /v1/watches/{id} は支払いではなく監視対象と設定を返します。検出した活動を確認するには、GET /v1/events を watch_id で絞り込んで取得してください。取引が検出される前に一覧が空なのは正常です。応答、エラー、他の言語の例。
Payments の請求書
プロジェクトで Payments を有効にし、Account で対応アドレスをプールに追加してください。既定のプロジェクト選択に頼らず、project を明示的に送信してください。amount は暗号資産単位の文字列で、invoice_currency/invoice_amount は注文の見積りを別途表します。
CRYPTANIO_PROJECT_ID に Payments プロジェクト、CRYPTANIO_API_KEY に請求書の権限を持つキーを設定してください。CRYPTANIO_OPERATION_ID は新しい注文ごとに一意でなければなりません。同じ操作の再試行では再利用してください。請求書は実データに作成されます。
#!/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
キーは invoices と Payments を許可する必要があります。Monitoring の例のキーは別のサービスに制限されている場合があります。Idempotency-Key は 16-80 文字の ASCII 英字、数字、-、_ で構成されます。同じキーで同じ正規化済みリクエストを繰り返すと、201 と既存の請求書を返します。内容を変更すると 409 conflict を返します。操作キーはアカウント全体で共通です。reference はその代わりになりません。
購入者に、返されたネットワーク、資産、アドレス、amount、有効期限を表示します。payment_routeがある場合は、そのkindと正確な文字列valueも渡してください。destination_tag、memo、comment、referenceは、このインボイスに支払いを対応付けるために必須です。注文のreferenceフィールドは別のものです。
返されたpayment_uriがある場合は、支払いQRにそのまま使用してください。Solana Pay referenceはウォレットのmemoではありません。URIを単なるアドレスに置き換えたり、再構築したりしないでください。ウォレットで必須の識別子を送れない場合は、支払者にcheckout_urlまたは対応ウォレットを案内してください。
checkout_urlは新規インボイスのホスト型支払いページです。返された正確なURLだけを支払者に共有し、IDから組み立てないでください。リンクでは支払いの詳細と状態を閲覧できるため、公開ログには記録しないでください。フィールドがなければ完全な支払い案内を表示します。ブラウザーのリダイレクトは支払いの証明になりません。APIまたは検証済みwebhookを確認してください。
注文を区別するため、askedがamountと異なる場合があります。amount_rawを任意精度の整数として照合してください。既定のTTLは60分、最大は10080分です。インボイス一覧はbeforeを受け取りますがnext_beforeは返しません。最後の項目のIDで続きを取得し、空のページで終了します。
Customer
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
id | string | はい | お客様のシステム内の顧客識別子。 maxLength: 120 |
Product
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
id | string | いいえ | 自分のシステム内の製品識別子。 maxLength: 120 |
name | string | いいえ | 製品名。 maxLength: 200 |
quantity | integer | いいえ | 数量。 minimum: 1、maximum: 1000000 |
Payer
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
comment | string | はい | 支払者のコメント。 maxLength: 500 |
InvoiceMetadata
最大 20 組、JSON は最大 8192 バイト。シークレットを含めないでください。
object 最大 20 組、JSON は最大 8192 バイト。シークレットを含めないでください。
Monitoring の監視
監視対象は単一の Monitoring プロジェクトに属します。同じアドレスを複数のプロジェクトで、それぞれ独立した方向・資産ルールとともに使用できます。アドレス帳リストと Address Sources は Account で接続してください。この REST API はそれらの管理コマンドを公開していません。
一覧は ID の降順です。next_before がある場合は、プロジェクトとフィルターを変更せず、次のリクエストで before として渡してください。limit の既定値は 50、上限は 200 です。ID は文字列で保存してください。削除した監視対象は有効な一覧から除外されます。この削除では、他のプロジェクトやアドレス帳からアドレスを削除しません。
イベントと履歴
/v1/events は各サービスでキーがアクセスできるイベントを返し、/v1/payments は Payments に限定されます。project、address、chain、type、watch_id、tx_id で絞り込めます。before は ID カーソルであり、日付ではありません。from/to フィルターはありません。next_before で次のページを取得できます。
検出したイベントの履歴は最大 30 日間参照できます。配信されたすべてのメッセージの保管庫ではなく、notice や webhook.test の復元は保証されません。REST Event は Webhook とは別のスキーマを持ち、v1 内でフィールドが追加される場合があります。
Event
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
event_id | string | はい | 内部構造を持たない識別子。文字列のまま保持してください。 minLength: 1 |
event_type | string | はい | イベントの種別。新しい種別が追加される場合があります。 |
chain | string | はい | ネットワークコード。 |
service | string | いいえ | 判明している場合のサービス。 |
watch_id | string | いいえ | 監視対象に紐付いている場合のプロジェクト監視 ID。 minLength: 1 |
occurred_at | string | はい | RFC 3339 形式の UTC 日時。date-time |
payment | object | null | はい | 支払いデータ。支払い以外のイベントでは null。GET /events は contract/notice ペイロードを返しません。 |
sandbox | boolean | いいえ | テストイベント。省略時は false。 |
EventPayment
REST/SSE の支払いデータ。フィールドはイベントとネットワークにより異なり、正規化された Webhook v1 の形式とは異なります。
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
tx_id | string | いいえ | 取引の識別子。 |
index | integer | いいえ | 取引内の送金インデックス。 minimum: 0 |
height | integer | いいえ | 分かる場合のブロック高。 minimum: 0 |
address | string | いいえ | 監視対象のアドレス。 |
asset | string | いいえ | REST/SSE の資産:文字列の識別子です。Webhook の asset オブジェクトではありません。 |
amount_raw | string | いいえ | 最小単位の整数金額を表す文字列。 pattern: ^[0-9]+$ |
amount | string | いいえ | 正確な小数の金額を表す文字列。浮動小数点は使用しないでください。 pattern: ^[0-9]+(?:\.[0-9]+)?$ |
decimals | integer | いいえ | 小数点以下の桁数。 minimum: 0 |
confirmations | integer | いいえ | 承認数。 minimum: 0 |
revision | integer | いいえ | 送金状態のリビジョン。 minimum: 0 |
direction | string | いいえ | 監視対象のアドレスを基準とする方向。in、out |
simulated | boolean | いいえ | シミュレーションされたイベント。 |
late | boolean | いいえ | 遅れて検出された送金。 |
block_hash | string | いいえ | ブロックハッシュ。 |
match_key | string | いいえ | ネットワークで使用される場合の照合識別子。 |
meta | object | いいえ | |
invoice | object | いいえ | |
customer | object | いいえ | |
product | object | いいえ | |
payer | object | いいえ | |
metadata | object | いいえ |
Webhook イベント
配信は少なくとも一度行われる方式で、同じイベントが複数回届く場合があります。署名を検証後、連携側で event_id により重複を排除してください。処理の記録と業務上の変更を同じデータベーストランザクションで保存します。tx_id/address/asset のキーは異なる遷移、方向、プロジェクトをまとめてしまうため、event_id の代わりにはなりません。
署名された本文から event_type と event_id を読み取ってください。X-Event-Type/X-Event-Id ヘッダーは HMAC に含まれないため、使用する場合は本文と照合してください。支払いの更新時は project_id、direction、payment.revision を考慮してください。配信順序を前提にせず、不明な種類は安全に無視しながら診断用に保存してください。
| 系統 | 本文 |
|---|---|
| payment.pending / confirmed / rolled_back | 入金 |
| debit.pending / confirmed / rolled_back | 出金 |
| contract.approval / owner_added / owner_removed / threshold_changed / permissions_changed | contract |
| asset.unexpected | contract。資産は受け付け済みの支払いとして計上されません |
| account.notice / account.notification / treasury.alarm / subscription.notice | notice.subject, notice.text |
| webhook.test | 支払いを伴わない制御イベント |
schema_version: v1 はイベントの種類に応じて payment、contract、notice を含みます。webhook.test にはありません。ID と金額は文字列です。amount_raw は最小単位、amount は小数表記です。ネットワークと資産は chains で確認してください。完全なオブジェクトスキーマは OpenAPI にあります。
| ヘッダー | 意味 |
|---|---|
| X-Timestamp | 署名時の Unix 秒 |
| X-Signature | hex HMAC-SHA256(timestamp + '.' + raw body) |
| X-Event-Id / X-Event-Type | 署名対象の本文と比較してください。 |
| X-Attempt | 1 から始まる試行番号 |
イベントを永続的に受け付けた後、2xx を返してください。各試行のタイムアウトは 10 秒です。ネットワーク障害、408、425、429、5xx は最長 24 時間再試行し、待機時間は 2 秒から 15 分でランダムな変動を加えます。Retry-After に従います。リダイレクトは追跡しません。その他の 3xx/4xx は配信を終了し、410 は送信先と未配信キューを廃止します。
{
"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
公開署名付き Webhook v1 の本文。payment.* と debit.* は payment、contract.* と asset.unexpected は contract、account.notice、account.notification、treasury.alarm、subscription.notice は notice を含みます。webhook.test には業務ペイロードがありません。配信再試行の重複は event_id で排除してください。
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
schema_version | string | はい | Webhook ペイロードのバージョン。v1 |
event_id | string | はい | イベント ID:配信の再試行時も変わりません。異なる状態には異なる event_id が付く場合があります。 minLength: 1 |
event_type | string | はい | 署名された本文内の種類。署名検証後に使用してください。新しい種類が追加される場合があります。 |
occurred_at | string | はい | RFC 3339 形式の UTC 日時。date-time |
project_id | string | はい | 内部構造を持たない識別子。文字列のまま保持してください。 minLength: 1 |
service | string | いいえ | 該当する場合のプロジェクトのサービス。 |
mode | string | はい | イベントのモード。live、test |
sandbox | boolean | はい | 明示的なシミュレーションフラグ。 |
payment | object | いいえ | |
contract | object | いいえ | |
invoice | object | いいえ | |
customer | object | いいえ | |
product | object | いいえ | |
payer | object | いいえ | |
metadata | object | いいえ | |
notice | object | いいえ |
WebhookPayment
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
chain | string | はい | ネットワークコード。 |
direction | string | はい | 入金:in、出金:out。in、out |
asset | object | はい | |
address | string | はい | 監視対象のアドレス。 |
tx_id | string | はい | 取引 ID。 |
index | integer | はい | 送金インデックス。どのネットワークでも 0 を前提にしないでください。 minimum: 0 |
height | integer | いいえ | 判明している場合のブロック高。 minimum: 0 |
block_hash | string | いいえ | 判明している場合のブロックハッシュ。 |
match_key | string | いいえ | 該当する場合のネットワーク照合識別子。 |
amount | string | はい | 正確な小数の金額を表す文字列。浮動小数点は使用しないでください。 pattern: ^[0-9]+(?:\.[0-9]+)?$ |
amount_raw | string | はい | 最小単位の整数金額を表す文字列。 pattern: ^[0-9]+$ |
decimals | integer | はい | 小数点以下の桁数。 minimum: 0 |
confirmations | integer | はい | 承認数。 minimum: 0 |
revision | integer | はい | 送金状態のリビジョン。取引の識別情報で異なる event_id を統合しないでください。 minimum: 0 |
late | boolean | いいえ | 遅れて検出された送金で、請求書の状態 late とは異なります。 |
simulated | boolean | いいえ | シミュレーションされた送金。 |
valuation | object | いいえ |
WebhookAsset
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
symbol | string | いいえ | 判明している場合のシンボル。シンボルだけではトークンを特定できません。 |
standard | string | いいえ | 判明している場合のトークン規格。 |
contract | string | いいえ | 該当する場合の、そのネットワーク上のトークンコントラクト。 |
identifier | string | いいえ | その他のネットワーク固有のトークン識別子。 |
WebhookContract
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
chain | string | はい | ネットワークコード。 |
address | string | はい | 監視対象のアドレスまたはコントラクト。 |
tx_id | string | はい | 取引 ID。 |
index | integer | はい | イベントのインデックス。 minimum: 0 |
height | integer | いいえ | ブロック高。 minimum: 0 |
block_hash | string | いいえ | ブロックハッシュ。 |
kind | string | いいえ | 変更の種類。 |
asset | string | いいえ | 判明している場合の対象資産識別子です。 |
detail | object | いいえ | |
simulated | boolean | いいえ | シミュレーションされたイベント。 |
WebhookInvoice
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
id | string | はい | 内部構造を持たない識別子。文字列のまま保持してください。 minLength: 1 |
reference | string | いいえ | 注文参照番号。 |
status | string | いいえ | pending は支払い待ち、seen は検出済み、partial は一部支払い済み、paid は支払い完了、underpaid/overpaid/late は判断が必要、expired は期限切れ、canceled はキャンセル済みです。pending、seen、paid、underpaid、partial、overpaid、expired、late、canceled |
currency | string | いいえ | 注文の見積もり通貨。 |
amount | string | いいえ | 正確な小数の金額を表す文字列。浮動小数点は使用しないでください。 pattern: ^[0-9]+(?:\.[0-9]+)?$ |
Notice
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
subject | string | はい | 通知の件名。 |
text | string | はい | 通知の本文。 |
Valuation
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
currency | string | はい | 評価額の通貨。例:USD。 |
amount | string | はい | 正確な小数の金額を表す文字列。浮動小数点は使用しないでください。 pattern: ^[0-9]+(?:\.[0-9]+)?$ |
rate | string | はい | 小数形式の文字列で表した資産の為替レート。 pattern: ^[0-9]+(?:\.[0-9]+)?$ |
rate_at | string | はい | RFC 3339 形式の UTC 日時。date-time |
provider | string | いいえ | 判明している場合の価格情報の提供元名。 |
署名の検証
JSON を解析する前に、空白や改行を含む元の本文バイト列に対して HMAC を検証してください。時刻の新しさの確認はリプレイを抑えますが、永続的な event_id による重複排除の代わりにはなりません。例では 64 文字の 16 進署名と、サーバー時刻から 300 秒以内のタイムスタンプだけを受け入れます。対象の Webhook 送信先のシークレットを使用してください。
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;
}
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
}
Webhook エンドポイント
特定のプロジェクトにポート 443 の公開 HTTPS URL を追加します。URL 内の認証情報、フラグメント、リダイレクト、非公開の宛先は許可されません。アカウントあたり最大 20 件のエンドポイントを登録できます。各エンドポイントのシークレットは初回作成時のみ返されるため、サーバーに保存してください。
同じプロジェクトとモードで同じ URL を再作成すると、200 と、シークレットを含まない既存のエンドポイントを返します。新規エンドポイントは 201 を返します。DELETE は安全な再実行も含め、200 と id、deleted: true を返します。キーで参照できるのはそのモードと許可されたプロジェクトのみで、配信はプロジェクト設定に従います。
SSE ストリーム
SSE はサーバー側の連携とリアルタイム表示用です。配信を保証せず、取り逃したイベントを再送することもありません。Bearer ヘッダーを持つサーバー側 HTTP クライアントを使用してください。標準のブラウザー EventSource はこのヘッダーを送信できません。API キーをブラウザーのコードやクエリ文字列に含めないでください。
メッセージは event: payment と独自の StreamEvent 形式を使い、webhook v1 や REST Event とは異なります。コメントはコロンで始まり、ハートビートは約 20 秒ごとに届きます。retry: 5000 は再接続のヒントです。切断後は events から利用可能なブロックチェーンイベント履歴を取得してください。
StreamEvent
SSE data の JSON で、webhook v1 とは異なります。支払い以外のイベントは payment を省略し、contract を含む場合があります。
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
event_id | string | はい | 内部構造を持たない識別子。文字列のまま保持してください。 minLength: 1 |
event_type | string | はい | イベントの種別。新しい種別が追加される場合があります。 |
chain | string | はい | ネットワークコード。 |
service | string | いいえ | 判明している場合のサービス。 |
watch_id | string | いいえ | 監視対象に紐付いている場合のプロジェクト監視 ID。 minLength: 1 |
occurred_at | string | はい | RFC 3339 形式の UTC 日時。date-time |
payment | object | null | いいえ | 支払いデータ。支払い以外のイベントでは null。GET /events は contract/notice ペイロードを返しません。 |
sandbox | boolean | いいえ | テストイベント。省略時は false。 |
project_id | string | いいえ | 内部構造を持たない識別子。文字列のまま保持してください。 minLength: 1 |
project_name | string | いいえ | プロジェクト名。 |
url | string | いいえ | Account のイベントへのリンク。uri |
contract | object | いいえ | |
mode | string | いいえ | live または test。live、test |
支払いと請求書の状態
ブロックチェーン上の支払い状態と注文状態は別です。payment.pending は十分な承認前の検出、payment.confirmed はネットワーク/プロジェクトの承認条件の達成、payment.rolled_back は巻き戻しを示します。pending、出金、シミュレーションのイベントを根拠に注文を履行しないでください。
| Invoice | 意味 |
|---|---|
| pending | 支払い待ち |
| partial | 一部を受領済み。プロジェクトの部分払い方針に従います |
| paid | 支払い受付済み |
| underpaid | 不足払いには判断が必要です |
| overpaid | 過払いには適用される方針に基づく判断が必要です |
| late | 期限後の支払いには判断が必要です |
| expired | 支払期限切れ |
| canceled | 請求書をキャンセルしました。記録は引き続き参照できます。 |
needs_decision は underpaid、overpaid、late の場合に存在します。これらの状態は Account で解決してください。チェーンの再編と再取り込みにより、新しい遷移と新しい payment.revision が発生する場合があります。confirmed は将来の変更がないという無条件の保証ではありません。
エラーと安全な再試行
{"error":{"code":"forbidden","message":"this API key is read-only"}}ロジックには HTTP ステータスと error.code、診断には message を使用してください。成功した一覧応答には data があり、単一のオブジェクトは直接返されます。Health は 503 の場合も含め、独自の status/version スキーマを使用します。message の厳密な文言に依存しないでください。
| HTTP | 操作 |
|---|---|
| 400 | JSON、形式、パラメーターを修正してください。変更せずに再試行しないでください。 |
| 401 | キー、有効期限、一時停止、失効を確認してください。 |
| 403 | スコープ、読み取り/書き込み、プロジェクト、サービス、IP、アカウント認証を確認してください。 |
| 404 | ID、キーのモード、アクセス権を確認してください。制限によってリソースが非表示になる場合があります。 |
| 402 | Monitoring の監視数上限です。プランを確認してください。 |
| 409 | 競合、無効なサービス、使用中のプール、または制限。コードを確認してください。 |
| 429 | Retry-After に従い、アカウント全体のリクエスト頻度を下げてください |
| 500 / 503 | 上限を設けたバックオフで再試行してください。請求書作成では元の Idempotency-Key を必ず使用します |
タイムアウトは操作が実行されなかったことを意味しません。再試行で請求書の操作キーを変更しないでください。重複防止のないメソッドは先に状態を確認し、すべての POST が冪等だと仮定しないでください。
ネットワークと制限
選択した API ホストの chains を使用して、その環境のネットワーク、資産、機能、確認回数のカタログを取得してください。一般カタログへの掲載は、その環境でのネットワークの有効化や、すべての操作への対応を保証しません。サービスの利用枠と予算は Account、価格は料金ページで確認してください。
アカウントの認証済み REST リクエストの上限は、有料サービスなしで毎秒 10 件、有料サービスありで毎秒 50 件です。短時間のバースト容量は 20/100 件です。アカウントのすべてのキーとモードでこの上限を共有します。超過時は Retry-After とともに 429 を返します。サービスの利用枠と API のレート制限は別の制限です。
API バージョン
このリファレンスの対象は v1(リリース 1.0.0 62)です。更新日:2026-10-10。新しい機能を使う前に、GET /v1/health でデプロイ済みリリースを確認してください。ドキュメントのバージョンだけでは、デプロイ済みであることは確認できません。
| 公開 API | 契約 |
|---|---|
https://api.cryptanio.com | /v1 |
安定した連携には /v1 を使用してください。バージョンのないパスは、その環境の現在の安定契約を選択します。不明な /vN は 404 を返します。X-API-Version は契約を識別し、X-Server-Version と health.version は製品リリースを識別します。別の API 契約を意味するものではありません。
API の変更
リリース 1.0.0 62 には Node.js、Python、PHP、Go、Rust のダウンロード可能な SDK と、AI エージェント向けローカル MCP が含まれています。リファレンス、Markdown、直接の HTTP リクエスト例は別途利用できます。公開サンドボックスは提供していません。API の動作は変わりません。
v1 では、クライアントは追加の応答フィールドを許容する必要があります。不明な種類のイベントを受け入れても、注文の履行や支払いの計上を意味するわけではありません。変更を利用する前に、選択した環境のバージョンで利用可能か確認してください。