Integrate MonCashConnect with Lovable or Claude

This guide is written for people building their application with an AI tool (Lovable, Claude, Bolt, v0, GitHub Copilot Workspaces, etc.) who want to accept MonCash payments through MonCashConnect. No prior programming knowledge is required — but a single security mistake can drain your account. Read the next section in full before doing anything else.

If you're a developer writing the code yourself, head to /en/docs instead, or pick a framework guide in /guides. This guide targets the "I describe what I want and the AI writes the code" workflow.

What you'll end up with

  • A MonCash checkout page wired to your Lovable or Claude application
  • A webhook that automatically marks your orders as "paid"
  • A secure setup — your keys are never exposed in public code, in the AI chat history, or in your Git repository

Prerequisites

  • An active MonCashConnect account (create one at /auth)
  • A Lovable, Claude (Claude.ai), Bolt or equivalent project
  • A domain where your application is deployed (or an ngrok tunnel for local testing — see the webhook-testing guide)

Security — non-negotiable

Read this before anything else. A single mistake can drain your account.

Your MonCashConnect secret key (sk_proj_…) and your webhook secret (whsec_…) give anyone who holds them the power to:

  • Create payments from your account (and therefore read your balance and your history)
  • Request MonCash withdrawals to their number
  • Have fraudulent webhooks issued with valid signatures

The golden rule

Never type your secret key or your webhook secret into an AI chat window (Lovable, Claude, ChatGPT, Bolt, etc.).

Why? The contents of your AI chat are:

  • Stored server-side (Anthropic, Lovable, OpenAI, etc.) — not end-to-end encrypted
  • Potentially visible to the platform's support engineers
  • Sometimes indexed by internal analytics or fine-tuning tooling
  • Persisted in the project history — accessible to any invited collaborator
  • Backed up in logs that can be exfiltrated in case of a breach

A key that appears even once in a chat must be considered compromised forever. Revoke it immediately and generate a new one.

The right reflex: in your prompt to the AI, always say "use process.env.MCC_SECRET_KEY" or "read the key from an environment variable named MCC_SECRET_KEY". You then configure that variable inside Lovable / your host's interface — without the actual value ever passing through the chat.

What can be public (safe)

Nom / CodeType / LimiteDescription
Your site URLSafe publicEx: https://my-shop.com — can appear in the chat without risk.
Your return URLSafe publicEx: https://my-shop.com/thanks — already shows up in the customer's browser.
Your webhook URLSafe publicEx: https://my-shop.com/api/webhook — the URL itself is not a secret.
The sk_proj_ prefixSafe publicThe first 8 characters. The suffix is secret.
The name of your MCC projectSafe publicIt shows up on the user consent screen anyway.

What is secret (NEVER paste into an AI chat)

Nom / CodeType / LimiteDescription
Full secret key🔒 SECRETsk_proj_XXXXXXXXXXXXXXXXXXXXXXXX (43 characters after the prefix)
Full webhook secret🔒 SECRETwhsec_XXXXXXXXXXXXXXXXXXXXXXXX
MCC account password🔒 SECRETObvious, but worth mentioning.

Step 1 — Get your keys from MonCashConnect

All configuration lives on the Developer page of your dashboard. Here's exactly where to click:

Navigate to the Developer page

  1. Go to moncashconnect.com and sign in (Sign in link at the top right).
  2. Once signed in, open the Dashboard menu.
  3. In the sidebar, click Developer (key icon). The direct URL is moncashconnect.com/developer.
  4. You'll see two tabs: "API Keys" and "Projects".

Create a project

For serious integrations (with a deployed site and a webhook), create a Project rather than just an API key. A Project bundles:

