GDPR - Delete answers and attachements of services request

Hi everyone!

I am setting up Freshservice for an HR client. They exclusively handle service requests, some of which require filling out forms with personal information from the requester. For example:

  • Name
  • Address
  • Social Security number

They also request supporting documents as attachments, most of which contain personal data.

Some service requests can generate documents with the new Self-service Document Request feature.

So, there are three items with personal data:

  1. Forms
  2. Attachments
  3. Generated Documents

I wanted to know if there is a way to delete after 30 days the ticket “closed”:

  • answers from forms,
  • all attachments
  • the generated document.

BUT, we want to keep the ticket alive for reporting purposes.

Thanks all



Conceptually, this could be implemented. It would likely be a custom serverless app or external scripted method using the API. Not sure about generated documents, but if it’s stored and manageable in the ticket object, then all of the items should be doable.

Using this Powershell module FreshservicePS, which is a wrapper library for the Freshservice API, we wanted to prove out the base concept.

  • Getting the tickets - There are no filters for finding tickets by resolved date based on the documentation for Filter Tickets. This is where you would need server\client side parsing to get tickets meeting the specified criteria. The best you can do is return Service Requests in a filter. Resolved at is an embedded property ‘stats’, so you would need to return that in the ticket query. After you have the data, then you can filter on resolved_at, the ticket subject or whatever filter criteria required to find the specific SR.

  • Form values - The field values appear to be stored in a custom_fields hash under “Requested Items” API endpoint. There is also has a Update Requested Items. The documentation doesn’t really have anything about the custom_fields, so we did need to update the module function to see if it would allow us to edit the fields. We would have to see if it’s supported, but you can overwrite the field values. The fields are tied to the SR Form, so they had to meet the data type requirements (date, number (int), string) and if there was a ‘Mandatory’ field, it could not be set to null. You could try the hammer approach like I did in my example or you would have to get more complex API calls to get form information or create a process for specific forms to wipe them.

  • Attachments - There is a Remove Attachment endpoint, but we have not implemented in the module. It should allow removal of attachments. There hasn’t been a use case to this point, but we could the functionality. It would be as simple as Get-FSTicketAttachment -id 123 | Remove-FSTicketAttachment when implemented.

Onto conceptualization, here is the basic logic. Note that this is using the PS Module and we would need to update it to support this functionality for custom_fields:

# Get service requests with stats. Would also update the subject or create a hidden
# field like 'gdpr_compliant' so tickets that have been already cleansed could be 
# filtered out and not re-processed.

#The Where clause can filter anything in the object such as as the stats
#to process exactly what you want...  -and $_.stats.resolved_at -lt (Get-Date).AddDays(-30)

$gdprTix = Get-FSTicket -type 'Service Request' -include_global stats | 
                Where-Object -FilterScript {$_.subject -like '*Car Rental*'} 

#Foreach service request in the filtered tickets              
foreach ($tix in $gdprTix[0]) {
    # Get the requested items details for the ticket
    $reqItem = Get-FSRequestedItem -id $

    # Process the custom_field properties and set them to default values
    foreach ($cf in $reqItem.custom_fields.PSObject.Properties) {
        if ([string]$cf.value -as [DateTime]) {
            $cf.value = Get-Date -Date '01-01-1900'
        elseif ([string]$cf.value -as [Int64]) {
            $cf.value = [int64]'000000000'
        else {
            $cf.value = '[GDPR]'

    #Update the requested items object with the clean values
    Set-FSRequestedItem -id $ -service_request_id $ -custom_fields $reqItem.custom_fields

For the concept, there was a Car Rental form, so it was populated with values:

PS C:\Build> $reqItems.custom_fields

name               : test
location           : jacksonville
from               : 11/28/2023 3:58:07 PM
to                 : 11/29/2023 3:58:07 PM
phone              : 8881234567
email              :
additional_details : more details
preferences        : suv

Using the code logic to detect data types, we updated the form like this:

PS C:\Build> $reqItem.custom_fields

name               : [GDPR]
location           : [GDPR]
from               : 1/1/1900 12:00:00 AM
to                 : 1/1/1900 12:00:00 AM
phone              : 0
email              : [GDPR]
additional_details : [GDPR]
preferences        : [GDPR]

Then we attempted to set the custom_fields. This is where you see the API tell us that the fields are still tied to the form with data validation:

     |  {   "description": "Validation failed",   "errors": [     {       "field": "phone",       "message": "is not a number",       "code": "datatype_mismatch"     }   ] }

After adding the field detection logic for dates and numbers, we were able to updated the SR with the clean values:

id                 : 21001400555
from_date          : 
to_date            : 
item_id            : 41
location           : 
quantity           : 1
service_request_id : 21013850512
remarks            : 
is_parent          : True
stage              : @{id=1; name=Requested}
cost               : 
ticket_id          : 636
document_fulfilled : False
custom_fields      : @{name=[GDPR]; location=[GDPR]; from=1/1/1900 12:00:00 AM; to=1/1/1900 12:00:00 AM; phone=0; email=[GDPR]; additional_details=[GDPR]; preferences=[GDPR]}
item               : @{id=21000487391; name=Car Rental; display_id=41; deleted=False; item_type=; workspace_id=2; cost_visibility=False; quantity_visibility=False; icon_detail=; ci_type=; product=; short_description=Request for car rental service; description=Request for car rental service

To re-iterate, it appears to be possible but it’s using ‘undocumented’ fields and the capability would need to be published in the FreshservicePS module.