Desenvolvedores/Integração

Catálogo e pedidos

Este guia mostra o fluxo de compra do começo ao fim: consultar o saldo, encontrar um produto, ver o preço, fazer o pedido e receber os códigos.

Veja também: Autenticação · Convenções · Webhooks

#Conta e saldo

#Conta

GET/api/v1/account mostra os dados da sua empresa e se a API está liberada.

JSON
{
  "merchant_id": "M00000001",
  "name": "Acme Shop",
  "legal_name": "Acme Shop Ltd",
  "tier": "standard",
  "billing_email": "[email protected]",
  "status": "active",
  "kyb_status": "approved",
  "api_access_enabled": true,
  "default_currency": "USD"
}
  • default_currency é a moeda da sua carteira. Todos os preços que você paga estão nessa moeda.
  • api_access_enabled fica true depois que a CardV aprova a sua empresa.

#Saldo

GET/api/v1/balance mostra quanto você tem para gastar.

JSON
{
  "currency": "USD",
  "balance": "1520.4000",
  "reserved_amount": "0.0000",
  "available_balance": "1520.4000",
  "low_balance_threshold": "200.0000",
  "low_balance_notified_at": null,
  "is_active": true
}
  • available_balance é o que você pode gastar agora: balance menos reserved_amount.
  • Um pedido maior que o available_balance é recusado, e nada é cobrado.
  • low_balance_threshold é o valor que dispara o e-mail de saldo baixo. Você define esse valor no Portal.
  • Para adicionar saldo, use o Portal.

#Produtos (SKUs)

Um SKU é um produto que você pode comprar, por exemplo "Steam Wallet 10 USD". O ID tem este formato: S000456. É pelo SKU que você consulta o preço e faz o pedido.

GET/api/v1/skus lista os SKUs que você pode comprar. Exemplo:

HTTP
GET /api/v1/skus?search=steam&region=US&limit=50&offset=0

Filtros (todos opcionais):

FiltroExemploO que busca
searchsteamID do SKU, nome ou marca
brandSteamNome da marca (maiúsculas ou minúsculas)
regionUSCódigo ou nome do país
verticalgift_cardLinha de produto
product_typepin_codeForma de entrega

Paginação: envie limit (padrão 100, máximo 500) e offset. Continue pedindo com um offset maior até offset chegar a count.

JSON
{
  "count": 7,
  "limit": 1,
  "results": [
    {
      "sku_id": "S000456",
      "product_id": "P000123",
      "name": "Steam Wallet 10 USD",
      "product_name": "Steam Wallet US",
      "brand": "Steam",
      "region": "US",
      "vertical": "gift_card",
      "product_type": "pin_code",
      "denomination_type": "fixed",
      "denomination_value": "10.0000",
      "face_currency": "USD",
      "merchant_price": "9.2500",
      "settlement_currency": "USD",
      "availability": "available",
      "min_quantity": 1,
      "max_quantity": 100,
      "required_input_schema": [],
      "...": "more fields"
    }
  ],
  "filter_options": {"brands": [], "regions": [], "verticals": []}
}

GET/api/v1/skus/{sku_id} retorna um único SKU, com os mesmos campos.

Os campos mais úteis:

CampoSignificado
sku_idO ID que você usa para ver o preço e fazer o pedido.
merchant_priceO seu preço por unidade, em settlement_currency.
availabilityavailable ou unavailable. Só compre SKUs available.
denomination_typefixed ou range. Veja valor fixo ou variável.
face_currencyMoeda impressa no cartão. Pode ser diferente da moeda da sua carteira.
min_quantity, max_quantityQuantas unidades cabem em um item do pedido.
product_typepin_code (você recebe um código) ou direct_charge (a CardV recarrega uma conta).
required_input_schemaDados que você precisa enviar nas recargas diretas.
brand_logo_url, image_urlImagens hospedadas pela CardV, ou "".
description, redemption_instructions, termsTextos que você pode mostrar aos seus clientes.

Dicas:

  • Você só vê SKUs ativos e liberados para a sua conta. Os outros retornam 404.
  • Atualize a lista de SKUs a cada 5–15 minutos. Consulte sempre o preço logo antes de fazer o pedido.
  • filter_options mostra as marcas, regiões e linhas de produto que você pode usar nos filtros.

#Valor fixo ou variável

A maioria dos SKUs tem valor de face fixo (fixed), como 10 USD. Alguns têm valor variável (range): o seu cliente escolhe o valor, por exemplo de 5 a 500 USD.

TipoAo consultar o preçoAo fazer o pedido
fixedEnvie quantityNão envie amount
rangeEnvie quantity e amountEnvie amount

Em um SKU de valor variável, amount precisa estar entre min_face_value e max_face_value. O valor é em face_currency.

#Recargas diretas

Alguns produtos recarregam direto a conta do seu cliente, por exemplo uma conta de jogo. Nesses casos, a CardV precisa dos dados da conta. O SKU informa quais são:

