Skip to main content

Cello + Lovable Detailed Integration (Credit-based Rewards)

This guide extends the standard Lovable Cello integration to support in-product credit rewards (e.g. “500 credits per conversion”) where your platform grants credits to users after Cello issues a reward. When complete, you’ll have:
  • Working Referral Widget (default floating launcher)
  • Attribution Tracking (UCC captured on public pages)
  • Signup Tracking (signup events sent to Cello)
  • Stripe Conversion Tracking (purchase/subscription events via Stripe webhook)
  • Credit Reward Fulfillment (Cello → your backend webhook → apply credits in DB)
Estimated Time: 1–2 hours (depends on how you model credits + idempotency)

What’s different vs cash rewards?

The referral capture, attribution, signup tracking, and Stripe conversion tracking steps are the same as the base guide: The key difference is the last mile: when Cello determines a conversion earned a reward, Cello notifies your platform via a credit reward webhook. Your platform must:
  • Authenticate the webhook request (HTTP Basic Auth)
  • Deduplicate events (at-least-once delivery)
  • Apply credits to the correct user (productUserId)

Prerequisites

Application requirements


Environment variables

These are the same as the base Lovable detailed integration plus two new values for the credit rewards webhook.

Steps 1–5: Implement the base Lovable integration

Complete the following guide end-to-end: Why you still need Steps 1–5
  • Step 2/3: Users need the referral widget + UCC attribution.
  • Step 4: Cello needs the signup event (POST /events) to link the new user to a referrer.
  • Step 5: Cello needs conversion/payment signals (Stripe webhook + customer metadata) to determine eligibility for credit rewards.
Once Steps 1–5 are working, continue below.

Step 6: Credit-based rewards webhook (Cello → your backend)

This step is the core of credit-based rewards: Cello notifies your platform when a credit reward is created, and your platform applies credits.

6.1 Documentation

6.2 Webhook basics

  • Method: POST
  • Authentication: HTTP Basic Auth
  • Headers:
    • Authorization: Basic base64({username}:{password})
    • Content-Type: application/json; charset=utf-8
    • X-Cello-Env: prod | sandbox
  • Delivery semantics: at-least-once (you must dedupe)

6.3 Event payload

Cello sends a new-reward event when a credit reward is issued:
Key fields
  • data.productUserId: the user who should receive credits (this should match your internal user ID used as productUserId when booting cello.js)
  • data.reward.amount: number of credits to grant
  • eventId: stable across retries, use it for deduplication

Step 7: Implement secure + idempotent credit fulfillment

  • Use a ledger (append-only credit transactions) rather than mutating a single balance field.
    • You can still maintain a credits_balance cache, but a ledger makes audit + idempotency much easier.
  • Deduplicate by eventId.
    • Store eventId in a table with a unique constraint so duplicates fail safely.
  • Process asynchronously if your stack allows it.
    • The webhook should respond 2xx quickly; apply credits in a background job if needed.

7.2 Minimal data model (example)

Create a table to dedupe + audit:
  • cello_reward_events
    • event_id (unique)
    • reward_id
    • product_user_id
    • amount
    • env (from X-Cello-Env)
    • received_at
    • raw_payload (JSON)
And either:
  • credit_ledger
    • id
    • user_id
    • source (e.g. cello)
    • source_id (store eventId and/or rewardId)
    • amount
    • created_at
or a users.credits_balance field you increment.

7.3 Webhook handler (Node / TypeScript example)

Use this pattern whether you implement it as a Next.js route handler, an Express route, or a Supabase edge function:
Critical implementation notes
  • Use a unique constraint on eventId for dedupe. This is the safest pattern under retries and concurrency.
  • Always return 2xx for events you’ve already processed (idempotency).
  • Treat productUserId as your lookup key for which user gets credits.

Step 8: Operational setup (Cello Support)

Per current documentation, the credit reward webhook configuration is coordinated through Cello Support. Share these with Cello Support for both environments:
  • Sandbox webhook endpoint URL
  • Production webhook endpoint URL
Cello Support will also provide:
  • Webhook Basic Auth username
  • Webhook Basic Auth password

Acceptance criteria (credit rewards)

  • A test conversion in sandbox results in a new-reward webhook call to your endpoint
  • Requests without valid Basic Auth return 401
  • A valid new-reward with rewardType: "credits" creates exactly one credit grant (no double credits on retry)
  • Replaying the exact same payload (same eventId) returns 2xx and does not change credits
  • Credits are applied to the user matching data.productUserId

Troubleshooting

Webhook retries keep happening

Symptoms
  • You see the same reward event multiple times
Likely causes
  • Your handler is not returning 2xx
  • Your handler times out
  • You return 5xx for validation failures
Fix
  • Return 2xx for processed events (idempotency)
  • Do strict validation but avoid expensive work synchronously

Credits are applied multiple times

Root cause
  • Missing dedupe by eventId
Fix
  • Store eventId in a table with a unique constraint and short-circuit duplicates

Credits go to the wrong user

Root cause
  • Your productUserId mapping is inconsistent
Fix
  • Ensure the user ID you pass to the widget JWT (productUserId) is the same ID you use in your DB
  • Ensure you apply credits using data.productUserId from the webhook payload

You now have a Lovable-ready Cello referral integration with credit-based rewards: Cello tracks attribution and conversions, and your platform fulfills the credits when rewards are issued.