Are you trying to automate ticket creation using the FreshService API v2? Have you encountered issues when adding multiple attachments to a ticket? This guide aims to assist those facing difficulties with the attachments[] array when integrating with FreshService's API.

Problem

When integrating with FreshService, the standard approach to adding attachments involves using the attachments[] array. However, navigating this array correctly to include multiple files in a single API call requires careful handling.

Understanding the API with POSTMAN

The FreshService API v2 documentation (which can be found by clicking here) section "Create Ticket with attachment" states that you can use the curl:

Code sample by FreshService
curl -v -u api_key:X -F 'attachments[]=@/Users/user/Desktop/api_attach.png' -F 'subject=Support Needed...' -F 'description=Details about the issue...' -F '[email protected]' -F 'priority=1' -F 'status=2' -F 'workspace_id=3' -X POST 'https://domain.freshservice.com/api/v2/tickets'

If you need to add multiple attachments using curl, simply include -F attachments[] multiple times, as demonstrated below:

Code sample by Cloudaen
curl -v -u api_key:X -F 'attachments[]=@/Users/user/Desktop/api_attach.png' -F 'attachments[]=@/Users/user/Desktop/api_attach2.png' -F 'subject=Support Needed...' -F 'description=Details about the issue...' -F '[email protected]' -F 'priority=1' -F 'status=2' -F 'workspace_id=3' -X POST 'https://domain.freshservice.com/api/v2/tickets'

Here’s how your setup should appear in POSTMAN:

Set up a POST to https://domain.freshservice.com/api/v2/tickets > get your API key from FreshService > add Basic Auth and your API key in the username text field.

Move towards the Body and create the following with your attachments:

Your POSTMAN request is functional, but have you considered automating this process with a script? In this guide, we'll show you how to use PHP to automate the creation of tickets, including handling multiple attachments.

Solution

Begin by creating a PHP page with the following script:

Note: Please obtain your Agent group ID from FreshService to ensure that the ticket is created in the correct group. You will need to add it to "group_id" => addGroupIDHere

Code sample by Cloudaen
<?php

// Get API Information
$password = 'YourAPIKeyHere';

// Function to build multipart/form-data request body
function build_data_files($boundary, $fields, $files){
    $data = '';
    $eol = "\r\n";

    // Add fields to the request body
    foreach ($fields as $name => $content) {
        $data .= "--" . $boundary . $eol
            . 'Content-Disposition: form-data; name="' . $name . '"' . $eol . $eol
            . $content . $eol;
    }

    // Add files to the request body
    foreach ($files as $file) {
        $filename = basename($file);
        $content = file_get_contents($file);
        $data .= "--" . $boundary . $eol
            . 'Content-Disposition: form-data; name="attachments[]"; filename="' . $filename . '"' . $eol
            . 'Content-Type: application/octet-stream' . $eol
            . 'Content-Transfer-Encoding: binary' . $eol . $eol
            . $content . $eol;
    }

    // End of request boundary
    $data .= "--" . $boundary . "--" . $eol;

    return $data;
}

// API Endpoint for creating tickets
$url = "https://yourdomain.freshservice.com/api/v2/tickets";

// File paths of the attachments
$attachments = array(
    "attachment1.txt",
    "attahcment2.txt",
	"image.png"
);

// Additional fields for ticket creation
$fields = array(
    "description" => "Some details on the issue ...",
    "subject" => "Support needed..",
    "email" => "[email protected]",
    "priority" => 1,
    "status" => 2,
    "group_id" => addGroupIDHere
);

// Generate a unique boundary identifier
$boundary = uniqid();

// Build multipart/form-data request body
$post_data = build_data_files($boundary, $fields, $attachments);

echo $post_data . '<br /><br />';

// Initialize cURL session
$ch = curl_init();

// Set cURL options for POST request
curl_setopt_array($ch, array(
    CURLOPT_URL => $url,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $post_data,
    CURLOPT_HTTPHEADER => array(
        'Content-Type: multipart/form-data; boundary=' . $boundary,
        'Authorization: Basic ' . base64_encode($password)
    ),
));

// Execute cURL and capture server response
$response = curl_exec($ch);

// Get HTTP status code and response info
$info = curl_getinfo($ch);

// Close cURL session
curl_close($ch);

// Check HTTP status code for success or failure
if ($info['http_code'] == 201) {
    echo "Ticket created successfully, the response is given below:\n";
    echo $response;
} else {
    echo "Error, HTTP Status Code : " . $info['http_code'] . "\n";
    echo "Response:\n" . $response . "\n";
}
?>

The code for the build_data_files function was made by a github user called maxivak found here.

Python Code

Here is the Python equivalent code:

Code sample by Cloudaen
import requests
import os

# API Information
password = 'YourAPIKeyHere'

# Function to build multipart/form-data request body
def build_data_files(fields, files):
    boundary = '----WebKitFormBoundary7MA4YWxkTrZu0gW'
    data = bytearray()

    # Add fields to the request body
    for name, content in fields.items():
        data.extend(('--' + boundary + '\r\n').encode())
        data.extend(('Content-Disposition: form-data; name="%s"\r\n\r\n' % name).encode())
        data.extend((content + '\r\n').encode())

    # Add files to the request body
    for file_path in files:
        filename = os.path.basename(file_path)
        with open(file_path, 'rb') as f:
            file_content = f.read()
            data.extend(('--' + boundary + '\r\n').encode())
            data.extend(('Content-Disposition: form-data; name="attachments[]"; filename="%s"\r\n' % filename).encode())
            data.extend(('Content-Type: application/octet-stream\r\n').encode())
            data.extend(('Content-Transfer-Encoding: binary\r\n\r\n').encode())
            data.extend(file_content)
            data.extend(('\r\n').encode())

    # End of request boundary
    data.extend(('--' + boundary + '--\r\n').encode())

    return data

# API Endpoint for creating tickets
url = "https://yourdomain.freshservice.com/api/v2/tickets"

# File paths of the attachments
attachments = [
    "attachment1.txt",
    "attachment2.txt",
    "image.png"
]

# Additional fields for ticket creation
fields = {
    "description": "Some details on the issue ...",
    "subject": "Support needed..",
    "email": "[email protected]",
    "priority": "1",
    "status": "2",
    "group_id": "addGroupIDHere"
}

# Build multipart/form-data request body
post_data = build_data_files(fields, attachments)

# Initialize headers with authentication
headers = {
    'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW',
    'Authorization': 'Basic ' + base64.b64encode(password.encode()).decode()
}

# Perform the POST request
response = requests.post(url, headers=headers, data=post_data)

# Check HTTP status code for success or failure
if response.status_code == 201:
    print("Ticket created successfully, the response is given below:")
    print(response.text)
else:
    print("Error, HTTP Status Code:", response.status_code)
    print("Response:", response.text)

This code should enable you to automate your ticket creation process from PHP forms or similar systems in Python where necessary.

Conclusion

API documentation sometimes lacks detailed explanations of endpoint capabilities, leaving users to interpret the information and create their own implementations. This blog post aims to assist users in utilizing FreshService's API for creating tickets with attachments. It includes examples in POSTMAN, PHP, and Python to provide a comprehensive understanding of how to upload multiple attachments effectively.

Related Documentation

FreshService API v2: Create Ticket

PHP upload file with curl (multipart/form-data)