VCNGuia de VCN

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:

TipoPara pagarIdentificadorTeto
HOTELuma reserva de hospedagemhotelBooking.reservationIdderivado do custo da reserva, em amount
AERIALuma reserva aéreaflightBooking.recordLocatorderivado do custo da reserva, em amount
CUSTOMum uso definido por você, ex.: um cartão por fornecedorreferenceo 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.

ItemRegra
Quem geraA Conta Simples gera o ID e o entrega a você no onboarding. Você só o envia.
Formatoptn_ seguido de um ULID de 26 caracteres (base32 de Crockford, em maiúsculas), ex.: ptn_01JQ8ZK7X4M8N2P5R6T7V8W9XY. Não é nome nem CNPJ.
ValorImutável e sensível a maiúsculas e minúsculas: envie exatamente como recebeu. Não é segredo.
Onde vaiSempre no header. Nunca na URL, em path ou query, nem no corpo.
AssinaturaA 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-Id da 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çãoResposta
Header ausente ou fora do formato400 bad-request-exception, com errors[].field headers.x-partner-id
Partner não vinculado à sua credencial403 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 startDate e fecha no fim do dia do endDate: o endDate é inclusivo.
  • Sem startDate, a janela começa no dia da emissão, e o cartão já nasce utilizável.
  • createdAt e updatedAt são instantes em UTC. Numa emissão entre 21h e 24h de Brasília, createdAt cai no dia seguinte ao startDate.
  • 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.

TipoFim padrãoJanela invertida sem endDate quando
HOTELcheckOut + 20 diaso checkOut foi há 20 dias ou mais
AERIALdia da emissão + 1 diao startDate é amanhã ou depois
CUSTOMdia da emissão + 60 diaso startDate é hoje + 60 dias ou depois

Limites das datas

RegraCriar VCNAtualizar VCN
IníciostartDate não pode ser anterior a hoje; hoje é aceito a qualquer horao startDate não muda
Fim depois do iníciocom 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 diasaté 365 dias do dia da emissão, com o 365º aceito; informar startDate não estende o tetoaté 365 dias da emissão
Validade do cartão de fundingo 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 é expostaa 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 do endDate ela ainda aceita atualização, e uma nova emissão na mesma chave ainda responde 409.
  • Vencida, Atualizar VCN responde 409 vcn-expired: não recarregue, emita outra.
  • Não existe status de vencida: uma VCN vencida continua ACTIVE. Compare o endDate com o dia de hoje em Brasília.
  • Encurtar o endDate nã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 limit e endDate.
  • O startDate de 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:

TipoChave
HOTELhotelBooking.reservationId — o id da reserva na plataforma onde ela foi feita
AERIALflightBooking.recordLocator — o localizador (PNR, Passenger Name Record)
CUSTOMreference — 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ó o CUSTOM envia reference.
  • A chave vale por empresa, type e plataforma integradora (o X-Partner-Id da chamada): a mesma chave em outro type ou em outro partner não colide.
  • Enquanto a VCN da chave está viva (ACTIVE ou BLOCKED, dentro da janela), uma nova emissão responde 409 vcn-already-issued, sem os dados do cartão e sem o vcnId. Guarde o vcnId do 201 junto com a chave.
  • No CUSTOM, esse 409 é o caminho esperado: o cartão daquela reference já existe. Recarregue-o em Atualizar VCN; cada reference nova 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 vcnId anterior passa a responder 404 em todas as rotas.
  • Não use dados pessoais na chave: ela é gravada e devolvida nas respostas.

Teto e recarga

  • HOTEL e AERIAL: o teto é derivado do custo, amount.rate + amount.taxes + amount.fees, que precisa ser maior que zero. No HOTEL, soma-se a margem de extras quando allowExtraCharges é true: o valor de extraChargesMargin ou, sem ele, a margem padrão — hoje R$ 150,00 por diária por hóspede, sujeita a mudança. Para controlar o teto, informe extraChargesMargin.
  • CUSTOM: o teto é o limit.value informado, a partir de 0.01. Só o CUSTOM é atualizável; os controles de HOTEL e AERIAL vê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

