This is a merchant walkthrough app for testing Cashfree Payment Gateway integration with:
- Cashfree Java Backend SDK:
com.cashfree.pg.java:cashfree_pg - Cashfree JS checkout on the frontend
- Return URL flow with backend status polling
- Transaction detail fetch using
PGOrderFetchPayments
The browser never receives the Cashfree client secret. The frontend only receives the payment_session_id returned by the backend after order creation.
- Java 17 or later
- Gradle installed
- Cashfree sandbox or production credentials
- A reachable
app.base-urlfor return URL testing
For local testing, http://localhost:8080 is enough. For hosted or production testing, use an HTTPS public URL.
All merchant-controlled values are in:
config/cashfree-demo.properties
Update this file before running the app:
server.port=8080
app.base-url=http://localhost:8080
cashfree.environment=SANDBOX
cashfree.client-id=your_cashfree_client_id
cashfree.client-secret=your_cashfree_client_secret
cashfree.sdk-version=5.0.1
cashfree.sdk-type=Java Backend SDKImportant:
cashfree.client-idandcashfree.client-secretmust match the selected environment.app.base-urlis used to build the Cashfreereturn_url.cashfree.sdk-versioncontrols the backend SDK dependency version. Rebuild after changing it.- Do not commit real credentials.
config/cashfree-demo.propertiesis ignored by git.
Use sandbox credentials:
cashfree.environment=SANDBOX
cashfree.client-id=your_sandbox_client_id
cashfree.client-secret=your_sandbox_client_secret
app.base-url=http://localhost:8080Start the app:
gradle bootRunOpen:
http://localhost:8080
If port 8080 is already in use, change:
server.port=8081
app.base-url=http://localhost:8081Then restart the app.
- Open the demo app.
- Enter a custom order ID or click Generate.
- Enter the amount.
- Click Create Order and Pay.
- Backend creates an order using
PGCreateOrder. - Frontend opens Cashfree JS checkout using
payment_session_id. - Cashfree redirects the customer to:
{app.base-url}/return.html?order_id={order_id}
- Return page polls:
GET /api/orders/{orderId}/status
- Backend calls:
PGFetchOrder
PGOrderFetchPayments
- Return page displays order status and transaction details.
The return URL page shows:
- Order ID
- Current status
- Cashfree Transaction ID from
cf_payment_id - Bank UTR from
bank_reference - Payment Mode from
payment_group - Payment Time from
payment_time - Failed Reason from
payment_message, only whenpayment_statusisFAILED
Payment outcome logic follows the Cashfree payments response:
if (payments.some(transaction => transaction.payment_status === "SUCCESS")) {
orderStatus = "Success";
} else if (payments.some(transaction => transaction.payment_status === "PENDING")) {
orderStatus = "Pending";
} else {
orderStatus = "Failure";
}When moving from sandbox to production, update config/cashfree-demo.properties:
cashfree.environment=PRODUCTION
cashfree.client-id=your_production_client_id
cashfree.client-secret=your_production_client_secret
app.base-url=https://your-production-domain.exampleProduction checklist:
- Use production Cashfree credentials, not sandbox credentials.
- Use
cashfree.environment=PRODUCTION. - Use an HTTPS
app.base-url. - Make sure the production domain can serve
/return.html. - Make sure the server can reach
https://api.cashfree.com. - Restart the app after changing config.
- Test with a small amount first.
Environment mapping:
| Config value | Cashfree API host |
|---|---|
SANDBOX |
https://sandbox.cashfree.com/pg |
PRODUCTION |
https://api.cashfree.com/pg |
The backend SDK version is controlled by:
cashfree.sdk-version=5.0.1Use only a version published to Maven Central. After changing it, rebuild:
gradle clean bootJarThen run:
java -jar build/libs/cashfree-pg-java-demo-0.0.1-SNAPSHOT.jarFor deployed environments, you can also override configuration with environment variables:
export CASHFREE_CLIENT_ID="your_client_id"
export CASHFREE_CLIENT_SECRET="your_client_secret"
export CASHFREE_ENVIRONMENT="SANDBOX"
export APP_BASE_URL="https://your-demo-domain.example"
export PORT="8080"Then run:
gradle bootRunor:
gradle clean bootJar
java -jar build/libs/cashfree-pg-java-demo-0.0.1-SNAPSHOT.jarGET /api/config
GET /api/orders/generate-id
POST /api/orders
GET /api/orders/{orderId}/status
/api/config is useful to confirm the app is reading the intended SDK version and environment. It does not expose client secrets.
- Never put
client_secretin frontend JavaScript. - Never commit real credentials.
- Rotate any credential accidentally shared in chat, screenshots, logs, or commits.
- Use HTTPS for production return URLs.
- Keep server error stack traces disabled in production.
- Treat this demo as a walkthrough app, not a complete production checkout system.
If transaction fields are blank on the return page:
- Restart the app after code or config changes.
- Hard refresh the browser with
Cmd + Shift + R. - Confirm
/api/orders/{orderId}/statusreturns apaymentobject. - Wait a few seconds; the return page polls while Cashfree transaction details are becoming available.
- Confirm the order ID in the return URL matches the created order.
- Confirm credentials match the configured environment.
If the app does not start:
- Check whether the configured port is already in use.
- Change
server.portandapp.base-urltogether. - Rebuild if you changed
cashfree.sdk-version.