Todos os posts

12 min de leitura

Construa sobre a API da CardanoWall

Como construir seu próprio produto sobre a CardanoWall: cote, faça upload, publique, leia, verifique e monitore registros Label 309 pela mesma API de gateway sobre a qual a própria CardanoWall roda.

Você pode integrar um recurso de Proof of Existence (prova de existência) ao seu próprio produto sem levar os usuários pelo site da CardanoWall. A CardanoWall é uma interface de usuário sobre um gateway hospedado, e esse gateway expõe uma API HTTP simples: cotar uma prova, fazer upload de conteúdo quando há necessidade de armazenamento, publicar um registro Label 309, acompanhar seu status, ler registros públicos, consultar saldos e receber webhooks. A prova que chega à Cardano são metadados Label 309 padrão, não um formato privado exclusivo da CardanoWall — então qualquer pessoa, com qualquer ferramenta, pode verificá-la depois.

Esse é o formato que importa. A experiência do produto pode ser inteiramente sua. A prova continua verificável de forma independente. Esta é a mesma API sobre a qual o próprio aplicativo web e o worker da CardanoWall rodam — não há porta privada nem caminho interno mais rápido.

O que você pode construir sobre ela?

Onde quer que a Proof of Existence se encaixe em um fluxo de trabalho, a API serve:

  • um produto SaaS que carimba documentos de clientes no tempo;
  • um pipeline de CI/CD que ancora manifestos de lançamento (veja provas em CI/CD);
  • uma plataforma de IA que publica registros de proveniência em escala;
  • um arquivo de conformidade que registra lotes diários de provas;
  • uma ferramenta jurídica que sela provas para destinatários específicos;
  • um sistema de auditoria interna que assina instantâneos de controles;
  • um explorador público ou página de perfil que lista os registros de quem publica.

A API não é apenas um invólucro de conveniência em torno do site. Ela é a superfície de automação — aquilo que você usa quando não há um humano no fluxo.

Qual é o fluxo principal de publicação?

