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.com.
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. To create a payment session:
-
Collect the payment details (amount, currency, etc.) and the hosted page parameters (success/failure URLs, customer info) from your application.
-
Call the Payment Session Create API from your server. Include the
hosted_page_parametersobject within theconfigurationsfield.
{
"amount": "500",
"currency": "USD",
"configurations": {
"allowed_payment_methods": [
"ach",
"card"
],
"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": [
"ach",
"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": "USD",
"amount": "500.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.com/hostedpages/<access_key>
https://payments.zoho.com/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 ACH transfers. The customer is redirected to the
success_url. You can verify the 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 (ACH). |
payment_id |
String | No | The unique identifier assigned to the payment transaction. The payment_id is not returned when the status is in_progress (ACH). |
payment_status |
String | No | The payment status: succeeded or failed. |
amount |
String | No | The amount charged (e.g., 1200.00). |
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.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
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.success and payment.failed to 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.