Documentação da API

Ligue o Cryptanio à sua aplicação.

Contrato v1 / 1.0.0 62 / 2026-10-10

Conteúdo

Começar

A API destina-se ao servidor. Configure primeiro projetos, serviços e conjuntos de endereços no Account; a API executa neles operações autorizadas pela chave.

  1. Verifique a conta e ative o serviço necessário em Os meus serviços.
  2. Crie uma chave API com permissões mínimas e mantenha-a no servidor.
  3. Escolha a tarefa: monitorizar um endereço, criar uma fatura ou receber eventos.

Os exemplos executam operações reais em dados live. Criar ou eliminar objetos pode consumir quotas do serviço. As chaves nunca são incorporadas nos exemplos; são lidas de variáveis de ambiente.

Instruções para o seu agente

Cole esta instrução no chat do agente ou regras do projeto. Ajuda-o a conhecer serviços, preços e referência e depois escrever uma integração pela API REST ou SDK. O agente pode responder no seu idioma.

Instruções de integração
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.

Este bloco não contém chaves nem dados de conta. Use uma chave API com permissões mínimas para a integração e mantenha-a no servidor da aplicação. Não partilhe a chave no chat do agente.

Referência da API

Métodos: 16

Autenticação

Envie Authorization: Bearer <API_KEY> do servidor. Crie uma chave para dados live em Account → Chaves API, limitada aos projetos e operações necessários. Não é oferecida atualmente uma sandbox pública.

Uma chave pode permitir apenas leitura, operações selecionadas, um projeto ou serviço e intervalos IP/CIDR específicos. A validade, suspensão e revogação também afetam o acesso. Para rodar a chave, crie uma substituta com restrições adequadas, altere a integração e revogue a antiga. Nunca incorpore chaves em código do navegador, aplicações móveis ou URLs.

ÂmbitoFinalidade
watchesMonitorização
eventsEventos e pagamentos
invoicesFaturas Payments
webhooksEndpoints webhook
streamSSE

Restrições aplicam-se em conjunto, não em substituição. 401 indica chave não aceite; 403 pode indicar permissões insuficientes ou IP não permitido. Um recurso inacessível pode devolver 404. Consulte erros e repetições.

SDK: clientes prontos a usar

Transfira o ficheiro da sua linguagem, guarde-o no servidor da aplicação e passe a chave ao construtor. Cada cliente cobre todos os 16 métodos desta referência. Não há pacote npm, PyPI, Composer ou crates.io para instalar: os ficheiros transferidos são o SDK.

IdiomaRequisitosFicheiro
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

Os ficheiros partilham a versão 1.0.0 62. O manifesto contém versão, contrato e SHA-256 de cada ficheiro. Defina primeiro CRYPTANIO_API_KEY e CRYPTANIO_PROJECT_ID no ambiente. Os exemplos só leem eventos, mas acedem a dados live da conta.

Node.js

Guarde o exemplo como .mjs junto de cryptanio.mjs.

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);

Para consultar as instruções de pagamento de uma fatura existente, defina o ID em CRYPTANIO_RESOURCE_ID. O exemplo preserva o payment_route obrigatório, o payment_uri retornado para o QR e o checkout_url exato. Envie o resultado ao pagador pela sua interface; não o publique em registros públicos. Os valores continuam como strings e os campos ausentes são omitidos.

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

Guarde o exemplo como .py junto de cryptanio.py.

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)

Para consultar as instruções de pagamento de uma fatura existente, defina o ID em CRYPTANIO_RESOURCE_ID. O exemplo preserva o payment_route obrigatório, o payment_uri retornado para o QR e o checkout_url exato. Envie o resultado ao pagador pela sua interface; não o publique em registros públicos. Os valores continuam como strings e os campos ausentes são omitidos.

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

Guarde o exemplo como .php junto de Cryptanio.php; ative a extensão cURL.

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);

