Skip to main content

Generate the Digital Signature for Payment Pages 2.0


Generate the Digital Signature for Payment Pages 2.0

This article describes how to generate the digital signature for the Payment Pages 2.0.

Request the Digital Signature

The REST API used in Payment Pages 2.0 is CORS (Cross-Origin Resource Sharing) enabled and therefore requires a digital signature. You need to pass the generated signature to your client for it to access Payment Pages 2.0.

To generate the digital signature and token for your Payment Pages 2.0 form, you can use one of the following methods.

  • Use the Generate RSA signature REST API. 
  • Submit a Zuora CORS REST request to the Zuora server in your local client.

The CORS REST response contains a token, a signature, and a public key. The following information is required for the request:

Here is a sample Curl request to generate a token and a digital signature.

curl -i -k -H "" -H "apiSecretAccessKey:password" -H "Accept:application/json" -H "Content-Type:application/json" -X POST -d '
   "uri": "",
   "method": "POST",

Manage Token Issuance

Zuora provides tools to detect and manage fraudulent and malicious use of Payment Pages once the iFrame is rendered. The token issuance process is entirely under your control and therefore it is important that you manage the token issuance process to reduce potential fraud.

An issued token is permission to submit a credit card for validation/payment. To avoid potential credit card fraud attacks, you should secure your Payment Pages from being accessed by fraudulent users before you issue client-side digital signatures and tokens. For example, implement bot detection, risk scoring, and/or two-step registration workflow for new customers, and limit the number of times one registered account can render or refresh the payment page (i.e. manage token issuance). Impacts of this type of fraud can include charges for declined validations from payment gateways and being blocked from transactions by card brands.

Validate Client-side HPM Parameters

The Client-side HPM Parameter Validation feature is supported to better protect the client-side HPM parameter in the request for rendering or submitting Payment Pages 2.0. 

When receiving such a request, Zuora validates the client parameters in this request by comparing with the value specified in the digital signature. Therefore, you have to specify these parameters when calling the REST Generate RSA signature operation to generate the digital signature.

When specifying the client parameters in the Generate RSA signature operation, if the parameter name contains field_ , use only the string after field_ as the field name. For example, field_currency is a supported client parameter. In the Generate RSA signature operation, use currency  instead of field_currency. The field name that can be supported by the Generate RSA signature operation is documented in the API Reference.

Note that the following client parameters in client parameters are not supported by the Client-side HPM Parameter Validation feature because they are only used to control the display in UI:

  • retainValues
  • countryBlackList
  • countryWhiteList

The url parameter is also not supported because it was already validated.

If the parameters contained in the rendering or submission request can match with the value specified in the digital signature, the validation succeeds. If they do not match, the validation fails. The Validate_Dynamic_Params_Failed error code is returned, and Zuora blocks the rendering or submission request. 

Zuora recommends that you enable the Client-side HPM Parameter Validation feature. See Configure Payment Pages 2.0 for how to enable this feature.

Here is a sample Curl request to generate a token and a digital signature. paymentGateway and localeare the client parameters specified for validation.

curl -i -k -H "" -H "apiSecretAccessKey:password" -H "Accept:application/json" -H "Content-Type:application/json" -X POST -d '
   "uri": "",
   "method": "POST",

Receive the Digital Signature

Write the server-side code to receive the digital signature for the Payment Pages 2.0 form. You need to pass the necessary information in the response to your client.

A successful call returns the following, all of which your client needs to load your Payment Pages form:

  • signature: Digital signature generated
  • token: Token generated
  • tenantId: ID of your Zuora tenant
  • key: Public key generated
  • success: True if the request is successful

Signature Expiration

Your Payment Page signature expires in the following scenario. When an expired signature is used, your user will receive the specified error code.

Page Load or Page Submit When Expires Error Code Returned
In the Payment Page load request When a Payment Page is not loaded within 30 minutes of the signature generation Invalid_Security error code
In the Payment Page load request When a signature is used by a Direct POST request Attempt_Exceed_Limitation
In the Payment Page load request When a signature is used to successfully render the page  Attempt_Exceed_Limitation
In the Payment Page submit request When the page is not submitted within 24 hours after its generation Invalid_Security error code
In the Payment Page submit request When a signature is used to submit page more than the threshold Attempt_Exceed_Limitation