JSON
"required_input_schema": [
  {"key": "player_id", "label": "Player ID", "required": true},
  {"key": "server", "label": "Server", "required": false}
]

Envie os valores no campo inputs do item do pedido, usando cada key:

JSON
"inputs": {"player_id": "123456789", "server": "EU"}
  • Todo campo é obrigatório, a menos que venha com "required": false.
  • Se faltar um valor obrigatório, o pedido é recusado com um erro em items.
  • Esses valores são dados pessoais do seu cliente. Proteja-os (veja Segurança).

#Consulta de preço

A consulta de preço (quote) informa o preço atual para uma quantidade.

HTTP
GET /api/v1/skus/S000456/quote?quantity=2
GET /api/v1/skus/S000789/quote?quantity=1&amount=25.00
JSON
{
  "sku_id": "S000456",
  "settlement_currency": "USD",
  "merchant_price": "9.2500",
  "quantity": 2,
  "total_price": "18.5000",
  "min_quantity": 1,
  "max_quantity": 100,
  "availability": "available"
}
  • A consulta não garante o preço. Os preços podem mudar a qualquer momento.
  • Para se proteger, envie o merchant_price como expected_unit_price ao fazer o pedido. Se o preço tiver mudado, a CardV recusa o pedido e não cobra nada.
  • Quantidade ou valor fora do intervalo retorna HTTP 400 com erro em quantity ou amount.

#Fazer um pedido

POST/api/v1/orders compra um ou mais SKUs e paga com a sua carteira. Esta chamada precisa ser assinada.

JSON
{
  "external_order_id": "SHOP-20260929-10001",
  "items": [
    {"sku_id": "S000456", "quantity": 2, "expected_unit_price": "9.2500"},
    {"sku_id": "S000789", "amount": "25.00", "expected_unit_price": "23.7500"},
    {
      "sku_id": "S000900",
      "expected_unit_price": "4.9000",
      "inputs": {"player_id": "123456789"}
    }
  ]
}
CampoObrigatórioSignificado
external_order_idSimO seu número de pedido, de 1 a 120 caracteres. Não pode se repetir.
itemsSimUm ou mais itens do pedido.
items[].sku_idSimO SKU que você quer comprar.
items[].quantityNãoQuantas unidades. Padrão: 1.
items[].amountSKUs de valor variávelO valor de face que você quer comprar.
items[].expected_unit_priceRecomendadoO merchant_price da consulta. Envie sempre.
items[].inputsRecargas diretasDados da conta para recargas diretas.

Quando a CardV aceita o pedido, ela cobra o valor total da sua carteira na hora. A entrega começa em seguida, em segundo plano.

A resposta é HTTP 201:

JSON
{
  "idempotent_replay": false,
  "order": {
    "order_id": "O-00001234",
    "external_order_id": "SHOP-20260929-10001",
    "status": "accepted",
    "total_amount": "46.2000",
    "...": "more fields"
  }
}

Guarde o order.order_id. Esta resposta nunca traz os códigos. Você os busca depois (veja Consultar um pedido).

#Pedidos recusados

Um pedido recusado retorna HTTP 400 e não cobra nada. A chave do erro diz o motivo:

ChaveMotivoO que fazer
itemsPreço mudou, SKU indisponível, valor inválido ou dado faltandoConsulte o preço de novo, corrija e reenvie
balanceSaldo insuficiente na carteiraAdicione saldo no Portal
riskAcima do seu limite por pedido ou do limite diárioFale com a CardV
external_order_idO seu número de pedido já foi usado em outro pedidoVeja Reenviar com segurança

Exemplo de mudança de preço:

JSON
{
  "items": "SKU S000456 price changed from 9.2500 to 9.4100 USD; refresh quote and confirm again."
}

O plano da sua conta define os limites por pedido, de gasto diário e de quantidade de pedidos por dia. Os limites diários zeram às 00:00 UTC. Pergunte à CardV quais são os seus limites.

#Reenviar com segurança

O seu número de pedido (external_order_id) evita que você compre duas vezes. Se você reenviar o mesmo pedido com o mesmo número, a CardV não cobra de novo. Ela devolve o pedido que já existe.

Você enviaVocê recebe
Um número de pedido novoHTTP 201. Um pedido novo. A carteira é cobrada.
O mesmo número e o mesmo pedidoHTTP 200 e "idempotent_replay": true. O pedido que já existe. Nenhuma cobrança.
O mesmo número, mas um pedido diferenteHTTP 400 em external_order_id. Nada acontece.

"O mesmo pedido" quer dizer os mesmos itens, na mesma ordem, com o mesmo SKU, quantidade, valor e dados de recarga. Se você enviar expected_unit_price, ele precisa ser igual ao preço do primeiro pedido.

A CardV reconhece o pedido repetido antes de verificar saldo e preço. Por isso a resposta é sempre o primeiro pedido, mesmo que o preço tenha mudado depois.

