Guia de VCN
O que é uma VCN, os três tipos, o ciclo de vida e as regras de janela, idempotência, teto e erros.
Este guia reúne as regras que valem para todos os endpoints de VCN; cada endpoint lista os próprios erros na API Reference.
Visão geral
A VCN (Virtual Card Number) é um cartão virtual de uso restrito, emitido a partir do cartão de funding da sua empresa, o cartão corporativo de onde ela sai. Cada VCN tem uma janela de uso, um teto de gastos e um número máximo de autorizações (maxPurchaseQuantity). PAN, CVV e validade voltam na emissão.
Tipos
Escolha o type pelo que o cartão vai pagar. O tipo define o identificador que você envia e de onde vem o teto:
| Tipo | Para pagar | Identificador | Teto |
|---|---|---|---|
HOTEL | uma reserva de hospedagem | hotelBooking.reservationId | derivado do custo da reserva, em amount |
AERIAL | uma reserva aérea | flightBooking.recordLocator | derivado do custo da reserva, em amount |
CUSTOM | um uso definido por você, ex.: um cartão por fornecedor | reference | o limit.value que você informa |
Só o CUSTOM é atualizável: os controles de HOTEL e AERIAL vêm da reserva.
Ciclo de vida
Emitir
Criar VCN devolve o vcnId, os dados do cartão e os controles vigentes. A VCN nasce ACTIVE. Guarde o vcnId junto com o identificador: ele endereça as outras rotas, e nenhum erro o devolve.
Reobter os dados do cartão
Revelar dados do VCN devolve PAN, CVV e validade de novo, quando você precisar deles depois da emissão.
Recarregar e ajustar
No CUSTOM, Atualizar VCN recarrega o teto, prorroga ou encurta a janela e ajusta os controles, sem trocar o cartão.
Acompanhar
Consultar VCN devolve o status, a janela de uso, o teto vigente e os controles, sem os dados do cartão.
Vencer ou cancelar
A VCN vence a partir do dia seguinte ao endDate. Para encerrar antes, nos três tipos, use Cancelar VCN: o cancelamento é definitivo, e a VCN não volta a ACTIVE.
As seções abaixo detalham as regras de cada etapa.
Identificação da plataforma (X-Partner-Id)
Toda chamada de VCN informa, no header X-Partner-Id, a plataforma integradora (partner) pela qual ela é feita. O header é obrigatório em todas as rotas de VCN.
| Item | Regra |
|---|---|
| Quem gera | A Conta Simples gera o ID e o entrega a você no onboarding. Você só o envia. |
| Formato | ptn_ seguido de um ULID de 26 caracteres (base32 de Crockford, em maiúsculas), ex.: ptn_01JQ8ZK7X4M8N2P5R6T7V8W9XY. Não é nome nem CNPJ. |
| Valor | Imutável e sensível a maiúsculas e minúsculas: envie exatamente como recebeu. Não é segredo. |
| Onde vai | Sempre no header. Nunca na URL, em path ou query, nem no corpo. |
| Assinatura | A API não exige que o X-Partner-Id entre na assinatura. Se quiser protegê-lo, inclua "x-partner-id" no Signature-Input, e aí qualquer alteração no header invalida a assinatura. |
- Credencial com mais de um partner: uma credencial pode estar vinculada a mais de uma plataforma. Envie, em cada chamada, o
X-Partner-Idda plataforma daquela operação. A chave de idempotência vale por partner: a mesma chave em outro partner não colide (veja Idempotência e reemissão).
| Situação | Resposta |
|---|---|
| Header ausente ou fora do formato | 400 bad-request-exception, com errors[].field headers.x-partner-id |
| Partner não vinculado à sua credencial | 403 caller-not-authorized, com details.reason PARTNER_NOT_BOUND |
curl -X GET https://api-sandbox.contasimples.com/credit-cards/v1/vcns/{vcnId}/reveal \
-H "Authorization: Bearer {TOKEN}" \
-H "User-Agent: {nome-do-seu-app}/{versao}" \
-H "X-Partner-Id: ptn_01JQ8ZK7X4M8N2P5R6T7V8W9XY"
Janela de uso
A VCN só autoriza compras dentro da janela startDate–endDate. As duas datas são dias de calendário no horário de Brasília — exceção à regra geral de datas em UTC da API —, e "hoje" é o dia corrente em Brasília.
- A janela abre às 00:00 do
startDatee fecha no fim do dia doendDate: oendDateé inclusivo. - Sem
startDate, a janela começa no dia da emissão, e o cartão já nasce utilizável. createdAteupdatedAtsão instantes em UTC. Numa emissão entre 21h e 24h de Brasília,createdAtcai no dia seguinte aostartDate.- A janela não é a validade física do cartão, que vem em
card.expirationDate.
Fim padrão por tipo
Sem endDate no pedido, o fim é o padrão do tipo. O padrão não acompanha o startDate: se o início cair no dia do padrão ou depois, a janela fica invertida e a emissão é recusada — nesse caso, informe o endDate.
| Tipo | Fim padrão | Janela invertida sem endDate quando |
|---|---|---|
HOTEL | checkOut + 20 dias | o checkOut foi há 20 dias ou mais |
AERIAL | dia da emissão + 1 dia | o startDate é amanhã ou depois |
CUSTOM | dia da emissão + 60 dias | o startDate é hoje + 60 dias ou depois |
Limites das datas
| Regra | Criar VCN | Atualizar VCN |
|---|---|---|
| Início | startDate não pode ser anterior a hoje; hoje é aceito a qualquer hora | o startDate não muda |
| Fim depois do início | com as duas datas no pedido, endDate igual ou anterior ao startDate → 400 bad-request-exception em body.endDate; sem startDate, o menor endDate aceito é amanhã | o novo endDate tem de ser posterior ao startDate da VCN |
| Fim e hoje | — | o novo endDate não pode ser anterior a hoje; hoje é aceito, e o cartão vale até o fim do dia |
| Teto de 365 dias | até 365 dias do dia da emissão, com o 365º aceito; informar startDate não estende o teto | até 365 dias da emissão |
| Validade do cartão de funding | o fim da janela, informado ou padrão, não pode passar da validade do cartão de funding (o cartão corporativo de onde a VCN é emitida), que não é exposta | a mesma regra, quando o pedido traz endDate |
Fora os casos marcados, a recusa é 400 invalid-vcn-request, sem errors[], com o motivo no message. No teto do cartão de funding, o motivo é end date must not exceed the funding card expiration: encurte a janela ou acione a Conta Simples.
Vencimento e encerramento
- A VCN vence a partir do dia seguinte ao
endDate. No próprio dia doendDateela ainda aceita atualização, e uma nova emissão na mesma chave ainda responde409. - Vencida, Atualizar VCN responde
409 vcn-expired: não recarregue, emita outra. - Não existe status de vencida: uma VCN vencida continua
ACTIVE. Compare oendDatecom o dia de hoje em Brasília. - Encurtar o
endDatenão encerra o cartão. Para encerrar, use Cancelar VCN. - Recargas não empurram a validade, e mudar a validade não mexe no teto: para os dois, envie
limiteendDate. - O
startDatede uma VCN emitida não muda.
Idempotência e reemissão
Cada tipo tem uma chave de idempotência, e ela é também o identificador que você envia:
| Tipo | Chave |
|---|---|
HOTEL | hotelBooking.reservationId — o id da reserva na plataforma onde ela foi feita |
AERIAL | flightBooking.recordLocator — o localizador (PNR, Passenger Name Record) |
CUSTOM | reference — texto de 1 a 255 caracteres, definido por você; é ele que define o que conta como "o mesmo cartão" |
- A resposta devolve a chave em
reference, como texto, nos três tipos. No pedido, só oCUSTOMenviareference. - A chave vale por empresa,
typee plataforma integradora (oX-Partner-Idda chamada): a mesma chave em outrotypeou em outro partner não colide. - Enquanto a VCN da chave está viva (
ACTIVEouBLOCKED, dentro da janela), uma nova emissão responde409 vcn-already-issued, sem os dados do cartão e sem ovcnId. Guarde ovcnIddo201junto com a chave. - No
CUSTOM, esse409é o caminho esperado: o cartão daquelareferencejá existe. Recarregue-o em Atualizar VCN; cadareferencenova cria um cartão novo. - A chave fica livre depois do vencimento ou do cancelamento. Uma nova emissão com ela gera outro cartão, com PAN novo, e o
vcnIdanterior passa a responder404em todas as rotas. - Não use dados pessoais na chave: ela é gravada e devolvida nas respostas.
Teto e recarga
HOTELeAERIAL: o teto é derivado do custo,amount.rate + amount.taxes + amount.fees, que precisa ser maior que zero. NoHOTEL, soma-se a margem de extras quandoallowExtraChargesétrue: o valor deextraChargesMarginou, sem ele, a margem padrão — hoje R$ 150,00 por diária por hóspede, sujeita a mudança. Para controlar o teto, informeextraChargesMargin.CUSTOM: o teto é olimit.valueinformado, a partir de0.01. Só oCUSTOMé atualizável; os controles deHOTELeAERIALvêm da reserva.- O teto não é saldo: o disponível é calculado pela rede do cartão (
disponível = teto − consumido), e a API não devolve o consumo.
Recarga no período TOTAL
⚠️ No período TOTAL, o padrão, limit.value é o teto acumulado da janela, não um incremento. Para adicionar crédito, envie teto vigente + crédito.
Exemplo: teto 100.01 e uma nova venda de R$ 80,00 → envie 180.01. Se enviar 80.00, o teto fica abaixo do que já foi gasto, e toda nova autorização passa a ser recusada.
O teto vigente volta no 201 de Criar VCN, no 200 de Atualizar VCN e em Consultar VCN: guarde o último que receber.
Período do teto
spendLimitPeriod | O teto vale para |
|---|---|
TOTAL (padrão) | a janela inteira |
MONTHLY | cada mês; renova a cada mês |
DAILY | cada dia; renova a cada dia |
- A conta de recarga acima só vale para
TOTAL. ComMONTHLYouDAILY,limit.valueé o teto de cada mês ou dia. - O período não interage com
maxPurchaseQuantity, que conta autorizações. - Em Atualizar VCN,
spendLimitPeriodomitido mantém o período vigente, e trocar o período não zera o que já foi gasto: um cartão que passa deTOTALparaMONTHLYnão ganha o mês limpo.
Recargas em paralelo
- Envie
limit.expectedValuecom o teto que você acredita estar vigente: a atualização só grava se ele bater. - Se não bater — ou se outra atualização da mesma VCN gravar no meio, o que também acontece sem
expectedValuee em chamadas seguidas muito próximas —, a resposta é409 vcn-limit-conflict. Recalcule o total a partir do teto mais recente e repita. Releia o teto em Consultar VCN; a leitura pode levar alguns instantes para refletir a última atualização.
Repetir chamadas
As regras gerais de retry da API não valem igual para todos os endpoints de VCN:
| Endpoint | Depois de 5xx ou tempo esgotado |
|---|---|
| Criar VCN | Não repita automaticamente. O cartão pode ter sido emitido, e a nova tentativa pode receber 409 vcn-already-issued sem o vcnId. Acione o suporte com o horário, o requestId do corpo e a chave de idempotência. |
| Atualizar VCN | 503 vcn-update-unavailable: repita. 500: acione o suporte com o horário e o requestId. |
| Revelar dados do VCN | Repetir é seguro. |
| Consultar VCN | Repetir é seguro. |
| Cancelar VCN | Repetir é seguro: uma VCN já cancelada responde 200 com o mesmo corpo. Depois de 500, 503 ou tempo esgotado, repita o DELETE ou confira o status em Consultar VCN. |
Em qualquer endpoint, se o erro persistir, acione o suporte com o horário da chamada e o requestId.
Leitura logo após escrever
A leitura é eventualmente consistente.
- Logo depois da emissão, Atualizar, Revelar, Consultar e Cancelar podem responder
404por alguns instantes: repita antes de concluir que a VCN não existe. - Logo depois de uma atualização ou de um cancelamento, Consultar VCN pode devolver o estado anterior por alguns instantes.
- Atualizações da mesma VCN em sequência muito rápida podem receber
409 vcn-limit-conflict(veja Recargas em paralelo).
Corpo da requisição
Criar VCN
- Envie exatamente um identificador, o do seu
type:hotelBooking,flightBookingoureference. O de outro tipo é recusado com400 bad-request-exception, e ofielddo erro aponta o identificador (ex.:body.referencenumHOTEL). - Dinheiro tem um campo por significado:
amounté o custo da reserva (obrigatório emHOTELeAERIAL, proibido noCUSTOM);limité o teto (obrigatório noCUSTOM, proibido nos tipos de reserva). - Valores monetários são decimais com até 2 casas. Mais casas →
400, sem arredondamento. A moeda é sempreBRL. - Chaves desconhecidas são descartadas sem erro — inclusive
partner: a plataforma vem só do headerX-Partner-Ide nunca é lida do corpo. nullnão equivale a campo ausente: num campo opcional, é recusado com400.referenceé texto. Um objeto ({"id": …}) é recusado com400.requestoré obrigatório: texto de 1 a 100 caracteres, com o e-mail de um usuário ou um identificador do seu sistema. Um objeto ({"name": …}) é recusado com400.customFieldsaceita até 50 itens, comnameaté 50 evalueaté 100 caracteres: são os limites que a rede do cartão aceita. Acima deles,400.
Atualizar VCN
- Envie
Content-Type: application/json, orequestor(como em Criar VCN) e só o que quer mudar: pelo menos um entrelimit,endDate,maxPurchaseQuantityespendLimitPeriod. Corpo vazio ou só com orequestor→400; campo não enviado não muda. - O corpo é fechado. Qualquer outra chave é recusada com
400 bad-request-exception, e ofielddo erro aponta a chave recusada (ex.:body.expirationDate,body.limit.currency). Isso inclui os campos imutáveistype,reference,startDate,customFields, a moeda dolimite o nome antigoexpirationDate.
Cancelar VCN
- Envie
Content-Type: application/jsone um corpo só com orequestor, como em Criar VCN. Sem corpo, semrequestorou com outra chave →400 bad-request-exception.
Formato dos erros
Todo erro dos endpoints de VCN tem code, message e requestId; errors[] vem só em bad-request-exception.
- Trate o erro pelo
code. O texto domessagepode mudar; o500responde sempreAn unexpected error occurred on the server. bad-request-exceptioné recusa de formato, com uma entrada emerrors[]por campo.invalid-vcn-requesté recusa de regra da janela ou do teto: vem semerrors[], e o motivo está nomessage.errors[].fieldsempre começa pela parte da requisição:body.,path.ouheaders.(ex.:body.amount.rate,path.vcnId,headers.x-partner-id). Quando a recusa é do corpo inteiro — nenhum campo a mudar em Atualizar VCN —, ofieldé sóbody. Não procureamount.ratesem o prefixo.requestIdidentifica a chamada: informe-o ao suporte junto com o horário.vcnIdinválido no path — mais de 255 caracteres, com/,\,?ou#, ou igual a.ou..— dá400 bad-request-exceptioncomfieldpath.vcnId.
Ordem de avaliação
Quando mais de uma regra falha, o erro que chega é o da primeira na ordem:
- Criar VCN:
409 vcn-already-issuedvem antes das regras de data. Uma chave viva responde409mesmo que as datas do pedido sejam inválidas. - Atualizar VCN:
vcn-not-updatable→vcn-not-active→vcn-expired→vcn-limit-conflict(porexpectedValue) →400 invalid-vcn-request(regras doendDate). - Revelar dados do VCN: a posse vem antes do cancelamento. Uma VCN cancelada de outra empresa responde
404, não409.