Uma publicação tem três etapas: cotar, fazer upload (somente quando os bytes precisam de armazenamento) e, então, publicar. No plano de dados do gateway (/api/v1/*), isso corresponde a:

  • POST /api/v1/poe/quote — trava o preço por uma janela curta.
  • POST /api/v1/poe/uploads — armazena conteúdo, retornando URIs endereçadas por conteúdo.
  • POST /api/v1/poe/uploads/sessions e suas rotas de chunk — o caminho retomável para arquivos grandes.
  • POST /api/v1/poe/publish — submete o registro finalizado.
  • POST /api/v1/poe/publish-batch — submete muitos registros em uma única chamada.
  • GET /api/v1/poe/events/{poe_id} — transmite atualizações de status via Server-Sent Events.

Os corpos exatos de requisição e resposta ficam no documento OpenAPI do gateway, servido por toda implantação — vincule-se a ele, não a um trecho de blog. O que permanece estável é o modelo mental: trave o preço primeiro, armazene qualquer conteúdo e, então, submeta os bytes do registro finalizado em CBOR canônico junto com o id da cotação.

Por que a cotação vem primeiro?

Porque publicar é uma operação paga, e o preço não é conhecível de antemão.

Um gateway paga custos reais em seu nome: taxas de transação da Cardano, armazenamento na Arweave quando há conteúdo anexado, exposição cambial entre o USD e essas redes, e a margem do operador. Uma cotação torna esse custo explícito antes de a chamada de publicação gastar qualquer coisa. (Para o raciocínio por trás da publicação paga, veja por que publicar tem um preço.)

Uma resposta de cotação carrega um quote_id, um detalhamento de preços (com componentes de rede, armazenamento e serviço), a margem aplicada, o quão recente está o instantâneo da taxa de câmbio e um carimbo de tempo de expiração. O preço fica travado apenas por uma janela limitada — cerca de quinze minutos — após a qual você solicita uma nova cotação.

Isso permite que seu aplicativo decida:

  • se a conta tem saldo para arcar com a publicação;
  • se o instantâneo da taxa de câmbio está recente o suficiente para a sua política;
  • se a operação precisa de confirmação do usuário;
  • se um lote grande deve ser dividido;
  • se deve tentar novamente com uma nova cotação quando a antiga expira.

Não exiba um rótulo de "grátis" até que o gateway confirme que a operação não custa nada. Um registro somente de hash, sem armazenamento, pode ser barato, mas a autoridade sobre o preço é o gateway, não a sua interface.

O que faz a etapa de upload?

O upload cuida dos bytes que precisam de um lugar para morar.

Uma prova somente de hash não faz upload de nada — você já tem o digest. Um registro com conteúdo anexado, um texto cifrado selado ou material de recuperação precisa de armazenamento endereçado por conteúdo, e os endpoints de upload armazenam esses bytes e retornam uma URI como ar://.... A API suporta uploads multipart, resultados por arquivo, deduplicação por hash do conteúdo dentro de uma conta e sessões retomáveis para arquivos grandes demais para enviar em uma única requisição. A CardanoWall não impõe nenhum tamanho máximo fixo de upload — o conteúdo é cobrado por byte, e uploads de vários gigabytes são esperados.

Trate o upload como seu próprio pequeno ciclo de vida:

  1. Faça upload dos bytes.
  2. Receba a URI endereçada por conteúdo.
  3. Construa ou finalize o registro Label 309 usando essa URI.
  4. Publique o registro.

Se um upload retornar um id de tentativa em andamento, consulte o endpoint de status dessa tentativa em vez de refazer o upload às cegas — reenviar um arquivo de vários gigabytes porque você perdeu uma resposta é exatamente o tipo de erro que o id de tentativa existe para evitar.

O que a publicação faz, e por que é assíncrona?

A publicação submete o registro e inicia o pipeline da cadeia.

A chamada de publicação aceita os bytes do registro finalizado em CBOR canônico mais o quote_id. O gateway ancora o registro na Cardano sob o rótulo de metadados 309, debita o valor cotado e retorna um id de registro do gateway (um valor poe_...) enquanto a transação ainda está em submissão e confirmação.

Essa assincronia importa para o seu design. Quando a chamada retorna, o hash da transação na cadeia talvez ainda não exista. Mostre um estado pendente e fique à escuta de atualizações. O status reportado pela API passa por estes valores:

  • submitting — a transação está sendo construída e transmitida;
  • confirming — está na cadeia, mas abaixo do limiar de confirmação;
  • confirmed — cruzou esse limiar e está liquidada;
  • failed — a publicação falhou de forma terminal e não vai chegar.

O fluxo de status em GET /api/v1/poe/events/{poe_id} existe exatamente para isso. Em uma falha terminal, o próprio gateway reverte o débito — assim seu produto pode dizer honestamente aos usuários "você só é cobrado pelo que chega à cadeia" sem precisar rodar sua própria reconciliação. Não construa um caminho de reembolso do lado do fornecedor para falhas de publicação; isso reembolsaria em dobro.

O que seu cliente da API deve armazenar?

Armazene o suficiente para reconectar o fluxo de trabalho — e nada além disso. No mínimo:

  • o id do seu próprio usuário ou conta;
  • o poe_id do gateway;
  • o id da cotação usado na publicação;
  • o digest do registro, ou um hash dos bytes do registro;
  • o hash final da transação Cardano, assim que ele existir;
  • status e carimbos de tempo;
  • quaisquer ids de tentativa de upload;
  • quaisquer URIs endereçadas por conteúdo;
  • qualquer material local de que você vá precisar para verificar depois.

Não trate seu banco de dados como a prova. Trate-o como um read model do produto. A prova é o registro Label 309 na cadeia mais o conteúdo ou as chaves necessárias para verificá-lo — e essa combinação se sustenta sozinha, independente dos seus servidores.

Como você lê e verifica registros?

A superfície de registros foi construída para leituras públicas e anônimas:

  • GET /api/v1/records — o feed de registros na cadeia, com filtros e paginação.
  • GET /api/v1/records/count — uma contagem para esse feed.
  • GET /api/v1/records/{tx_hash} — um único registro por hash de transação.
  • POST /api/v1/records/{tx_hash}/verify — um relatório de verificação no servidor.

As rotas de listagem e de obtenção atendem chamadores anônimos — páginas públicas de verificação e exploradores não precisam de credencial. Um bearer token pode adicionar contexto de conta onde for relevante, mas a verificação pública de registros nunca deve depender de uma sessão privada da CardanoWall.

Use esses endpoints pela conveniência do produto. Para checagens de alta garantia, rode também um verificador autônomo que busca os dados da cadeia por uma infraestrutura Cardano que ele escolhe e produz um relatório independente. Essa é a divisão saudável: a API torna mais fácil construir aplicativos, mas a prova ainda precisa se sustentar fora da API. Os SDKs e a CLI de código aberto entregam exatamente esse verificador — veja verificando um registro Label 309 para entender como ele funciona de ponta a ponta.

Como a autenticação deve funcionar?

Mantenha as credenciais estreitas e mantenha as credenciais de operador no seu backend.

O gateway separa dois planos. Seus usuários atuam pelo plano de dados (/api/v1/*) com um account token de vida curta ou uma chave de API que seu backend emite por sessão. Apenas o seu backend detém a credencial de operador para o plano de controle (/control/v1/*) — provisionar contas, aplicar créditos quando sua cobrança arrecada dinheiro, definir margens e emitir esses account tokens.

O acesso ao plano de dados é escopado. Os escopos que você vai usar:

  • poe:create — cotar, fazer upload, publicar e publicar em lote;
  • poe:read — leituras de registros, a rota de verificação e o fluxo de status quando chamado com um bearer;
  • account:read — leituras de saldo e do ledger;
  • webhooks:read e webhooks:write — gerenciamento de webhooks no escopo da conta;
  • billing:read — reservado para superfícies de cobrança do fornecedor.

Uma página de publicação precisa de poe:create; um widget de saldo precisa de account:read; nenhum dos dois precisa de mais. Credenciais de operador nunca devem chegar a um bundle de navegador, a um aplicativo móvel, ao script de um parceiro ou a um job de CI que só precisa publicar provas — esses emitem seu próprio account token escopado. Um account token vazado deve ser um problema de uma hora, não um incidente.

Como retentativas e idempotência devem funcionar?

Projete as retentativas antes da produção, porque sistemas de publicação falham de maneiras banais: oscilações de rede, cotações expiradas, saldo insuficiente, limites de taxa, um upload ainda em andamento ou um fluxo de status interrompido.

Uma integração sólida deve:

  • usar idempotência onde a API a suportar, com chave em um id de origem estável;
  • tratar a expiração da cotação como algo normal — busque uma nova cotação e siga em frente;
  • consultar o endpoint autoritativo de tentativa ou de registro após uma falha incerta, em vez de resubmeter às cegas;
  • evitar fazer upload em dobro de arquivos grandes;
  • evitar creditar saldos em dobro (use o próprio id do pagamento como chave de cada crédito);
  • registrar ids de requisição e ids de gateway para suporte;
  • distinguir, nos seus relatórios, uma publicação que falhou de um registro não verificável.

A publicação deduplica pelos bytes do registro, e os lotes de upload suportam replay idempotente. Apoie-se nessas semânticas em vez de um laço de "tentar de novo e torcer".

O que os webhooks devem fazer?

Os webhooks são a forma de você construir read models — não consultando a cada segundo e, com certeza, não lendo as tabelas do banco de dados do gateway, que são internas ao engine e mudam sem aviso.

Registre uma assinatura de webhook e o gateway envia eventos de ciclo de vida: poe_status_changed, balance_changed, intenções de reembolso, falhas de upload. Operadores podem assinar o firehose completo de toda a instância; rotas de webhook no escopo da conta também existem no plano de dados. Uma visão de "itens enviados" — em que cada usuário vê os registros que publicou, com status ao vivo — é o uso canônico: consuma poe_status_changed, projete-o na sua própria tabela e renderize a partir daí.

Seu receptor deve verificar a assinatura de cada entrega, aceitar entrega ao menos uma vez, usar o id do evento ou da entrega como chave das projeções e tratar uma reentrega como um no-op. O read model pertence ao seu aplicativo. O estado canônico de gasto e publicação pertence ao gateway — coloque-o em cache para renderização se precisar, mas leia do gateway para qualquer decisão que controle um gasto.

O que nunca deve sair do cliente?

Material privado de identidade. Seu aplicativo chama a API para publicar registros; ele nunca deve entregar ao gateway a Identity Seed do usuário, a chave privada de assinatura ou a chave privada do destinatário.

  • Para registros assinados, assine localmente ou use assinatura fora do host — os SDKs expõem um fluxo em que a chave privada vive em um KMS, em um HSM ou em uma máquina isolada (air-gapped), e apenas a chave pública e a assinatura cruzam a rede.
  • Para registros selados, cifre localmente antes do upload quando o caso de uso exigir confidencialidade fim-a-fim.
  • Para a verificação do destinatário, decifre localmente.

A API é para operações de publicação e de ciclo de vida. Ela não é a raiz de confiança, e foi projetada para nunca precisar ser. Para o princípio mais amplo, veja por que as chaves nunca saem do dispositivo.

Por onde começar

O caminho mais rápido são os SDKs e a CLI de código aberto em github.com/cardanowall: um SDK em TypeScript (@cardanowall/sdk-ts), um SDK em Python (cardanowall-sdk), um SDK em Rust (cardanowall) e a CLI cardanowall. Todos são agnósticos quanto ao gateway — você fornece a URL base e uma chave de API opaca — e todos entregam o mesmo verificador autônomo. Se você preferir antes operar a API à mão, publique sua primeira prova percorre um registro de ponta a ponta, e usando a CLI em automação cobre o caminho via script. Se você prefere rodar o backend por conta própria em vez de usar o hospedado, o gateway também é código aberto — veja rode seu próprio gateway.

Leitura complementar

apidevelopersgateway