Integrating Hosted Payment Pages
The Hosted Payment Page is a pre-built, secure payment interface hosted by Zoho Payments. Instead of embedding a checkout widget in your website, you redirect customers to a hosted page where they can complete their payment. Check out our API Docs for endpoint details and request examples.
Follow the steps below to integrate the hosted payment page.
1. Establish Communication
To communicate with our APIs and webhooks, you must first establish connectivity. Ensure that your setup allows or whitelists the Zoho Payments domain, payments.zoho.in.
2. Create Payment Session
To initiate the payment process, create a payment session on your server. The session captures the payment amount, currency, and hosted page configuration, including redirect URLs and customer details. Based on your payment type, you can create the session for one-time or recurring payments.
Payment Session for One-time Payments
To accept a one-time payment through the hosted payment page, create a payment session and follow the steps below to obtain the payment_session_id.
-
Collect the payment details (amount, currency, etc.) and the hosted page parameters (success or failure URLs, customer info) from your application.
-
Call the Payment Session Create API from your server. Include the
hosted_page_parametersobject within theconfigurationsfield.
The API will return a response containing a payment_session_id and an access_key. Use the access_key to construct the hosted page URL and redirect the customer to complete the payment.
Create Customer
Collect customer details (name, email, phone, and metadata) and call the Create Customer API using the OAuth token.
The API will return a customer_id, which you can use to initiate a payment session for mandate enrollment.
Create Payment Session for Mandate Enrollment
Call the Create Payment Session for Mandate Enrollment API on your server using an OAuth token to obtain a payment_session_id.
The API will return a response containing a payment_session_id and an access_key. Use the access_key to construct the hosted page URL and redirect the customer to complete the payment.
{
"amount": "500",
"currency": "INR",
"configurations": {
"allowed_payment_methods": [
"upi"
],
"hosted_page_parameters": {
"phone": "7654345673",
"description": "Test Payment",
"email": "test@example.com",
"success_url": "https://example.com/success",
"failure_url": "https://example.com/failure",
"udf1": "testingudf1",
"udf2": "testingudf2",
"udf3": "testingudf3",
"udf4": "testingudf4",
"udf5": "testingudf5"
}
}
}
The hosted_page_parameters object supports the following fields:
| Parameter | Type | Required | Description |
|---|---|---|---|
success_url* |
String | Yes | The URL to redirect the customer to after a successful payment. |
failure_url* |
String | Yes | The URL to redirect the customer to after a failed payment. |
phone |
String | No | Customer’s phone number. |
email |
String | No | Customer’s email address. |
description* |
String | No | A brief description of the payment. |
udf1 – udf5 |
String | No | Custom fields for passing additional information. These values are returned in the redirect URL after payment completion. Do not pass any sensitive information in these fields. |
*Indicates mandatory fields.
Notes:
-
The
max_retry_countis set to 1 by default for hosted pages. If you set a higher value via the Payment Session API, the customer gets multiple attempts to complete the payment. If you’re listening to thepayment.failedwebhook, note that it is triggered for each failed attempt, not once for the entire session. For example, if a payment attempt fails three times before succeeding, you’ll receive threepayment.failedwebhooks for that session. -
Once a payment is successful, the session is closed, and no further attempts are allowed. Ensure your server handles these webhook events correctly to determine the final payment status.
- The API will return a response containing an
access_key. Use this key to construct the hosted page URL in the next step.
{
"code": 0,
"message": "success",
"payments_session": {
"access_key": "8VMvUrsh2WdUpkwGaiM4SAfPrP-RgbD3s2OFZ-Y0Uw",
"configurations": {
"allowed_payment_methods": [
"upi",
"card"
],
"hosted_page_parameters": {
"phone": "7654345673",
"description": "Test Payment",
"failure_url": "https://example.com/failure",
"udf1": "testingudf1",
"udf2": "testingudf2",
"udf3": "testingudf3",
"udf4": "testingudf4",
"udf5": "testingudf5",
"email": "test@example.com",
"success_url": "https://example.com/success"
}
},
"payments_session_id": "9324000001068001",
"currency": "INR",
"amount": "5.00",
"created_time": 1774939546,
"expiry_time": 1774940446,
"meta_data": []
}
}
3. Redirect Customer
After creating the payment session, redirect the customer to the hosted payment page using the access_key from the response.
https://payments.zoho.in/hostedpages/<access_key>
https://payments.zoho.in/hostedpages/8VMvUrsh2WdUpkwGaiM4SAfPrP-RgbD3s2OFZ-Y0Uw
The customer will be able to choose a payment method and complete their payment.
4. Handle Payment Outcome
Once the customer completes the payment, they are redirected to either the success_url or failure_url you provided during session creation, based on the payment outcome:
- Succeeded: The customer is redirected to the
success_url. - Failed: The customer is redirected to the
failure_url. - In Progress: Applicable for bank transfers. The customer is redirected to the
success_url. You can verify the final payment status using configured webhooks.
The redirect URL includes the following query parameters:
| Parameter | Type | Always Present | Description |
|---|---|---|---|
payments_session_id |
String | Yes | The unique identifier assigned to the payment session. |
payment_session_status |
String | Yes | The status of the session: succeeded, failed, or in_progress (bank transfers). |
payment_id |
String | No | The unique identifier of the payment transaction. The payment_id is not returned when the status is in_progress (bank transfers). |
payment_status |
String | No | The payment status: succeeded or failed. |
amount |
String | No | The amount charged (e.g., 1200.00). |
mandate_id |
String | No | The unique identifier assigned to the mandate, if applicable. |
udf1 – udf5 |
String | No | Custom fields passed during session creation. |
signature |
String | Yes | HMAC-SHA256 signature for verification. |
Note: In some cases, you may not receive the payment_id if the customer accidentally closes the browser or navigates away before a response is returned. In such cases, use your configured webhooks or the payment_session_id to retrieve the payment status.
5. Verify Signature
To ensure the redirect is authentic and has not been tampered with, verify the signature parameter included in the return URL. The signature is an HMAC-SHA256 hash computed over key parameters. To verify the signature:
- Concatenate the following fields with
.(dot) as the separator, in this exact order. Use an empty string for any absent field.
payments_session_id.payment_session_status.payment_id.payment_status.amount.mandate_id.udf1.udf2.udf3.udf4.udf5
-
Use your signing key to compute the HMAC-SHA256 hash of the message string constructed in the previous step.
-
Compare the computed hash with the
signatureparameter from the redirect URL.
For example, a successful payment returns the following URL:
https://example.com/success?payments_session_id=4000000106013&payment_session_status=succeeded&payment_id=4000000106034&payment_status=succeeded&amount=5.000&udf1=customerid1234&udf2=orderref5678&udf3=productskuabc&udf4=merchantrefxyz&udf5=campaignsummer24&signature=81515cc0deb8f0d95cc4a4cb755bbef33aa7fa068325756df5b4e360a2b3a0d2
The message to sign would be:
4000000106013.succeeded.4000000106034.succeeded.5.000..customerid1234.orderref5678.productskuabc.merchantrefxyz.campaignsummer24
Note: Absent fields such as mandate_id contribute an empty string. Their dot separators are still included.
Insight: Always verify the signature on your server before trusting the payment status from the redirect URL. This prevents tampering and ensures the payment outcome is authentic.
6. Verify Payment Status
You can verify your payment status in two ways:
-
Verify via Webhooks: Use your configured webhooks for the events
payment.successandpayment.failedto receive the final payment status directly. -
Verify via Session ID: Use this method when the payment status is not received through the widget response or webhooks. This can happen in the following scenarios:
- The customer closes the payment widget before completion.
- The
payment.successorpayment.failedwebhooks are not configured. - Webhooks are temporarily inactive due to repeated delivery failures.
In such cases, retrieve the payment status using the Payment Session Retrieve API. This allows you to check the final outcome of the payment using the session ID.
Note: Ensure that all three options are configured for reliable payment verification.
Update your system only after verifying the payment status using any of the methods listed above.