The Zendesk help center provides a built-in web form that end users can use to submit support requests. Zendesk also offers web widgets that let you embed customer service directly into your websites and web apps.

An alternative to these options is to build a custom ticket form that submits requests using the Ticketing API. Such forms are highly customizable and let users submit support requests directly from your website. However, they require server-side code to make the related API requests.

In this tutorial, you'll build a basic web app that provides a custom ticket form for end users. When users submit a request using the form, the app makes a call to Create Request endpoint. The API call creates a corresponding ticket in your Zendesk Support instance. You can use the app's code as a starting point for building your own custom ticket forms.

Disclaimer: Zendesk provides this article for instructional purposes only. Zendesk doesn't provide support for the apps or example code. Zendesk doesn't support third-party technologies, such as Node.js, Python, or related libraries.

Differences between tickets and requests

The Ticketing API offers two ways to create and manage tickets:

When creating a ticket form for end users, Zendesk recommends using the request endpoints instead of the ticket endpoints. A request is an end user's perspective of a ticket.

For more information about the differences between tickets and requests, see Tickets vs Requests APIs: How to select the right option for your project.

What you'll need

To complete this tutorial, you'll need the following:

Protecting your form from spam attacks

Zendesk strongly recommends using CAPTCHA to protect your ticket forms from spam submissions and other attacks. Popular CAPTCHA options include:

This tutorial uses Google reCAPTCHA v2. Two keys are required to use reCAPTCHA: a site key and a secret key. For easier setup, the tutorial uses test keys provided by Google:

  • Site key: 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
  • Secret key: 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe

Don't use the test keys in production. The test keys work on any domain and always pass verification. When using the test keys, the reCAPTCHA widget displays a related warning message.

Creating a web app for your ticket form

Next, create a web app that serves up a ticket form. If an end user submits a request using the form, the app should make a call to the Create Request endpoint. To prevent spam, the form should also validate submissions using Google reCAPTCHA.

Instructions for creating the app are provided for both Node.js and Python. Use the programming language you prefer:

Node.js

Use the following instructions to create the web app using Node.js.

To create the web app using Node.js

  1. In your terminal, create and navigate to a folder named ticket_form_example. Example:

    mkdir ticket_form_examplecd ticket_form_example
  2. In the folder, use the following command to create an npm package.

    npm init -y
  3. Install dependencies for the project.

    npm install express body-parser axios express-recaptcha

    This project requires the following libraries:

  4. In the ticket_form_example folder, create an app.js file. Paste the following code into the file.

    const express = require("express")const bodyParser = require("body-parser")const axios = require("axios")const Recaptcha = require("express-recaptcha").RecaptchaV2
    const app = express()const port = 3000
    // In production, store credentials in environment variablesconst ZENDESK_SUBDOMAIN = "YOUR_ZENDESK_SUBDOMAIN"const ZENDESK_USER_EMAIL = "YOUR_ZENDESK_EMAIL_ADDRESS"const ZENDESK_API_TOKEN = "YOUR_ZENDESK_API_TOKEN"const RECAPTCHA_SITE_KEY = "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"const RECAPTCHA_SECRET_KEY = "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe"
    const recaptcha = new Recaptcha(RECAPTCHA_SITE_KEY, RECAPTCHA_SECRET_KEY)
    app.use(bodyParser.urlencoded({ extended: true }))
    app.get("/", recaptcha.middleware.render, (req, res) => {  const form = `    <form action="/submit" method="post">    <div>        <label for="subject">Subject</label><br>        <input type="text" name="subject" required><br>        <label for="description">Description</label><br>        <textarea name="description" rows="6" required></textarea><br>        <label for="name">Name</label><br>        <input type="text" name="name" required><br>        <label for="email">Email</label><br>        <input type="email" name="email" required><br><br>    </div>    <div>        ${recaptcha.render()}    </div>    <div>        <button>Submit</button>    </div>    </form>`  res.send(form)})
    app.post("/submit", recaptcha.middleware.verify, async (req, res) => {  if (!req.recaptcha.error) {    const options = {      method: "post",      url: `https://${ZENDESK_SUBDOMAIN}.zendesk.com/api/v2/requests.json`,      headers: {         "Content-Type": "application/json"      },      auth: {        username: ZENDESK_EMAIL + '/token',        password: ZENDESK_API_TOKEN      },      data: {        request: {          subject: req.body.subject,          comment: {            body: req.body.description          },          requester: {            name: req.body.name,            email: req.body.email          }        }      }    }
        try {      await axios(options)      res.status(200).send("Form submitted successfully")    } catch (error) {      res.status(500).send("Error")    }  } else {    res.status(400).send("reCAPTCHA verification failed")  }})
    app.listen(port, () => {  console.log(    `Server running on port ${port}. Visit http://localhost:${port}`  )})

    In the code, replace the following placeholders:

    • "YOUR_ZENDESK_SUBDOMAIN"
    • "YOUR_ZENDESK_EMAIL_ADDRESS"
    • "YOUR_ZENDESK_API_TOKEN"
  5. To start a local web server using the app, run the following terminal command from the ticket_form_example folder:

    node app.js

    To stop the server, press Ctrl+C.

  6. To test the app's ticket form, skip to Testing the ticket form.

