Skip to main content
X402 é um protocolo de pagamento em blockchain “cobrado por HTTP 402” proposto pela Coinbase: o servidor retorna 402 Payment Required em uma solicitação sem token, anexando o campo accepts: [...] que lista as cadeias / ativos / preços aceitáveis; o cliente assina localmente uma autorização (no EVM é Permit2 / EIP-712, no Solana é autorização de transferência de token SPL), coloca o envelope codificado em base64 no cabeçalho PAYMENT-SIGNATURE e reenvia. O servidor valida e realmente liquida na blockchain, retornando o resultado do negócio.
O cliente X402 da Ace Data Cloud chama diretamente a API de destino e usa o 402 Payment Required e accepts retornados em tempo real como base para preço e assinatura. A capacidade de pagamento do Facilitator pode ser verificada em /.well-known/x402.
@acedatacloud/sdk e acedatacloud expõem um gancho paymentHandler: quando uma solicitação feita pelo SDK recebe 402, ele chama o handler injetado para obter o cabeçalho PAYMENT-SIGNATURE e reenvia a solicitação original. Usando @acedatacloud/x402-client / acedatacloud-x402 em conjunto com o SDK, todo o processo é completamente transparente para o código de negócios — você só precisa usar client.openai.chat.completions.create(...), que parece idêntico ao modo token, mas a base é paga por chamada, sem necessidade de recarga prévia. Este artigo:
  • Realizou uma verificação completa do fluxo “sem token + injeção de handler X402” no lado do TS (Verificação T12)
  • Listou as diferenças entre os dois fluxos de assinatura EVM / Solana
  • Apresentou três adaptações: modo de chave privada viem, modo de carteira de navegador, modo EVMAccountSigner em Python
  • Esclareceu o campo preferScheme / prefer_scheme, que pode causar confusão

I. Visão Geral do Protocolo (Leitura Obrigatória)

Uma chamada X402 bem-sucedida envolve 3 RTT HTTP:
O envelope X402 é um JSON que, após ser codificado em base64, é colocado no cabeçalho PAYMENT-SIGNATURE. Estrutura (trecho):
O nível superior do envelope é x402Version: 2, e usa o objeto accepted para declarar o scheme e network escolhidos (identificação CAIP-2). preferScheme / prefer_scheme é usado para escolher a preferência quando o servidor oferece múltiplos schemes ao mesmo tempo. Se o servidor expuser apenas exact, esse campo será ignorado; se upto for definido, mas o servidor não o expuser, ele reverterá para o primeiro item correspondente.

II. TypeScript: Uso de Carteira de Navegador + viem no Servidor

Instalação

Versões testadas:

Assinatura Completa de createX402PaymentHandler

O valor de retorno é um (ctx) => Promise&lt;{ headers: Record<string, string> }> que corresponde exatamente à assinatura do gancho paymentHandler do SDK.

Uso 1: Navegador (MetaMask / WalletConnect)

Na primeira chamada, o navegador exibirá duas solicitações de assinatura: a primeira é a aprovação única do Permit2 para USDC (o valor é MaxUint256, gravado na blockchain); a segunda é a assinatura EIP-712 do envelope X402 (não vai para a blockchain, apenas para verificação do facilitator). Chamadas subsequentes precisam apenas da segunda assinatura, a experiência é “um clique para assinar → obter resultado”.

Uso 2: Servidor Node + chave privada viem (adequado para backend / CLI)

@acedatacloud/x402-client no lado TS aceita apenas o provedor EIP-1193 — ele não gerencia diretamente a chave privada. No cenário Node / CLI, a prática padrão é usar viem para encapsular a chave privada em um WalletClient, e então usar @ethereumjs/util ou a adaptação EIP-1193 interna do viem.
Se achar que a adaptação EIP-1193 do viem não é estável o suficiente, você também pode usar a signEVMUptoPayment de forma mais básica, conectando accepts → signed envelope → PAYMENT-SIGNATURE header, pulando os ganchos do SDK; mas ainda assim, é recomendado usar createX402PaymentHandler para evitar a manutenção de atualizações de protocolo.

Uso 3: Solana

A cadeia Solana atualmente só expõe o esquema exact, portanto preferScheme não tem efeito na Solana.

Três, Python: Modo de Chave Privada

O acedatacloud-x402 em Python segue o caminho de assinar diretamente com a chave privada (sem abstração EIP-1193), mais adequado para servidores / executores de tarefas.

Instalação

Versão testada:

EVM (Base / Skale)

Solana

Aprovação única (apenas EVM na primeira vez)

No EVM Base, o X402 utiliza Permit2, e a carteira precisa fazer uma aprovação de MaxUint256 para o contrato Permit2 em USDC. O acedatacloud-x402 possui a função approve_permit2 embutida:
Essa transação precisa ser enviada apenas uma vez, e depois todas as pagamentos X402 EVM usarão essa autorização. Solana não precisa.

Quatro, Verificação de Execução Real

Objetivo do teste: SDK TS sem passar token, injetar manipulador X402, conseguir construir e iniciar requisições normalmente (sem consumir USDC real na cadeia para validação leve).
Saída:
Resultados explicam:
  • Não foi passado apiToken, a construção do SDK não gerou erro, provando que o modo X402 é de fato um substituto legítimo para o token.
  • createX402PaymentHandler retorna uma função (gancho), que o SDK só chamará ao receber 402.
  • Testes de ponta a ponta de pagamento na cadeia real não foram incluídos neste tutorial, pois envolvem deduções reais de USDC; consulte o Guia de Integração X402 para exemplos e2e.
O lado Python create_x402_payment_handler também fez a mesma verificação - o valor de retorno da função é chamável, e ao injetar payment_handler=..., a construção de AceDataCloud(...) não gera erro. A semântica está alinhada em ambos os lados.

Cinco, Comparação com o “Modo de Token Bearer”

六、常见陷阱

  1. chat 类必须 preferScheme=upto:用 exact 会让 facilitator 按 maxAmountRequired(不是实际用量)扣 USDC。
  2. Node 端别传裸私钥给 createX402PaymentHandler:TS 包不接受 { privateKey },必须包成 EIP-1193 provider(推荐 viem WalletClient)。
  3. 首次调用是双签名:第一次签 Permit2 approve(上链、有 gas),第二次签 X402 envelope(不上链)。后续调用只剩第二次。
  4. Solana 没有 Permit2 概念:直接签 SPL token transfer 授权,不需要 approve;但目前 Solana 链上只支持 exact。
  5. 业务报错和支付错误区分:402 → handler 失败抛 X402SignError(具体类型按链不同);后续重发后业务接口的报错(401 / 422 / 5xx)仍然按普通 SDK 异常分类。
  6. viem 适配最稳的写法:evmProvider: walletClient as any 会失去类型检查但兼容性最好;如果想保留类型,用 viem 的 .transport.request 单独包一层 { request } 对象传进去。

了解更多