@geekapps/billing-nextjs
v0.7.0
Published
Geekapps Billing SDK for Next.js — create charges server-side and render the hosted checkout/payment page client-side
Readme
@geekapps/billing-nextjs
SDK para Next.js — cria cobranças no servidor e redireciona o usuário para a página de checkout hospedada (billing-dashboard), onde o pagamento acontece de fato.
Server (Server Components / Server Actions / Route Handlers)
// lib/billing.ts — crie uma única instância e reutilize em todo o app
import { GeekappsBilling } from "@geekapps/billing-nextjs";
export const billing = new GeekappsBilling({
apiUrl: process.env.BILLING_API_URL!,
token: createServiceAccountToken({ /* ... */ }), // de @geekapps/billing-fastify
mode: process.env.NODE_ENV === "production" ? "prod" : "dev", // definido uma vez
});// app/checkout/actions.ts
"use server";
import { billing } from "@/lib/billing";
export async function createCheckout(customerId: string) {
const charge = await billing.createCharge({
customer_id: customerId,
item_id: "...",
method: "CARD",
});
return billing.checkoutUrl(process.env.CHECKOUT_BASE_URL!, charge.checkout_token);
}Cobrança avulsa simples (sempre cartão)
"use server";
import { billing } from "@/lib/billing";
export async function chargeCustomer(customerId: string) {
const result = await billing.charge(customerId, 5000); // R$ 50,00, sempre em cartão
if (result.charged_off_session) {
// cobrado direto no cartão salvo do cliente — já pode liberar o que for
return { done: true };
}
// cliente ainda não tem cartão salvo: abra checkout_url (nova aba) para ele cadastrar e pagar
return { done: false, checkoutUrl: result.checkout_url };
}Assinatura de plano (checkout + confirmação + status)
Fluxo público (cliente final anônimo, ainda sem Customer cadastrado — coleta nome/e-mail no checkout):
"use server";
import { billing } from "@/lib/billing";
export async function subscribeToPlan(planId: string, name: string, email: string) {
const { checkout_url, checkout_token, management_token } =
await billing.createPlanCheckout(planId, { name, email });
// 1. Redirecione o cliente para checkout_url (ou use <CheckoutRedirectButton> no client)
// 2. Depois do retorno, confirme se realmente foi pago:
const status = await billing.getPublicCheckoutStatus(checkout_token);
// 3. Guarde management_token associado ao seu usuário — a qualquer momento depois,
// verifique se a assinatura segue ativa e qual item ela cobre:
const subStatus = await billing.checkSubscriptionStatus(management_token);
if (subStatus.subscription.active) {
console.log("cobrando", subStatus.item.name);
}
return { checkout_url, status, subStatus };
}Fluxo simplificado (autenticado, o Customer já existe na sua org — sem formulário de nome/e-mail):
"use server";
import { billing } from "@/lib/billing";
export async function subscribeExistingCustomer(planId: string, customerId: string) {
const { checkout_url } = await billing.checkoutPlan(planId, customerId);
// redirecione o cliente para checkout_url; ele paga e volta para sua URL de retorno
return checkout_url;
}
export async function confirmSubscription(planId: string, customerId: string) {
const { active, item } = await billing.confirmPlanSubscription(planId, customerId);
if (active) {
// ativa o plano real no seu sistema
}
return { active, item };
}Plano avulso (sem página pública)
"use server";
import { billing } from "@/lib/billing";
export async function createStandalonePlan(itemId: string) {
// plan_page_id omitido — plano fica avulso
return billing.createPlan({ item_id: itemId, interval: "MONTHLY" });
}Client (estado de pagamento)
"use client";
import { useCheckoutStatus } from "@geekapps/billing-nextjs/client";
function PaymentStatus({ token, initialStatus }: { token: string; initialStatus: string }) {
const { status } = useCheckoutStatus({
apiUrl: process.env.NEXT_PUBLIC_BILLING_API_URL!,
checkoutToken: token,
initialStatus,
});
return <p>Status: {status}</p>;
}Assim como no @geekapps/billing-fastify, o mode é definido uma única vez ao criar GeekappsBilling — nenhuma chamada precisa recebê-lo de novo.
