MVP sem integrações = produto pela metade.
Integrações com serviços externos são a espinha dorsal de qualquer aplicação moderna. Processar pagamentos, enviar e-mails, armazenar arquivos, exibir mapas — nenhuma dessas funcionalidades deveria ser construida do zero. Os provedores de API investem milhoes de dolares em infraestrutura, seguranca e compliance para que voce nao precise fazer isso. Tentar replicar internamente o que Stripe, Resend ou Cloudinary ja fazem e desperdicar semanas (ou meses) de desenvolvimento em problemas que ja foram resolvidos. O papel do seu time e conectar essas pecas e focar no que torna o seu produto unico.
Realidade: 80% dos MVPs precisam de pelo menos 3 integrações:
- Pagamento (Stripe, Mercado Pago)
- E-mail transacional (SendGrid, Resend)
- Storage de arquivos (Cloudinary, AWS S3)
Mais 40% precisam de: 4. Mapas/geolocalização (Google Maps) 5. SMS (Twilio) 6. Videoconferência (Daily.co, Zoom)
Este artigo mostra implementação completa das 3 integrações essenciais — do zero ao funcionando em menor que 8h cada, com código pronto e custos reais.
1. Pagamentos: Stripe (implementação completa)
Pagamento e a integracao mais critica de qualquer produto digital. Tambem e a que mais gera duvidas sobre “comprar vs construir”. A resposta curta: nunca construa um sistema de pagamento proprio. O processamento de cartao de credito exige certificacao PCI-DSS, que envolve auditorias anuais, criptografia de dados de cartao em repouso e em transito, e uma serie de controles de seguranca que custam facilmente R$ 200 mil por ano para manter. Alem disso, voce precisa lidar com chargebacks, fraude, conciliacao bancaria e regulamentacoes financeiras de cada pais onde opera. Provedores como Stripe absorvem toda essa complexidade. Voce paga uma taxa por transacao e em troca recebe compliance automatico, deteccao de fraude com machine learning e suporte a dezenas de metodos de pagamento, tudo via uma API bem documentada.
Por que Stripe: Melhor API, aceita cartão internacional, compliance automático (PCI-DSS).
Alternativa BR: Mercado Pago (aceita apenas LATAM, API pior).
Setup inicial (15min)
# 1. Criar conta em stripe.com/br
# 2. Pegar chaves API (Dashboard → Developers → API keys)
# 3. Instalar SDK
npm install stripe @stripe/stripe-js
# 4. Configurar env
# .env.local
STRIPE_SECRET_KEY=sk_test_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
Checkout básico (one-time payment)
Frontend (Next.js):
// app/checkout/page.tsx
'use client';
import { loadStripe } from '@stripe/stripe-js';
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!);
export default function CheckoutPage() {
const handleCheckout = async () => {
const res = await fetch('/api/create-checkout-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
amount: 19900, // R$ 199,00 em centavos
description: 'Plano Premium - Mensal',
}),
});
const { sessionId } = await res.json();
const stripe = await stripePromise;
await stripe?.redirectToCheckout({ sessionId });
};
return (
<button onClick={handleCheckout} className="btn-primary">
Assinar por R$ 199/mês
</button>
);
}
Backend (API Route):
// app/api/create-checkout-session/route.ts
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: '2024-11-20.acacia',
});
export async function POST(req: Request) {
const { amount, description } = await req.json();
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: [
{
price_data: {
currency: 'brl',
product_data: { name: description },
unit_amount: amount,
},
quantity: 1,
},
],
mode: 'payment',
success_url: `${process.env.NEXT_PUBLIC_URL}/success`,
cancel_url: `${process.env.NEXT_PUBLIC_URL}/cancel`,
});
return Response.json({ sessionId: session.id });
}
Cobrança recorrente (assinatura)
// Criar produto e preço (apenas 1x, via Dashboard ou API)
const price = await stripe.prices.create({
currency: 'brl',
unit_amount: 19900, // R$ 199
recurring: { interval: 'month' },
product_data: { name: 'Plano Premium' },
});
// Criar assinatura para cliente
const subscription = await stripe.subscriptions.create({
customer: customerId, // ID do cliente no Stripe
items: [{ price: price.id }],
payment_behavior: 'default_incomplete',
expand: ['latest_invoice.payment_intent'],
});
return Response.json({
subscriptionId: subscription.id,
clientSecret: subscription.latest_invoice.payment_intent.client_secret,
});
Webhook (confirmar pagamento)
Webhooks sao o mecanismo que permite ao Stripe notificar sua aplicacao quando algo acontece — um pagamento foi confirmado, uma assinatura foi cancelada, uma cobranca falhou. Sem webhooks, voce teria que ficar consultando a API do Stripe repetidamente para saber se o pagamento foi concluido (polling), o que e lento, ineficiente e fragil. Com webhooks, o Stripe envia um POST para uma URL sua no momento exato em que o evento ocorre. Isso permite que voce ative contas, libere acessos ou envie e-mails de confirmacao de forma instantanea e confiavel. O ponto critico aqui e a verificacao da assinatura: todo webhook deve ter sua assinatura validada para garantir que a requisicao realmente veio do Stripe e nao de um atacante tentando simular um pagamento.
// app/api/webhooks/stripe/route.ts
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const body = await req.text();
const sig = req.headers.get('stripe-signature')!;
let event;
try {
event = stripe.webhooks.constructEvent(
body,
sig,
process.env.STRIPE_WEBHOOK_SECRET!
);
} catch (err) {
return Response.json({ error: 'Webhook signature verification failed' }, { status: 400 });
}
// Pagamento confirmado
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
// Ativar conta do usuário
await activateUserAccount(session.customer);
}
// Assinatura criada
if (event.type === 'customer.subscription.created') {
const subscription = event.data.object;
// Lógica de ativação
}
// Pagamento recorrente falhou
if (event.type === 'invoice.payment_failed') {
const invoice = event.data.object;
// Enviar e-mail de lembrete
await sendPaymentFailedEmail(invoice.customer_email);
}
return Response.json({ received: true });
}
Custo Stripe:
- Taxa: 3,4% + R$ 0,80 por transação
- Exemplo: R$ 199 → Taxa de R$ 7,57 (3,8%)
2. E-mail transacional: Resend (mais simples que SendGrid)
E-mail transacional e diferente de e-mail marketing. E-mail marketing e aquele que voce envia em massa para uma lista de contatos — newsletters, promocoes, lancamentos. E-mail transacional e disparado por uma acao do usuario: confirmacao de cadastro, recibo de compra, reset de senha, notificacao de atividade. A diferenca importa porque os provedores de e-mail (Gmail, Outlook) tratam os dois tipos de forma diferente. Se voce envia e-mails transacionais pelo mesmo dominio e IP que usa para marketing, a reputacao do seu dominio pode cair e seus e-mails de reset de senha comecam a parar na caixa de spam. Provedores como Resend e SendGrid gerenciam reputacao de IP, autenticacao SPF/DKIM/DMARC e infraestrutura de envio para garantir que seus e-mails transacionais cheguem na caixa de entrada. Deliverability nao e um detalhe: se o e-mail de confirmacao de compra nao chega, o usuario acha que o pagamento falhou e abre um chamado de suporte (ou pior, um chargeback).
Por que Resend: API moderna, templates em React (TSX), deliverability excelente.
Setup (10min)
npm install resend react-email @react-email/components
# .env.local
RESEND_API_KEY=re_...
Template de e-mail em React
// emails/welcome.tsx
import {
Body,
Button,
Container,
Head,
Html,
Preview,
Section,
Text,
} from '@react-email/components';
interface WelcomeEmailProps {
userName: string;
loginUrl: string;
}
export default function WelcomeEmail({ userName, loginUrl }: WelcomeEmailProps) {
return (
<Html>
<Head />
<Preview>Bem-vindo ao OrientMe, {userName}!</Preview>
<Body style={{ backgroundColor: '#f6f9fc', fontFamily: 'Arial' }}>
<Container style={{ margin: '40px auto', padding: '20px' }}>
<Text style={{ fontSize: '24px', fontWeight: 'bold' }}>
Olá {userName}! 👋
</Text>
<Text>
Sua conta foi criada com sucesso. Estamos animados para ter você conosco!
</Text>
<Section style={{ textAlign: 'center', margin: '32px 0' }}>
<Button
href={loginUrl}
style={{
backgroundColor: '#23a4ff',
color: '#fff',
padding: '12px 24px',
borderRadius: '6px',
textDecoration: 'none',
}}
>
Acessar minha conta
</Button>
</Section>
<Text style={{ fontSize: '14px', color: '#666' }}>
Dúvidas? Responda este e-mail ou acesse nossa central de ajuda.
</Text>
</Container>
</Body>
</Html>
);
}
Enviar e-mail
// lib/email.ts
import { Resend } from 'resend';
import WelcomeEmail from '@/emails/welcome';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function sendWelcomeEmail(to: string, userName: string) {
await resend.emails.send({
from: 'OrientMe <noreply@orientme.com.br>',
to,
subject: `Bem-vindo, ${userName}!`,
react: WelcomeEmail({ userName, loginUrl: 'https://app.orientme.com.br/login' }),
});
}
// Uso
await sendWelcomeEmail('joao@exemplo.com', 'João Silva');
Custo Resend:
- Grátis: 3.000 e-mails/mês
- R$ 100/mês: 50.000 e-mails
3. Storage de arquivos: Cloudinary
Lidar com imagens parece simples ate voce precisar fazer isso em producao. Usuarios enviam fotos de 8MB tiradas pelo celular quando voce precisa de thumbnails de 50KB. Cada navegador suporta formatos diferentes — WebP e mais leve que JPEG, mas nem todo client antigo renderiza. Voce precisa de versoes em tamanhos diferentes para desktop, tablet e mobile. E as imagens precisam ser servidas por uma CDN global para que carreguem rapido em qualquer lugar do mundo, nao apenas no data center onde esta seu servidor. Construir esse pipeline de upload, processamento, conversao de formato e distribuicao via CDN exige semanas de trabalho e infraestrutura dedicada. Cloudinary resolve tudo isso com uma unica integracao: o usuario faz upload direto do navegador, e voce aplica transformacoes (resize, crop, conversao para WebP) via parametros na URL da imagem. E storage, CDN e otimizacao em um unico servico.
Por que Cloudinary: Upload direto do browser, transformações automáticas (resize, crop), CDN global.
Setup (15min)
npm install cloudinary next-cloudinary
# .env.local
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=...
CLOUDINARY_API_KEY=...
CLOUDINARY_API_SECRET=...
Upload de imagem (frontend)
// components/image-upload.tsx
'use client';
import { CldUploadWidget } from 'next-cloudinary';
import { useState } from 'react';
export default function ImageUpload() {
const [imageUrl, setImageUrl] = useState('');
return (
<div>
<CldUploadWidget
uploadPreset="ml_default" // Criar no Cloudinary Dashboard
onSuccess={(result) => {
setImageUrl(result.info.secure_url);
}}
>
{({ open }) => (
<button onClick={() => open()}>
Upload de foto
</button>
)}
</CldUploadWidget>
{imageUrl && (
<img src={imageUrl} alt="Upload" width={200} />
)}
</div>
);
}
Transformações automáticas
import { CldImage } from 'next-cloudinary';
// Imagem otimizada (webp, lazy load, responsive)
<CldImage
src={publicId} // ID da imagem no Cloudinary
width={400}
height={300}
crop="fill"
gravity="face" // Foca no rosto se for foto de pessoa
alt="Foto de perfil"
/>
// Thumbnail circular (avatar)
<CldImage
src={publicId}
width={80}
height={80}
crop="thumb"
gravity="face"
radius="max" // Torna circular
alt="Avatar"
/>
Custo Cloudinary:
- Grátis: 25GB storage + 25GB bandwidth/mês
- R$ 400/mês: 100GB storage + 100GB bandwidth
4. Mapas e geolocalização: Google Maps API
Nem todo MVP precisa de mapas, mas quando precisa, a funcionalidade e central para o produto. Marketplaces que conectam prestadores de servico a clientes precisam calcular distancia e mostrar profissionais proximos. Apps de delivery dependem de rotas, tempo estimado de entrega e geocodificacao de enderecos. Plataformas de imoveis ou turismo precisam exibir localizacoes em um mapa interativo. Se o seu produto envolve qualquer relacao geografica entre usuarios, locais ou servicos, a integracao com mapas nao e um “nice to have” — e parte do core. O Google Maps continua sendo a opcao mais completa por cobrir autocomplete de enderecos, geocodificacao, calculo de distancia e rotas, e renderizacao de mapas, tudo em uma unica plataforma. O custo pode assustar a primeira vista, mas o credito gratuito mensal de R$ 750 cobre a maioria dos MVPs em fase de validacao.
Setup (20min):
npm install @googlemaps/js-api-loader
# 1. Criar projeto em console.cloud.google.com
# 2. Ativar APIs: Maps JavaScript API, Geocoding API, Places API
# 3. Criar chave API
# .env.local
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=AIza...
Autocomplete de endereço
'use client';
import { useLoadScript, StandaloneSearchBox } from '@react-google-maps/api';
import { useRef, useState } from 'react';
const libraries: ('places')[] = ['places'];
export default function AddressAutocomplete() {
const { isLoaded } = useLoadScript({
googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY!,
libraries,
});
const searchBoxRef = useRef<google.maps.places.SearchBox | null>(null);
const [address, setAddress] = useState('');
const handlePlacesChanged = () => {
const places = searchBoxRef.current?.getPlaces();
if (places && places.length mais de 0) {
const place = places[0];
setAddress(place.formatted_address || '');
// Latitude e longitude
const lat = place.geometry?.location?.lat();
const lng = place.geometry?.location?.lng();
console.log({ lat, lng, address: place.formatted_address });
}
};
if (!isLoaded) return <div>Carregando...</div>;
return (
<StandaloneSearchBox
onLoad={(ref) => (searchBoxRef.current = ref)}
onPlacesChanged={handlePlacesChanged}
>
<input
type="text"
placeholder="Digite seu endereço"
className="w-full p-2 border rounded"
/>
</StandaloneSearchBox>
);
}
Calcular distância entre 2 pontos
// lib/maps.ts
export async function calculateDistance(
origin: { lat: number; lng: number },
destination: { lat: number; lng: number }
) {
const response = await fetch(
`https://maps.googleapis.com/maps/api/distancematrix/json?origins=${origin.lat},${origin.lng}&destinations=${destination.lat},${destination.lng}&key=${process.env.GOOGLE_MAPS_API_KEY}`
);
const data = await response.json();
return {
distance: data.rows[0].elements[0].distance.value, // metros
duration: data.rows[0].elements[0].duration.value, // segundos
};
}
// Uso
const { distance, duration } = await calculateDistance(
{ lat: -23.550520, lng: -46.633308 }, // São Paulo
{ lat: -22.906847, lng: -43.172896 } // Rio de Janeiro
);
console.log(`Distância: ${distance / 1000}km`); // 429km
console.log(`Duração: ${duration / 60}min`); // 382min
Custo Google Maps:
- R$ 750 de crédito grátis/mês
- Autocomplete: $2,83 por 1.000 requests
- Geocoding: $5,00 por 1.000 requests
- Realidade: R$ 0 até ~5K usuários/mês
5. Bônus: SMS (Twilio)
Setup rápido:
npm install twilio
# .env.local
TWILIO_ACCOUNT_SID=AC...
TWILIO_AUTH_TOKEN=...
TWILIO_PHONE_NUMBER=+55...
Enviar SMS:
import twilio from 'twilio';
const client = twilio(
process.env.TWILIO_ACCOUNT_SID,
process.env.TWILIO_AUTH_TOKEN
);
export async function sendSMS(to: string, message: string) {
await client.messages.create({
body: message,
from: process.env.TWILIO_PHONE_NUMBER,
to,
});
}
// Uso
await sendSMS(
'+5521987654321',
'Seu código de confirmação é: 739281'
);
Custo Twilio:
- R$ 0,30 por SMS enviado no Brasil
Resumo de custos (mensal)
Um dos maiores beneficios do modelo baseado em APIs e que os custos escalam de forma gradual junto com o seu produto. No inicio, quando voce tem poucos usuarios e esta validando a ideia, praticamente todas as integracoes ficam dentro dos tiers gratuitos. Voce nao precisa pagar R$ 5 mil por mes em infraestrutura antes de ter o primeiro cliente pagante. A medida que o numero de usuarios cresce e a receita aumenta, os custos de integracao sobem proporcionalmente — mas a essa altura o produto ja esta gerando receita para cobrir esses custos. Esse modelo de pay-as-you-grow e ideal para MVPs porque elimina o risco financeiro da fase de validacao. A tabela abaixo mostra como os custos evoluem em tres faixas de usuarios.
| Integração | 0-1K usuários | 1K-10K | 10K-100K |
|---|---|---|---|
| Stripe | R$ 0 (apenas taxa 3,4%) | R$ 0 | R$ 0 |
| Resend | R$ 0 (3K e-mails) | R$ 100 | R$ 300 |
| Cloudinary | R$ 0 (25GB) | R$ 80 | R$ 400 |
| Google Maps | R$ 0 (crédito) | R$ 0 | R$ 200 |
| Twilio | R$ 0-150 | R$ 300-1K | R$ 2K-5K |
| TOTAL | R$ 0-150 | R$ 480-1.180 | R$ 2.900-5.900 |
Conclusão: Integrações custam quase R$ 0 até validar produto com 1K usuários. Depois escalam gradualmente.
Não desenvolva sistema de pagamento, e-mail ou storage próprio. Use APIs prontas e foque no core do seu produto.
O conceito por tras de tudo isso e o desenvolvimento API-first: em vez de construir cada funcionalidade internamente, voce monta seu produto como uma composicao de servicos especializados conectados por APIs. Pagamento com Stripe, e-mail com Resend, storage com Cloudinary, mapas com Google Maps. Cada um desses provedores tem times inteiros dedicados a resolver um unico problema de forma excelente. Quando voce adota essa abordagem, seu time de desenvolvimento fica livre para trabalhar no que realmente diferencia o seu produto no mercado — a logica de negocio, a experiencia do usuario, os fluxos que geram valor. O codigo deste artigo pode ser implementado em menos de uma semana. Depois disso, voce tem uma base solida de infraestrutura que aguenta escalar de 10 a 100 mil usuarios sem precisar reescrever nada. Comece pelas integrações que o seu MVP precisa hoje, valide rapido e adicione as demais conforme a demanda real dos usuarios pedir.