Uma API, um único fluxo hospedado
A CryptoPayIn precifica um pedido na moeda de apresentação escolhida, trava snapshots verificados de fiat/USD e cripto/USD, aloca um endereço de depósito dedicado e monitora seus próprios nós de blockchain à espera do pagamento. A contabilidade interna, as taxas e os saldos permanecem em USD. Seu backend recebe uma URL de checkout imediatamente e, em seguida, eventos de ciclo de vida assinados.
Esta é uma API de produção. Não existe prefixo de sandbox. Toda criação bem-sucedida aloca um endereço on-chain real. Use um valor pequeno em moeda suportada para testes ponta a ponta e mantenha as chaves secretas no seu servidor.
Como a integração se encaixa
Gere um segredo no Painel -> Desenvolvedores.
Envie via POST a moeda do pedido, o valor e o ativo escolhido.
Envie o cliente para a URL hospedada retornada.
Verifique o HMAC e atualize seu pedido de forma idempotente.
Crie seu primeiro pagamento
Gere uma chave de API no painel do lojista, armazene o segredo em uma variável de ambiente e crie um pagamento a partir do seu backend. O exemplo usa ETH para que possa ser testado sem escolher uma rede de token.
curl --request POST https://cryptopayin.com/v1/payments \
--header "Authorization: Bearer $CPI_SECRET_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: order_1042" \
--data '{
"amount": 49.99,
"currency": "USD",
"asset": "ETH",
"order_ref": "order_1042",
"redirect_url": "https://shop.example/orders/1042/paid"
}'
const response = await fetch("https://cryptopayin.com/v1/payments", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.CPI_SECRET_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "order_1042"
},
body: JSON.stringify({
amount: 49.99, currency: "USD", asset: "ETH",
order_ref: "order_1042",
redirect_url: "https://shop.example/orders/1042/paid"
})
});
if (!response.ok) throw new Error(await response.text());
const payment = await response.json();
$payload = json_encode([
'amount' => 49.99, 'currency' => 'USD', 'asset' => 'ETH',
'order_ref' => 'order_1042',
'redirect_url' => 'https://shop.example/orders/1042/paid',
]);
$ch = curl_init('https://cryptopayin.com/v1/payments');
curl_setopt_array($ch, [
CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CPI_SECRET_KEY'),
'Content-Type: application/json',
'Idempotency-Key: order_1042',
],
]);
$payment = json_decode(curl_exec($ch), true, flags: JSON_THROW_ON_ERROR);
import os, requests
response = requests.post(
"https://cryptopayin.com/v1/payments",
headers={
"Authorization": f"Bearer {os.environ['CPI_SECRET_KEY']}",
"Idempotency-Key": "order_1042",
},
json={
"amount": 49.99, "currency": "USD", "asset": "ETH",
"order_ref": "order_1042",
"redirect_url": "https://shop.example/orders/1042/paid",
}, timeout=15,
)
response.raise_for_status()
payment = response.json()Use a resposta
Salve o id do pagamento junto ao seu pedido e redirecione o cliente para checkout_url. Não calcule o valor em cripto nem o endereço de depósito por conta própria.
{
"id": "P-9F27C1E4KD",
"object": "payment",
"status": "created",
"amount": 49.99,
"amount_decimal": "49.99",
"amount_minor": 4999,
"currency": "USD",
"currency_minor_units": 2,
"amount_usd": 49.99,
"amount_usd_cents": 4999,
"fx_rate_usd": "1.000000000000",
"fx_source": "fixed:USD",
"fx_observed_at": "2026-07-17T13:00:00+00:00",
"fx_discrepancy_bps": 0,
"asset": "ETH",
"network": "mainnet",
"crypto_amount": "0.01388612",
"crypto_received": "0",
"deposit_address": "0x71b8c3d4700000000000000000000000000084e2",
"exchange_rate": "3600.00000000",
"exchange_rate_currency": "USD",
"exchange_rate_source": "median:cb,cg,cl",
"exchange_rate_source_count": 3,
"exchange_rate_observed_at": "2026-07-17T13:00:00+00:00",
"exchange_rate_discrepancy_bps": 12,
"confirmations": 0,
"confirmations_required": 12,
"order_ref": "order_1042",
"checkout_url": "https://cryptopayin.com/i/P-9F27C1E4KD",
"expires_at": "2026-07-17T13:30:00+00:00",
"created_at": "2026-07-17T13:00:00+00:00",
"completed_at": null
}Autenticação
Toda requisição à API usa a chave secreta em um cabeçalho HTTP Bearer. As chaves secretas começam com csk_live_. O valor cpk_live_ correspondente é um identificador público do seu painel e não deve ser usado como credencial Bearer.
Authorization: Bearer csk_live_...Todos os endpointsO segredo bruto é retornado somente no momento da criação da chave. A CryptoPayIn armazena um hash de senha e um índice SHA-256 para consulta, nunca o segredo em texto plano.
Crie chaves separadas por aplicação ou ambiente e revogue-as de forma independente. Uma conta pode manter até 50 chaves ativas.
Nunca coloque um valor csk_live_ em JavaScript de navegador, em um binário mobile, em um repositório público ou em uma página de checkout.
Um endpoint de webhook pode valer para toda a conta ou ficar vinculado a uma única chave de API, mantendo as integrações isoladas.
Um segredo ausente, malformado, revogado ou desconhecido retorna 401 unauthorized. Uma conta de lojista suspensa ou encerrada é rejeitada da mesma forma. Uma chave válida usada fora das permissões concedidas retorna 403 insufficient_scope.
Idempotência
Envie um Idempotency-Key exclusivo em cada criação de pagamento. Se sua conexão cair após o envio, repita o mesmo JSON com a mesma chave: a CryptoPayIn retorna o pagamento original em vez de alocar outro endereço.
| Caso | Resultado | HTTP |
|---|---|---|
| Primeiro uso | Cria e retorna um novo pagamento. | 201 |
| Mesma chave + mesmo JSON | Retorna o pagamento existente com Idempotent-Replayed: true. | 200 |
| Mesma chave + JSON diferente | Rejeita a requisição como idempotency_conflict. | 409 |
As chaves são vinculadas à credencial de API e podem conter de 1 a 128 letras, dígitos, pontos, sublinhados, dois-pontos ou hífens. Um UUID duradouro do pedido é uma boa escolha. O mesmo mecanismo também protege os saques, de modo que uma nova tentativa de saque nunca movimenta os fundos duas vezes.
Referência da API
A API cobre pagamentos, links de pagamento, lojas, produtos, saldos e saques. As respostas usam JSON em UTF-8 sobre HTTPS; toda criação ou atualização exige Content-Type: application/json. As mutações são controladas pelas permissões da chave usada na chamada. Não há, propositalmente, fluxo CORS para navegador: as chamadas pertencem ao seu backend.
/v1/assetsDescubra os ativos disponíveis/v1/currenciesDescubra as moedas fiduciárias de apresentação/v1/paymentsCriar um pagamento/v1/paymentsListar e filtrar pagamentos/v1/payments/{id}Consultar um pagamentoA Versão 1 pode receber campos e endpoints compatíveis com versões anteriores. Uma mudança de contrato que quebre a compatibilidade usará um novo caminho base, em vez de alterar silenciosamente /v1.
Listar ativos
/v1/assetsAutenticação Bearer obrigatóriaUse este endpoint como fonte da verdade para as opções de checkout. Ele retorna as entradas ativas do catálogo, as cotações atuais verificadas de forma independente, os valores mínimos equivalentes em USD e se o nó e o feed de preços estão prontos. Uma entrada pode continuar listada com available: false enquanto um nó está sincronizando ou seu preço não pode ser verificado.
curl https://cryptopayin.com/v1/assets \
--header "Authorization: Bearer $CPI_SECRET_KEY"{
"object": "list",
"data": [{
"asset": "USDT",
"network": "TRC20",
"type": "token",
"decimals": 6,
"minimum_amount": 1,
"currency": "USD",
"base_confirmations": 19,
"available": true,
"rate_usd": "1.00000000",
"rate_source": "median:cb,cg,cl",
"rate_source_count": 3,
"rate_discrepancy_bps": 4,
"rate_status": "healthy",
"rate_updated_at": "2026-07-17T13:00:00+00:00"
}]
}Catálogo e identificadores de rede
| Ativo | Valor de rede | Abreviação | Confirmações base |
|---|---|---|---|
| BTC | mainnet | BTC | 2 |
| ETH | mainnet | ETH | 6 |
| USDT | TRC20 / ERC20 | USDT.TRC20 | 19 / 6 |
| USDC | ERC20 | USDC.ERC20 | 6 |
| DAI | ERC20 | DAI | 6 |
| SHIB | ERC20 | SHIB | 6 |
| PEPE | ERC20 | PEPE | 6 |
| LTC | mainnet | LTC | 6 |
| TRX | mainnet | TRX | 19 |
| DOGE | mainnet | DOGE | 20 |
| XMR | mainnet | XMR | 10 |
| SOL | mainnet | SOL | 32 |
A disponibilidade é dinâmica. Não fixe a tabela acima como uma lista de permissões em produção. Para símbolos com múltiplas redes, como o USDT, envie network explicitamente ou use a abreviação ASSET.NETWORK.
Listar moedas fiduciárias
/v1/currenciesAutenticação Bearer obrigatóriaRetorna as moedas de apresentação habilitadas, sua precisão ISO e a saúde atual da conversão para USD. Ofereça apenas as linhas com available: true. O USD é intrínseco; toda outra moeda exige uma cotação em tempo real e uma checagem de referência independente. minimum_amount converte o piso mínimo configurado do ativo habilitado mais barato para essa moeda; o ativo escolhido pode exigir um valor maior, então sempre leia também GET /v1/assets.
curl https://cryptopayin.com/v1/currencies \
--header "Authorization: Bearer $CPI_SECRET_KEY"{
"object": "list",
"accounting_currency": "USD",
"data": [{
"currency": "EUR",
"name": "Euro",
"symbol": "€",
"minor_units": 2,
"available": true,
"minimum_amount": "0.86",
"rate_usd": "1.160000000000",
"rate_source": "coinbase+ecb",
"rate_source_count": 2,
"rate_discrepancy_bps": 18,
"rate_updated_at": "2026-07-17T13:00:00+00:00",
"rate_reference_at": "2026-07-16T00:00:00+00:00"
}]
}A moeda omitida em POST /v1/payments ainda significa USD por compatibilidade com versões anteriores. Moedas sem casas decimais, como o JPY, rejeitam valores fracionários. Trate os mínimos e as cotações do catálogo como dados em tempo real, nunca como constantes fixas.
Criar um pagamento
/v1/payments120 requisições / minuto / chaveCria uma fatura na moeda de apresentação solicitada, trava snapshots recentes e verificados de fiat/USD e cripto/USD, calcula o valor exato em cripto e vincula um endereço de depósito on-chain dedicado.
Corpo da requisição
| Campo | Tipo | Obrigatoriedade | Descrição |
|---|---|---|---|
| amount | number or decimal string | obrigatório | Valor em currency, na precisão ISO dessa moeda. Seu equivalente travado em USD não pode exceder $1,000,000.00; os mínimos do ativo também se aplicam. |
| currency | string | opcional | Moeda habilitada de 3 letras a partir de GET /v1/currencies. Padrão: USD. |
| asset | string | obrigatório | Símbolo como ETH, ou abreviação como USDT.TRC20. |
| network | string | condicional | Obrigatório quando o símbolo existe em múltiplas redes. Exemplo: ERC20. |
| order_ref | string | opcional | Identificador do seu pedido, com no máximo 128 caracteres. Retornado nas respostas da API e nos eventos. |
| customer_email | string | opcional | Endereço de e-mail válido, com no máximo 190 caracteres. Armazenado junto ao registro de pagamento do lojista. |
| redirect_url | string | opcional | URL HTTPS, com no máximo 255 caracteres, oferecida após o checkout bem-sucedido. |
Campos da resposta
| Campo | Tipo | Descrição |
|---|---|---|
| id | string | Identificador estável do pagamento, começando com P-. |
| status | string | Estado atual do ciclo de vida. |
| amount / amount_decimal / amount_minor | number / string / integer | Valor de apresentação solicitado nas formas conveniente, decimal exata e em unidades menores ISO. |
| currency / currency_minor_units | string / integer | Moeda de apresentação travada e sua precisão. |
| amount_usd / amount_usd_cents | number / integer | Valor contábil interno imutável em USD. |
| fx_rate_usd / fx_source / fx_observed_at | decimal string / string / ISO 8601 | Snapshot travado de USD por unidade de apresentação e seus metadados de auditoria. |
| asset / network | string | Ativo on-chain resolvido. |
| crypto_amount | decimal string | Valor exato que o cliente deve enviar. Nunca interprete decimais de cripto como floats binários. |
| crypto_received | decimal string | Total atualmente observado no endereço de depósito. |
| deposit_address | string | Endereço dedicado alocado para este pagamento. |
| exchange_rate | decimal string | Cotação cripto/USD travada, usada para calcular crypto_amount; este campo mantém seu significado original da v1. |
| exchange_rate_source / exchange_rate_observed_at | string / ISO 8601 | Snapshot imutável de auditoria da cotação em cripto. |
| confirmations | integer | Confirmações atuais na rede. |
| confirmations_required | integer | Limite exigido para este pagamento. Faixas de valor em USD mais altas podem exigir confirmações adicionais. |
| checkout_url | URL | Fatura hospedada para exibir ao cliente. |
| expires_at | ISO 8601 | Prazo final para uma fatura não paga. |
| completed_at | ISO 8601 / null | Horário final da liquidação, quando concluída. |
As duas conversões em tempo real são validadas quanto a atualidade, número de fontes e divergência antes da criação. Se a verificação falhar, a criação retorna um erro em vez de usar uma cotação desatualizada. O valor em cripto é arredondado para cima, na precisão útil do ativo, de modo que o arredondamento nunca deixa o lojista no prejuízo.
Listar pagamentos
/v1/payments240 requisições / minuto / chaveRetorna primeiro os pagamentos mais recentes da conta de lojista autenticada. Use paginação por cursor para conciliação e filtros exatos para localizar um pedido sem percorrer todo o histórico.
Parâmetros de consulta
| Parâmetro | Padrão | Descrição |
|---|---|---|
| limit | 20 | Tamanho da página, de 1 a 100. |
| starting_after | — | ID de pagamento retornado como next_cursor da página anterior. |
| status | — | Status exato do ciclo de vida, como pending, completed ou expired. |
| order_ref | — | Referência exata do pedido do lojista, com no máximo 128 caracteres. |
curl "https://cryptopayin.com/v1/payments?status=completed&limit=20" \
--header "Authorization: Bearer $CPI_SECRET_KEY"{
"object": "list",
"data": [{
"id": "P-9F27C1E4KD",
"object": "payment",
"status": "completed",
"amount": 49.99,
"currency": "USD",
"asset": "ETH",
"network": "mainnet",
"crypto_amount": "0.01388612",
"crypto_received": "0.01388612",
"order_ref": "order_1042",
"confirmations": 12,
"confirmations_required": 12,
"completed_at": "2026-07-17T13:12:42+00:00"
}],
"has_more": true,
"next_cursor": "P-9F27C1E4KD"
}Quando has_more for true, envie next_cursor sem alterações como starting_after. Parâmetros de consulta desconhecidos ou repetidos em formato de array são rejeitados, e não ignorados.
Consultar um pagamento
/v1/payments/{id}240 requisições / minuto / chaveRetorna o mesmo objeto de pagamento da criação, com status atualizado, valor recebido, hash da transação e confirmações. Uma chave só pode consultar pagamentos pertencentes à sua conta de lojista.
curl https://cryptopayin.com/v1/payments/P-9F27C1E4KD \
--header "Authorization: Bearer $CPI_SECRET_KEY"Os webhooks devem conduzir as atualizações normais do pedido. Use a consulta para conciliar após um timeout, verificar um evento, renderizar uma página de status no backend ou corrigir entregas perdidas.
Ciclo de vida do pagamento
Sempre trate o status da API como autoritativo. Não deduza a conclusão a partir de um redirecionamento do navegador ou porque o cliente disse que pagou.
| Status | Significado | Ação do lojista |
|---|---|---|
| created | Fatura e endereço alocados; nenhum aporte detectado ainda. | Exiba o checkout hospedado. |
| pending | Aguardando um pagamento on-chain utilizável. | Mantenha o pedido em aberto. |
| underpaid | Os fundos chegaram abaixo da tolerância do lojista. | Peça ao pagador que envie o valor restante exibido. |
| confirming | Valor suficiente detectado; aguardando confirmações. | Ainda não entregue o pedido. |
| completed | Valor exigido e confirmações alcançados. | Entregue o pedido uma única vez. |
| overpaid | Mais do que o esperado foi confirmado. | Entregue o pedido e analise o excedente. |
| expired | Nenhum pagamento válido foi detectado antes da expiração. | Crie um novo pagamento. |
| failed | Falha na alocação do endereço ou no processamento. | Registre o erro e crie um novo pagamento. |
As transferências on-chain são irreversíveis e a CryptoPayIn não possui mecanismo de reembolso — um pagamento confirmado é definitivo. Qualquer devolução por cortesia é tratada diretamente entre você e seu cliente, fora da plataforma.
Checkout hospedado
Cada pagamento da API inclui um checkout_url responsivo. Ele exibe o lojista, o valor de apresentação solicitado, o equivalente em USD travado quando pertinente, o valor exato em cripto, o endereço de depósito, o código QR, o aviso de rede, a contagem regressiva e o progresso das confirmações em tempo real.
O cliente vê o mesmo crypto_amount retornado pela API durante a janela da fatura.
O pagador não cria uma conta na CryptoPayIn nem compartilha credenciais.
A página consulta o pagamento com segurança e avança de aguardando para confirmando até pago.
Um redirect_url HTTPS é oferecido após o sucesso; ele não é prova de pagamento.
Mantenha a entrega do pedido no seu backend. A navegação no navegador pode ser abandonada, repetida ou forjada; somente um webhook verificado ou um GET autenticado comprova o estado do pagamento.
Permissões & escopos
Cada chave de API carrega um conjunto fixo de permissões, escolhido no momento da criação em Painel → Desenvolvedores. Todo endpoint verifica os escopos da chave antes de executar qualquer ação; uma chamada fora do escopo concedido retorna 403 insufficient_scope com um cabeçalho X-Required-Scope indicando a permissão ausente. Os escopos são definidos uma única vez na criação e não podem ser ampliados depois — emita uma nova chave em vez disso. Chaves criadas antes da existência dos escopos mantêm exatamente sua capacidade original: payments:read e payments:write.
| Escopo | Concede | Endpoints |
|---|---|---|
payments:read | Listar e consultar pagamentos | GET /v1/payments, GET /v1/payments/{id} |
payments:write | Criar pagamentos hospedados | POST /v1/payments |
links:read | Listar e consultar links de pagamento | GET /v1/links, GET /v1/links/{id} |
links:write | Criar, editar, pausar e excluir links de pagamento | POST/PATCH/DELETE /v1/links |
shops:read | Listar e consultar lojas e seus produtos | GET /v1/shops, GET .../products |
shops:write | Criar e editar lojas, produtos e variantes | POST/PATCH/DELETE /v1/shops e produtos |
balance:read | Ler saldos em cripto e estimativas em USD | GET /v1/balance |
payouts:read | Listar e consultar saques | GET /v1/payouts, GET /v1/payouts/{id} |
payouts:write | Solicitar saques on-chain | POST /v1/payouts |
payouts:write movimenta fundos on-chain e é irreversível. Conceda-o somente a chaves em que você confia plenamente, mantenha essas chaves no servidor e prefira uma chave dedicada por processo automatizado. GET /v1/account informa os escopos da chave usada na chamada e os limites da sua conta.
Links de pagamento
Links hospedados reutilizáveis que um cliente pode pagar qualquer número de vezes. Um link tem a mesma lógica de precificação, ativo, entrega e perguntas de checkout do criador de links do painel — a API apenas o conduz. Uma conta mantém até 50 links de pagamento.
/v1/linkslinks:read/v1/linkslinks:write/v1/links/{id}links:read/v1/links/{id}links:write/v1/links/{id}links:writeCorpo da requisição
| Campo | Tipo | Obrigatoriedade | Descrição |
|---|---|---|---|
| title | string | obrigatório | 3–120 caracteres. |
| description | string | opcional | Até 2,000 caracteres, exibidos no checkout. |
| template | string | opcional | Tema do checkout: signature (padrão), midnight, atelier, horizon, compact ou ledger. |
| public_label | string | opcional | Nome público do vendedor exibido aos compradores (2–80 caracteres). Nunca um ID de conta. |
| amount_type | string | opcional | fixed (padrão) ou open (o cliente escolhe dentro do mínimo/máximo). |
| currency | string | opcional | Moeda de apresentação a partir de GET /v1/currencies. Padrão: a moeda da sua conta. |
| amount | number or string | condicional | Obrigatório para fixed. Em currency na sua precisão ISO. |
| min / max | number or string | condicional | Limites para links open. max pode ser 0/omitido para não haver teto. |
| accepted_assets | array of strings | opcional | Códigos de ativos, como ["BTC","USDT.TRC20"]. Omita para incluir todos os ativos disponíveis. |
| max_uses | integer | opcional | Limite de pagamentos concluídos. 0 significa ilimitado. |
| expires_at | ISO 8601 | opcional | No mínimo 5 minutos à frente, no máximo 12 meses. UTC. |
| delivery_type | string | opcional | none, text, url ou keys — produtos digitais entregues após o pagamento. |
| delivery_text / delivery_url | string | condicional | Conteúdo (≤50,000 caracteres) ou uma URL https para o tipo de entrega correspondente. |
| delivery_keys | array of strings | condicional | Uma chave por elemento para entrega keys. Até 10,000, cada uma com ≤500 caracteres. |
| checkout_fields | array | opcional | Até 5 objetos {label, type, required}; o tipo é text, email, textarea ou number. |
| success_message / redirect_url | string | opcional | Mensagem pós-pagamento (≤500 caracteres) e um redirecionamento https. |
| status | string | opcional | Somente PATCH: active ou paused. |
curl -X POST https://cryptopayin.com/v1/links \
-H "Authorization: Bearer $CPI_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Pro license",
"amount": 49.99,
"currency": "EUR",
"accepted_assets": ["BTC", "ETH", "USDT.TRC20"],
"delivery_type": "keys",
"delivery_keys": ["ABC-1", "ABC-2", "ABC-3"]
}'{
"id": "PL-N5PKTYB7",
"object": "payment_link",
"url": "https://cryptopaylink.co/pay/PL-N5PKTYB7",
"status": "active",
"title": "Pro license",
"amount_type": "fixed",
"currency": "EUR",
"amount": 49.99,
"amount_decimal": "49.99",
"accepted_assets": [{"asset":"BTC","network":"mainnet"},{"asset":"ETH","network":"mainnet"},{"asset":"USDT","network":"TRC20"}],
"uses": {"started": 0, "completed": 0, "in_flight": 0},
"delivery": {"type": "keys", "keys_available": 3, "keys_total": 3},
"expires_at": null,
"created_at": "2026-07-19T19:00:00+00:00"
}PATCH é uma atualização parcial: envie somente os campos que deseja alterar, e o restante é preservado, incluindo chaves de licença ainda não vendidas. Para links keys, enviar delivery_keys substitui o conjunto de chaves não vendidas; as chaves já entregues nunca são alteradas. Excluir um link que já possui pagamentos é recusado implicitamente, mantendo seu histórico intacto.
Checkout para agentes
Todo link de pagamento ativo também é um checkout legível por máquina: um agente de IA ou qualquer script pode descobri-lo, criar uma fatura e ler a entrega sem navegador — e sem nenhuma chave de API, porque esses são endpoints públicos de comprador no domínio do link, não endpoints de lojista. Contrato completo e exemplo prático: cryptopayin.com/agents.
https://cryptopaylink.co/pay/{link}.jsonpúblico · descobertaRetorna o estado, a precificação, os ativos aceitos e o contrato exato de entrada para a chamada da fatura (campos obrigatórios, esquema de envio, variantes).
https://cryptopaylink.co/pay/{link}/invoicepúblico · aceita Idempotency-KeyCria a fatura pelo mesmo núcleo, snapshot de precificação e limites antiabuso da página hospedada, e retorna o endereço de depósito, o valor exato em cripto, uma URI de carteira e a URL do recibo. Em seguida, o agente paga on-chain a partir de qualquer carteira que controle.
https://cryptopaylink.co/pay/{link}/receipt?p={payment}público · consulte a cada 5–10 sStatus e confirmações em tempo real; quando o pagamento é concluído, a resposta traz a entrega — seu conteúdo de texto, URL privada ou uma chave de licença reservada para aquele pagamento — além da sua mensagem de sucesso e da URL de redirecionamento.
As lojas falam o mesmo protocolo
As vitrines expõem o mesmo fluxo em seu próprio domínio: o catálogo com estoque em tempo real e, em seguida, uma única chamada que valida o carrinho, reserva o estoque e retorna a fatura.
https://shopycrypto.com/s/{shop}.jsonpúblico · catálogohttps://shopycrypto.com/s/{shop}/orderpúblico · carrinho → fatura, aceita Idempotency-Keyhttps://shopycrypto.com/s/{shop}/o/{order}/receipt?p={payment}público · consulte a cada 5–10 sControles do vendedor
O checkout para agentes vem habilitado por padrão e custa a mesma taxa fixa de 1%. Desative-o para toda a conta em Painel → Configurações → Geral → IA & checkout para agentes: os endpoints de máquina em links e lojas passam então a responder 403 agents_disabled enquanto suas páginas de checkout humano continuam funcionando. Pagamentos criados por agentes não carregam nenhuma sinalização especial — são pagamentos comuns no seu painel, webhooks e exportações.
Lojas
Uma vitrine hospedada que agrupa produtos em uma única página com a marca do lojista. Uma conta mantém até 10 lojas. Os produtos são gerenciados pelos endpoints de produto aninhados abaixo.
/v1/shopsshops:read/v1/shopsshops:write/v1/shops/{id}shops:read/v1/shops/{id}shops:write/v1/shops/{id}shops:writeCorpo da requisição
| Campo | Tipo | Obrigatoriedade | Descrição |
|---|---|---|---|
| name | string | obrigatório | 2–80 caracteres. |
| tagline | string | opcional | Até 160 caracteres. |
| theme | string | opcional | light (padrão) ou dark. |
| accent | string | opcional | Cor de destaque em hexadecimal, da paleta da loja retornada como accent_palette em GET /v1/shops. |
| accepted_assets | array of strings | opcional | Ativos padrão para os produtos da loja, ex.: ["BTC","LTC","XMR"]. Aplicado a todos os produtos quando alterado. |
| status | string | opcional | Somente PATCH: active ou paused. |
Uma loja desativada pela CryptoPayIn por motivos de política não pode ser reativada nem excluída pela API, e retorna admin_disabled (403). Excluir uma loja remove seus produtos; os pagamentos anteriores permanecem intactos.
Produtos & variantes
Os produtos existem dentro de uma loja. Cada loja mantém até 50 produtos. Um produto pode ser digital (com entrega instantânea) ou físico (com países de envio), e pode expor até 30 combinações de variantes, construídas a partir de 1–3 grupos de opções.
/v1/shops/{shop}/productsshops:read/v1/shops/{shop}/productsshops:write/v1/shops/{shop}/products/{id}shops:read/v1/shops/{shop}/products/{id}shops:write/v1/shops/{shop}/products/{id}shops:writeCorpo da requisição
| Campo | Tipo | Obrigatoriedade | Descrição |
|---|---|---|---|
| title | string | obrigatório | 3–120 caracteres. |
| description / blurb | string | opcional | Descrição completa e uma linha de ≤200 caracteres para o cartão da loja. |
| emoji | string | opcional | Um único emoji exibido no cartão do produto. |
| featured | boolean | opcional | No máximo um produto em destaque por loja. |
| product_type | string | opcional | digital (padrão) ou physical. |
| shipping_countries | array of strings | condicional | Somente físico: códigos ISO como ["FR","BE"], ou ["*"] para envio mundial. |
| amount_type / currency / amount / min / max | mixed | condicional | Precificação base, com regras idênticas às dos links de pagamento. Produtos físicos devem ser fixed. |
| max_uses | integer | opcional | Limite total de vendas (0 = ilimitado). |
| delivery_type + delivery_text/url/keys | mixed | opcional | Entrega digital para o produto base, nos mesmos formatos dos links de pagamento. |
| variant_options | array | opcional | 1–3 grupos {name, values[]}, cada um com 2–10 valores. As combinações não podem exceder 30. |
| variants | array | condicional | Um objeto por combinação (veja abaixo). Obrigatório e exaustivo quando variant_options está presente. |
| status | string | opcional | Somente PATCH: active ou paused. |
Objeto de variante
| Campo | Tipo | Descrição |
|---|---|---|
| options | array of strings | Um valor por grupo de opções, na ordem dos grupos, ex.: ["Pro","Lifetime"]. |
| price | number or string | Preço da variante na moeda do produto. |
| stock | integer or null | Unidades restantes, ou null para ilimitado. |
| delivery_type + delivery_text/url/keys | mixed | Substituição opcional de entrega digital por variante (inherit por padrão). As chaves devem ser únicas em todo o produto. |
curl -X POST https://cryptopayin.com/v1/shops/SH-JYRK8TFJ/products \
-H "Authorization: Bearer $CPI_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Software license",
"amount": 30,
"currency": "USD",
"variant_options": [
{"name": "Edition", "values": ["Standard", "Pro"]},
{"name": "Term", "values": ["1 year", "Lifetime"]}
],
"variants": [
{"options": ["Standard","1 year"], "price": 30, "delivery_type": "keys", "delivery_keys": ["S1Y-1"]},
{"options": ["Standard","Lifetime"], "price": 79, "stock": 10, "delivery_type": "keys", "delivery_keys": ["SLT-1"]},
{"options": ["Pro","1 year"], "price": 59, "delivery_type": "keys", "delivery_keys": ["P1Y-1"]},
{"options": ["Pro","Lifetime"], "price": 149, "stock": 5, "delivery_type": "keys", "delivery_keys": ["PLT-1"]}
]
}'PATCH preserva os pedidos existentes e as chaves já entregues. Para ajustar preços ou estoque, reenvie o array variants correspondente; as combinações omitidas são pausadas se tiverem pedidos, ou removidas caso contrário. Um produto pode manter no máximo 10,000 chaves de licença ativas entre sua base e suas variantes, e cada chave deve ser única dentro do produto.
Saldo
/v1/balancebalance:readRetorna seus saldos liquidados em cripto por ativo, com uma estimativa em USD de melhor esforço e a taxa de rede cobrada em um saque. A contabilidade interna é sempre em USD; os saldos acumulam a partir dos pagamentos concluídos, líquidos da taxa do lojista.
{
"object": "list",
"accounting_currency": "USD",
"minimum_payout_usd": 25,
"data": [{
"asset": "USDT",
"network": "TRC20",
"amount": "99.099",
"usd_estimate": 99.02,
"payout_network_fee": "2.445463"
}]
}usd_estimate é null quando uma cotação verificada em tempo real está momentaneamente indisponível; o saldo subjacente continua exato. Use esses valores para decidir saques, não para a contabilidade final.
Saques
Transfere cripto liquidada para uma carteira externa. Os saques são irreversíveis, portanto este endpoint aplica todas as proteções que o painel aplica: um destino válido para o ativo, uma cotação verificada em tempo real, o mínimo da conta, saldo suficiente incluindo a taxa de rede, e confirmação de dois fatores quando a conta tem 2FA habilitado.
/v1/payoutspayouts:read/v1/payoutspayouts:write · 30 / min / chave/v1/payouts/{id}payouts:readCorpo da requisição
| Campo | Tipo | Obrigatoriedade | Descrição |
|---|---|---|---|
| asset | string | obrigatório | Símbolo ou abreviação, ex.: LTC ou USDT.TRC20. |
| network | string | condicional | Obrigatório quando o símbolo existe em múltiplas redes. |
| amount | number or string | obrigatório | Valor a enviar, excluindo a taxa de rede, na precisão do ativo. Seu valor em USD deve atingir o mínimo da conta. |
| address | string | obrigatório | Endereço de destino, validado para a rede do ativo. |
| note | string | opcional | Sua própria referência, com até 255 caracteres. |
| totp_code | string | condicional | Código atual de 6 dígitos ou código de recuperação. Obrigatório quando o 2FA está habilitado na conta. |
curl -X POST https://cryptopayin.com/v1/payouts \
-H "Authorization: Bearer $CPI_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: withdraw-2026-07-19-01" \
-d '{
"asset": "USDT.TRC20",
"amount": "50",
"address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"note": "weekly settlement"
}'{
"id": "W-EM64ZCJB",
"object": "payout",
"status": "requested",
"asset": "USDT",
"network": "TRC20",
"amount": "50",
"fee": "2.445463",
"total_debited": "52.445463",
"address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"txid": null,
"confirmations": 0,
"created_at": "2026-07-19T19:10:00+00:00"
}Ciclo de vida do status
| Status | Significado |
|---|---|
requested | Reservado do seu saldo; aguardando análise do operador ou aprovação automática. |
approved / processing | Aprovado e na fila para transmissão pelo executor. |
sent | Transmitido on-chain; txid é preenchido. |
confirmed | Atingiu as confirmações exigidas. Definitivo. |
failed | Não pôde ser enviado; failure_message explica o motivo e o saldo é devolvido. |
cancelled | Cancelado antes da transmissão; o saldo reservado é devolvido. |
Envie um Idempotency-Key para que uma nova tentativa de rede nunca crie um segundo saque: a mesma chave com o mesmo corpo retorna o saque original (Idempotent-Replayed: true); a mesma chave com um corpo diferente retorna 409 idempotency_conflict. O código de 2FA é deliberadamente excluído da impressão digital de idempotência, para que um código rotativo não gere um falso conflito. A reserva debita seu saldo imediatamente; um saque com falha ou cancelado o devolve.
Conta
/v1/accountqualquer chave válidaRetorna o perfil da sua conta, os escopos da chave usada na chamada, a taxa da plataforma e todos os limites em tempo real — útil para uma integração autoconfigurável ou uma checagem prévia.
{
"object": "account",
"id": "MC67T3PHQZ",
"fee_bps": 100,
"fee_percent": 1,
"default_currency": "USD",
"two_factor_enabled": false,
"api_key": {"label": "production", "scopes": ["payments:read","payments:write"]},
"limits": {
"shops": {"used": 1, "max": 10},
"payment_links": {"used": 0, "max": 50},
"products_per_shop_max": 50,
"variant_combinations_per_product_max": 30,
"license_keys_per_product_max": 10000,
"active_api_keys_max": 50,
"checkout_fields_per_link_max": 5
},
"minimum_payout_usd": 25
}Webhooks
Adicione até 10 endpoints HTTPS públicos em Painel -> Desenvolvedores. Cada endpoint recebe seu próprio segredo de assinatura whsec_..., exibido uma única vez. Ele pode ouvir toda a conta ou ficar vinculado a uma chave de API ativa específica; endpoints vinculados a uma chave recebem somente os pagamentos criados com ela.
Verifique antes de fazer o parsing
A CryptoPayIn assina o corpo bruto exato da requisição usando o segredo do endpoint. A Versão 1 assina timestamp + "." + raw_body. Rejeite timestamps desatualizados antes de aceitar o evento.
import crypto from "node:crypto";
const timestamp = req.headers["x-cpi-timestamp"];
const signature = req.headers["x-cpi-signature"];
const rawBody = req.rawBody; // Buffer captured before JSON parsing
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
throw new Error("stale webhook");
}
const expected = "sha256=" + crypto
.createHmac("sha256", process.env.CPI_WEBHOOK_SECRET)
.update(Buffer.concat([Buffer.from(`${timestamp}.`), rawBody]))
.digest("hex");
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
if (!valid) throw new Error("invalid webhook signature");
$rawBody = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_CPI_TIMESTAMP'] ?? '';
$received = $_SERVER['HTTP_X_CPI_SIGNATURE'] ?? '';
if (!ctype_digit($timestamp) || abs(time() - (int)$timestamp) > 300) {
http_response_code(400); exit('stale webhook');
}
$expected = 'sha256=' . hash_hmac(
'sha256', $timestamp . '.' . $rawBody, getenv('CPI_WEBHOOK_SECRET')
);
if (!hash_equals($expected, $received)) {
http_response_code(401); exit('invalid signature');
}
$event = json_decode($rawBody, true, flags: JSON_THROW_ON_ERROR);
import hashlib, hmac, os, time
raw_body = request.get_data() # bytes, before JSON decoding
timestamp = request.headers.get("X-CPI-Timestamp", "")
received = request.headers.get("X-CPI-Signature", "")
if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > 300:
raise ValueError("stale webhook")
signed = timestamp.encode() + b"." + raw_body
expected = "sha256=" + hmac.new(
os.environ["CPI_WEBHOOK_SECRET"].encode(), signed, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, received):
raise ValueError("invalid signature")Cabeçalhos de entrega
| Cabeçalho | Exemplo | Finalidade |
|---|---|---|
| Content-Type | application/json | Corpo JSON em UTF-8. |
| X-CPI-Timestamp | 1784293200 | Segundos Unix incluídos na mensagem assinada. |
| X-CPI-Signature | sha256=... | HMAC-SHA256 em hexadecimal. |
| X-CPI-Signature-Version | v1 | Versão do esquema de assinatura. |
| X-CPI-Event-Id | evt_a12b... | ID lógico estável do evento; idêntico em todas as tentativas. |
| X-CPI-Delivery-Id | 1842 | ID estável do registro de entrega do endpoint. |
Payload do pagamento
{
"event_id": "evt_a12b34c56d78e90f12345678",
"event": "payment.completed",
"id": "P-9F27C1E4KD",
"status": "completed",
"order_ref": "order_1042",
"amount": 49.99,
"amount_decimal": "49.99",
"amount_minor": 4999,
"currency_minor_units": 2,
"currency": "USD",
"amount_usd": 49.99,
"amount_usd_cents": 4999,
"fx_rate_usd": "1.000000000000",
"fx_source": "fixed:USD",
"fx_observed_at": "2026-07-17T13:00:00Z",
"fx_discrepancy_bps": 0,
"exchange_rate": "3600.00000000",
"exchange_rate_currency": "USD",
"exchange_rate_source": "median:cb,cg,cl",
"exchange_rate_source_count": 3,
"exchange_rate_observed_at": "2026-07-17T13:00:00Z",
"exchange_rate_discrepancy_bps": 12,
"asset": "ETH",
"network": "mainnet",
"crypto_amount": "0.01388612",
"crypto_received": "0.01388612",
"txid": "0x9d81...75af",
"confirmations": 12,
"confirmations_required": 12,
"deposit_address": "0x71b8c3d4700000000000000000000000000084e2",
"sent_at": "2026-07-17T13:12:42Z"
}Novas tentativas e segurança do endpoint
Uma entrega é bem-sucedida com HTTP 200-299. Execute tarefas custosas de forma assíncrona e responda rapidamente.
O corpo exato e o ID do evento são mantidos; as falhas são reenviadas após aproximadamente 1 minuto, 5 minutos, 30 minutos, 2 horas e 6 horas.
Respostas 3xx não são seguidas. Registre diretamente a URL HTTPS final.
IPs privados, loopback, link-local e reservados são bloqueados; toda resposta DNS é validada e a conexão é fixada (pinned).
As entregas são "pelo menos uma vez". Torne seu manipulador idempotente, registrando event_id com uma restrição de unicidade antes da entrega. Consulte o objeto da API ao conciliar um evento inesperado.
Referência de eventos
payment.completedValor esperado confirmado.payment.overpaidMais do que o esperado foi confirmado.payment.underpaidAporte abaixo da tolerância detectado.payment.expiredJanela de fatura não paga encerrada.payment.failedFalha na configuração ou no processamento do pagamento.payout.sentSaque transmitido on-chain.payout.confirmedSaque atingiu as confirmações.payout.failedO saque não pôde ser concluído.webhook.testTeste manual de conectividade.Formato do evento de saque
{
"event_id": "evt_b98c76d54e32a10f87654321",
"event": "payout.sent",
"id": "W-8J2K7M4RQP",
"status": "sent",
"asset": "ETH",
"network": "mainnet",
"amount": "0.25",
"fee": "0.00081768",
"address": "0x84f2...9bc1",
"txid": "0xa1c4...07ee",
"confirmations": 0,
"note": "weekly treasury",
"sent_at": "2026-07-17T14:08:31Z"
}Erros e limites de taxa
Os erros sempre usam um único envelope JSON. Trate a lógica com base em error.type; a mensagem legível para humanos pode ser aprimorada sem mudança de versão. Informe error.request_id ou o cabeçalho de resposta X-Request-Id correspondente ao contatar o suporte.
{
"error": {
"type": "ambiguous_asset",
"message": "specify network (e.g. USDT.ERC20 or USDT.TRC20)",
"request_id": "b942e21f8dca4b06b8672eb9"
}
}| HTTP | Tipos típicos | Significado |
|---|---|---|
| 400 | invalid_request, unknown_parameter | JSON, consulta ou cabeçalho de idempotência malformados. |
| 401 | unauthorized | Credencial/conta ausente, inválida ou inativa. |
| 403 | insufficient_scope, admin_disabled | Chave válida sem a permissão exigida (veja X-Required-Scope), ou um recurso bloqueado por um administrador. |
| 404 | not_found | Endpoint desconhecido, ou um recurso fora desta conta de lojista. |
| 405 | method_not_allowed | Use o método indicado no cabeçalho Allow. |
| 409 | idempotency_conflict | Chave reutilizada com JSON diferente. |
| 413 | request_too_large | O corpo JSON excede 64 KiB. |
| 415 | unsupported_media_type | O corpo do POST não está declarado como application/json. |
| 422 | invalid, limit, invalid_amount, below_minimum, bad_address, 2fa_required, unsupported_asset | Requisição bem formada falhou em uma validação determinística ou atingiu um limite de recurso. |
| 429 | rate_limited | Aguarde Retry-After. |
| 500 | server_error | Falha inesperada; tente novamente com segurança usando a mesma chave de idempotência. |
| 503 | maintenance, temporarily_unavailable, asset_unavailable, no_rate, price_stale, fiat_rate_unavailable, fiat_rate_stale, derive_failed | Falha transitória de plataforma, nó, preço ou alocação de endereço. Nenhuma conversão desatualizada é usada em substituição. |
Limites atuais
| Escopo | Limite | Janela |
|---|---|---|
| Teto de segurança do Nginx por IP | 10 requisições/segundo, burst 30 | Contínuo |
| Teto para IP não autenticado | 300 requisições | 60 segundos |
| POST /v1/payments, links, shops, products | 120 requisições por chave de API | 60 segundos |
| POST /v1/payouts | 30 requisições por chave de API | 60 segundos |
| Endpoints GET | 240 requisições por chave de API | 60 segundos |
Limites da conta
| Recurso | Limite |
|---|---|
| Lojas por conta | 10 |
| Links de pagamento por conta | 50 |
| Produtos por loja | 50 |
| Combinações de variantes por produto | 30 |
| Chaves de licença por produto / link | 10,000 |
| Perguntas de checkout por link | 5 |
| Chaves de API ativas por conta | 50 |
Consulte seu uso em tempo real em relação a esses limites em GET /v1/account.
Respostas bem-sucedidas limitadas por aplicação expõem X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset. Repita 429, 500 e 503 com espera exponencial e jitter. Para POST, sempre reutilize o Idempotency-Key original e o mesmo JSON.
Segurança da integração
Carregue-os em tempo de execução; nunca registre o valor completo em log nem o envie para o controle de versão.
Um navegador ou cliente mobile não pode armazenar um segredo de lojista com segurança.
Verifique a atualidade do timestamp e use comparação de assinatura em tempo constante antes de fazer o parsing do JSON.
Registre eventos/pedidos processados de forma transacional, para que novas tentativas nunca entreguem em duplicidade.
Consulte o pagamento quando um evento for inesperado ou seu estado local divergir.
Crie uma chave substituta, implante-a, verifique o tráfego e só então exclua a chave antiga.
O acesso à conta é controlado por uma chave de lojista de 16 dígitos não recuperável, opcionalmente protegida por TOTP. Armazene tanto o acesso do lojista quanto os segredos de API com o mesmo cuidado dado a credenciais de carteira.
Checklist de lançamento
Não reutilize a cópia pessoal de um desenvolvedor entre serviços.
Use GET /v1/assets e GET /v1/currencies; renderize somente as entradas presentes e available: true.
Salve o segredo de assinatura uma única vez; verifique o timestamp e a assinatura e, em seguida, deduplique o ID estável do evento.
Teste uma nova tentativa duplicada e confirme que existe apenas um ID de pagamento.
O estado do seu pedido deve permanecer seguro diante de cotações fiat desatualizadas, ativos indisponíveis, confirmações atrasadas e todo caminho fora do fluxo ideal.
Compare seus pedidos com os estados de pagamento da API, os logs de webhook e o razão do lojista.
Pronto para integrar?
Crie uma conta em segundos, gere uma chave e mantenha esta referência ao lado do seu código.