If the signature expires, resend the request to get a new signature and validate again. 

If you are implementing a Payment Page with the Submit button outside, see Validate the Digital Signature for Payment Pages 2.0 for validating the digital signature in your callback page.

Prevent Multiple Renderings with One Signature 

You can render a Payment Page only once with one generated signature. To prevent multiple renderings, you need to enable the Prevent Multiple Renderings with One Signature feature by setting the Limit the number of submissions before blocking submission field value in the Payment Page to a positive integer. With this feature enabled, you need to regenerate a signature if you want to re-render a Payment Page in the callback page. One common case is that for the Inline Button Outside mode, your callback page is triggered when a submission fails. Usually, you would want to re-render the Payment Page. You need to generate a new signature for re-rendering. If you attempt to re-render the page with a used signature, an error will occur and the error message will be displayed on the Payment Page. 

Limit on Number of Payment Page Submissions 

You can enable this feature by setting a positive integer for the Limit the number of submissions before blocking submission field in the Zuora UI.  When an end-user hits this threshold by repeatedly submitting incorrect information on the Payment Page, they will see the error message and will be blocked from further submission. When the submission limit is reached, you need to provide your end-users with a way to re-render the page, which requires the regeneration of a signature.

See Advanced Security Measures for Payment Pages 2.0 for more information.

This submission limit is not applicable to the Inline Button Outside mode.

Checklist for signature generation

Go through the following checklist for signature generation:

  1. Generate a signature for each Payment Page render.
  2. Generate a signature in your callback code before re-rendering a Payment Page when a previous submission fails.
  3. Generate a signature for each Direct POST request.
  4. Customize the error message for the Attempt_Exceed_Limitation error code. See Error Handling for Payment Pages 2.0 for the steps.
  5. Provide a way for end users to re-render the Payment Page when they hit the limits.

Troubleshoot Failed Signature Validation

A signature validation failure could be a result of several possible causes. Examples are:

  • A failure caused by your implementation
  • If you are constructing the integration for the first time, check the process of validation in the following areas:
    • Did you use the correct username and password to send signature POST request? 
    • Was the signature request sent to the correct endpoint?
    • Was the POST response received successfully and parsed correctly?
    • Was the signature decrypted correctly? Debug the decryption action.
    • Were the correct parameters used to validate the signature?
  • If your integration has worked for a while before you started seeing validation failures, it may be a security issue. Perform security-related checks.
  • If none of the above is the cause of the signature validation failure, contact Zuora Global Support with the error message for help.

Sample Code to Generate the Digital Signature

Here is a sample code in Java that requests the digital signature and other information from Zuora:

package com.zuora.hpm;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.json.JSONObject;

