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
amountnumber✅Amount in INR (e.g. 5000 for ₹5000)
currencystring✅Always "INR" for now
customer.namestring✅Customer full name
customer.emailstring✅Customer email address
customer.phonestring✅10-digit mobile number
descriptionstring❌Short description shown on checkout
metadataobject❌Any JSON data to associate with this payment
returnUrlstring❌Where to redirect after payment (overrides default)
webhookUrlstring❌Where 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.