SolveEase Pay — Integration Guide

For product developers integrating with pay.solveease.in


Overview

SolveEase Pay handles your payment collection in 3 simple steps:

  1. Create an order → your backend calls our API → we return a paymentUrl
  2. Redirect the customer → send the customer to paymentUrl
  3. Receive confirmation → we call your webhook + redirect customer back

Prerequisites

  1. Request an API key from the SolveEase DevOps team
  2. Store it securely as an environment variable — never expose in frontend code
  3. Set up a webhook endpoint in your product that can receive HTTPS POST requests

Step 1: Create an Order

Call our API from your backend (server-side only):

// Example: Node.js / Next.js API route

const response = await fetch('https://pay.solveease.in/api/v1/orders', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.SOLVEEASE_PAY_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    amount: 5000,             // Amount in INR (₹5000)
    currency: 'INR',
    customer: {
      name: 'Priya Sharma',
      email: 'priya@example.com',
      phone: '9876543210',   // 10-digit Indian mobile
    },
    description: 'Mridu AI Pro - Monthly Subscription',
    metadata: {
      // Anything you need to identify this payment in your system
      userId: 'usr_abc123',
      planId: 'pro_monthly',
      subscriptionId: 'sub_xyz',
    },
    returnUrl: 'https://mridu-ai.com/billing/success',
    webhookUrl: 'https://mridu-ai.com/api/payments/webhook',
  }),
});

const { orderId, paymentUrl } = await response.json();
// Save orderId in your DB, redirect customer to paymentUrl

Request Body

FieldTypeRequiredDescription
amountnumberAmount in INR (e.g. 5000 for ₹5000)
currencystringAlways "INR" for now
customer.namestringCustomer full name
customer.emailstringCustomer email address
customer.phonestring10-digit mobile number
descriptionstringShort description shown on checkout
metadataobjectAny JSON data to associate with this payment
returnUrlstringWhere to redirect after payment (overrides default)
webhookUrlstringWhere to send payment events (overrides default)

Response

{
  "orderId": "se_ord_abc123def456",
  "paymentUrl": "https://pay.solveease.in/pay/se_ord_abc123def456",
  "expiresAt": "2026-08-03T15:05:00Z"
}

Step 2: Redirect the Customer

Redirect your customer to the paymentUrl. SolveEase Pay will show a branded checkout page.

// Next.js Server Action or API route
redirect(paymentUrl);

// Or client-side
window.location.href = paymentUrl;

The checkout page will:

  • Show your product's branding (logo from your tenant config)
  • Offer multiple payment methods (Card, UPI, Net Banking, Wallets)
  • Handle the full Cashfree payment flow

Step 3: Receive Payment Confirmation

Option A: Webhook (Recommended)

We will POST to your webhookUrl after payment completes:

// Your webhook endpoint

import crypto from 'crypto';

export async function POST(req: Request) {
  const body = await req.text();
  const signature = req.headers.get('x-solveease-signature');

  // VERIFY THE SIGNATURE (critical for security!)
  const expectedSig = crypto
    .createHmac('sha256', process.env.SOLVEEASE_WEBHOOK_SECRET!)
    .update(body)
    .digest('hex');

  if (signature !== expectedSig) {
    return new Response('Unauthorized', { status: 401 });
  }

  const event = JSON.parse(body);

  switch (event.event) {
    case 'payment.success':
      // Activate subscription, send receipt, etc.
      await activateSubscription(event.metadata.subscriptionId);
      break;
    case 'payment.failed':
      // Handle failure
      break;
  }

  return new Response('OK', { status: 200 });
}

Webhook Payload

{
  "event": "payment.success",
  "orderId": "se_ord_abc123def456",
  "amount": 5000,
  "currency": "INR",
  "paidAt": "2026-08-02T15:10:00Z",
  "customer": {
    "name": "Priya Sharma",
    "email": "priya@example.com",
    "phone": "9876543210"
  },
  "metadata": {
    "userId": "usr_abc123",
    "subscriptionId": "sub_xyz"
  }
}

Events: payment.success | payment.failed | payment.expired

Option B: Poll the Status API

const status = await fetch(
  `https://pay.solveease.in/api/v1/orders/${orderId}`,
  {
    headers: { Authorization: `Bearer ${API_KEY}` }
  }
).then(r => r.json());

// status.status: 'PENDING' | 'ACTIVE' | 'PAID' | 'FAILED' | 'EXPIRED'

Error Handling

HTTP StatusCodeMeaning
400VALIDATION_ERRORInvalid request body
401UNAUTHORIZEDMissing or invalid API key
403FORBIDDENTenant is disabled
429RATE_LIMITToo many requests (100/min limit)
500INTERNAL_ERRORServer-side error

Testing

Use these test credentials in your integration:

  • Test API Key: Provided by DevOps team per environment
  • Cashfree Sandbox Test Card: 4111111111111111, any future expiry, any CVV
  • UPI Test VPA: success@cashfree
  • Failure Test Card: 4000000000000002

Set your environment to point to our staging server:

SOLVEEASE_PAY_API_URL=https://staging.pay.solveease.in

FAQ

Q: Can I send the amount from the frontend?
A: No. The amount is fixed at order creation (server-side). The browser never controls the payment amount.

Q: How long is a payment link valid?
A: 24 hours by default.

Q: What happens if my webhook endpoint is down?
A: We retry up to 5 times with exponential backoff (1m, 5m, 30m, 2h, 12h).

Q: Can I issue refunds?
A: Refund support is coming in v1.1. Contact DevOps for manual refunds in the meantime.