Nom / CodeType / LimiteDescription
Project namee.g. My-ShopVisible on the customer's consent screen.
Secret keysk_proj_…Used to sign every API request.
Webhook URLhttps://my-shop.com/api/webhookWhere MCC sends payment confirmations.
Webhook secretwhsec_…Used to verify that the webhook really comes from MCC.
Allowed domainsmy-shop.comComma-separated list. CORS allow-list.
  1. On /developer, click the "Projects" tab.
  2. Click the "New project" button (top right of the list).
  3. Fill in:
    • Name: the name of your shop / app.
    • Webhook URL: https://your-site.com/api/moncash-webhook (you'll configure this route in step 4 — leave it blank if you don't know yet).
    • Allowed domains: your-site.com, www.your-site.com (comma-separated).
  4. Click "Create".
  5. ONLY ONCE, MonCashConnect shows you:
    • Your full secret key sk_proj_xxxxxxxxxxxxxxxx
    • Your full webhook secret whsec_xxxxxxxxxxxxxxxx
  6. Click the "Copy" buttons next to each value and paste them into a password manager (1Password, Bitwarden, the macOS keychain, etc.) — not into a text file on your desktop, and especially not into the AI chat.
If you close the window without copying the keys, they are lost forever. You'll have to generate a new secret (which revokes the old one). Take 30 seconds to store them properly now.

Step 2 — Store your keys in the right place

You now have your two secrets in your password manager. You need to make them available to your code without the value going through the AI. The standard technique: environment variables.

If you use Lovable

  1. In your Lovable project, click the ⚙️ Settings icon (or the gear icon depending on your version).
  2. Look for the "Environment Variables" or "Secrets" section.
  3. Click "Add a variable".
  4. Create these two variables (one at a time):
    MCC_SECRET_KEY=sk_proj_VOTRE_CLE_SECRETE_ICI
    MCC_WEBHOOK_SECRET=whsec_VOTRE_SECRET_WEBHOOK_ICI
  5. Save. Lovable redeploys automatically. The values are encrypted at rest and injected into process.env at runtime.

If you use Claude to generate code that you host elsewhere

Claude generates the code, but you deploy it (Vercel, Netlify, Cloudflare, etc.). Never hardcode the key inside the generated code. Instead, add the same two variables in your host's environment panel:

Nom / CodeType / LimiteDescription
VercelDashboardSettings → Environment Variables → Add
NetlifyDashboardSite settings → Environment variables → Add a variable
Cloudflare PagesDashboardSettings → Environment variables → Add variable
RailwayDashboardProject → Variables → New variable
RenderDashboardService → Environment → Add Environment Variable
Locally.env.localCreate .env.local at the root; add .env.local to your .gitignore
Never commit .env or .env.local into Git. Check your .gitignore:
# .gitignore
.env
.env.local
.env.*.local

Step 3a — Prompt for Lovable

Here's a copy-paste-ready prompt for Lovable. Notice that the key appears nowhere — we just tell Lovable to use the environment variable.

Prompt — Checkout (payment)

Ajoute une intégration de paiement MonCash via MonCashConnect.

**Côté serveur (Edge Function ou API Route) :**
- Crée une route POST `/api/moncash/create` qui reçoit { amount, orderId, returnUrl }.
- Appelle `https://hvlmeoqyxaguzcujpmit.supabase.co/functions/v1/pay-create` avec :
  - Header: `Authorization: Bearer ${process.env.MCC_SECRET_KEY}`
  - Body JSON: { amount, referenceId: orderId, returnUrl }
- Si la réponse est 201, renvoie au client le champ `paymentUrl`.
- Si erreur, renvoie l'erreur structurée (champ `error` + `code`).
- **N'expose JAMAIS `MCC_SECRET_KEY` côté client. Lis-la uniquement depuis process.env.**

**Côté client :**
- Sur le bouton "Payer", fais un POST à `/api/moncash/create` avec
  { amount: total_en_HTG_entier, orderId: id_de_la_commande, returnUrl: window.location.origin + "/merci" }.
- À la réception de `paymentUrl`, redirige le navigateur avec window.location.href = paymentUrl.