public class SignatureTest {
    public static void main(String[] args) throws Exception {
        JSONObject requestObject = new JSONObject();
        requestObject.put("pageId", "2c92c0f849369b9401493aab4b111111");
        RequestEntity requestEntity = 
           new StringRequestEntity(
              requestObject.toString(), "application/json", "UTF-8");
        PostMethod postRequest = ​​​​​new PostMethod(
           "apiAccessKeyId", $ZuoraUserName);
        postRequest.addRequestHeader("apiSecretAccessKey", $ZuoraPassword);
        postRequest.addRequestHeader("Accept", "application/json");
        HttpClient httpClient = new HttpClient();
        if(httpClient.executeMethod(postRequest) != 200) {
            System.out.println("Fail to get signature.");
        byte[] res = postRequest.getResponseBody();
        JSONObject resultObject = new JSONObject(new String(res));
        String token = resultObject.getString("token");
        String key = resultObject.getString("key");
        String tenantId = resultObject.getString("tenantId");
        String signature = resultObject.getString("signature");
        Boolean success = resultObject.getBoolean("success");
        ​​​   "success: %s\n token: %s\n tenantId: %s\n signature: %s\n public key: %s\n", 
           success, token, tenantId, signature, key);   

The following is a sample response from the above request:

success: true
token: FZ8Xtefcm5qvZi3Fz4rvTWU0pMVbNCzq
tenantId: 123
signature: Oio9UxQ+sUfHXOy7K5sSyQ6QJNVkoHfPRoGdjlkY70q2dlAOKthpKaZPc8DIUhOY6Oz/jbP0bAiZsjW9fnEMLi43bUV5prBc5HE1urPN4LGFK/mlmXSOkKpTWXF0JnQSvyl57bQCLusd+LLpaSnraC1N3J/DsJQuGpyhCRQeZxM3lUKm/AWUiJAIgGPqiIsNKRj9eS5Zz03hPRajTzDPG00M3jiG8EX+a2MvptXjFc0lJK8eZz1g0/piLaFxNlhI59dJpxwhO0K0onE19EgJWHbkYJzxbi4UMoI6WOi9axa877Z6bijUqV9+F2DvVUdQb47Q2+56foIitKc1NtxCCZ6VuOF97JwjXdkr8oSqF7JKC55IVNyh7clCHziPag2q+tjRW8VqhHa2dont+lDvN14uuA2F1Rro6Txrh0tdJu/gxTCCzgTaqzAQzHjtf4hL3aHH40K6sI9ZIAlL6rqzO1THHkr35kueolDnSIegVfM0sC2u7g799JBfgS9d/3EjSwRCyOxk5jGk4Ec6cmU++bNqIshVsr0DnnNw9gvoKqck6uRRoZkCOWo2NA128CHdm6qhbC62oJaWNadYomByonjF3WY5hbmOvEfIi8V4M2K0F1jbodFJVcCQCemmd9M9ElI0wnG/X0s2Lop/ZhR8lseOgsnQloRoRYfioOAcUj8=
public key: MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6WzeUhwUnQoshk0QokZlKjwcSiYoDP3/BRIa40lfsmlTzBquhZgOq7qhgYqaSNq1Mqk1oEIAEhPtv6s7EELGO76Avo1niwVJw3A78gMS2T35Li4mjH+Kzf3nqSP6AhsV6EF8frLgQklvHV1nem5HZrMdmqlsqK1j4oc6YwR9mVPrbzzolMMZOnTwap7RsApxfMi5OSYxIWJ7PykQNwPH8G99smY6yb095zlJDl9/yPt9amCKIdjgfCdXlVNqhfIq/633i4R5I+dMqiW6JblxzqoQ3Xg/gP+5LKzXQUBgnMW4G0r8VP7kyZh8yfEplNxRjpGzGFjdmAlm0XhvF525IkUqjQaEY3J8lfMruaf/Rwo44Grb3+8lKNyGZfh39AfnJNkZHO/NFkcPhcq6gOtTV1OFCDrqAJTzGMVwVB05PTAPX0osH1fktvlYERtVa4YrJrZrF+E+1MXdtVx/pxGEzLBdE/AISXxDLN6r11upTbNi8f+H5Hc30iAk32hQSOf12R4nwYSvCPhtHh6O8+/XD9QfBJtLErqo0BnkZRljRA8jF3YFQ7Vwg+k5iqeMA4kt51pgOdEAbD13eeinOQQnx8sBwFO+PELUXOmxEWAMmUxkqklU0rjH6cHyl290hgRK6y9B0Oogd+QfbL8p4+Dwyp7tqwIs0XkJhEHWHVkXz1cCAwEAAQ==

Here is a sample code in Python that requests the digital signature and other information from Zuora:

import requests
import json

rest_call_url = ‘’
my_hosted_page_url = ‘’
my_hosted_page_id = ‘’
my_username = $ZuoraUserName
my_password = $ZuoraPassword

data = {"uri": my_hosted_page_url, "method": "POST", "pageId": my_hosted_page_id}
headers = {'content-type': 'application/json'}

response =, data=json.dumps(data), auth=(my_username, my_password), headers=headers)
response_json = response.json()

token = response_json['token']
signature = response_json['signature']
key = response_json['key']
tenant_id = response_json[‘tenantId’]