Para consultar as instruções de pagamento de uma fatura existente, defina o ID em CRYPTANIO_RESOURCE_ID. O exemplo preserva o payment_route obrigatório, o payment_uri retornado para o QR e o checkout_url exato. Envie o resultado ao pagador pela sua interface; não o publique em registros públicos. Os valores continuam como strings e os campos ausentes são omitidos.

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

Coloque o ficheiro num diretório cryptanio/ do módulo Go. O exemplo usa o módulo example.local/myapp; substitua o caminho de importação pelo seu módulo. Não exige dependências externas.

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)
}

Para consultar as instruções de pagamento de uma fatura existente, defina o ID em CRYPTANIO_RESOURCE_ID. O exemplo preserva o payment_route obrigatório, o payment_uri retornado para o QR e o checkout_url exato. Envie o resultado ao pagador pela sua interface; não o publique em registros públicos. Os valores continuam como strings e os campos ausentes são omitidos.

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

Guarde o ficheiro como src/cryptanio.rs e o exemplo como src/main.rs. Adicione as dependências abaixo a Cargo.toml. Cliente síncrono bloqueante: não o execute diretamente num worker assíncrono.

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(())
}

Para consultar as instruções de pagamento de uma fatura existente, defina o ID em CRYPTANIO_RESOURCE_ID. O exemplo preserva o payment_route obrigatório, o payment_uri retornado para o QR e o checkout_url exato. Envie o resultado ao pagador pela sua interface; não o publique em registros públicos. Os valores continuam como strings e os campos ausentes são omitidos.

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(())
}

Chamar métodos

Node.js e PHP usam listEvents, Python e Rust list_events, Go ListEvents. Cada método corresponde a um pedido na referência. Filtros são objeto/mapa, ou lista de pares em Rust. Métodos Go recebem sempre context.Context primeiro. Filtros desconhecidos são rejeitados antes do envio.

Método Node.js / PHPHTTP
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

Criar monitorizações e webhooks exige corpo do pedido. Métodos de um recurso recebem o ID em cadeia. createInvoice(body, idempotencyKey) exige chave de 16–80 caracteres ASCII: letras, dígitos, hífenes ou sublinhados. Reutilize chave e corpo nas repetições; SDK não gera nova chave nem repete automaticamente. Consulte corpos, erros e permissões em cada método.

Respostas, erros e streaming

Respostas JSON mantêm nomes dos campos; IDs, montantes e cursores continuam cadeias. Paginação manual conforme cada método. Erros expõem estado HTTP, code, message e Retry-After. Sem resposta HTTP, status é 0 (Rust usa None). Não segue redirecionamentos. Respostas JSON normais limitadas a 8 MiB. Tempo limite predefinido de 30 segundos, configurável até 300. Em Python aplica-se a uma operação de rede; nos restantes clientes, ao pedido completo, incluindo streaming. Exceder o tempo limite não prova que a escrita não foi executada.

Linguagem / erroCampos
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 expõe bytes SSE originais sem reconexão ou análise de eventos: Node.js ReadableStream, resposta HTTP Python fechável, Go io.ReadCloser ou Rust blocking::Response. Liberte o fluxo quando desnecessário. PHP passa blocos a callback; devolva false para parar. Streaming não substitui webhooks nem garante repetição de histórico; consulte regras SSE.

A sua primeira monitorização

No Account, crie um projeto com Monitoring ativo e uma chave com permissões watches e events. Conclua a verificação da conta quando exigida. Copie o ID das definições; adicione apenas um endereço que queira efetivamente monitorizar.

Defina CRYPTANIO_API_KEY e CRYPTANIO_PROJECT_ID no ambiente do servidor. Substitua o endereço de exemplo pelo seu. Este pedido associa uma monitorização real; não simula uma transação.

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

