Cobranças

Criar

curl -X POST https://api-crpay.deskhotel.com.br/v1/payments \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 131640,
    "payment_method": "card",
    "reference": "RES-99871",
    "card": {
      "number": "4532015112830366",
      "holder_name": "FULANO DE TAL",
      "expiration_month": 12,
      "expiration_year": 2028,
      "security_code": "737",
      "brand": "visa"
    }
  }'
{
  "id": "pay_01KYFSX27TJEHQEF18TSH8YFQD",
  "status": "captured",
  "amount": 131640,
  "currency": "BRL",
  "payment_method": "card",
  "installments": 1,
  "reference": "RES-99871",
  "card": { "brand": "visa", "bin": "453201", "last4": "0366" },
  "acquirer": {
    "name": "cielo",
    "payment_id": "0f4e...",
    "tid": "1006993069...",
    "nsu": "674532",
    "authorization_code": "123456"
  },
  "error": null,
  "metadata": null,
  "created_at": "2026-07-23T18:09:55.116Z",
  "updated_at": "2026-07-23T18:09:56.086Z"
}

Valores

amount é inteiro em centavos. R$ 1.316,40 se envia como 131640.

Decimal, string, zero e negativo são recusados com 400 invalid_amount.

Referência

reference é o seu identificador — número do pedido, da reserva, do contrato. É por ele que a conciliação localiza a transação na adquirente, e é único por conta: a mesma reference não vira duas cobranças.

Cartão

O número completo e o código de segurança não são armazenados. A resposta e todas as consultas devolvem apenas os seis primeiros dígitos, os quatro últimos e a bandeira.

brand é opcional — se omitido, é deduzido do número.

Idempotência

O header Idempotency-Key é obrigatório em toda operação que movimenta valores.

Gere um identificador único por operação — um UUID serve — e guarde-o junto do seu registro antes de chamar a API. Em caso de timeout ou falha de rede, repita a requisição com a mesma chave: se a cobrança já tiver sido criada, a resposta original é devolvida sem cobrar de novo.

Gerar uma chave nova para a retentativa anula a proteção e é o caminho direto para a cobrança duplicada.

Reutilizar a mesma chave para uma requisição diferente devolve 409 idempotency_key_reuse. A chave é por operação, não por objeto de negócio: não use a mesma para cobrar e depois para estornar.

Pré-autorização

Envie capture: false para reservar o valor sem efetivá-lo:

curl -X POST https://api-crpay.deskhotel.com.br/v1/payments \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 50000, "payment_method": "card", "capture": false, "card": { … } }'

A cobrança fica em authorized. Para efetivar:

curl -X POST https://api-crpay.deskhotel.com.br/v1/payments/$ID/capture \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: $(uuidgen)"

Informe amount no corpo para capturar menos que o autorizado.

Cancelar e estornar

curl -X POST https://api-crpay.deskhotel.com.br/v1/payments/$ID/cancel \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 30000, "reason": "Cancelamento de uma diária" }'

A operação depende do estado da cobrança:

Estado Operação Resultado
authorized Cancelamento — desfaz antes de o valor sair canceled
captured Estorno — devolve o valor refunded ou partially_refunded

Omitir amount estorna o saldo restante.

Estornos parciais são somados: pedir mais que o saldo devolve 400 refund_amount_exceeds_payment. Não é possível devolver mais que o valor da cobrança, mesmo em várias chamadas.

Consultar

curl https://api-crpay.deskhotel.com.br/v1/payments/$ID \
  -H "Authorization: Bearer $TOKEN"

Listagem, da mais recente para a mais antiga, com filtros opcionais:

curl "https://api-crpay.deskhotel.com.br/v1/payments?reference=RES-99871" \
  -H "Authorization: Bearer $TOKEN"

curl "https://api-crpay.deskhotel.com.br/v1/payments?status=refused&limit=50" \
  -H "Authorization: Bearer $TOKEN"

A paginação é por cursor. Use o next_cursor da resposta como parâmetro cursor da chamada seguinte; null indica a última página.

Histórico do ciclo de vida:

curl https://api-crpay.deskhotel.com.br/v1/payments/$ID/events \
  -H "Authorization: Bearer $TOKEN"

Estados

Estado Significado
authorized Valor reservado no cartão, não capturado
captured Valor efetivado
refused A adquirente recusou
canceled Autorização desfeita antes da captura
refunded Valor devolvido integralmente
partially_refunded Parte do valor devolvida
unknown Resultado não confirmado — ver abaixo

O estado unknown

Se a adquirente não responder a tempo, o crpay não adivinha. A requisição foi enviada e a resposta não chegou: não há como saber se a cobrança foi processada.

Nesse caso a resposta é 502 acquirer_unknown_state, com o payment_id da cobrança, e ela fica em unknown.

Não repita com uma chave nova. A conciliação consulta a adquirente e resolve o estado automaticamente — para captured ou refused, conforme o que de fato aconteceu. Consulte a cobrança pelo payment_id até o estado mudar.

Repetir com chave nova nesse momento é justamente o que cobraria o cliente duas vezes.

Recusas

Cartão recusado devolve 402 com o motivo normalizado:

{
  "error": {
    "type": "card_error",
    "code": "insufficient_funds",
    "message": "Sem saldo disponível.",
    "request_id": "req_01KYF...",
    "payment_id": "pay_01KYF..."
  }
}

O code é estável e independente da adquirente — insufficient_funds, invalid_cvv, expired_card, card_blocked, entre outros. Programe contra ele.

Repetir a mesma requisição após uma recusa não muda o resultado. Ver Erros para a lista completa e a política de retentativa.