Desenvolvedores

Checkout pela API

Monte o catálogo, o carrinho e o pagamento no seu próprio site, usando os gateways conectados na loja.

Com a API, o seu site mostra os produtos, monta o carrinho e fecha o pedido. A cobrança é criada no gateway conectado na loja e o dinheiro cai direto na sua conta do gateway, como numa venda pela vitrine. Entregas, e-mails ao cliente, cupons, ofertas e proteção de checkout funcionam do mesmo jeito.

Antes de começar

  • Um gateway conectado e uma rota para cada forma de pagamento que você vai oferecer, em Configurações › Gateways. Teste primeiro com o gateway em Sandbox. Veja Gateways de pagamento.
  • Pelo menos um produto publicado, com preço ativo.
  • Uma chave publicável com os escopos Catálogo (leitura) e Carrinho e checkout (catalog:read e checkout:write). Veja Autenticação.

Chame direto do navegador

Todas as rotas deste guia aceitam a chave publicável. Chamá-las do navegador do comprador é o caminho recomendado: os limites de carrinho e checkout contam por IP, e chamadas que saem todas do seu servidor dividem o mesmo limite. Veja Limites de requisição.

Visão geral do fluxo

  1. GET /products e GET /products/{productId}: mostre os produtos e escolha o preço (priceId).
  2. POST /carts: crie o carrinho e guarde o id e o token.
  3. /carts/{cartId}/**: adicione itens, altere quantidades e aplique cupom, sempre com o cabeçalho X-Cart-Token.
  4. GET /payment-methods: mostre as formas de pagamento que a loja aceita e carregue o SDK do gateway de cartão com a configuração pública.
  5. POST /checkout: feche o pedido com os dados do comprador e a forma de pagamento.
  6. Mostre o Pix ou o boleto, conclua a etapa do cartão quando o gateway pedir e leve o comprador à página do pedido. Se o pagamento for recusado, pague de novo com POST /orders/{orderId}/payments.
  7. No seu servidor, receba order.paid por webhook para saber que o pagamento foi confirmado.

Liste os produtos

GET /products traz os produtos publicados, na ordem do catálogo, com o preço em destaque de cada um. Filtre por categoria com category=<slug> e busque pelo nome com q.

const MINEPAG_PUBLISHABLE_KEY = 'pk_…';
const api = (path, init = {}) =>
  fetch(`https://minepag.com.br/api/v1${path}`, {
    ...init,
    headers: { Authorization: `Bearer ${MINEPAG_PUBLISHABLE_KEY}`, 'Content-Type': 'application/json', ...init.headers }
  }).then(async response => {
    const body = await response.json();
    if (!response.ok) throw Object.assign(new Error(body.error.message), { code: body.error.code, issues: body.error.issues });
    return body;
  });

const { data: products } = await api('/products?limit=24');

Para a página do produto, use GET /products/{productId} com o id ou o endereço (slug) do produto. A resposta traz todos os preços em prices (com variações em attributes e estoque em stock), as imagens, os benefícios e os campos de checkout em checkoutFields.

Cada preço tem um id: é ele que vai para o carrinho. amount já vem com o desconto de promoções ativas; compareAtAmount é o valor "de" para riscar. Preços do tipo "pague quanto quiser" trazem minimumAmount.

Crie o carrinho

const { data: cart } = await api('/carts', {
  method: 'POST',
  body: JSON.stringify({
    items: [{ priceId: '0193b7c2-3c11-7a44-9b1e-0f1a2b3c4d05', quantity: 1 }],
    context: { utmSource: 'instagram', utmCampaign: 'lancamento' }
  })
});

localStorage.setItem('minepag:cart', JSON.stringify({ id: cart.id, token: cart.token }));

A resposta (201) traz o carrinho completo e o token, que também vem no cabeçalho X-Cart-Token. Guarde os dois: o id sozinho não dá acesso ao carrinho. O token vale por 30 dias, o mesmo prazo do carrinho (expiresAt).

Campos úteis do carrinho:

CampoO que mostrar
items[]Produto, preço, quantidade, unitAmount, descontos e total de cada linha. available: false indica item que não pode mais ser comprado.
totalssubtotal, offerDiscountTotal, couponDiscount, discountTotal e total, em centavos.
couponCódigo, se foi aplicado (applied) e message quando deixou de valer.
issuesPendências por linha (ex.: produto indisponível). Resolva antes do checkout.
suggestedOffersOfertas que o lojista configurou para o carrinho (versão superior, venda complementar, combo).

Altere o carrinho

Todas as rotas de carrinho exigem o cabeçalho X-Cart-Token. Sem ele, ou com o token de outro carrinho, a resposta é 404 cart_not_found. Cada rota devolve o carrinho atualizado.

AçãoRota
ConsultarGET /carts/{cartId}
Adicionar item (soma a quantidade se o preço já estiver no carrinho)POST /carts/{cartId}/items
Alterar quantidade, valor livre ou campos de checkoutPATCH /carts/{cartId}/items/{itemId}
Remover itemDELETE /carts/{cartId}/items/{itemId}
Aplicar cupomPUT /carts/{cartId}/coupon
Remover cupomDELETE /carts/{cartId}/coupon
Informar o e-mail (para a recuperação de carrinho abandonado)PATCH /carts/{cartId}
const saved = JSON.parse(localStorage.getItem('minepag:cart'));
const { data: updated } = await api(`/carts/${saved.id}/coupon`, {
  method: 'PUT',
  headers: { 'X-Cart-Token': saved.token },
  body: JSON.stringify({ code: 'BEMVINDO10' })
});

Se o produto tem campos de checkout (ex.: nick do Minecraft), envie os valores em checkoutFields ao adicionar ou alterar o item, no formato { "nick": "Steve" }. Os campos obrigatórios que faltarem impedem o checkout com 422 validation_failed, e error.issues aponta o item em checkoutFields.<itemId>.

Feche o pedido

POST /checkout recebe o carrinho, os dados do comprador e a forma de pagamento. Envie o X-Cart-Token e um Idempotency-Key gerado uma vez por tentativa de compra.

const idempotencyKey = crypto.randomUUID();
// Guarde o momento em que o comprador marcou "Li e aceito os termos" no seu checkout.
const termsAcceptedAt = new Date();

const { data: checkout } = await api('/checkout', {
  method: 'POST',
  headers: { 'X-Cart-Token': saved.token, 'Idempotency-Key': idempotencyKey },
  body: JSON.stringify({
    cartId: saved.id,
    buyer: { name: 'Steve Silva', email: 'steve@exemplo.com.br', phone: '11987654321', document: '12345678909' },
    payment: { method: 'pix' },
    marketingConsent: false,
    termsAcceptedAt: termsAcceptedAt.toISOString()
  })
});
CampoRegra
buyer.nameDe 2 a 120 caracteres.
buyer.emailE-mail válido. É por ele que o cliente é identificado na loja.
buyer.phoneOpcional. Com DDD, de 10 a 15 dígitos.
buyer.documentCPF ou CNPJ. Obrigatório no boleto e no cartão.
payment.methodpix, boleto ou card.
payment.environmentproduction (padrão) ou sandbox. Sandbox só com a chave secreta, para testar.
payment.installmentsDe 1 a 12. Padrão: 1.
payment.billingAddressObrigatório no boleto: street, number, complement (opcional), district, city, state (UF, ex.: SP), postalCode (8 dígitos) e country: "BR".
payment.cardObrigatório no cartão: o token gerado pelo gateway. Veja Pagamento com cartão.
marketingConsentSe o comprador aceitou receber comunicações da loja. Padrão: false.
termsAcceptedAtObrigatório. Data e hora ISO 8601 em que o comprador aceitou os termos da loja, nas últimas 24 horas.
buyer.ip e buyer.userAgentSó com a chave secreta, quando o pedido sai do seu servidor: IP e navegador do comprador. Com a chave publicável, a MinePag usa os da própria requisição.
checkoutFieldsOpcional. Valores dos campos de checkout por item: { "<itemId>": { "<chave>": "<valor>" } }.

Mostre no seu checkout os links dos termos de uso e da política de privacidade cadastrados em Site › Vitrine, e a política de reembolso. O pedido guarda o momento do aceite, os links e a versão da política vigentes, e o IP e o navegador do comprador. Tudo isso entra no dossiê de contestação: sem eles, a defesa de um chargeback perde força.

A resposta (201) traz:

{
  "data": {
    "order": {
      "id": "0193b7c2-5b2f-7d66-8e30-2b3c4d5e6f02",
      "number": 1042,
      "status": "pending",
      "paymentStatus": "pending",
      "subtotal": 4990,
      "discountTotal": 0,
      "total": 4990,
      "expiresAt": "2026-10-12T15:15:00.000Z"
    },
    "payment": {
      "id": "0193b7c2-5b40-7d66-8e30-2b3c4d5e6f07",
      "method": "pix",
      "status": "pending",
      "amount": 4990,
      "instructions": {
        "method": "pix",
        "copyPaste": "00020101021226…6304ABCD",
        "qrCodeImage": "data:image/png;base64,iVBORw0KGgo…",
        "expiresAt": "2026-10-12T15:00:00.000Z"
      },
      "clientAction": { "kind": "none" },
      "failureReason": null
    },
    "accessToken": "eyJvcmRlcklkIjoi…",
    "orderUrl": "https://minha-loja.minepag.app/order/0193b7c2-5b2f-7d66-8e30-2b3c4d5e6f02?token=…"
  },
  "meta": { "requestId": "5b0f7a52-0d8e-4b51-9a57-1f0c6b7e2d10" }
}

O preço é sempre recalculado no servidor: o total do pedido pode ser diferente do que o seu site mostrou se uma promoção acabou ou o estoque mudou. Mostre order.total na confirmação.

Pedidos de valor zero são confirmados na hora: payment vem null e o pedido já sai pago.

Mostre o pagamento

Siga payment.instructions e payment.clientAction:

FormaO que fazer
PixMostre instructions.copyPaste com um botão de copiar e o QR Code. qrCodeImage pode ser uma imagem em data:, um endereço https:// ou null; quando vier null, gere o QR Code a partir de copyPaste. O Pix vence em 30 minutos (expiresAt).
BoletoMostre instructions.digitableLine (linha digitável), o link instructions.pdfUrl e instructions.dueDate. Alguns gateways também devolvem pixCopyPaste para pagar o boleto por Pix. O boleto vence em 3 dias.
CartãoVeja clientAction abaixo. Com payment.status igual a confirmed, o pagamento já foi aprovado.

clientAction.kind diz se falta alguma etapa no navegador:

  • none: nada a fazer.
  • stripe_confirm: a Stripe pediu autenticação do cartão (3D Secure). Chame stripe.handleNextAction({ clientSecret }) com o clientAction.clientSecret recebido.
  • redirect: leve o comprador para clientAction.url.

Acompanhe a confirmação

O jeito mais simples é levar o comprador para orderUrl: a página do pedido na vitrine (no domínio próprio da loja, quando houver) mostra o Pix ou o boleto, atualiza sozinha quando o pagamento é confirmado, lista as entregas e deixa o comprador tentar outra forma de pagamento se o cartão for recusado. O link vale por 90 dias.

Se você quer manter o comprador no seu site, confirme o pagamento no seu servidor:

  • Receba o webhook order.paid (recomendado). Veja Webhooks.
  • Ou consulte GET /orders/{orderId} com uma chave secreta, a partir do seu servidor, até paymentStatus virar paid.

Pagamento com cartão

O número do cartão nunca passa pela MinePag nem pelo seu servidor. O formulário do cartão roda no navegador com o SDK do gateway, que devolve um token. Esse token vai em payment.card, com o provider do gateway que atende cartão na loja (veja em Configurações › Gateways). Token de outro gateway é recusado com 422 validation_failed em payment.card.

As chaves públicas do gateway (Public Key, chave publicável, identificador de conta) ficam na sua conta do gateway. Use as do mesmo ambiente (Sandbox ou Produção) da conexão na MinePag.

Monte o Payment Element com a sua chave publicável da Stripe e, no envio, gere um token de confirmação com stripe.createConfirmationToken({ elements }).

{ "provider": "stripe", "confirmationTokenId": "ctoken_1Q…" }

Se a resposta trouxer clientAction.kind: "stripe_confirm", conclua a autenticação com stripe.handleNextAction({ clientSecret }).

Erros comuns no checkout

CódigoO que aconteceuO que fazer
cart_not_foundCarrinho expirado, ou X-Cart-Token ausente ou de outro carrinho.Crie outro carrinho.
cart_emptyO carrinho não tem itens.Volte para o catálogo.
cart_already_checked_outEste carrinho já virou um pedido com outra Idempotency-Key.Consulte o pedido gerado ou crie outro carrinho.
validation_failedDados inválidos. error.issues aponta cada campo (ex.: buyer.document).Mostre a mensagem ao lado do campo.
product_unavailable, out_of_stockUm item saiu de venda ou ficou sem estoque.Atualize o carrinho e mostre issues.
coupon_invalid, coupon_not_applicableO cupom deixou de valer.Remova o cupom e mostre o novo total.
payment_method_unavailableA loja não tem gateway para essa forma de pagamento.Ofereça só as formas de GET /payment-methods.
payment_declined (402)O gateway recusou o pagamento. O pedido foi criado e continua aguardando pagamento.Pague de novo com outra forma (veja abaixo).
payment_provider_unavailable (502)O gateway não respondeu. O pedido foi criado sem cobrança: error.details traz order, payment, accessToken e orderUrl.Repita com a mesma Idempotency-Key e o mesmo corpo: a MinePag devolve o pedido e cria a cobrança que faltou (veja abaixo).
checkout_blockedA proteção de checkout da loja barrou a compra.Mostre a mensagem. Não repita automaticamente.
checkout_pausedO checkout da loja está pausado por pendência de faturamento.Mostre a mensagem e tente mais tarde.
rate_limitedMuitas tentativas do mesmo IP.Espere o tempo de Retry-After.

Pagamento recusado e nova tentativa

Quando o gateway recusa o pagamento, POST /checkout responde 402 payment_declined. O pedido já existe e continua aguardando pagamento: error.details traz o mesmo objeto da resposta de sucesso, com order, payment (status: "failed" e o motivo em failureReason), accessToken e orderUrl.

Para pagar de novo, peça outro cartão ou outra forma de pagamento e chame POST /orders/{orderId}/payments com o accessToken no cabeçalho X-Order-Token:

curl -X POST https://minepag.com.br/api/v1/orders/$ORDER_ID/payments \
  -H "Authorization: Bearer $MINEPAG_PUBLISHABLE_KEY" \
  -H "X-Order-Token: $ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "buyer": { "name": "Ana Souza", "email": "ana@example.com" }, "payment": { "method": "pix" } }'

A resposta tem o mesmo formato do checkout. Cada tentativa é um novo pagamento do mesmo pedido; outra recusa responde 402 de novo. A rota responde 409 conflict se ainda houver um pagamento em andamento e 409 order_not_payable se o pedido já foi pago, cancelado ou expirou. Se preferir, leve o comprador para orderUrl: a página do pedido também oferece a nova tentativa.

Gateway fora do ar e nova tentativa

Quando o gateway não responde, POST /checkout responde 502 payment_provider_unavailable. O carrinho já virou pedido, mas a cobrança não foi criada: error.details traz order, payment (status: "pending" e instructions: null), accessToken e orderUrl.

{
  "data": null,
  "error": {
    "code": "payment_provider_unavailable",
    "message": "O gateway de pagamento não respondeu. O pedido #1042 foi criado e continua aguardando pagamento: abra o pedido para tentar de novo.",
    "details": {
      "order": { "id": "0193b7c2-5b2f-7d66-8e30-2b3c4d5e6f02", "number": 1042, "status": "pending", "paymentStatus": "pending", "total": 4990 },
      "payment": { "id": "0193b7c2-5b40-7d66-8e30-2b3c4d5e6f07", "method": "pix", "status": "pending", "instructions": null },
      "accessToken": "eyJvcmRlcklkIjoi…",
      "orderUrl": "https://minha-loja.minepag.app/order/0193b7c2-5b2f-7d66-8e30-2b3c4d5e6f02?token=…"
    },
    "requestId": "5b0f7a52-0d8e-4b51-9a57-1f0c6b7e2d10"
  }
}

Para tentar de novo, escolha um caminho:

  1. Mesma forma de pagamento: repita POST /checkout com a mesma Idempotency-Key e o mesmo corpo, com espera crescente (ex.: 1 s, 2 s, 4 s). A resposta de erro 5xx não fica guardada, então a repetição executa de verdade: a MinePag encontra o pedido já criado e cria a cobrança que faltou. A resposta é 200 com o pedido e as instruções de pagamento. A cobrança vai ao gateway com a mesma chave de idempotência, sem risco de cobrar duas vezes.
  2. Outra forma de pagamento, ou mais tarde: chame POST /orders/{orderId}/payments com o accessToken no cabeçalho X-Order-Token, como na recusa acima. Com a mesma forma de pagamento, a cobrança é criada no pagamento que ficou pendente; com outra, esse pagamento é cancelado e uma nova tentativa começa. Também dá para levar o comprador para orderUrl.

Não monte outro carrinho nem use outra Idempotency-Key no mesmo carrinho: a resposta seria 409 cart_already_checked_out. Se o gateway continuar fora do ar, as duas rotas respondem 502 de novo, com os mesmos details.

A lista completa está em Erros da API.

Testar

  1. Conecte o gateway em Sandbox. As formas que ele aceita entram na coluna Equipe testando · Sandbox da seção Checkout, sem mexer nas rotas de Produção.
  2. Faça uma compra completa com os dados de teste do gateway, usando a chave secreta no seu servidor e payment.environment: "sandbox". Com a chave publicável, as formas de pagamento em Sandbox não aparecem em GET /payment-methods e o checkout em Sandbox responde payment_method_unavailable, para nenhum cliente cair num gateway de teste.
  3. Confira o pedido em Vendas › Pedidos e as entregas em Entregas.
  4. Pedidos em Sandbox não contam na sua fatura da MinePag.

Nesta página