Uma resposta bem-sucedida contém id: guarde-o. GET /v1/watches/{id} devolve a monitorização e as definições, não pagamentos. Para consultar atividade detetada, solicite GET /v1/events com o filtro watch_id. É normal a lista estar vazia antes de se detetar uma transação. Resposta, erros e exemplos noutras linguagens.

Faturas Payments

Ative Payments no projeto e adicione endereços suportados ao respetivo conjunto no Account. Envie project explicitamente, em vez de depender do projeto predefinido. amount é uma cadeia em unidades do criptoativo; invoice_currency/invoice_amount descrevem separadamente o preço cotado da encomenda.

Defina CRYPTANIO_PROJECT_ID como o projeto Payments e CRYPTANIO_API_KEY como chave com permissão invoices. CRYPTANIO_OPERATION_ID deve ser único para nova encomenda; reutilize-o ao repetir a mesma operação. A fatura é criada em dados live.

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

A chave deve permitir invoices e Payments; a chave do exemplo Monitoring pode estar restrita a outro serviço. Idempotency-Key contém 16-80 letras ASCII, dígitos, - e _. Repetir o mesmo pedido normalizado com a mesma chave devolve a fatura existente com 201; conteúdo alterado devolve 409 conflict. Chaves de operação são comuns à conta. reference não as substitui.

Mostre ao comprador a rede, o ativo, o endereço, amount e o prazo retornados. Quando houver payment_route, envie seu kind e o valor exato de value como string: destination_tag, memo, comment ou reference é obrigatório para atribuir o pagamento a esta fatura. O campo reference do pedido é separado.

Use o payment_uri retornado no QR de pagamento quando estiver presente. Uma referência Solana Pay não é um memo da carteira: não substitua a URI por um endereço simples nem a reconstrua. Se a carteira não puder incluir o identificador obrigatório, ofereça ao pagador checkout_url ou uma carteira compatível.

checkout_url é a página de pagamento hospedada para novas faturas. Compartilhe apenas a URL exata retornada com o pagador; não a construa a partir do ID. O link revela os detalhes e o status do pagamento, portanto não o publique em registros públicos. Se não existir, mostre as instruções completas. Um redirecionamento do navegador não confirma o pagamento: verifique a API ou um webhook validado.

asked pode diferir de amount para distinguir pedidos. Faça a conciliação usando amount_raw como inteiro de precisão arbitrária. O TTL padrão é de 60 minutos, com máximo de 10080 minutos. As listas de faturas aceitam before, mas não retornam next_before: continue com o ID do último item e pare ao receber uma página vazia.

Customer

CampoTipoObrigatórioDescrição
idstringSimIdentificador do cliente no seu sistema.
maxLength: 120
Product

CampoTipoObrigatórioDescrição
idstringNãoIdentificador do produto no seu sistema.
maxLength: 120
namestringNãoNome do produto.
maxLength: 200
quantityintegerNãoQuantidade.
minimum: 1; maximum: 1000000
Payer

CampoTipoObrigatórioDescrição
commentstringSimComentário do pagador.
maxLength: 500
InvoiceMetadata

Até 20 pares, no máximo 8192 bytes JSON. Não inclua segredos.

object Até 20 pares, no máximo 8192 bytes JSON. Não inclua segredos.

Monitorizações Monitoring

Uma monitorização pertence a um projeto Monitoring. O mesmo endereço pode existir em vários projetos com regras de direção e ativos independentes. Associe listas do livro de endereços e Address Sources no Account; esta API REST não disponibiliza os seus comandos de gestão.

Lista por ID descendente. Se houver next_before, passe-o como before no pedido seguinte mantendo projeto e filtros. limit tem predefinição 50, máximo 200. Guarde IDs como cadeias. Monitorizações removidas saem da lista ativa; o endereço permanece noutros projetos e no livro de endereços.

Eventos e histórico

/v1/events devolve eventos disponíveis à chave entre serviços; /v1/payments limita-se a Payments. Filtre por project, address, chain, type, watch_id e tx_id. before é cursor ID, não data; não há filtro from/to. next_before permite obter a página seguinte.