Python

Use the following instructions to create the web app using Python.

To create the web app using Python

  1. In your terminal, create and navigate to a folder named ticket_form_example. Example:

    mkdir ticket_form_examplecd ticket_form_example
  2. Install dependencies for the project.

    pip3 install flask requests google-recaptcha-flask
  3. In the ticket_form_example folder, create an app.py file. Paste the following code into the file.

    from flask import Flask, request, render_template_stringimport requestsimport osfrom google_recaptcha_flask import ReCaptcha
    app = Flask(__name__)PORT = 3000
    # In production, store credentials in environment variablesZENDESK_SUBDOMAIN = "YOUR_ZENDESK_SUBDOMAIN"ZENDESK_USER_EMAIL = "YOUR_ZENDESK_EMAIL_ADDRESS"ZENDESK_API_TOKEN = os.getenv('ZENDESK_API_TOKEN')
    RECAPTCHA_SITE_KEY = "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"RECAPTCHA_SECRET_KEY = "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe"
    recaptcha = ReCaptcha(app)app.config.update(    dict(        GOOGLE_RECAPTCHA_ENABLED=True,        GOOGLE_RECAPTCHA_SITE_KEY=RECAPTCHA_SITE_KEY,        GOOGLE_RECAPTCHA_SECRET_KEY=RECAPTCHA_SECRET_KEY,        GOOGLE_RECAPTCHA_LANGUAGE="en",    ))recaptcha.init_app(app)
    
    @app.route("/", methods=["GET"])def form():    return render_template_string(        """        <form action="/submit" method="post">        <div>            <label for="subject">Subject</label><br>            <input type="text" name="subject" required><br>            <label for="description">Description</label><br>            <textarea name="description" rows="6" required></textarea><br>            <label for="name">Name</label><br>            <input type="text" name="name" required><br>            <label for="email">Email</label><br>            <input type="email" name="email" required><br><br>        </div>        <div>
                {{ recaptcha }}
            </div>        <div>            <button>Submit</button>        </div>        </form>    """    )
    
    @app.route("/submit", methods=["POST"])def submit():    if recaptcha.verify():        subject = request.form["subject"]        body = request.form["description"]        requester_name = request.form["name"]        requester_email = request.form["email"]        headers = {            "Content-Type": "application/json"        }        data = {            "request": {                "subject": f"{subject}",                "comment": {"body": f"{body}"},                "requester": {                    "name": f"{requester_name}",                    "email": f"{requester_email}",                },            }        }        response = requests.post(            f"https://{ZENDESK_SUBDOMAIN}.zendesk.com/api/v2/requests.json",            headers=headers,            auth = f'{ZENDESK_USER_EMAIL}/token', ZENDESK_API_TOKEN,            json=data,        )        if response.ok:            return "Form submitted successfully", 200        else:            return "Error", 500    else:        return "reCAPTCHA verification failed", 400
    
    if __name__ == "__main__":    app.run(debug=True, port=PORT)

    In the code, replace the following placeholders:

    • "YOUR_ZENDESK_SUBDOMAIN"
    • "YOUR_ZENDESK_EMAIL_ADDRESS"
    • "ZENDESK_API_TOKEN"
  4. To start a local web server using the app, run the following terminal command from the ticket_form_example folder:

    python app.py

    To stop the server, press Ctrl+C.

  5. To test the app's ticket form, skip to Testing the ticket form.

Testing the ticket form

Test the form to ensure it creates tickets as intended.

To test the ticket form

  1. Use your app to start a local web server.

  2. In a web browser, go to http://localhost:3000/.

    A blank ticket form opens.

  3. Fill out the form with test data, check the reCAPTCHA box, and click Submit.

  4. Sign in to Zendesk and check the Agent Workspace for a ticket related to your form. To view recently updated tickets, click Views > Recently updated tickets.

    Registered end users can also manage their requests in the help center. See Tracking your support requests in Zendesk help.

Congratulations! You've created a custom ticket form using the Ticketing API. As a next step, you can expand the app and get it ready for production. Consider tackling the following tasks:

  • Replace the app's RECAPTCHA_SITE_KEY and RECAPTCHA_SECRET_KEY values with reCAPTCHA keys for your production domain. You can create production keys using the Google reCAPTCHA Admin Console: https://www.google.com/recaptcha/admin/create. For instructions, see the Settings guide in the Google reCAPTCHA docs.

  • Update the app to use a Zendesk OAuth access token to authenticate the Create Request call. OAuth access tokens give external apps limited permission to your Zendesk account and are easily revoked. See Creating and using OAuth tokens with the API.

  • Update the app's code to store credentials, such as your production reCAPTCHA keys and OAuth access token, in environment variables. This helps ensure you don't accidentally share them.

  • Update the form to better align with your website. For example, you can use HTML templates or add CSS for styling.

  • Integrate the form and its server-side logic into your site. For example, you can deploy the app to a server or app host, such as Heroku or AWS Elastic Beanstalk. You can then use an iframe or other method to embed the form onto your website.