coal
coal

Environments

Coal runs two environments: development (local) and production. The backend is a Next.js API application; the frontend is a separate Next.js application. Both must be running locally for full end-to-end development.


Environment Overview

EnvironmentFrontend URLBackend (API) URL
Developmenthttp://localhost:3000http://localhost:3001
Productionhttps://usecoal.xyzhttps://api.usecoal.xyz

Base URL in Code

typescript
1// Use the environment variable — never hardcode URLs
2const COAL_API_URL = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:3001';
3
4// Example request
5const res = await fetch(`${COAL_API_URL}/api/checkout/init`, {
6 method: 'POST',
7 headers: { 'Content-Type': 'application/json' },
8 body: JSON.stringify({ slug: 'my-product' }),
9});

Local Development Setup

Prerequisites

  • Node.js 20+
  • A PostgreSQL database (we use Neon — the free tier is sufficient)
  • Optional: an Upstash Redis instance for rate limiting (the app runs fine without it using an in-memory fallback)

1. Clone the Repository

bash
1git clone https://github.com/your-org/coal.git
2cd coal

2. Install Dependencies

bash
1# Install backend dependencies
2cd backend && npm install
3
4# Install frontend dependencies
5cd ../frontend && npm install

3. Configure Environment Variables

Copy the example files and fill in your values:

bash
1cp backend/.env.example backend/.env.local
2cp frontend/.env.example frontend/.env.local

Then edit each file — see the variable reference tables below.

4. Push the Database Schema

bash
1cd backend
2npx prisma db push

This creates all tables in your PostgreSQL database. No migration files are generated — db push is used for rapid development iteration.

5. Start Both Servers

bash
1# Terminal 1 — backend API on port 3001
2cd backend && npm run dev
3
4# Terminal 2 — frontend on port 3000
5cd frontend && npm run dev

Open http://localhost:3000 to see the app.


Environment Variables

Backend (backend/.env.local)

VariableDescriptionExample
DATABASE_URLNeon PostgreSQL connection stringpostgresql://user:pass@host/db?sslmode=require
ALCHEMY_API_KEYAlchemy API key for Base RPC accessabc123xyz...
NEXT_PUBLIC_API_URLPublic URL of this backendhttp://localhost:3001
NEXT_PUBLIC_APP_URLPublic URL of the frontendhttp://localhost:3000
NEXT_PUBLIC_FRONTEND_URLAlias for frontend URL (used in emails)http://localhost:3000
CRON_SECRETSecret for authenticating cron job callsAny random string
UPSTASH_REDIS_REST_URLUpstash Redis endpoint for rate limitinghttps://your-db.upstash.io
UPSTASH_REDIS_REST_TOKENUpstash Redis auth tokenAXxx...
RESEND_API_KEYResend API key for transactional emailre_abc123...
UPLOADTHING_SECRETUploadThing secret for file uploadssk_live_...
UPLOADTHING_TOKENUploadThing tokeneyJ...
PRIVY_APP_IDPrivy application IDclxxxxxxxxxxxxxxx
PRIVY_APP_SECRETPrivy application secretyour-privy-secret
CHAIN_ENVChain selector: testnet = Base Sepolia, unset = Base mainnettestnet
SETTLEMENT_TOKEN_ADDRESSOptional custom settlement token address on Base0xYourTokenAddress
SETTLEMENT_TOKEN_DECIMALSSettlement token decimal places6
SETTLEMENT_TOKEN_SYMBOLToken symbol shown in UI and receiptsUSDC
SETTLEMENT_TOKEN_NAMEHuman-readable token nameUSDC
MNEE_BASE_ADDRESSLegacy alias for SETTLEMENT_TOKEN_ADDRESS0xYourTokenAddress
MNEE_BASE_DECIMALSLegacy alias for SETTLEMENT_TOKEN_DECIMALS6
GOOGLE_CLIENT_IDGoogle OAuth client IDxxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRETGoogle OAuth client secretGOCSPX-...

Frontend (frontend/.env.local)

VariableDescriptionExample
NEXT_PUBLIC_API_URLBackend API base URLhttp://localhost:3001
NEXT_PUBLIC_APP_URLFrontend base URLhttp://localhost:3000
NEXT_PUBLIC_PRIVY_APP_IDPrivy app ID (public — safe to expose)clxxxxxxxxxxxxxxx
NEXT_PUBLIC_CHAIN_ENVChain environment for frontend wallettestnet
NEXT_PUBLIC_SETTLEMENT_TOKEN_ADDRESSPublic settlement token contract address0xYourTokenAddress
NEXT_PUBLIC_SETTLEMENT_TOKEN_DECIMALSSettlement token decimals for display formatting6
NEXT_PUBLIC_SETTLEMENT_TOKEN_SYMBOLSymbol displayed in the checkout UIUSDC
NEXT_PUBLIC_SETTLEMENT_TOKEN_NAMEFull token name displayed in the checkout UIUSDC
NEXT_PUBLIC_MNEE_BASE_ADDRESSLegacy alias for NEXT_PUBLIC_SETTLEMENT_TOKEN_ADDRESS0xYourTokenAddress
NEXT_PUBLIC_MNEE_BASE_DECIMALSLegacy alias for NEXT_PUBLIC_SETTLEMENT_TOKEN_DECIMALS6
NEXT_PUBLIC_MOONPAY_API_KEYMoonPay publishable key used to expose the card-funding option in the checkout UIpk_test_...
NEXT_PUBLIC_MOONPAY_ENVMoonPay modesandbox or production
NEXT_PUBLIC_CARD_PAYMENTS_STATUSCard rail visibility modecoming_soon or live
UPLOADTHING_SECRETUploadThing secret (server-side routes)sk_live_...
UPLOADTHING_TOKENUploadThing tokeneyJ...

Chain Configuration

Coal's backend verifies payments on the Base blockchain (an Ethereum L2). Two networks are supported:

CHAIN_ENV valueNetworkChain IDBlock Explorer
testnetBase Sepolia84532https://sepolia.basescan.org
(unset)Base Mainnet8453https://basescan.org

During development, set CHAIN_ENV=testnet in both your backend and frontend .env.local files. This routes all on-chain verification to Base Sepolia so you can test with a non-production settlement token without spending real funds.

Important: Your settlement token contract address can differ between mainnet and testnet. Always set SETTLEMENT_TOKEN_ADDRESS and NEXT_PUBLIC_SETTLEMENT_TOKEN_ADDRESS to the correct contract for your current CHAIN_ENV. Legacy MNEE_* names still work if you already use them, but new integrations should prefer the settlement-token variables.

MoonPay uses a server-signed funding session behind the scenes. The frontend only needs the publishable key to show the card path. The backend still needs:

  • MOONPAY_PUBLISHABLE_KEY
  • MOONPAY_SECRET_KEY
  • MOONPAY_WEBHOOK_API_KEY
  • MOONPAY_ENV

Coal stays non-custodial: MoonPay funds the payer wallet first, and Coal only completes the merchant payment after the payer signs the onchain transfer from that wallet.


Production Deployment

Coal is designed to deploy on Vercel. Both the backend and frontend are standard Next.js applications and can be deployed independently.

Set all environment variables in Vercel → Project → Settings → Environment Variables. Never commit .env.local or any file containing secrets to version control.

For the cron job (/api/cron/verify-payments), configure a Vercel Cron or external scheduler to POST to that endpoint every minute with:

text
1Authorization: Bearer <your CRON_SECRET>

The cron job is what transitions sessions from verifying to confirmed — if it stops running, payments will remain in verifying indefinitely.