O histórico de eventos detetados está disponível até 30 dias. Não é um arquivo de todas as mensagens entregues: não se garante a recuperação de notice e webhook.test por esta via. REST Event tem um esquema próprio, separado dos webhooks; podem ser adicionados campos em v1.

Event

CampoTipoObrigatórioDescrição
event_idstringSimIdentificador opaco; mantenha-o como cadeia.
minLength: 1
event_typestringSimTipo de evento; podem ser adicionados novos tipos.
chainstringSimCódigo da rede.
servicestringNãoServiço, se conhecido.
watch_idstringNãoID de monitorização do projeto, quando associado.
minLength: 1
occurred_atstringSimData e hora UTC em RFC 3339.
date-time
paymentobject | nullSimDocumento de pagamento, ou null para eventos sem pagamento. GET /events não devolve conteúdos contract/notice.
sandboxbooleanNãoEvento de teste; omissão significa false.
EventPayment

Documento de pagamento REST/SSE. Campos dependem do evento e rede; não é o formato normalizado webhook v1.

CampoTipoObrigatórioDescrição
tx_idstringNãoIdentificador da transação.
indexintegerNãoÍndice da transferência na transação.
minimum: 0
heightintegerNãoAltura do bloco, quando conhecida.
minimum: 0
addressstringNãoEndereço observado.
assetstringNãoAtivo REST/SSE: identificador de texto, não o objeto de ativo webhook.
amount_rawstringNãoMontante inteiro nas unidades mínimas como cadeia.
pattern: ^[0-9]+$
amountstringNãoMontante decimal exato como cadeia; não use vírgula flutuante.
pattern: ^[0-9]+(?:\.[0-9]+)?$
decimalsintegerNãoCasas decimais.
minimum: 0
confirmationsintegerNãoConfirmações.
minimum: 0
revisionintegerNãoRevisão do estado da transferência.
minimum: 0
directionstringNãoDireção em relação ao endereço observado.
in, out
simulatedbooleanNãoEvento simulado.
latebooleanNãoTransferência detetada tardiamente.
block_hashstringNãoHash do bloco.
match_keystringNãoIdentificador de correspondência, quando usado pela rede.
metaobjectNão
invoiceobjectNão
customerobjectNão
productobjectNão
payerobjectNão
metadataobjectNão

Eventos webhook

A entrega ocorre pelo menos uma vez: um evento pode chegar várias vezes. Após verificar a assinatura, elimine duplicados por event_id na integração. Grave o processamento e a alteração de negócio numa única transação de base de dados. Uma chave tx_id/address/asset não substitui event_id: junta transições, direções e projetos diferentes.

Leia event_type e event_id do corpo assinado. Cabeçalhos X-Event-Type/X-Event-Id não estão no HMAC; compare-os com o corpo se os usar. Considere project_id, direction e payment.revision ao atualizar pagamentos. Não pressuponha ordem de entrega; ignore tipos desconhecidos com segurança e conserve-os para diagnóstico.

FamíliaCorpo
payment.pending / confirmed / rolled_backPagamento recebido
debit.pending / confirmed / rolled_backPagamento de saída
contract.approval / owner_added / owner_removed / threshold_changed / permissions_changedcontract
asset.unexpectedcontract; o ativo não é creditado como pagamento aceite
account.notice / account.notification / treasury.alarm / subscription.noticenotice.subject, notice.text
webhook.testEvento de controlo sem pagamento

schema_version: v1 contém payment, contract ou notice conforme o tipo; webhook.test não contém nenhum. IDs e montantes são cadeias. amount_raw contém unidades mínimas; amount é representação decimal. Verifique redes e ativos via chains. Esquemas completos em OpenAPI.

