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)
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
| Requirement | Description |
|---|---|
| Auth (Supabase) | Users can sign up and log in (Lovable + Supabase). |
| User Model | Each user has a unique ID, email, and name, saved in the database. |
| Credits Storage | You have either a credits_balance field or a credits ledger (recommended). |
| Server-side endpoints | You can create API routes / edge functions to receive webhooks. |
| Stripe subscription flow | Stripe is set up (required if your campaign rewards are based on payments/subscriptions). |
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.
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-8X-Cello-Env: prod | sandbox
- Delivery semantics: at-least-once (you must dedupe)
6.3 Event payload
Cello sends anew-reward event when a credit reward is issued:
data.productUserId: the user who should receive credits (this should match your internal user ID used asproductUserIdwhen bootingcello.js)data.reward.amount: number of credits to granteventId: stable across retries, use it for deduplication
Step 7: Implement secure + idempotent credit fulfillment
7.1 Design decisions (recommended)
- Use a ledger (append-only credit transactions) rather than mutating a single balance field.
- You can still maintain a
credits_balancecache, but a ledger makes audit + idempotency much easier.
- You can still maintain a
- Deduplicate by
eventId.- Store
eventIdin a table with a unique constraint so duplicates fail safely.
- Store
- Process asynchronously if your stack allows it.
- The webhook should respond
2xxquickly; apply credits in a background job if needed.
- The webhook should respond
7.2 Minimal data model (example)
Create a table to dedupe + audit:cello_reward_eventsevent_id(unique)reward_idproduct_user_idamountenv(fromX-Cello-Env)received_atraw_payload(JSON)
credit_ledgeriduser_idsource(e.g.cello)source_id(storeeventIdand/orrewardId)amountcreated_at
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:- Use a unique constraint on
eventIdfor dedupe. This is the safest pattern under retries and concurrency. - Always return 2xx for events you’ve already processed (idempotency).
- Treat
productUserIdas 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
- Webhook Basic Auth username
- Webhook Basic Auth password
Acceptance criteria (credit rewards)
- A test conversion in sandbox results in a
new-rewardwebhook call to your endpoint - Requests without valid Basic Auth return
401 - A valid
new-rewardwithrewardType: "credits"creates exactly one credit grant (no double credits on retry) - Replaying the exact same payload (same
eventId) returns2xxand 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
- Your handler is not returning
2xx - Your handler times out
- You return
5xxfor validation failures
- Return
2xxfor processed events (idempotency) - Do strict validation but avoid expensive work synchronously
Credits are applied multiple times
Root cause- Missing dedupe by
eventId
- Store
eventIdin a table with a unique constraint and short-circuit duplicates
Credits go to the wrong user
Root cause- Your
productUserIdmapping is inconsistent
- 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.productUserIdfrom 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.