spendLimitPeriodO teto vale para
TOTAL (padrão)a janela inteira
MONTHLYcada mês; renova a cada mês
DAILYcada dia; renova a cada dia
  • A conta de recarga acima só vale para TOTAL. Com MONTHLY ou DAILY, 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, spendLimitPeriod omitido mantém o período vigente, e trocar o período não zera o que já foi gasto: um cartão que passa de TOTAL para MONTHLY não ganha o mês limpo.

Recargas em paralelo

  • Envie limit.expectedValue com 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 expectedValue e 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:

EndpointDepois de 5xx ou tempo esgotado
Criar VCNNã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 VCN503 vcn-update-unavailable: repita. 500: acione o suporte com o horário e o requestId.
Revelar dados do VCNRepetir é seguro.
Consultar VCNRepetir é seguro.
Cancelar VCNRepetir é 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 404 por 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, flightBooking ou reference. O de outro tipo é recusado com 400 bad-request-exception, e o field do erro aponta o identificador (ex.: body.reference num HOTEL).
  • Dinheiro tem um campo por significado: amount é o custo da reserva (obrigatório em HOTEL e AERIAL, proibido no CUSTOM); limit é o teto (obrigatório no CUSTOM, proibido nos tipos de reserva).
  • Valores monetários são decimais com até 2 casas. Mais casas → 400, sem arredondamento. A moeda é sempre BRL.
  • Chaves desconhecidas são descartadas sem erro — inclusive partner: a plataforma vem só do header X-Partner-Id e nunca é lida do corpo.
  • null não equivale a campo ausente: num campo opcional, é recusado com 400.
  • reference é texto. Um objeto ({"id": …}) é recusado com 400.
  • 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 com 400.
  • customFields aceita até 50 itens, com name até 50 e value até 100 caracteres: são os limites que a rede do cartão aceita. Acima deles, 400.

Atualizar VCN

  • Envie Content-Type: application/json, o requestor (como em Criar VCN) e só o que quer mudar: pelo menos um entre limit, endDate, maxPurchaseQuantity e spendLimitPeriod. Corpo vazio ou só com o requestor → 400; campo não enviado não muda.
  • O corpo é fechado. Qualquer outra chave é recusada com 400 bad-request-exception, e o field do erro aponta a chave recusada (ex.: body.expirationDate, body.limit.currency). Isso inclui os campos imutáveis type, reference, startDate, customFields, a moeda do limit e o nome antigo expirationDate.

Cancelar VCN

  • Envie Content-Type: application/json e um corpo só com o requestor, como em Criar VCN. Sem corpo, sem requestor ou 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 do message pode mudar; o 500 responde sempre An unexpected error occurred on the server.
  • bad-request-exception é recusa de formato, com uma entrada em errors[] por campo. invalid-vcn-request é recusa de regra da janela ou do teto: vem sem errors[], e o motivo está no message.
  • errors[].field sempre começa pela parte da requisição: body., path. ou headers. (ex.: body.amount.rate, path.vcnId, headers.x-partner-id). Quando a recusa é do corpo inteiro — nenhum campo a mudar em Atualizar VCN —, o field é só body. Não procure amount.rate sem o prefixo.
  • requestId identifica a chamada: informe-o ao suporte junto com o horário.
  • vcnId inválido no path — mais de 255 caracteres, com /, \, ? ou #, ou igual a . ou .. — dá 400 bad-request-exception com field path.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-issued vem antes das regras de data. Uma chave viva responde 409 mesmo que as datas do pedido sejam inválidas.
  • Atualizar VCN: vcn-not-updatable → vcn-not-active → vcn-expired → vcn-limit-conflict (por expectedValue) → 400 invalid-vcn-request (regras do endDate).
  • Revelar dados do VCN: a posse vem antes do cancelamento. Uma VCN cancelada de outra empresa responde 404, não 409.