Stack 16/12/2025

Integrando Lemon Squeezy em Extensões Chrome com Webhooks

Aprenda a integrar pagamentos com Lemon Squeezy em sua extensão Chrome, desde a configuração inicial até o tratamento de webhooks.
EQ
Por Equipe Midiaville
Especialistas em desenvolvimento web
16 de Dezembro de 2025

Stack

No mundo dinâmico do desenvolvimento web, a monetização de extensões para Chrome é um tópico de crescente importância. Uma das maneiras mais eficazes de gerar receita é através de assinaturas e pagamentos únicos, e a Lemon Squeezy surge como uma solução promissora para essa finalidade. Este artigo detalha como integrar a Lemon Squeezy, uma plataforma de pagamentos projetada para criadores digitais, em sua extensão do Chrome, utilizando webhooks para gerenciar assinaturas e pagamentos de forma eficiente. Acompanhe este guia completo e descubra como simplificar o processo de monetização da sua extensão.

Parte 1: Configurando a Lemon Squeezy

Antes de mergulharmos no código, é crucial configurar sua conta Lemon Squeezy e obter as credenciais necessárias. Este processo envolve a criação de uma conta, a definição de produtos e a geração de chaves de API. Siga os passos abaixo para garantir que tudo esteja configurado corretamente.

Passo 1: Criar sua Conta Lemon Squeezy

Comece acessando o site da Lemon Squeezy em https://www.lemonsqueezy.com/ e criando uma conta de teste. A conta de teste permite que você experimente a plataforma sem incorrer em custos reais, ideal para o desenvolvimento e testes iniciais. Certifique-se de completar o processo de onboarding para ter acesso total às funcionalidades.

Passo 2: Criar Seu Produto

No painel da Lemon Squeezy, navegue até a seção "Produtos" e clique em "Novo Produto". Aqui, você criará um produto de assinatura (por exemplo, "Plano Premium - Mensal"). Defina o preço da sua assinatura (por exemplo, R$9,99/mês). Após criar o produto, clique nele para visualizar os detalhes. Copie o ID da Variante (não o ID do Produto), pois você precisará dele para criar os links de checkout na sua extensão do Chrome. O ID da variante tem um formato numérico, como: 123456.

Passo 3: Gerar a Chave da API

Acesse "Configurações" → "API" no painel da Lemon Squeezy. Clique em "Criar Chave de API". Dê um nome à chave (por exemplo, "Chrome Extension API") e copie a chave imediatamente, pois ela não será exibida novamente. Guarde-a em um local seguro.

Passo 4: Obter o ID da Sua Loja

Vá para "Configurações" → "Lojas". Você verá sua loja com um número, como #123456. Copie apenas os números (sem o símbolo #). Este é o ID da sua loja, essencial para configurar a comunicação com a API.

Passo 5: Criar Segredo do Webhook

Ao contrário de outros processadores de pagamento, a Lemon Squeezy não fornece um token secreto de webhook. Portanto, você precisa criar uma string aleatória em um arquivo `.env` para usar como segredo.

Passo 6: Configurar Variáveis de Ambiente

Crie um arquivo `.env.local` no seu projeto Next.js (ou equivalente) e adicione as seguintes variáveis:

  • LEMONSQUEEZY_API_KEY=sua_chave_api_aqui
  • LEMONSQUEEZY_STORE_ID=123456
  • LEMONSQUEEZY_WEBHOOK_SECRET=seu_segredo_aleatorio
  • NEXT_PUBLIC_CHECKOUT_SUCCESS_URL=https://seusite.com/checkout-success

Observações importantes:

  • Use o ID da Variante, não o ID do Produto.
  • NEXT_PUBLIC_CHECKOUT_SUCCESS_URL é onde os usuários são redirecionados após o pagamento (opcional).
  • Mantenha LEMONSQUEEZY_API_KEY e WEBHOOK_SECRET seguros e nunca os exponha no código do cliente.

Parte 2: Configurando o Backend (Funções Serverless)

Para processar os pagamentos e gerenciar as assinaturas, você precisará de um backend. Funções serverless são ideais para essa finalidade, pois são fáceis de implementar e escaláveis. Criaremos duas funções serverless:

  1. Gerar links de checkout.
  2. Lidar com eventos de webhook.

Passo 1: Instalar Dependências

Utilize o gerenciador de pacotes npm para instalar a biblioteca da Lemon Squeezy:

npm install @lemonsqueezy/lemonsqueezy.js

Passo 2: Criar Cliente Lemon Squeezy

Crie o arquivo lib/lemonSqueezy/lemonSqueezyClient.ts com o seguinte código (em TypeScript):


