Payments

LGTM × Dodo Payments

Dodo Payments powers LGTM's INR subscriptions: GST-compliant invoicing, Merchant-of-Record for international users, refund + dispute flows, idempotent webhook handling via Svix.

Why Dodo Payments (vs Stripe / Razorpay)

Dodo Payments is the Indian-built Merchant-of-Record payment processor. They sit between your SaaS and your customers, handle GST collection + invoicing as the Indian-entity-of-record, support both INR and international currencies, and remit your earnings post-tax.

Why not Stripe: Stripe doesn't take India as a country of incorporation (a hard issue for India-incorporated SaaS). Stripe Atlas exists but requires a US Delaware C-Corp — overhead an indie founder doesn't want.

Why not Razorpay: Razorpay is excellent for domestic INR payments but isn't a Merchant-of-Record. For international customers, you'd need additional setup. Dodo wraps both INR and USD in one merchant relationship.

Why not Paddle: Paddle's tier 1 customers are European/US — fine for global SaaS but doesn't handle Indian GST natively. Dodo is built India-first with GST as a primary concern.

Subscription lifecycle on LGTM

Customer clicks 'Upgrade to Pro' on /pricing. Frontend redirects to a Dodo-hosted checkout page (Dodo's official SDK in the app/api/billing/checkout route). Customer enters payment details on Dodo's domain — LGTM never sees credit card numbers; PCI scope is Dodo's.

Successful payment → Dodo POSTs a subscription.created webhook to api.looksgoodtomeow.in/webhooks/dodo. LGTM verifies the Svix-Signature header against Dodo's webhook secret, dedupes by Svix-Id (preventing replay), and atomically promotes the user's plan to Pro in MongoDB.

Renewal: every month, Dodo bills the customer's saved payment method and fires another webhook (subscription.payment_succeeded). LGTM's quota counter rolls over.

Failed renewal: Dodo retries 3 times over 7 days, then fires subscription.payment_failed. LGTM downgrades the customer to Free + sends a notification email with a 'Update payment method' link.

GST + invoicing

Every transaction Dodo processes generates a GST-compliant invoice automatically. Indian customers get an 18% IGST/CGST+SGST breakdown depending on their billing state; international customers don't have GST applied but get a tax-clean invoice anyway.

Invoices are emailed to the billing address on file AND downloadable from the customer's LGTM Settings → Billing → Invoices panel. PDF generation is handled by Dodo; we just expose the download URL.

LGTM's GSTIN appears on the invoice as the issuer (because LGTM is the underlying product), but the legal Merchant-of-Record is Dodo. This is the Indian regulatory pattern — Dodo holds the customer-payment relationship for compliance purposes, LGTM holds the customer-product relationship.

Refund + dispute flows

Refund: customer requests within 7 days → LGTM Support → admin triggers a refund via the Dodo Admin API. Dodo processes the refund within 1-3 business days to the original payment method. Webhook subscription.refunded fires; LGTM atomically downgrades the user.

Dispute / chargeback: customer disputes a charge with their bank → Dodo notifies LGTM via dispute.created webhook. LGTM auto-downgrades the user (no service while dispute is open) and the founder gets a Slack alert + email with the dispute details. We have 14 days to submit evidence (review request was legitimate, service was delivered, no fraud signals). Win or lose, dispute.closed fires.

Idempotency on all of this: every webhook delivery has a Svix-Id. LGTM stores processed IDs in MongoDB with a TTL of 30 days. Duplicate deliveries (rare but happen) acknowledge with 200 but don't re-execute side effects.

Test mode vs live mode

Dodo offers a test environment (test-mode API keys) with sandbox cards that always succeed / always fail / always dispute. LGTM's development environment uses test mode; production uses live mode.

Switching to live mode required: (1) Dodo KYC complete (PAN, bank account, address proof). (2) Live API keys configured in Fly Secrets. (3) Webhook URLs registered for production endpoint. (4) Test transaction executed end-to-end before announcing public availability.

Webhook signing: test mode and live mode have separate webhook secrets. Each environment verifies its own secret. Cross-environment webhook delivery is impossible (test webhooks never reach prod).

Implementation examples

Dodo webhook handler (signature + idempotency)
// app/api/webhooks/dodo/route.ts
import { Webhook } from 'svix';
import { WebhookEvent } from '@/lib/db/models';

export async function POST(req: Request) {
  const headers = {
    'svix-id': req.headers.get('svix-id'),
    'svix-timestamp': req.headers.get('svix-timestamp'),
    'svix-signature': req.headers.get('svix-signature'),
  };
  const body = await req.text();

  // 1. Verify signature
  const wh = new Webhook(process.env.DODO_WEBHOOK_SECRET!);
  let event;
  try {
    event = wh.verify(body, headers);
  } catch {
    return new Response('Invalid signature', { status: 401 });
  }

  // 2. Dedupe by svix-id
  const existing = await WebhookEvent.findOne({ svixId: headers['svix-id'] });
  if (existing) return new Response('Already processed', { status: 200 });
  await WebhookEvent.create({ svixId: headers['svix-id'], at: new Date() });

  // 3. Side effect (atomic plan update)
  await handleDodoEvent(event);
  return new Response('OK', { status: 200 });
}

See LGTM pricing + Dodo checkout

INR-native · GST-compliant · 7-day refund · cancel anytime

Go to the product page

Dodo Payments integration FAQs

Is Dodo Payments secure for handling my card?

Dodo is PCI-DSS compliant Merchant-of-Record. Card details never reach LGTM's servers — they go directly to Dodo on Dodo's domain. LGTM only receives webhook events about the subscription lifecycle, never the payment method itself.

Can I pay in USD instead of INR?

Yes. Dodo supports multiple currencies. The pricing page detects your location and shows INR for Indian visitors, USD for international. The underlying subscription is recorded in the currency you chose at checkout.

How does GST work for me as an Indian customer?

GST is automatically applied at the standard SaaS rate (18%) on top of the listed price. Your GST-compliant invoice is emailed and downloadable from LGTM Settings → Billing. If you have a GSTIN, enter it at checkout to get a B2B invoice you can claim input credit on.

Refund policy?

First 7 days from purchase, full refund on request (email tarinagarwal@gmail.com or use the in-product 'Request Refund' button). After 7 days, prorated for the unused subscription period. Refunds process via Dodo back to the original payment method within 1-3 business days.

What happens if my payment fails on renewal?

Dodo retries 3 times over a 7-day grace window. During that window, your Pro features stay active. After the grace window, LGTM auto-downgrades to Free and sends a notification email with a payment-update link. Re-add a valid payment method to restore Pro immediately.

Related across LGTM

Other integrations