Accessing end user uploaded attachments

If you've built a custom ticket form using the Ticketing API, accessing end user uploaded attachments requires a valid Zendesk session by default. This also applies to all attachments when Secure Downloads is enabled. Users on external websites don't have a Zendesk session, so attachment URLs cannot be accessed directly in the browser.

To serve these attachments on your website, create a proxy endpoint that requests the content_url with your API token on behalf of the user. Zendesk responds with a 302 and a Location header containing a temporary download URL. The proxy redirects the user's browser to this URL to download the file.

Attachment URLs returned by the Ticketing API in the content_url field should be routed through your proxy endpoint. For example:

https://yoursubdomain.zendesk.com/attachments/token/abc/?name=file.png

becomes:

https://yourserver.com/attachments/token/abc/?name=file.png

Node.js

app.get('/attachments/token/:token/', async (req, res) => {  const { token } = req.params  const filename = req.query.name  const contentUrl = `https://${ZENDESK_SUBDOMAIN}.zendesk.com/attachments/token/${token}/?name=${filename}`  try {    const response = await axios.get(contentUrl, {      auth: {        username: `${ZENDESK_USER_EMAIL}/token`,        password: ZENDESK_API_TOKEN      },      maxRedirects: 0,      validateStatus: status => status === 302    })    res.redirect(response.headers['location'])  } catch (error) {    // Handle error based on your application's requirements    res.status(500).send('Unable to retrieve attachment')  }})

Python

@app.route('/attachments/token/<token>/')def proxy_attachment(token):    filename = request.args.get('name')    content_url = f"https://{ZENDESK_SUBDOMAIN}.zendesk.com/attachments/token/{token}/?name={filename}"    response = requests.get(        content_url,        auth=(f"{ZENDESK_USER_EMAIL}/token", ZENDESK_API_TOKEN),        allow_redirects=False    )    if response.status_code != 302:        # Handle error based on your application's requirements        return 'Unable to retrieve attachment', 500    return redirect(response.headers['Location'])

Note: The error handling shown above is minimal. Adjust the error responses based on your application's requirements.