CabeçalhoSignificado
X-TimestampSegundos Unix no momento da assinatura
X-Signaturehex HMAC-SHA256(timestamp + '.' + raw body)
X-Event-Id / X-Event-TypeComparar com o corpo assinado
X-AttemptNúmero da tentativa a partir de 1

Devolva 2xx após aceitar duravelmente o evento. Tempo limite da tentativa: 10 segundos. Falhas de rede, 408, 425, 429 e 5xx repetem até 24 horas, com atrasos de 2 segundos a 15 minutos e variação aleatória; respeita Retry-After. Não segue redirecionamentos. Outros 3xx/4xx terminam a entrega; 410 desativa o destino e a sua fila pendente.

Exemplo de formato webhook (ilustrativo)
{
  "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

Corpo público assinado webhook v1. payment.* e debit.* contêm payment; contract.* e asset.unexpected contêm contract; webhook.test não tem conteúdo de negócio; account.notice, account.notification, treasury.alarm e subscription.notice contêm notice. Elimine duplicados de entrega por event_id.

CampoTipoObrigatórioDescrição
schema_versionstringSimVersão do conteúdo webhook.
v1
event_idstringSimID do evento: inalterado nas repetições de entrega. Estados diferentes podem ter valores event_id diferentes.
minLength: 1
event_typestringSimTipo no corpo assinado; use após verificar a assinatura. Podem surgir novos tipos.
occurred_atstringSimData e hora UTC em RFC 3339.
date-time
project_idstringSimIdentificador opaco; mantenha-o como cadeia.
minLength: 1
servicestringNãoServiço do projeto, quando aplicável.
modestringSimModo do evento.
live, test
sandboxbooleanSimIndicador explícito de simulação.
paymentobjectNão
contractobjectNão
invoiceobjectNão
customerobjectNão
productobjectNão
payerobjectNão
metadataobjectNão
noticeobjectNão
WebhookPayment

CampoTipoObrigatórioDescrição
chainstringSimCódigo da rede.
directionstringSimPagamento recebido: in; débito de saída: out.
in, out
assetobjectSim
addressstringSimEndereço observado.
tx_idstringSimID da transação.
indexintegerSimÍndice da transferência; não pressuponha 0 em todas as redes.
minimum: 0
heightintegerNãoAltura do bloco, se conhecida.
minimum: 0
block_hashstringNãoHash do bloco, se conhecido.
match_keystringNãoIdentificador de correspondência da rede, quando aplicável.
amountstringSimMontante decimal exato como cadeia; não use vírgula flutuante.
pattern: ^[0-9]+(?:\.[0-9]+)?$
amount_rawstringSimMontante inteiro nas unidades mínimas como cadeia.
pattern: ^[0-9]+$
decimalsintegerSimCasas decimais.
minimum: 0
confirmationsintegerSimConfirmações.
minimum: 0
revisionintegerSimRevisão do estado da transferência. Não junte valores event_id distintos pela identidade da transação.
minimum: 0
latebooleanNãoTransferência detetada tardiamente; não equivale ao estado de fatura late.
simulatedbooleanNãoTransferência simulada.
valuationobjectNão
WebhookAsset

CampoTipoObrigatórioDescrição
symbolstringNãoSímbolo, se conhecido; não basta para determinar a identidade do token.
standardstringNãoNorma do token, se conhecida.
contractstringNãoContrato do token na sua rede, quando aplicável.
identifierstringNãoOutro identificador de token específico da rede.
WebhookContract

CampoTipoObrigatórioDescrição
chainstringSimCódigo da rede.
addressstringSimEndereço ou contrato observado.
tx_idstringSimID da transação.
indexintegerSimÍndice do evento.
minimum: 0
heightintegerNãoAltura do bloco.
minimum: 0
block_hashstringNãoHash do bloco.
kindstringNãoTipo de alteração.
assetstringNãoIdentificador do ativo afetado, se conhecido.
detailobjectNão
simulatedbooleanNãoEvento simulado.
WebhookInvoice

CampoTipoObrigatórioDescrição
idstringSimIdentificador opaco; mantenha-o como cadeia.
minLength: 1
referencestringNãoReferência da encomenda.
statusstringNãopending aguarda pagamento; seen detetado; partial parcialmente pago; paid liquidado; underpaid/overpaid/late exigem decisão; expired prazo terminado; canceled anulado.
pending, seen, paid, underpaid, partial, overpaid, expired, late, canceled
currencystringNãoMoeda da cotação da encomenda.
amountstringNãoMontante decimal exato como cadeia; não use vírgula flutuante.
pattern: ^[0-9]+(?:\.[0-9]+)?$
Notice

CampoTipoObrigatórioDescrição
subjectstringSimAssunto do aviso.
textstringSimTexto do aviso.
Valuation

CampoTipoObrigatórioDescrição
currencystringSimMoeda de avaliação, como USD.
amountstringSimMontante decimal exato como cadeia; não use vírgula flutuante.
pattern: ^[0-9]+(?:\.[0-9]+)?$
ratestringSimTaxa de câmbio do ativo como cadeia decimal.
pattern: ^[0-9]+(?:\.[0-9]+)?$
rate_atstringSimData e hora UTC em RFC 3339.
date-time
providerstringNãoNome da fonte de cotação, se conhecido.

Verificar assinaturas

Verifique HMAC nos bytes originais do corpo antes de analisar JSON, incluindo espaços e quebras de linha. A verificação temporal limita repetição, mas não substitui deduplicação persistente de event_id. Exemplos aceitam apenas assinaturas hex de 64 caracteres e timestamps a 300 segundos da hora do servidor. Use o segredo do destino webhook específico.

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;
}

