Integre o Café SaaS em qualquer site.
Uma tag de script (ou um componente React) que adiciona um rodapé global, um splash de doação e checkout via Mercado Pago.
Prioridade: Componente React
Se seu app é React, Next.js, Remix, TanStack Start ou qualquer Vite + React — use sempre o Componente React. A Script Tag é o último caso, apenas para hosts sem React (HTML estático, WordPress, Webflow, Shopify Liquid, Astro sem React, etc.).
Início rápido
- 1. Entre no painel e cadastre seu site — você recebe um
SEU_SLUG. - 2. O Mercado Pago já está configurado neste servidor — você não precisa de conta, chave nem nada. O checkout roda no domínio do Café SaaS.
- 3. Em apps React, instale o Componente React. Em sites não-React, use a Script Tag.
Componente React (recomendado)
Esta é a forma padrão de integrar em qualquer app React. O pacote @joaosmfilho/cafe-embed-react não está publicado no npm — o tarball pronto é hospedado pelo próprio servidor. Não precisa clonar nada, não precisa buildar nada.
Passo 1 — Download direto
Tarball oficial, versionado, servido como asset estático:
Passo 2 — Instalar
npm, bun, pnpm e yarn aceitam instalar direto de uma URL HTTPS de tarball. Rode no projeto onde quer usar o componente:
# Instale direto da URL hospedada — não precisa clonar nada. npm install https://cafe.joaosmfilho.org/downloads/cafe-embed-react-0.1.0.tgz # Equivalentes: bun add https://cafe.joaosmfilho.org/downloads/cafe-embed-react-0.1.0.tgz pnpm add https://cafe.joaosmfilho.org/downloads/cafe-embed-react-0.1.0.tgz yarn add https://cafe.joaosmfilho.org/downloads/cafe-embed-react-0.1.0.tgz
Passo 3 — Renderizar
Coloque <CafeEmbed> uma única vez no layout raiz da sua aplicação.
import { CafeEmbed } from "@joaosmfilho/cafe-embed-react";
export default function App() {
return (
<>
{/* ...sua app */}
<CafeEmbed siteSlug="SEU_SLUG" baseUrl="https://cafe.joaosmfilho.org" />
</>
);
}SSR e como funciona
O componente injeta a tag <script src="https://cafe.joaosmfilho.org/api/public/embed.js?site=SEU_SLUG"> no host via useEffect. SSR-safe: o efeito só roda no client e o componente retorna null no servidor — funciona em Next.js, Remix e TanStack Start sem next/dynamic.
Props
export type CafeEmbedProps = {
siteSlug: string; // slug do site cadastrado no painel
baseUrl: string; // URL do servidor Café SaaS
};Essas são as únicas props expostas. Não há eventos ou refs.
Script Tag (último caso)
Use somente se o host não for React. Para qualquer app React/Next/Remix/TanStack Start, prefira o Componente React acima — ele evita duplicação e respeita o ciclo de vida do framework.
Em sites HTML estáticos, WordPress, Webflow, Shopify Liquid, Astro sem React etc., cole esta tag antes do fechamento de </body>:
<script src="https://cafe.joaosmfilho.org/api/public/embed.js?site=SEU_SLUG" defer></script>
Substitua SEU_SLUG pelo slug do seu site. O script aceita apenas o parâmetro ?site=. CORS aberto. Servido com Cache-Control: public, max-age=0, must-revalidate + ETag — o browser revalida a cada page-load do hospedeiro, então mudanças no painel aparecem no próximo carregamento (servidor responde 304 quando nada mudou).
Alternativa: rota dedicada /cafezinho
Em vez do modal (Métodos 1 e 2), o hospedeiro pode criar uma rota real /cafezinho que renderiza um <iframe> apontando direto para o checkout servido por cafe.joaosmfilho.org. A página de checkout (/checkout/{slug}) já é servida com frame-ancestors *, então pode ser embutida em qualquer origem.
Quando usar: quer URL real (compartilhável, indexável, bookmarkable), CSP do hospedeiro mínima e zero JS de terceiros executando fora do iframe. Quando NÃO usar: precisa do footer global e do splash automático em todas as páginas — para isso, use Método 1 ou 2 (que continuam padrão).
TanStack Start / React
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/cafezinho")({
component: Cafezinho,
});
function Cafezinho() {
return (
<iframe
src="https://cafe.joaosmfilho.org/checkout/SEU_SLUG"
title="Me pague um café"
allow="payment"
style={{ width: "100%", height: "100vh", border: 0, display: "block" }}
/>
);
}HTML puro
<!doctype html>
<html><head><meta charset="utf-8"><title>Me pague um café</title>
<style>html,body,iframe{margin:0;padding:0;height:100%;width:100%;border:0}</style>
</head><body>
<iframe src="https://cafe.joaosmfilho.org/checkout/SEU_SLUG" allow="payment" title="Me pague um café"></iframe>
</body></html>Substitua SEU_SLUG. O atributo allow="payment" habilita a Payment Request API dentro do iframe (necessário para alguns fluxos do Mercado Pago).
CSP mínima do hospedeiro
Como nenhum script de terceiros roda no DOM do hospedeiro, a única diretiva extra necessária é frame-src:
frame-src https://cafe.joaosmfilho.org
Eventos opcionais
O iframe envia window.postMessage ao pai com { source: "cafe-checkout", type, payload }. Tipos atuais: ready, success, error. Escute se quiser reagir (analytics, redirect pós-pagamento, etc.):
useEffect(() => {
function onMsg(e: MessageEvent) {
if (e.origin !== "https://cafe.joaosmfilho.org") return;
if (e.data?.source !== "cafe-checkout") return;
if (e.data.type === "success") {
// pagamento aprovado — e.data.payload tem { id, status, ... }
}
}
window.addEventListener("message", onMsg);
return () => window.removeEventListener("message", onMsg);
}, []);O que o embed faz
- Busca a config do site em
GET /api/public/config/{slug}(cache de 5 min). - Renderiza um rodapé
#cafe-embed-footerno fim do<body>com o texto configurado, o link e uma pílula âmbar "Me pague um café" apontando para/cafezinhono domínio do site hospedeiro (o clique é interceptado e abre o modal sem navegar). Abrir/cafezinhodiretamente também abre o modal automaticamente. - Abre o splash de doação assim que a config carrega (sem delay, sem countdown). Frequência (
session/once/always) vem da config. - Renderiza o Checkout Bricks do Mercado Pago dentro do próprio modal. Carrega
https://sdk.mercadopago.com/js/v2, chamaPOST /api/public/checkout/{slug}para obterpublic_keyeamount, e monta o Payment Brick (cartão de crédito/débito, Pix, boleto e Conta Mercado Pago) no container#cafe-payment-brick. O pagamento é finalizado sem sair do site hospedeiro. - No envio do formulário, o Brick chama
POST /api/public/process-payment/{slug}comformData+selectedPaymentMethod; o servidor cria o pagamento na API do Mercado Pago (POST /v1/payments) comX-Idempotency-Key. O modal mostra QR code (Pix), link do boleto, ou confirmação de aprovação direto na tela.
Configuração do site
Tudo é editado no painel. A config pública exposta para o embed inclui o texto/links do rodapé, título/mensagem/CTA do splash, se o splash está ativado, a frequência e o valor padrão da doação (em centavos).
Endpoint de checkout
POST /api/public/checkout/{slug} — corpo opcional { "amount": 1500 } (centavos, entre 100 e 1.000.000). Sem corpo, usa o valor padrão da config. Responde { "amount": 500, "public_key": "...", "site": { "slug": "...", "name": "..." } }. Não cria preference no Mercado Pago (evita bloqueio do PolicyAgent). O embed monta o Payment Brick só com amount + public_key; o charge real acontece em /api/public/process-payment/{slug} via POST /v1/payments. CORS aberto.
POST /api/public/process-payment/{slug} — corpo { formData, selectedPaymentMethod } exatamente como entregue pelo callback onSubmit do Payment Brick. O servidor valida o valor (server-side, limites de /checkout), chama POST https://api.mercadopago.com/v1/payments com X-Idempotency-Key e registra o resultado em payments. Responde com { id, status, status_detail, payment_method_id, point_of_interaction, transaction_details } — o embed usa point_of_interaction.transaction_data.qr_code_base64 para Pix e transaction_details.external_resource_url para boleto.
POST /api/public/pix/{slug} — atalho Pix direto, sem Payment Brick. Corpo opcional { "amount": 1500, "email": "voce@exemplo.com" }. Sem corpo, usa o valor padrão do site; sem email, usa fallback interno. O servidor cria o pagamento em POST /v1/payments com payment_method_id: "pix", registra em payments e responde com { id, status, amount, qr_code, qr_code_base64, ticket_url, expires_at }. É o que o embed usa para o botão "Pix copia e cola" da tela de valor e o checkout usa na aba Pix.
CSP do hospedeiro — leia antes de integrar
Desde a v2, o checkout do Café SaaS roda dentro de um iframe servido por cafe.joaosmfilho.org. A CSP que vale para os scripts do Mercado Pago é a do iframe, configurada pelo Café SaaS — não a sua. Sua CSP só precisa permitir o domínio do Café SaaS:
script-src https://cafe.joaosmfilho.org connect-src https://cafe.joaosmfilho.org frame-src https://cafe.joaosmfilho.org
Snippet copy-paste para index.html:
<meta http-equiv="Content-Security-Policy" content=" default-src 'self'; script-src 'self' 'unsafe-inline' https://cafe.joaosmfilho.org; style-src 'self' 'unsafe-inline' https://cafe.joaosmfilho.org; connect-src 'self' https://cafe.joaosmfilho.org; frame-src https://cafe.joaosmfilho.org; img-src 'self' data: https:;" />
Modo legado (sem iframe)
Se você está usando uma versão antiga do embed que monta o Brick direto no DOM do hospedeiro, a CSP precisa liberar TODOS estes domínios:
script-src https://sdk.mercadopago.com https://http2.mlstatic.com connect-src https://api.mercadopago.com https://*.mercadopago.com https://http2.mlstatic.com https://api.mercadolibre.com https://www.mercadolibre.com frame-src https://*.mercadopago.com https://www.mercadolibre.com img-src https://http2.mlstatic.com data:
Webhook do Mercado Pago
Configure esta URL na sua aplicação Mercado Pago (Webhooks → Notificações), tópico payment:
https://cafe.joaosmfilho.org/api/public/mp-webhookSe a variável MP_WEBHOOK_SECRET estiver definida no servidor, o endpoint valida a assinatura via header x-signature e rejeita inválidas com 401. Sem a secret, o endpoint aceita o webhook sem validar (apropriado só para testes).
Todo evento recebido é registrado em webhook_events. Quando o tipo contém payment, o endpoint busca o pagamento na API do MP e grava o resultado vinculado ao site (via external_reference).
Prompt Lovable / Claude Code
Cole este prompt no Lovable, Claude Code, Cursor ou qualquer agente de código para integrar o Café SaaS automaticamente. Ele descreve só o que existe de verdade — script tag, componente React e o comportamento do embed — sem inventar APIs.
Quero integrar o Café SaaS no meu site.
Servidor: https://cafe.joaosmfilho.org
Meu slug: SEU_SLUG
PRIORIDADE ABSOLUTA: use o COMPONENTE REACT. Só caia para script tag se o host
NÃO for React (HTML puro, WordPress, Webflow, Shopify Liquid, Astro sem React).
1) [PADRÃO] Componente React — para React, Next.js, Remix, TanStack Start, Vite + React.
O pacote @joaosmfilho/cafe-embed-react NÃO está no npm. O próprio servidor
hospeda o tarball pronto. Instale direto da URL (não clone, não builde nada):
npm install https://cafe.joaosmfilho.org/downloads/cafe-embed-react-0.1.0.tgz
Renderize UMA vez no layout raiz:
import { CafeEmbed } from "@joaosmfilho/cafe-embed-react";
<CafeEmbed siteSlug="SEU_SLUG" baseUrl="https://cafe.joaosmfilho.org" />
O componente é SSR-safe (retorna null no servidor) e só injeta a tag de
script abaixo via useEffect. Props expostas: APENAS siteSlug e baseUrl.
2) [ÚLTIMO CASO] Script tag — APENAS quando o host não é React.
Cole antes do </body>:
<script src="https://cafe.joaosmfilho.org/api/public/embed.js?site=SEU_SLUG" defer></script>
3) [ALTERNATIVA] Rota dedicada /cafezinho — sem modal, sem footer global.
Use quando preferir URL real (compartilhável) e CSP mínima no hospedeiro,
abrindo mão do footer automático e do splash. Crie uma rota /cafezinho que
renderiza um <iframe> apontando direto para o checkout:
<iframe src="https://cafe.joaosmfilho.org/checkout/SEU_SLUG"
allow="payment"
style="width:100%;height:100vh;border:0"></iframe>
CSP do hospedeiro nesse cenário: apenas frame-src https://cafe.joaosmfilho.org.
Opcionalmente, escute window.postMessage para reagir a "ready" / "success" / "error".
Regras importantes:
- Se o projeto usa React em qualquer forma, use o Componente React. Nunca
inclua o <script> manualmente em um app React (vai gerar duplicação).
- Use apenas o parâmetro ?site= no script. Não invente outros parâmetros.
- Não duplique o embed: uma única instância no layout raiz basta.
- Não tente reimplementar o footer, o splash ou o checkout — tudo é renderizado
pelo próprio script (footer #cafe-embed-footer, modal com Payment Brick do
Mercado Pago no container #cafe-payment-brick).
- O link /cafezinho no domínio hospedeiro abre o modal automaticamente.
- Hosts com CSP estrito precisam permitir https://sdk.mercadopago.com
(script-src) e https://api.mercadopago.com / https://*.mercadopago.com
(connect-src / frame-src).
Tarefa: aplique a integração no meu projeto seguindo exatamente essas
instruções. Não adicione nada que não esteja descrito acima.Baixar documentação completa
Exporte todo o conteúdo desta página para usar offline ou como referência no seu agente de IA. O arquivo SKILL.md é o que você sobe em Lovable Settings → Skills (já inclui o frontmatter YAML obrigatório).