1

I am trying to add attachments to existing invoices in xero.

I am using xero-node sdk (https://github.com/XeroAPI/xero-node#readme) for this integration and they provide a method for adding attachment as follows:

this.xero.accountingApi.createInvoiceAttachmentByFileName(tenantId, invoiceid, filenameInvoice,includeOnline,readStream )

The issue here is it requires an fs.ReadStream object for readStream.

The file I am trying to upload is present in cloud and I cannot download it and store it in file system before sending to Xero. I want to send the file present in azure cloud directly to xero. I have the url of file so I can get the content as a variable by making http request but there is no option to send this content to Xero.

There is an API available for this as well (here https://developer.xero.com/documentation/api/attachments) apart from the sdk. But I am not sure how I can send the file that I have to this API in body as it expects RAW data. Are there any specific headers or encodings required to call this API with file content in body? Because this is also not working for me if I just pass the body of the response I got from azure file url, as body to this Xero Attachment API. It tries for a long time and gives timeout error.

Faizal
  • 41
  • 6

2 Answers2

1

yes you are correct. There are additional headers/manipulation you need to do to upload files.

Please checkout the sample app - we've got it queued up to show exactly how to upload files: https://github.com/XeroAPI/xero-node-oauth2-app/blob/master/src/app.ts#L1188

Something like the following should get you sorted:

import * as fs from "fs";

const path = require("path");
const mime = require("mime-types");


const totalInvoices = await xero.accountingApi.getInvoices('your-tenantId-uuid', undefined, undefined, undefined, undefined, undefined, undefined, ['PAID']);

// Attachments need to be uploaded to associated objects https://developer.xero.com/documentation/api/attachments

// CREATE ATTACHMENT
const filename = "xero-dev.png";
const pathToUpload = path.resolve(__dirname, "../path-to-your.png");
const readStream = fs.createReadStream(pathToUpload);
const contentType = mime.lookup(filename);

const fileAttached = await xero.accountingApi.createInvoiceAttachmentByFileName(req.session.activeTenant.tenantId, totalInvoices.body.invoices[0].invoiceID, filename, true, readStream, {
  headers: {
    "Content-Type": contentType,
  },
});
SerKnight
  • 2,502
  • 1
  • 16
  • 18
  • Actually I dont have a file system here, the files are stored in azure blob and I have the url of file now I want to upload this file to xero without storing this file on local system first. I can get the file as body using request-promise package but I am not sure how to pass it to xero as it only takes fs.ReadStream and not raw content or any other type of stream. Is there a way to send the content directly? if not through sdk can we do this directly through API? – Faizal May 01 '20 at 06:46
  • Or else is there a field where we can put some custom text, we would like to put the url of file in xero as reference for our accountants – Faizal May 01 '20 at 08:42
  • You likely found the same S/O post https://stackoverflow.com/questions/14544911/fs-createreadstream-equivalent-for-remote-file-in-node - I'm not 100% certain you can get this into the correct "multipart MIME" file type from a remote server though. Would have to do some investigating. Here are the raw API docs if you needed to code this outside the SDK: https://developer.xero.com/documentation/files-api/files#POST – SerKnight May 04 '20 at 19:44
  • @Faizal Your second comment might be the easiest. If you already have a hosted image / file.. You might just want to add that as a HISTORY/NOTES object on the object if it supports that.. https://developer.xero.com/documentation/api/history-and-notes#POST Most models support it. – SerKnight May 04 '20 at 19:46
0

I ended up adding the link to file in History and Notes section of the invoice. Even though this is not the best solution, It serves the purpose of showing invoices to the customer.

Thanks to @SerKnight for your answer.

Faizal
  • 41
  • 6