hostedPaymentUrl que você encaminha ao cliente. Seu cliente entra com magic link no e-mail, completa KYC se ainda não tiver feito, e paga. Você fica sabendo de cada transição via webhooks de saída.
Quando usar isto vs. invoices
POST /v1/payment-intents— seu CMS é dono da fatura; a Caratuva é o motor de pagamento + compliance + liquidação. Pula a etapa de aprovação do lado do vendedor (a chamada de API é a aprovação).POST /v1/invoices— o painel da Caratuva é dono da fatura. Vendedores criam, um colega aprova caso sua organização exija aprovação, e a plataforma envia o magic link. Use se você não tem sistema de faturamento próprio.
Pré-requisitos
- KYB aprovado. Sua organização precisa ter completado o KYB e ter uma conta virtual provisionada. Caso contrário, a API retorna
400 KybNotApproved. - Chave de API. Uma chave de produção (
pk_live_...) — veja Chaves de API. - Inscrição de webhook. Você vai querer uma antes de criar intents em produção — veja Webhooks.
Criar um payment intent
Corpo da requisição
| Campo | Tipo | Obrigatório | Notas |
|---|---|---|---|
externalId | string (1–200) | sim | Sua chave primária. Único por (organization, externalId). Re-POSTar o mesmo valor retorna o intent existente — seguro sob retentativa de rede. |
amount | decimal string | sim | Precisão de duas casas; passe como string para evitar drift de float ("12500.00", não 12500). **Mínimo de US 10, então um valor menor em USD não pode ser pago e é rejeitado com AmountBelowMinimum. |
currency | código ISO 4217 | não | Default USD. |
buyer.email | string | sim | Endereço real — o comprador recebe um magic link nesse e-mail. |
buyer.name, buyer.country, buyer.phone | string | não | Pré-preenche o formulário de KYC; o comprador pode ajustar. |
returnUrl | URL | não | Para onde a página hospedada redireciona após a liquidação. |
display.title, display.notes, display.lineItems | varia | não | Renderizados na página hospedada. Texto livre — a Caratuva não valida códigos NCM ou de origem aqui. |
metadata | objeto | não | Volta verbatim em todo webhook. Nunca exibido ao comprador. |
expiresAt | RFC 3339 | não | O intent vai para expired se não for pago até este horário. |
Idempotência
EnvieIdempotency-Key: <uuid> em toda retentativa do mesmo create lógico. Replays retornam a resposta original sem reexecutar efeitos colaterais. Duas chaves distintas com o mesmo externalId colapsam para o mesmo intent (o externalId por organização é único).
Resposta
hostedPaymentUrl é o único campo de que a maioria dos integradores precisa da resposta. Encaminhe ao cliente pelo seu canal (e-mail, SMS, mensagem no app). A Caratuva não envia e-mail automático ao comprador quando um payment intent é criado — isso é responsabilidade do integrador nesta superfície, porque você é dono do relacionamento.
Jornada do comprador na página hospedada
Quando o comprador clica emhostedPaymentUrl, ele:
- Chega no portal do comprador (
pay.caratuva.com/r/<publicId>) e vê o seu blocodisplaymais o nome do vendedor. - Informa o e-mail; recebe um magic link; entra (sessão gerenciada pela Caratuva).
- Completa o KYC se o
kycStatusainda não forapproved. A etapa é obrigatória — sem fast-forward. Um comprador que voltou e já está verificado em outro fluxo pula essa etapa. - Confirma a cotação de câmbio e completa o pagamento.
- A Caratuva roda a transferência internacional e o repasse PIX para a conta BRL do vendedor.
- O comprador é redirecionado para
returnUrlse definido; caso contrário, vê uma página de confirmação da Caratuva.
Máquina de estados
Intents criados via API pulam a aprovação do vendedor (awaiting_approval / approved) e começam em awaiting_buyer. A partir daí:
failed, cancelled, expired.
Ler um intent
Cancelar um intent
Válido apenas antes do início do repasse em BRL. Apóssettled, cancele o pedido no seu sistema.
Erros
| Status | error | Causa |
|---|---|---|
| 400 | KybNotApproved | Sua organização não tem conta virtual. Complete o KYB primeiro. |
| 400 | AmountBelowMinimum | O amount em USD está abaixo do piso de US$ 10,00 da transferência bancária. Aumente o valor. |
| 400 | ValidationError | Schema Zod rejeitou o body. O campo message lista os caminhos ofensores. |
| 401 | InvalidApiKey | Chave malformada, desconhecida ou revogada. |
| 401 | InvalidApiKeyFormat | Header não está no formato pk_(test|live)_<id>.<segredo>. |
| 409 | IdempotencyKeyConflict | A Idempotency-Key foi usada antes para uma fatura não-payment-intent. Use uma chave nova. |
| 429 | RateLimitExceeded | Limite por chave de API em POST /v1/payment-intents. Faça backoff e tente. |
{ statusCode, error, message }.