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.
{
"merchant_id": "M00000001",
"name": "Acme Shop",
"legal_name": "Acme Shop Ltd",
"billing_email": "[email protected]",
"status": "active",
"kyb_status": "approved",
"api_access_enabled": true,
"default_currency": "USD",
"purchase_limits": {
"currency": "USD",
"verified": true,
"max_order_amount": "1000.00",
"daily_order_amount_limit": "10000.00",
"daily_order_count_limit": 1000,
"used_today_amount": "120.50",
"used_today_count": 3,
"day_resets_at": "2026-10-01T00:00:00+00:00"
}
}default_currencyé a moeda da sua carteira. Todos os preços que você paga estão nessa moeda.api_access_enabledficatruedepois que a CardV aprova a sua empresa.
#Saldo
GET/api/v1/balance mostra quanto você tem para gastar.
{
"currency": "USD",
"balance": "1520.40",
"reserved_amount": "0.00",
"available_balance": "1520.40",
"low_balance_threshold": "200.00",
"low_balance_notified_at": null,
"is_active": true
}available_balanceé o que você pode gastar agora:balancemenosreserved_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.
#Taxa de câmbio
GET/api/v1/fx-rates?quote=EUR retorna a taxa de câmbio de USD para outra moeda.
Use-a se sua loja vende em uma moeda diferente de USD. A CardV sempre debita sua carteira em USD. A taxa serve apenas para você definir seus próprios preços.
{
"base": "USD",
"quote": "EUR",
"rate": "0.9234",
"as_of": "2026-10-11T07:05:00Z"
}quoteé um código de moeda ISO 4217, comoEUR,GBPouJPY.baseé opcional. SomenteUSDé aceito.rateé quantas unidades dequotevocê recebe por 1 USD. É uma string decimal. Não a leia como float.as_ofé quando a CardV atualizou esta taxa pela última vez. As taxas são atualizadas a cada hora.quote=USDretorna"rate": "1".- Guarde a taxa do seu lado. Consultar algumas vezes por dia é suficiente.
| Status | Significado | O que fazer |
|---|---|---|
| 400 | quote está ausente ou não é um código de 3 letras, ou base não é USD | Corrija a requisição |
| 404 | No exchange rate for this currency. | Defina você mesmo os preços nesta moeda |
| 503 | Exchange rate temporarily unavailable. | Continue usando a última taxa salva e tente novamente mais tarde |
Assine esta requisição como qualquer outra. O caminho assinado inclui a query string, por exemplo /api/v1/fx-rates?quote=EUR.
#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.
#Modelos de produto
Todo SKU segue um destes modelos. Use denomination_type e product_type para diferenciá-los.
| Modelo | Como reconhecer | Preço | Pedido | O que você recebe |
|---|---|---|---|---|
| Valor fixo | denomination_type: "fixed" | merchant_price é o preço de uma unidade. | Envie quantity. | Códigos em deliveries. |
| Valor variável | denomination_type: "range" | De merchant_price_min a merchant_price_max. O preço real depende do valor: peça uma cotação. | Envie quantity e amount. | Códigos em deliveries. |
| Recarga direta | product_type: "direct_charge" | Igual ao valor fixo. | Envie também inputs (veja recargas diretas). | Normalmente sem códigos. succeeded significa que a conta foi recarregada. |
| Recarga de celular | Fora deste catálogo | Cotação própria | API própria | Veja Recarga de celular. |
verticalé a linha de produto, não o modelo. Recargas diretas também podem tervertical: "gift_card".- Qualquer SKU de valor fixo ou variável pode ser entregue como um link de resgate da CardV em vez de um código. Nesse caso, o SKU tem
delivery_mode: "voucher". Você recebe um link (delivery_type: "link", o link fica emredeem_url). O seu cliente o abre para obter o código. Envie-o ao seu cliente como faria com um código.
GET/api/v1/skus lista os SKUs que você pode comprar. Exemplo:
GET /api/v1/skus?search=steam®ion=US&limit=50&offset=0Filtros (todos opcionais):
| Filtro | Exemplo | O que busca |
|---|---|---|
search | steam | ID do SKU, nome ou marca |
brand | Steam | Nome da marca (maiúsculas ou minúsculas) |
region | US | Código ou nome do país. GLC = global, EU = Europa |
category | Travel | Categoria comercial, por exemplo Travel, Digital Wallets & Payment, Game Credits |
vertical | gift_card | Linha de produto |
product_type | pin_code | Forma 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.
{
"count": 7,
"limit": 2,
"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",
"face_currency": "USD",
"merchant_price": "9.25",
"merchant_price_min": "9.25",
"merchant_price_max": "9.25",
"settlement_currency": "USD",
"availability": "available",
"min_quantity": 1,
"max_quantity": 100,
"required_input_schema": [],
"...": "more fields"
},
{
"sku_id": "S006126",
"product_id": "P002210",
"name": "Apple ES",
"product_name": "Apple ES",
"brand": "Apple",
"region": "ES",
"vertical": "gift_card",
"product_type": "pin_code",
"denomination_type": "range",
"denomination_value": "0",
"min_face_value": "2",
"max_face_value": "250",
"amount_step": null,
"face_currency": "EUR",
"merchant_price": "2.28",
"merchant_price_min": "2.28",
"merchant_price_max": "284.15",
"price_label": "From 2.28 USD",
"settlement_currency": "USD",
"availability": "available",
"...": "more fields"
}
],
"filter_options": {"brands": [], "regions": [], "categories": [], "verticals": []}
}GET/api/v1/skus/{sku_id} retorna um único SKU, com os mesmos campos.
Os campos mais úteis:
| Campo | Significado |
|---|---|
sku_id | O ID que você usa para ver o preço e fazer o pedido. |
merchant_price | O seu preço por unidade, em settlement_currency. Num SKU range é apenas o preço de min_face_value, um preço inicial. Não o use para outros valores: peça uma cotação com amount. |
availability | available ou unavailable. Só compre SKUs available. |
denomination_type | fixed ou range. Veja valor fixo ou variável. |
denomination_value | Valor de face de um SKU fixed. "0" num SKU range. |
min_face_value, max_face_value | SKUs range: o valor mínimo e máximo que o seu cliente pode escolher, em face_currency. |
merchant_price_min, merchant_price_max | Preço do valor mínimo e do máximo. Em SKUs fixed, são iguais a merchant_price. Use-os para mostrar uma faixa de preço; antes de fazer o pedido, peça sempre uma cotação do valor exato. merchant_price_max é "" quando não pode ser calculado no momento. |
price_label | merchant_price como texto de exibição. Em SKUs range começa com From, por exemplo From 2.28 USD. |
face_value_label | Valor de face como texto de exibição, por exemplo 10 USD ou 50 - 1000 GBP. |
discount | Desconto sobre o valor de face, por exemplo 7.50% off face value. Só em SKUs fixed cuja moeda do cartão é a moeda da sua carteira; caso contrário, "". |
amount_step | Só SKUs de valor variável. O valor precisa ser múltiplo deste número; por exemplo, "1" significa apenas números inteiros. null significa sem incremento. |
face_currency | Moeda impressa no cartão. Pode ser diferente da moeda da sua carteira. |
min_quantity, max_quantity | Quantas unidades cabem em um item do pedido. |
product_type | pin_code (você recebe um código) ou direct_charge (a CardV recarrega uma conta). |
delivery_type | O que o fornecedor entrega: code, code_pin, code_serial, url ou direct_charge. Quando delivery_mode é voucher, você recebe um link no lugar. |
delivery_mode | code (você recebe o próprio código) ou voucher (você recebe um link de resgate da CardV). |
voucher_instructions | Em SKUs voucher: texto que explica ao seu cliente como usar o link. Caso contrário, "". |
vertical, category | Linha de produto e categoria de negócio, para filtros e exibição. |
region, region_name, region_label | Código do país ou região, o nome dele e um rótulo de exibição. |
required_input_schema | Dados que você precisa enviar nas recargas diretas. |
brand_logo_url, image_url | Imagens hospedadas pela CardV, ou "". |
description, redemption_instructions, terms, disclaimer | Textos 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.
- Mostre aos seus clientes os preços da sua lista sincronizada. Não chame o endpoint de cotação a cada visualização de página ou visitante.
- Os preços de SKUs de valor variável acompanham o custo do fornecedor e podem mudar algumas vezes por dia. Atualize
merchant_price_minemerchant_price_maxjunto com a sincronização de SKUs. filter_optionsmostra as marcas, regiões e linhas de produto que você pode usar nos filtros.
#Sincronizar por produto
Se a sua loja mostra uma página por produto com seletor de valor, sincronize produtos em vez de SKUs.
GET/api/v1/products lista produtos. Cada produto traz todos os SKUs que você pode comprar nele.
GET /api/v1/products?brand=Steam®ion=GB&limit=50&offset=0Aceita os mesmos filtros e a mesma paginação de GET/api/v1/skus. count conta produtos e sku_count conta os SKUs deles.
{
"count": 1,
"sku_count": 4,
"limit": 50,
"results": [
{
"product_id": "P000123",
"product_name": "Steam Wallet UK",
"brand": "Steam",
"category": "Gaming",
"region": "GB",
"product_type": "pin_code",
"image_url": "https://b2b.cardv.net/api/v1/catalog-assets/steam.png",
"required_input_schema": [],
"skus": [
{
"sku_id": "S000456",
"name": "Steam Wallet 5 GBP",
"label": "5 GBP",
"denomination_type": "fixed",
"denomination_value": "5",
"face_currency": "GBP",
"merchant_price": "7.61",
"settlement_currency": "USD",
"availability": "available",
"min_quantity": 1,
"max_quantity": 100,
"...": "more fields"
}
]
}
],
"filter_options": {"brands": [], "regions": [], "categories": [], "verticals": []}
}GET/api/v1/products/{product_id} retorna um produto com seus SKUs, além de description, redemption_instructions, terms e disclaimer.
- Cada SKU em
skustem os mesmos campos e valores deGET/api/v1/skus. Cote e compre com osku_idcomo sempre. - Use
labelcomo texto da opção, por exemplo5 GBPouTinder Plus 1 Month. Alguns produtos são planos, não valores. - Um produto tem uma única moeda de valor de face e um único tipo de valor. Um SKU de valor variável é sempre um produto separado.
- A lista não traz os textos longos. Leia-os uma vez por produto em
GET/api/v1/products/{product_id}.
#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.
| Tipo | Ao consultar o preço | Ao fazer o pedido |
|---|---|---|
fixed | Envie quantity | Não envie amount |
range | Envie quantity e amount | Envie amount |
Em um SKU de valor variável, amount precisa estar entre min_face_value e max_face_value.
O valor é em face_currency.
Preço de um SKU de valor variável. Nas listas de SKUs e de produtos, merchant_price e price_label são apenas o preço de min_face_value. merchant_price_min e merchant_price_max dão o preço do valor mínimo e do máximo. O preço de um valor intermediário não é um múltiplo simples de nenhum deles. Antes de definir o seu preço de venda ou de encomendar, peça uma cotação com o amount exato e envie o merchant_price dessa cotação como expected_unit_price.
Alguns SKUs de valor variável também têm um amount_step. Quando não é null, amount precisa ser múltiplo dele.
Por exemplo, com "amount_step": "1" você pode enviar 25, mas não 25.50.
Uma cotação ou pedido com um valor que não respeita o incremento retorna HTTP 400 e não cobra nada.
#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:
"required_input_schema": [
{"key": "player_id", "label": "Player ID", "type": "text", "required": true},
{"key": "server", "label": "Server", "type": "text", "required": false}
]Envie os valores no campo inputs do item do pedido, usando cada key:
"inputs": {"player_id": "123456789", "server": "EU"}- Todo campo é obrigatório, a menos que venha com
"required": false.typeé uma dica para o campo do seu formulário, comotext. - 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.
GET /api/v1/skus/S000456/quote?quantity=2
GET /api/v1/skus/S000789/quote?quantity=1&amount=25.00{
"sku_id": "S000456",
"settlement_currency": "USD",
"merchant_price": "9.25",
"quantity": 2,
"total_price": "18.50",
"min_quantity": 1,
"max_quantity": 100,
"availability": "available"
}- A consulta não garante o preço. Os preços podem mudar a qualquer momento.
- Consulte o preço uma única vez, quando o cliente finalizar a compra, com um tempo limite curto, por exemplo 5 segundos. Se a consulta exceder o tempo limite, continue mostrando o preço sincronizado e tente de novo; nunca mostre uma página de erro porque uma consulta demorou.
- Para se proteger, envie o
merchant_pricecomoexpected_unit_priceao fazer o pedido. Envie o preço de uma consulta, não um preço que você mesmo calculou: ele precisa ser exatamente igual, até o centavo. Se o preço tiver mudado, a CardV recusa o pedido e não cobra nada. - Quantidade ou valor fora do intervalo, ou um valor que não é múltiplo de
amount_step, retorna HTTP 400 com erro emquantityouamount.
#Fazer um pedido
POST/api/v1/orders compra um ou mais SKUs e paga com a sua carteira.
Como toda chamada, ela precisa ser assinada.
{
"external_order_id": "SHOP-20260929-10001",
"items": [
{"sku_id": "S000456", "quantity": 2, "expected_unit_price": "9.25"},
{"sku_id": "S000789", "amount": "25.00", "expected_unit_price": "23.75"},
{
"sku_id": "S000900",
"expected_unit_price": "4.90",
"inputs": {"player_id": "123456789"}
}
]
}| Campo | Obrigatório | Significado |
|---|---|---|
external_order_id | Sim | O seu número de pedido, de 1 a 120 caracteres. Não pode se repetir. |
items | Sim | Um ou mais itens do pedido. |
items[].sku_id | Sim | O SKU que você quer comprar. |
items[].quantity | Não | Quantas unidades. Padrão: 1. |
items[].amount | SKUs de valor variável | O valor de face que você quer comprar. Precisa respeitar min_face_value, max_face_value e amount_step. |
items[].expected_unit_price | Recomendado | O merchant_price da consulta. Envie sempre. |
items[].inputs | Recargas diretas | Dados 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:
{
"idempotent_replay": false,
"order": {
"order_id": "O-00001234",
"external_order_id": "SHOP-20260929-10001",
"status": "accepted",
"total_amount": "46.20",
"...": "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:
| Chave | Motivo | O que fazer |
|---|---|---|
items | Preço mudou, SKU indisponível, valor inválido ou dado faltando | Consulte o preço de novo, corrija e reenvie |
balance | Saldo insuficiente na carteira | Adicione saldo no Portal |
risk | Acima do seu limite por pedido ou do limite diário | Fale com a CardV |
external_order_id | O seu número de pedido já foi usado em outro pedido | Veja Reenviar com segurança |
Exemplo de mudança de preço:
{
"items": "SKU S000456 price changed from 9.25 to 9.41 USD; refresh quote and confirm again."
}A sua conta tem limites por pedido, de gasto diário e de quantidade de pedidos por dia.
GET/api/v1/account mostra esses limites em purchase_limits, com o quanto você já usou hoje.
0 significa sem limite. Os limites diários zeram às 00:00 UTC.
#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ê envia | Você recebe |
|---|---|
| Um número de pedido novo | HTTP 201. Um pedido novo. A carteira é cobrada. |
| O mesmo número e o mesmo pedido | HTTP 200 e "idempotent_replay": true. O pedido que já existe. Nenhuma cobrança. |
| O mesmo número, mas um pedido diferente | HTTP 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.
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.
{
"order_id": "O-00001234",
"external_order_id": "SHOP-20260929-10001",
"status": "succeeded",
"currency": "USD",
"total_amount": "18.50",
"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.25",
"total_price": "18.50",
"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[].deliveriestraz os códigos completos. Trate a resposta como confidencial.invoice_urledelivery_file_urlsã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
accepted ──► processing ──► succeeded
│
├──► partially_succeeded (alguns itens entregues, outros não)
│
└──► failed ──► refunded (dinheiro devolvido à sua carteira)| Status | Terminou? | O que fazer |
|---|---|---|
accepted | Não | Aguarde. A carteira já foi cobrada e a entrega ainda não começou. |
processing | Não | Aguarde. Não faça o pedido de novo. |
succeeded | Sim | Busque os códigos e entregue ao seu cliente. |
partially_succeeded | Sim | Entregue o que chegou. O restante é reembolsado depois. |
failed | Ainda não | Aguarde o refunded. Falha ainda não é reembolso. |
refunded | Sim | O 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:
{
"status": "stored",
"delivery_type": "card_pin",
"card_number": "X1234",
"pin_code": "9876",
"redeem_url": "",
"expiry_date": "2027-09-29",
"instructions": "Redeem at ..."
}| Campo | O que é |
|---|---|
card_number | O código principal: número do cartão, código do voucher ou PIN. |
pin_code | O segundo código, como um PIN ou código de segurança. Vazio quando não existe. |
redeem_url | Link de resgate. Nas entregas do tipo link, o próprio link é o código. |
expiry_date | Último dia em que o código pode ser usado, no formato YYYY-MM-DD. "" significa que o fornecedor não informou data de validade. Não significa que o código expirou. |
- Entregue ao seu cliente todos os campos que não estiverem vazios:
card_number,pin_code,redeem_url,expiry_dateeinstructions. delivery_typediz o que você recebeu:code,card_pin,link,code_linkouqr.- Mantenha
redeem_urlem sigilo, como um código. - Nunca exclua, oculte ou anule um código porque
expiry_dateestá vazio. Mostre uma data de validade ao seu cliente apenas quando ela não estiver vazia. - Nunca entregue ao cliente uma unidade com
statusigual avoided. - Produtos de recarga direta normalmente não têm entregas.
succeededsignifica que a conta foi recarregada. - 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.