MenuCashfree

Revenue attribution

Cashfree

Connect Cashfree with your client id and secret so ProductLense records every payment, refund and chargeback in INR, with the exact fee and GST Cashfree kept.

ProductLense reads your Cashfree Payment Gateway payments, refunds, chargebacks and subscriptions, with the exact service charge on each payment. ProductLense only reads: it never creates orders, refunds, captures or changes anything in your Cashfree account.

What you need

FieldSecretWhere to find it
Client IDNoCashfree Merchant Dashboard → Developers → API Keys (Payment Gateway).
Client secretYesThe secret paired with the client id. Cashfree also signs webhooks with it, so there is no separate webhook secret.
ModeNoproduction, or sandbox for test keys.

Every plan includes one billing connection per site, Free too; Growth and Scale allow any number. See plans and limits.

Permissions

Cashfree API keys are not scoped; ProductLense only reads with yours. It calls one endpoint, POST /pg/recon (PG reconciliation), which returns the ledger of payments, refunds and chargebacks for a date range.

Set up

  1. In the Cashfree Merchant Dashboard, open Developers → API Keys and copy the Payment Gateway client id and secret.
  2. In ProductLense, open your site's Settings → Billing connections → Cashfree, paste them, set the mode and click Connect and import history.
  3. Copy the webhook URL from the connection card.
  4. In Cashfree, open Developers → Webhooks, add an endpoint with that URL and subscribe to the events below. Include Success Payment TDR so each payment's fee arrives the next day.

Webhook

URL: https://api.productlense.app/api/webhooks/cashfree/<connection-id> (ProductLense shows the exact URL after you save).

Events ProductLense uses:

  • PAYMENT_SUCCESS_WEBHOOK, PAYMENT_FAILED_WEBHOOK, PAYMENT_USER_DROPPED_WEBHOOK
  • PAYMENT_CHARGES_WEBHOOK (Success Payment TDR: the fee)
  • REFUND_STATUS_WEBHOOK
  • SUBSCRIPTION_STATUS_CHANGED, SUBSCRIPTION_PAYMENT_SUCCESS, SUBSCRIPTION_PAYMENT_FAILED, SUBSCRIPTION_REFUND_STATUS

Verification: the x-webhook-signature header, a base64 HMAC-SHA256 of the x-webhook-timestamp value followed by the raw body, with your client secret. Deliveries whose timestamp is more than five minutes old are refused, and replays are recognised by the signed body.

What ProductLense reads

  • Customers: the customer on each order. ProductLense keys a payer by your customer_id, else their email, else their phone number.
  • Subscriptions: status, plan amount and interval from subscription webhooks. Cashfree has no API that lists subscriptions, so they appear from the first subscription event after you connect. Their payments are in the history either way.
  • Payments: successful payments count as revenue. Failed and dropped attempts are kept with status failed and add nothing to revenue. The small mandate authorisation charge of a subscription is not counted.
  • Refunds and chargebacks: processed refunds and chargebacks reduce revenue on the day they happen.
  • History: the last 12 months on first connect, read from the reconciliation ledger in 30-day slices, then a nightly reconcile at 03:00 UTC from the last sync minus 48 hours.

INR amounts stay in INR and are also converted to USD at the European Central Bank rate for the payment's day.

How fees are derived

The fee is Cashfree's service charge (TDR) plus the GST on it, as Cashfree reports them. It is exact, not estimated. Cashfree computes it after the payment, so a payment first appears with no fee and gets its fee from the charges webhook or the next nightly reconcile.

Match payments to visitors

ProductLense reads ids from the order's order_tags: pl_user_id, user_id, userId or uid for your user id, and pl_visitor_id for a ProductLense visitor id. Use the same user id you pass to identify. Without them, ProductLense falls back to the customer email, matched to the email trait sent with identify.

Cashfree order with order_tags (Node)
await fetch('https://api.cashfree.com/pg/orders', {
  method: 'POST',
  headers: {
    'x-client-id': process.env.CASHFREE_CLIENT_ID,
    'x-client-secret': process.env.CASHFREE_CLIENT_SECRET,
    'x-api-version': '2025-01-01',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    order_amount: 2499,
    order_currency: 'INR',
    order_tags: { pl_user_id: user.id },
    customer_details: { customer_id: user.id, customer_email: user.email, customer_phone: user.phone },
  }),
});

For subscriptions, put the same keys in subscription_tags.

Limits

  • Disputes, refund reversals and other ledger adjustments are not counted; chargebacks are.
  • Auto-refunds of failed attempts are not counted, because the attempt never counted as revenue.

See how payments are attributed.

    ↑ ↓ to move, Enter to open