Frappe Cloud Support Partners Foundation Frappe School

[solved] cURL example of an attachment upload RPC call?

I need to use the RPC API to attach a few files to a specified Sales Invoice.

I would be most grateful if somone could point me to a worked through and working example of how that is done?

I’m using:

ERPNext:  v12.7.1 (version-12)
Frappe Framework:  v12.5.1 (version-12)
Description: Ubuntu 18.04.4 LTS
Codename: bionic

there is:

frappe.utils.file_manager.add_attachments(doctype, name, attachments)

does it work for you?

1 Like


So I figured it out myself, after a timely hint from @revant_one .

I started with a File Manager like this …

… an Attachments subsection like this …

… a Sales Invoice like this …

… and files directories looking like this …

├── backups
└── files
    ├── UOM.csv
    └── docType_Chart_of_Accounts_Importer.csv
└── files

I execute this script …

# sudo apt install jq;
export PRTCL="http";
export HOST="";

export ERP_KEY="2604a8329cb8834";
export ERP_SCT="4a5e6872df8c5c7";

export DOCTYPE="Sales Invoice";
export DOCID="ACC-SINV-2020-00001";

export THEFILE="Trump-Sad-Pig.jpg";
export FILEDATA=$(base64 -w 0 ${THEFILE});

curl -s -X POST "${PRTCL}://${HOST}/api/method/frappe.client.attach_file" \
        -H "Content-Type: application/x-www-form-urlencoded" \
        -H "Authorization: token ${ERP_KEY}:${ERP_SCT}" \
        --data-urlencode "filename=${THEFILE}" \
        --data-urlencode "filedata=${FILEDATA}" \
        --data-urlencode "doctype=${DOCTYPE}" \
        --data-urlencode "docname=${DOCID}" \
        --data-urlencode "is_private=1" \
        --data-urlencode "decode_base64=1" \
  | jq -r .;

… and get the following response …

  "message": {
    "name": "641967bdb5",
    "owner": "Administrator",
    "creation": "2020-05-03 09:19:30.788658",
    "modified": "2020-05-03 09:19:30.788658",
    "modified_by": "Administrator",
    "parent": null,
    "parentfield": null,
    "parenttype": null,
    "idx": 0,
    "docstatus": 0,
    "file_name": "Trump-Sad-Pig.jpg",
    "is_private": 1,
    "is_home_folder": 0,
    "is_attachments_folder": 0,
    "file_size": 96392,
    "file_url": "/private/files/Trump-Sad-Pig.jpg",
    "thumbnail_url": null,
    "folder": "Home/Attachments",
    "is_folder": 0,
    "attached_to_doctype": "Sales Invoice",
    "attached_to_name": "ACC-SINV-2020-00001",
    "attached_to_field": null,
    "old_parent": null,
    "content_hash": "e5d16af3081403db0ad9e6eb0ec8dfdd",
    "uploaded_to_dropbox": 0,
    "uploaded_to_google_drive": 0,
    "doctype": "File"

… and then my site files directories look like this …

├── backups
└── files
    ├── Trump-Sad-Pig.jpg
    ├── UOM.csv
    └── docType_Chart_of_Accounts_Importer.csv
└── files

… my Sales Invoice like this …

… and my Attachments subsection like this …

Clicking on the indicated file link gets me to the file meta-data and thumbnail:


  • "decode_base64=1" - text (JSON, XML) arrives intact and properly formatted without needing this to be set.

  • -H "Authorization: token ${ERP_KEY}:${ERP_SCT}" - the older, alternate RPC method upload_file only works with basic authentication. For permanent server to server comms, frappe.client.attach_file works much better.

  • "is_private=1" - if this is left false the file will be placed in public/files

  • "filename=${THEFILE}" - The name here does not need to be the same as original file on the uploader machine. If you upload a file with the same name, but different content, the File Manager accepts any number of repeated identical names. Files are distinguished by content hash not by name.


*** UPDATES 2020/06/15 ***

If you wish for the file to be public this will not work:

      :           :           :           
--data-urlencode "docname=${DOCID}" \
--data-urlencode "is_private=0" \
--data-urlencode "decode_base64=1" \

However, this will:

       :           :           :           
--data-urlencode "docname=${DOCID}" \
--data-urlencode "decode_base64=1" \

Also note that if you attempt to upload a file that’s already present, even if you try to give it a different name, you’ll get an error (409 I believe, “content conflict”) because the content exists already.