#Fluxo de reenvio seguro

Se você não tiver uma resposta clara, basta reenviar o mesmo pedido.

Text
POST /orders com o número de pedido R
 ├─ 201 ou 200 → guarde o order_id. Pronto.
 ├─ 400 items / balance / risk → nenhum pedido foi criado.
 │      Corrija a causa e reenvie. Você pode usar R de novo.
 ├─ 400 external_order_id → R pertence a outro pedido. Pare e verifique.
 ├─ 403 erro de assinatura → assine de novo e envie o mesmo corpo.
 ├─ 429 → espere o Retry-After, assine de novo e envie o mesmo corpo.
 └─ timeout, 5xx ou conexão perdida
        → reenvie o mesmo corpo com o mesmo R.
          Você recebe 201 (a primeira tentativa não chegou) ou 200 (chegou).

Regras:

  • Nunca crie um número de pedido novo só porque uma resposta se perdeu. Se a primeira requisição tiver chegado, um número novo compraria tudo duas vezes.
  • Cada reenvio precisa de timestamp, nonce e assinatura novos. O corpo continua igual.

#Consultar um pedido

GET/api/v1/orders/{order_id} retorna o pedido, o status e os códigos.

JSON
{
  "order_id": "O-00001234",
  "external_order_id": "SHOP-20260929-10001",
  "status": "succeeded",
  "currency": "USD",
  "total_amount": "18.5000",
  "created_at": "2026-09-29T08:15:30.123456Z",
  "updated_at": "2026-09-29T08:15:41.004211Z",
  "items": [
    {
      "sku_id": "S000456",
      "product_name": "Steam Wallet US",
      "quantity": 2,
      "unit_price": "9.2500",
      "total_price": "18.5000",
      "delivery_count": 2,
      "deliveries": [{"...": "see Codes below"}]
    }
  ],
  "...": "more fields"
}
  • total_amount é o valor cobrado quando o pedido foi aceito.
  • items[].unit_price é o preço travado para este pedido.
  • items[].deliveries traz os códigos completos. Trate a resposta como confidencial.
  • invoice_url e delivery_file_url são caminhos para a fatura e para os códigos em CSV. Os dois só funcionam no Portal. Com chave de API, retornam HTTP 403.
  • A resposta também traz id (um número antigo, não use), events (histórico só para exibição) e o andamento da entrega de cada item. Você pode ignorar esses campos.
  • Um número de pedido desconhecido retorna HTTP 404.

#Status do pedido e códigos

#Status

Text
accepted ──► processing ──► succeeded
                  │
                  ├──► partially_succeeded   (alguns itens entregues, outros não)
                  │
                  └──► failed ──► refunded   (dinheiro devolvido à sua carteira)
StatusTerminou?O que fazer
acceptedNãoAguarde. A carteira já foi cobrada e a entrega ainda não começou.
processingNãoAguarde. Não faça o pedido de novo.
succeededSimBusque os códigos e entregue ao seu cliente.
partially_succeededSimEntregue o que chegou. O restante é reembolsado depois.
failedAinda nãoAguarde o refunded. Falha ainda não é reembolso.
refundedSimO dinheiro voltou para a sua carteira.

Se você não usa webhooks, consulte o pedido assim: depois de 5 segundos, depois 10 s, 30 s, 60 s e então a cada 5 minutos. Respeite o limite de requisições. A maioria dos pedidos termina em segundos. Alguns precisam de verificação manual e podem levar horas.

#Códigos

Cada unidade entregue é um objeto em items[].deliveries:

JSON
{
  "status": "stored",
  "delivery_type": "card_pin",
  "display_fields": [
    {"key": "card_number", "label": "Card number", "value": "X1234", "kind": "secret"},
    {"key": "pin_code", "label": "PIN", "value": "9876", "kind": "secret"}
  ],
  "redeem_url": "",
  "expiry_date": "2027-09-29",
  "instructions": "Redeem at ...",
  "is_masked": false
}
  • Mostre ao seu cliente os display_fields: cada um tem um label e um value. Mostre também redeem_url, expiry_date e instructions quando não estiverem vazios.
  • kind é secret para códigos e PINs, e reference para dados como números de série.
  • delivery_type diz o que você recebeu: code, card_pin, link, code_link ou qr. Podem surgir tipos novos, então monte a exibição sempre a partir de display_fields.
  • Nas entregas do tipo link, o próprio redeem_url é o código. Mantenha-o em sigilo.
  • Nunca entregue ao cliente uma unidade com status igual a voided.
  • Produtos de recarga direta normalmente não têm entregas. succeeded significa que a conta foi recarregada.
  • Cópias como card_number e pin_code também aparecem como campos separados. Elas podem vir vazias.
  • Os webhooks nunca trazem códigos. Consulte o pedido depois que o webhook chegar.

Dúvidas sobre a integração? Envie um e-mail para [email protected] com seu Merchant ID e o ID do pedido ou da requisição.