**Stocke la commande en BDD avec status="awaiting_payment" AVANT la redirection.**
La confirmation finale viendra par webhook (je l'ajouterai ensuite).

**Référence officielle :** docs sur https://moncashconnect.com/docs (section "Créer un paiement").

Prompt — Webhook (confirmation)

Run this prompt after the checkout works, to add automatic confirmation:

Ajoute un webhook qui marque une commande comme payée quand MonCashConnect
confirme le paiement.

- Crée une route POST `/api/moncash/webhook` qui reçoit un POST de MCC.
- **Lis le corps brut (raw body) AVANT toute désérialisation JSON.**
- Récupère ces headers :
  - `x-mcc-signature` (format: "sha256=<hex>")
  - `x-mcc-timestamp` (epoch en secondes)
- Vérifie HMAC-SHA256 du corps brut avec process.env.MCC_WEBHOOK_SECRET ;
  rejette en 401 si signature invalide.
- Rejette en 401 si abs(now - timestamp) > 300 secondes.
- Sinon parse le JSON :
  - { event: "payment.completed", reference, amount, status, completedAt }
  - { event: "payment.failed",    reference, amount, status, completedAt }
- Trouve la commande par `reference === orderId` et mets à jour son status.
- **Réponds 200 toujours, même si la commande a déjà été marquée.**
  Les retries de MCC doivent être idempotents.

**N'expose pas process.env.MCC_WEBHOOK_SECRET côté client.**

**Référence officielle :** https://moncashconnect.com/docs (section "Webhooks").
Pro tip. If Lovable asks you for the key again "to test", refuse — tell it to test with a fake value. You'll test with the real key once deployed, where the environment variable is available.

Step 3b — Prompt for Claude (claude.ai)

If you use Claude (claude.ai) to generate code that you then paste into your project, here's the prompt to use. Same principle: the key never appears in the chat.

Prompt — Generate the code (Next.js example)

J'ai un projet Next.js App Router. Génère le code complet pour accepter
des paiements MonCash via l'API MonCashConnect.

**Contraintes de sécurité (impératives) :**
- Mes secrets sont dans process.env.MCC_SECRET_KEY et process.env.MCC_WEBHOOK_SECRET.
- Ne mets JAMAIS de valeur en dur. Ne demande pas la valeur de mes clés.
- Ne crée pas de variable NEXT_PUBLIC_* pour ces clés.

**Ce que je veux :**

1. `app/api/moncash/create/route.ts` :
   - POST { amount: number, orderId: string, returnUrl: string }
   - Appelle https://hvlmeoqyxaguzcujpmit.supabase.co/functions/v1/pay-create avec Bearer + body JSON.
   - Retourne { paymentUrl } ou { error, code }.

2. `app/api/moncash/webhook/route.ts` :
   - Force `export const runtime = "nodejs"` (pas Edge).
   - Lis le corps avec await req.text() (jamais req.json() avant vérif HMAC).
   - Récupère X-MCC-Signature (format "sha256=<hex>") et X-MCC-Timestamp.
   - Vérifie HMAC-SHA256(raw_body, MCC_WEBHOOK_SECRET) en temps constant.
   - Vérifie |now - timestamp| ≤ 300s.
   - Parse l'événement et appelle ma fonction handleEvent(event) (laisse-la TODO).
   - Renvoie 200 toujours sur succès, 401 sur signature invalide.

3. `components/PayButton.tsx` :
   - Composant client avec un bouton "Payer X HTG".
   - Au clic : POST vers /api/moncash/create, puis window.location.href = paymentUrl.
   - Gère l'état loading + l'affichage d'erreur si le serveur renvoie un `error`.

Référence : https://moncashconnect.com/docs (section "Créer un paiement" et "Webhooks").
Donne-moi le code complet, prêt à coller, en TypeScript strict.

Once the code is generated

  1. Copy each file into your local project.
  2. Create .env.local at the root and add your real keys (from your password manager):
    MCC_SECRET_KEY=sk_proj_VOTRE_CLE
    MCC_WEBHOOK_SECRET=whsec_VOTRE_SECRET
  3. Make sure .env.local is in your.gitignore.
  4. Run npm run dev and test locally with an ngrok tunnel (see /guides/webhook-testing).
  5. For production, add the same variables in your host's dashboard (Vercel, Netlify, etc.).

Step 4 — Wire the webhook

Now that your application has a working /api/moncash/webhook route, you need to tell MonCashConnect where to send it.

  1. Go back to moncashconnect.com/developer.
  2. Click the "Projects" tab.
  3. Click the "⋯" (three dots) to the right of your project, then "Edit".
  4. In Webhook URL, paste the full URL: for example https://my-shop.com/api/moncash/webhook.
  5. Make sure Allowed domains contains the domain your client page will call /api/moncash/create from.
  6. Click "Save".

Test before going to production

On the /developer page, at the bottom, there's a "Webhook Tester" section. You can send a test event to your URL, check that your code answers 200, and inspect the received signature. Use this before pushing to production.

To test locally (without deploying), use ngrok or cloudflared as explained in /guides/webhook-testing.

Step 5 — Verification checklist

Tick every box before announcing your integration to real users:

Security
My `.env.local` is in `.gitignore` and has NEVER been committed.
Security
My keys have not appeared in ANY Lovable / Claude / ChatGPT message.
Security
My keys are stored in a password manager.
Security
No source file contains `sk_proj_…` or `whsec_…` hardcoded.
Security
No `NEXT_PUBLIC_MCC_*` or `VITE_MCC_*` variable exists (these prefixes expose to the client).
Config
My project has a webhook URL configured in /developer → Projects.
Config
My webhook URL is HTTPS (not HTTP).
Config
My allowed domains include the production domain.
Test
The Webhook Tester on /developer returns 200 against my endpoint.
Test
I tested a real 1 HTG payment end-to-end.
Test
The payment.completed event marked my order as paid.
Test
If I replay the webhook (re-run in the Tester), my order stays in the same state (idempotent).
Prod
My MCC_SECRET_KEY and MCC_WEBHOOK_SECRET variables are in my host's production environment.
Prod
The production deploy restarts after the variables are added.
Prod
My MCC plan supports the expected monthly volume (see /pricing).

What you must NEVER do (or you'll lose your money)

Never paste your secret key into the chat

Lovable, Claude, ChatGPT, Bolt — they all store history. A key that appears once in a chat is compromised. Revoke it immediately.

Never prefix a variable with NEXT_PUBLIC_, VITE_, PUBLIC_, or REACT_APP_

Those prefixes inject the value into the JavaScript bundle shipped to the browser. Anyone can read it with View Source. Just use MCC_SECRET_KEY (no public prefix).

Never commit .env, .env.local, or a secrets.json file

Check your .gitignore before any git push. If you committed by accident, revoke the key immediately on /developer and generate a new one — Git history doesn't disappear.

Don't set your webhook URL to HTTP (without the S)

MonCashConnect will refuse to sign properly, and any public wifi network can read or rewrite the requests. HTTPS is mandatory.

Don't disable the webhook HMAC verification

Without verification, anyone can send a fake "payment.completed" to your endpoint and mark an order as paid without paying.

Don't store the keys in your app's database

Environment variables only. A leaking database must not leak your MCC secrets.

Don't share your Lovable / Claude project with someone without rotating the keys

Collaborators have access to the secrets configured on the project. If you invite then un-invite, rotating is safer.

Don't use the same key on staging and production

Create TWO separate MCC projects ("My-Shop-Staging" and "My-Shop-Prod"), each with its own keys. If staging leaks, prod stays safe.

If a key leaks

  1. Go immediately to moncashconnect.com/developer.
  2. "Projects" tab → ⋯ → "Rotate keys"(or delete and recreate the project).
  3. Copy the new key and the new secret.
  4. Update the environment variables at your host.
  5. Redeploy. The old key is revoked immediately — any future request using it fails with 401.
  6. If you see suspicious payments or withdrawals, contact support at support@moncashconnect.com.