import { lemonSqueezySetup } from "@lemonsqueezy/lemonsqueezy.js";

export function configureLemonSqueezy() {
  lemonSqueezySetup({
    apiKey: process.env.LEMONSQUEEZY_API_KEY!,
    onError: (error) => {
      console.error("Lemon Squeezy Error:", error);
      throw error;
    },
  });
}

Passo 3: Criar Endpoint da API de Checkout

Crie o arquivo app/api/checkout/route.ts com o seguinte código (em TypeScript):


import { createCheckout } from "@lemonsqueezy/lemonsqueezy.js";
import { configureLemonSqueezy } from "@/lib/lemonSqueezy/lemonSqueezyClient";

async function createCheckoutLS(
  productId: string,
  userEmail?: string
) {
  configureLemonSqueezy();

  const storeId = process.env.LEMONSQUEEZY_STORE_ID;

  if (!storeId) {
    throw new Error("LEMONSQUEEZY_STORE_ID is not set");
  }

  const checkoutData = {
    productOptions: {
      redirectUrl: process.env.NEXT_PUBLIC_CHECKOUT_SUCCESS_URL,
    },
    checkoutData: {
      email: userEmail || undefined,
    },
  };

  const checkout = await createCheckout(
    storeId,
    productId,
    checkoutData
  );

  if (checkout.error) {
    throw new Error(checkout.error.message);
  }

  return checkout.data?.data.attributes.url;
}

export async function POST(request: Request) {
  try {
    const { productId, userEmail } = await request.json();

    if (!productId) {
      return new Response(
        JSON.stringify({ error: 'Product variant ID is required' }),
        {
          status: 400,
          headers: { 'Content-Type': 'application/json' },
        }
      );
    }

    const checkoutUrl = await createCheckoutLS(
      productId,
      userEmail || undefined
    );

    return new Response(
      JSON.stringify({ checkout_url: checkoutUrl }),
      {
        status: 201,
        headers: { 'Content-Type': 'application/json' },
      }
    );
  } catch (error) {
    console.error('Checkout creation error:', error);
    return new Response(
      JSON.stringify({
        error: 'Failed to create checkout',
        details: error instanceof Error ? error.message : 'Unknown error'
      }),
      {
        status: 500,
        headers: { 'Content-Type': 'application/json' },
      }
    );
  }
}

Este código aceita requisições POST com productId e userEmail (opcional), cria um link de checkout personalizado através da API da Lemon Squeezy, pré-preenche o e-mail do usuário na página de checkout e retorna a URL de checkout para a sua extensão.

Parte 3: Construindo Sua Extensão Chrome

Agora, vamos integrar a Lemon Squeezy na sua extensão do Chrome. Isso envolve a criação de um manipulador de checkout, configuração do script de background e criação da interface do usuário para o upgrade premium.

Passo 1: Criar Manipulador de Checkout

Crie o arquivo src/handleCheckout.ts na sua extensão com o seguinte código:


/**
 * Creates a checkout URL by calling your serverless function
 * @param email - User's email to pre-fill at checkout
 * @param productId - Lemon Squeezy variant ID
 * @returns Checkout URL or null if failed
 */
export async function createCheckoutURL(
  email: string | null,
  productId: string
): Promise<string | null> {
  const CHECKOUT_ENDPOINT = 'https://your-app.vercel.app/api/checkout';

  try {
    const response = await fetch(CHECKOUT_ENDPOINT, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        productId,
        userEmail: email,
      }),
    });

    if (!response.ok) {
      console.error('Checkout creation failed:', response.statusText);
      return null;
    }

    const results = await response.json();
    return results.checkout_url;
  } catch (error) {
    console.error('Error creating checkout URL:', error);
    return null;
  }
}

/**
 * Initiates checkout flow by sending message to background script
 * @param email - User's email
 * @param productId - Product variant ID to purchase
 */
export async function invokeCheckout(email?: string, productId?: string) {
  await chrome.runtime.sendMessage({
    type: 'checkout',
    userEmail: email,
    productId: productId || import.meta.env.WXT_LEMONSQUEEZY_PRODUCT_ID,
  });
}

Adicione a seguinte linha ao seu arquivo .env.local (na pasta da sua extensão, não na pasta das funções serverless):


WXT_LEMONSQUEEZY_PRODUCT_ID=seu_id_da_variante_aqui  # pro plan

Passo 2: Configurar Script de Background

Crie ou atualize o arquivo src/background.ts com o seguinte código:


import { createCheckoutURL } from './lib/handleCheckout';

type CheckoutMessage = {
  type: 'checkout';
  userEmail?: string;
  productId: string;
};