Transferir exemplo Node.js

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
}

Transferir exemplo Go

Endpoints webhook

Adicione uma URL HTTPS pública na porta 443 para um projeto específico. Não são permitidos credenciais na URL, fragmentos, redirecionamentos ou destinos não públicos. São permitidos até 20 endpoints por conta. Cada um tem um segredo próprio, devolvido apenas na criação inicial; guarde-o no servidor.

Criar novamente a mesma URL no mesmo projeto e modo devolve 200 e o endpoint existente sem o segredo. Um novo endpoint devolve 201. DELETE devolve 200 com id e deleted: true, incluindo uma repetição segura. Uma chave só vê o seu modo e projetos permitidos; a entrega segue as definições do projeto.

Fluxo SSE

SSE serve para integração no servidor e visualização em direto; não garante entrega nem repetição de eventos perdidos. Use cliente HTTP no servidor com cabeçalho Bearer. EventSource padrão do navegador não o envia; não coloque a chave API em código do navegador ou query string.

As mensagens usam event: payment e formato StreamEvent próprio, não webhook v1 ou REST Event. Comentários começam por dois pontos; heartbeats chegam a cada cerca de 20 segundos. retry: 5000 sugere reconexão. Após desligar, obtenha o histórico blockchain disponível através de events.

StreamEvent

JSON em data SSE; difere de webhook v1. Eventos sem pagamento omitem payment e podem incluir contract.

CampoTipoObrigatórioDescrição
event_idstringSimIdentificador opaco; mantenha-o como cadeia.
minLength: 1
event_typestringSimTipo de evento; podem ser adicionados novos tipos.
chainstringSimCódigo da rede.
servicestringNãoServiço, se conhecido.
watch_idstringNãoID de monitorização do projeto, quando associado.
minLength: 1
occurred_atstringSimData e hora UTC em RFC 3339.
date-time
paymentobject | nullNãoDocumento de pagamento, ou null para eventos sem pagamento. GET /events não devolve conteúdos contract/notice.
sandboxbooleanNãoEvento de teste; omissão significa false.
project_idstringNãoIdentificador opaco; mantenha-o como cadeia.
minLength: 1
project_namestringNãoNome do projeto.
urlstringNãoLigação ao evento no Account.
uri
contractobjectNão
modestringNãolive ou test.
live, test

