5Verifying Payment Status
After payment completion or when a customer returns to your application, you may need to verify the payment status in your database to show the appropriate confirmation or error page.
Payment Verification Implementation
Implement a payment verification function to check the status:
// In your return route or payment verification endpoint
import { PrismaClient, PaymentStatus } from "@prisma/client";
import type { LoaderFunctionArgs } from "react-router";
const prisma = new PrismaClient();
export const loader = async ({ params }: LoaderFunctionArgs) => {
const { referenceId } = params;
try {
// Fetch payment from database
const payment = await prisma.payment.findUnique({
where: { externalId: referenceId },
include: {
paymentMethod: true,
statusHistory: {
orderBy: { createdAt: "desc" },
take: 5,
},
},
});
if (!payment) {
return {
success: false,
status: "NOT_FOUND",
message: "Payment not found",
};
}
// Prepare response based on payment status
let message, details;
switch (payment.status) {
case PaymentStatus.COMPLETED:
message = "Payment completed successfully";
details = {
paymentDate: payment.paidAt,
transactionId: payment.transactionId,
};
break;
case PaymentStatus.PROCESSING:
message = "Payment is still processing";
details = {
lastUpdated: payment.updatedAt,
};
break;
case PaymentStatus.FAILED:
message = "Payment failed";
details = {
reason: payment.statusHistory[0]?.notes || "Unknown error",
failedAt: payment.updatedAt,
};
break;
case PaymentStatus.CANCELLED:
message = "Payment was cancelled";
details = {
cancelledAt: payment.updatedAt,
};
break;
default:
message = `Payment status: ${payment.status}`;
details = {
lastUpdated: payment.updatedAt,
};
}
return {
success: true,
status: payment.status,
message,
details,
payment: {
id: payment.id,
externalId: payment.externalId,
amount: payment.amount,
currency: payment.currency,
createdAt: payment.createdAt,
updatedAt: payment.updatedAt,
description: payment.description,
}
};
} catch (err) {
console.error("Payment verification error:", err);
return {
success: false,
status: "ERROR",
message: "Failed to verify payment",
};
}
};Payment Status Handling
Here's how to handle different payment statuses:
COMPLETED
Payment has been successfully processed
Handling:
- Update order status to 'paid'
- Send confirmation email to customer
- Trigger order fulfillment process
PROCESSING
Payment is being processed by the payment gateway
Handling:
- Display waiting message to customer
- Provide estimated processing time
- Enable status checking functionality
FAILED
Payment attempt was unsuccessful
Handling:
- Show specific failure reason to customer
- Offer retry options with alternative payment methods
- Provide support contact information
CANCELLED
Payment was cancelled by customer or merchant
Handling:
- Release reserved inventory
- Provide option to restart checkout
- Log cancellation reason for analytics
REFUNDED
Payment was refunded to customer
Handling:
- Update order status to 'refunded'
- Send refund confirmation email
- Record refund reason for reporting
Direct API Verification
Alternatively, you can verify payment status directly with the SaligPay API:
// Alternative: Verify directly with SaligPay APIBest Practice: Always verify payment status on your server before providing access to purchased goods or services. Relying solely on client-side verification is not secure as it could be manipulated.
Displaying Payment Result
In your return page component, display appropriate messages based on the payment status:
import { useLoaderData, Link } from "react-router";
export default function PaymentReturn() {
const { success, payment, status, message } = useLoaderData();
if (!success) {
return (
<div className="error-container">
<h2>Payment Verification Failed</h2>
<p>{message || "Unable to verify payment status"}</p>
<Link to="/">Return to Home</Link>
</div>
);
}
// Render based on payment status
return (
<div className="payment-result">
<h2>Payment {payment.status}</h2>
<p>{payment.message}</p>
{payment.status === "COMPLETED" && (
<div className="success-details">
<p>Thank you for your payment!</p>
<p>Transaction ID: {payment.details.transactionId}</p>
<p>Amount: {"$" + (payment.amount / 100).toFixed(2)}</p>
</div>
)}
{payment.status === "FAILED" && (
<div className="failure-details">
<p>We encountered an issue with your payment:</p>
<p>{payment.details.reason}</p>
<Link to="/payment" className="retry-button">
Try Again
</Link>
</div>
)}
<Link to="/">Return to Home</Link>
</div>
);
}