async function handleMessages(
  message: CheckoutMessage,
  sender: chrome.runtime.MessageSender,
  sendResponse: (response?: any) => void
) {
  if (message.type === 'checkout') {
    console.log('🛒 Starting checkout flow...');

    // Generate the checkout link
   // productId is coming from invokeCheckout <- popup.tsx

    const checkoutLink = await createCheckoutURL(
      message.userEmail || null,
      message.productId
    );

    if (!checkoutLink) {
      console.error('❌ Failed to create checkout link');
      sendResponse({ success: false, error: 'Failed to create checkout' });
      return;
    }

    // Redirect user to checkout page (no manifest permission needed)
    chrome.tabs.create({ url: checkoutLink }, (tab) => {
      console.log('✅ Redirected to checkout:', checkoutLink);
      sendResponse({ success: true, tabId: tab.id });
    });
  }
}

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  handleMessages(request, sender, sendResponse);
  return true; // Required for async sendResponse
});

Este script escuta mensagens do tipo 'checkout' vindas do popup ou scripts de conteúdo, chama sua função serverless para gerar a URL de checkout e abre uma nova aba com a página de checkout. Não são necessárias permissões de manifesto para abrir abas.

Passo 3: Criar Interface do Usuário para Upgrade Premium

Crie um componente no seu popup (src/components/PremiumCard.tsx) com o seguinte código:


import React from 'react';
import { invokeCheckout } from '../lib/handleCheckout';

export default function PremiumCard() {

  async function handleUpgradeClick() {
    try {
    // Get user's email from your auth system or chrome.storage
      await invokeCheckout('[email protected]');
    } catch (error) {
      console.error('Checkout error:', error);

    } 
  }

  return (
    <div className="premium-card">
      <div className="premium-header">
        <h3>🚀 Upgrade to Premium</h3>
        <p className="price">$9.99/month</p>
      </div>

      <ul className="features">
        <li>✨ Unlimited AI generations</li>
        <li>🎯 Advanced features</li>
        <li>⚡ Priority support</li>
        <li>🔒 Ad-free experience</li>
      </ul>

      <button
        onClick={handleUpgradeClick}
        className="upgrade-button"
      >
        {'Get Premium Now'}
      </button>
    </div>
  );
}

O fluxo de usuário é o seguinte: o usuário clica em "Get Premium Now", uma mensagem é enviada ao script de background, a URL de checkout é gerada com o e-mail pré-preenchido, o usuário é redirecionado para o checkout da Lemon Squeezy e, após o pagamento, é redirecionado para a página de sucesso (opcional).

Parte 4: Configuração do Banco de Dados (Supabase)

Para armazenar informações sobre seus usuários premium e suas assinaturas, você precisará de um banco de dados. O Supabase é uma excelente opção, pois oferece uma interface intuitiva e recursos poderosos.

Passo 1: Criar Tabela no Supabase

Execute o seguinte SQL no seu editor SQL do Supabase:


CREATE TABLE PremiumUsers (
  user_email TEXT PRIMARY KEY,
  subscription_status TEXT NOT NULL,
  plan_type TEXT,
  credits_used INTEGER DEFAULT 0,
  subscribed_at TIMESTAMPTZ,
  expires_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  subscription_id TEXT,
  customer_id TEXT
);

-- Add index for faster queries
CREATE INDEX idx_subscription_status ON PremiumUsers(subscription_status);
CREATE INDEX idx_expires_at ON PremiumUsers(expires_at);

Passo 2: Configurar Cliente Supabase

Crie o arquivo lib/supabase/supabaseAdmin.ts com o seguinte código:


import { createClient } from '@supabase/supabase-js';

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;

// Use service role key for admin operations
const supabaseAdmin = createClient(supabaseUrl, supabaseServiceKey);

export default supabaseAdmin;

Adicione as seguintes linhas ao seu arquivo .env.local:


NEXT_PUBLIC_SUPABASE_URL=sua_url_do_supabase
SUPABASE_SERVICE_ROLE_KEY=sua_chave_de_servico_do_supabase

Parte 5: Webhooks

Os webhooks são essenciais para manter seu banco de dados sincronizado com a Lemon Squeezy, garantindo que as informações sobre seus usuários premium estejam sempre atualizadas.

Passo 1: Criar Definições de Tipo (Opcional)

Crie o arquivo app/api/webhooks/lemon-squeezy/types.ts com o seguinte código:


export interface LemonSqueezyWebhookPayload {
        

Compartilhe este artigo

Artigos Relacionados

Continue explorando nossos insights sobre desenvolvimento web e estratégias digitais

Precisa de Uma Solução Personalizada?

Nossa equipe especializada está pronta para desenvolver a solução ideal para o seu negócio.