Downloading Attachments through API

I have been trying to access and download attachments to rows in a Smartsheet through API using Access token. In how many ever ways, I tried to do so, that didn't work.

However, I am able to access the attachments directly that are attached to a sheet and not to a row. Are there any different permissions to access row and sheet attachments. User permission for this Smartsheet is Admin.

The error:

{'errorCode': 1006, 'message': 'Not Found', 'refId': 'p7hg71'}

Even though there are attachments, I am getting this Not Found error.

Did anyone encounter this issue before, any help here is highly appreciated.

Thank you,

Manaswitha P.

Answers

  • BKing
    BKing ✭✭✭


    @Manaswitha

    Here is some c# code:

              PaginatedResult<Attachment> attachments = smartsheet.SheetResources.RowResources.AttachmentResources.ListAttachments(

               sheetId,     // sheetId

               rowId,      // rowId

               null       // PaginationParameters

              );


              if (attachments.TotalCount > 0)

              {

                for (int i = 0; i < attachments.TotalCount; i++)

                {

                  Attachment temp = attachments.Data[i];

                  Attachment at = smartsheet.SheetResources.AttachmentResources.GetAttachment(

                   sheetId,         // sheetId

                   (long)temp.Id      // attachmentId

                  );


                  if (at.AttachmentType == AttachmentType.FILE)

                  {

                    SiteSmartsheetLinkedFileMap map = new()

                    {

                      Id = at.Id.ToString(),

                      URL = at.Url,

                      FileName = at.Name,

                      MimeType = at.MimeType,

                      RowId = rowId.ToString()

                    };

                    siteSmartSheet.RowAttachments.Add(map);

                  }

                }

              }

    Regards,

    Brian

  • Lee Joramo
    Lee Joramo ✭✭✭✭✭✭
    edited 02/20/24

    The permissions should be the same for accessing Row and Sheet Attachments. I can confirm that I have accessed Row Attachments with Admin level permissions. I have written code using Javascript to both upload and download Attachments.

  • Hi,

    Thank you for your response. Yes, I have been able to access and download the sheet and row attachments. But, after downloading, when I am trying to open the attachments, I wasn't able to.

    Was getting an error as below:


    Please find the code used below:

    import requests

    import os


    # Define your Smartsheet API access token

    access_token = "ACCESS_TOKEN"


    # Define your Smartsheet sheet ID

    sheet_id = "SHEET_ID"


    # Define the endpoint for fetching sheet data

    endpoint = f"https://api.smartsheet.com/2.0/sheets/sheet_id?include=attachments"


    # Define headers with authorization token

    headers = {

        "Authorization": f"Bearer {access_token}",

        "Content-Type": "application/json"

    }


    # Send a GET request to fetch sheet data

    response = requests.get(endpoint, headers=headers)


    if response.status_code == 200:

        rows_data = response.json()['rows']

       

        for row in rows_data:

            if 'attachments' in row:

                x = row['cells'][0]['value']  # Assuming SAP Card Number is in the first column

                row_id = row['id']

               

                # Create folder for SAP Card Number

                folder_name = f"Card_{x}"

               

                # Create folder in the file system if it doesn't exist

                folder_path = os.path.join("D:\\SAPMANAGER", folder_name)

                if not os.path.exists(folder_path):

                    try:

                        os.makedirs(folder_path)

                        print(f"Folder created for SAP Card Number {x} at path: {folder_path}")

                    except OSError as e:

                        print(f"Failed to create folder for SAP Card Number {x}: {e}")

               

                # Iterate over attachments and download/save them

                attachments = row['attachments']

                for attachment in attachments:

                    attachment_id = attachment['id']

                    attachment_name = attachment['name']

                   

                    # Download attachment and save it to the SAP folder

                    attachment_url = f"https://api.smartsheet.com/2.0/sheets/sheet_id?rowid=row_id?include=attachments"

                    attachment_response = requests.get(attachment_url, headers=headers)

                   

                    if attachment_response.status_code == 200:

                        attachment_content = attachment_response.content

                        attachment_path = os.path.join(folder_path, attachment_name)

                        with open(attachment_path, 'wb') as f:

                            f.write(attachment_content)

                        print(f"Attachment '{attachment_name}' downloaded and saved to folder: {folder_path}")

                    else:

                        print(f"Failed to download attachment '{attachment_name}' for SAP Card Number {x}")

    else:

        print("Failed to fetch sheet data")

  • Lee Joramo
    Lee Joramo ✭✭✭✭✭✭
    edited 02/21/24

    This works for me to get a pdf using python3 and requests:

    import requests
    
    def download_pdf(url, save_path):
        response = requests.get(url)
        if response.status_code == 200:
            with open(save_path, 'wb') as f:
                f.write(response.content)
            print("PDF downloaded")
        else:
            print("Failed to download: ", response.status_code)
    
    url = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"  
    save_path = "downloaded.pdf"
    download_pdf(url, save_path)
    

    Most of my code for dealing with Smartsheet Attachments was done in Javascript.

    Looking at your code, I see the variable attachment_url to be highly suspect. You should be getting the a JSON object from Smartsheet for the specific attachment id. Here is how it is done in Javascript:

    const attachmentObj = await smartsheet.sheets.getAttachment({
        sheetId: sheetId,
        attachmentId: attachmentId
    })
    

    Then attachmentObj.url will provide a URL of the file which should look something like:

    https://s3.amazonaws.com/SmartsheetB1/OBJECT_ID?response-content-disposition=attachment%3Bfilename%3DMY_FILE.PDF&Signature=%2THE_SIGNATURE%3D&Expires=EXPIRES_DATETIME&AWSAccessKeyId=ACEESS_KEY_ID 
    

    So it should be a URL to an S3 object and will get you the PDF.

    Hopefully, this will get you past your next hurdle

  • Hello Everyone,

    I am able to download the attachments into a folder and segregating each row attachments into sub folders based on a unique column from the Smartsheet using the below Python code. Hope it should be useful for anyone who wants to work on it:


    import smartsheet

    import os

    import requests


    # Initialize Smartsheet client

    smartsheet_client = smartsheet.Smartsheet('ACCESS KEY')

     

    # Specify the sheet ID

    sheet_id = 'SHEET_ID'


    path = "FOLDER_PATH"


    try:

        # Load the sheet with include discussions and attachments

        sheet = smartsheet_client.Sheets.get_sheet(sheet_id, include='attachments, discussions')

     

        print("Loaded", len(sheet.rows), "rows from sheet:", sheet.name)

       

        # Attachments that exist on the SHEET object

        for attachment in sheet.attachments:

            print("Attachment found (at SHEET-level):", attachment.name, "(attachment ID =", attachment.id, ")")

            # Add logic to process attachment here.

     

        # Attachments that exist on ROW objects

        for row in sheet.rows:

            for attachment in row.attachments:

                # print("Attachment found (at ROW-level) on Row #", row.row_number, ":", attachment.name, "(attachment ID =", attachment.id, ")")

                # Add logic to process attachment here.

                print("rowid: ", row.id, ":", attachment.id, " : ", attachment.name)

               

                response = smartsheet_client.Attachments.get_attachment(sheet_id, str(attachment.id))


               # print(response)

                if response.request_response.status_code == 200:


                    url = response.url

                    attachmentFile = requests.get(url)


                    sapCardId = row.cells[0].value #Assuming the unique column is in the first column

                    dir = path + f'/SAP_Card_Number_{sapCardId}'

                    isDirExist = os.path.exists(dir)


                    # remove existing directory including file(s) (tree structure)

                    if not isDirExist:

                        os.makedirs(dir)


                    fileName = dir + f'/{attachment.name}'

                    f = open(fileName, "wb")

                    f.write(attachmentFile.content)

                    f.close()


                break


               

        print("---------")

     

    except Exception as ex:

        print("Error:", ex)


    Replace the access token and sheet id.. that should work :)

    Thanks everyone for your suggestions.


    Manaswitha.

  • Lee Joramo
    Lee Joramo ✭✭✭✭✭✭

    @Manaswitha

    Thanks for providing your solution. I will likely use it in the future.

    Hint for the Future: In Smartsheet Community Discussions, you can click the paragraph symbol ¶ to the left your current typing position to format the text as code which will make much more readable and typically provides basic syntax highlighting.

    For example:

    #include <stdio.h>int main()
    {
      printf("Hello world\n");
      return 0;
    }
    
  • I am getting the same error again and again, how did you solve it? What was the exact issue?

  • Hi ,
    I am trying to download row level attachments through API 2.0
    But I am failing.

    Can anyone help with the process