Estados de pagamentos e faturas

O estado do pagamento na blockchain difere do estado da encomenda. payment.pending indica deteção antes de confirmações suficientes; payment.confirmed indica que foi atingida a regra de confirmação da rede/projeto; payment.rolled_back comunica uma reversão. Não satisfaça encomendas com pending, débitos de saída ou eventos simulados.

FaturaSignificado
pendingA aguardar pagamento
partialParte recebida; sujeita à política de pagamentos parciais do projeto
paidPagamento aceite
underpaidPagamento insuficiente exige decisão
overpaidPagamento excessivo exige decisão segundo a política aplicável
latePagamento após o prazo exige decisão
expiredPrazo de pagamento terminado
canceledFatura cancelada; o registo continua consultável

needs_decision está presente em underpaid, overpaid e late. Resolva no Account. Reorganização e reinclusão podem criar novas transições e novo payment.revision; confirmed não garante incondicionalmente ausência de alterações futuras.

Erros e repetições seguras

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

Use estado HTTP e error.code na lógica, message para diagnóstico. Listas bem-sucedidas têm data; um objeto é devolvido diretamente. Health usa esquema status/version próprio, inclusive em 503. Não dependa da redação exata da mensagem.

HTTPAção
400Corrija JSON, formatos e parâmetros; não repita sem alterações
401Verifique chave, validade, suspensão e revogação
403Verifique âmbitos, leitura/escrita, projeto, serviço, IP e verificação da conta
404Verifique ID, modo da chave e acesso; as restrições podem ocultar o recurso
402Limite de monitorizações Monitoring; verifique o plano
409Conflito, serviço inativo, conjunto ocupado ou limite; consulte code
429Respeite Retry-After; reduza a taxa conjunta de pedidos da conta
500 / 503Repita com espera progressiva limitada; criação de fatura apenas com a Idempotency-Key original

Um tempo limite excedido não significa que a operação não foi executada. Não altere a chave de operação da fatura numa repetição. Em métodos sem proteção contra duplicados, consulte primeiro o estado; nem todo POST é idempotente.

Redes e limites

Use chains no host API selecionado para catálogo de redes, ativos, capacidades e confirmações. Constarem do catálogo geral não garante que uma rede esteja ativa nesse ambiente ou suporte todas as operações. Verifique quotas e orçamento no Account; preços na página Preços.

Quota REST autenticada da conta: 10 pedidos/s sem serviço pago, 50 com serviço pago; capacidade de pico breve 20/100. Todas as chaves e modos da conta partilham a quota. Exceder devolve 429 com Retry-After. Quotas de serviço e limites de taxa API são restrições distintas.

Preços e quotas dos serviços

Versões da API

Esta referência descreve v1 na versão 1.0.0 62; atualizada em 2026-10-10. Antes de usar novas capacidades, verifique a versão implantada via GET /v1/health. A versão da documentação não confirma implantação.

API públicaContrato
https://api.cryptanio.com/v1

Use /v1 para integrações estáveis. Um caminho sem versão escolhe o contrato estável atual do ambiente; /vN desconhecido devolve 404. X-API-Version identifica o contrato; X-Server-Version e health.version a versão do produto, não um contrato API diferente.

Transferir OpenAPI 3.1

Alterações da API

A versão 1.0.0 62 inclui SDKs transferíveis para Node.js, Python, PHP, Go e Rust e MCP local para agentes de IA. Referência, Markdown e exemplos HTTP diretos continuam disponíveis separadamente. Não há sandbox pública. O comportamento API mantém-se.

Em v1, clientes devem tolerar campos adicionais de resposta. Aceitar um tipo desconhecido não significa satisfazer encomenda ou creditar pagamento. Verifique disponibilidade das alterações na versão do ambiente escolhido antes de usar.