public async static Task <object> Run(
            [HttpTrigger(AuthorizationLevel.Function, "post", Route = "")] HttpRequestMessage req,
            [Table("receiptsTable", Connection = "AzureWebJobsStorage")] CloudTable receiptTable,
            [Queue("receiptitems", Connection = "AzureWebJobsStorage")] ICollector <ReceiptQueueMessage> receiptQueue,
            TraceWriter log)
        {
            log.Info($"Webhook was triggered!");

            string jsonContent = await req.Content.ReadAsStringAsync();

            OCRResult result = JsonConvert.DeserializeObject <OCRResult>(jsonContent);

            if (result.StatusCode == "Retry")
            {
                // there is a possibility the OCR processing failed because the service was unavailable or there was too many
                // concurrent connections (this is something that can happen with Azure ML web services
                // therefore, rather than throwing an error, re-add the expense item back to the queue and try to re-process.

                // queue message to move to next step
                receiptQueue.Add(new ReceiptQueueMessage
                {
                    ExpenseId      = result.ItemId,
                    Status         = "Retry",
                    ProcessingStep = 99 // set to 99 to restart process
                });
            }
            else
            {
                // the process either succeeded or failed in which case update the table with the appropriate data or error text
                // inform the expense processor (via a queue message) that processing is complete

                // add row to results table
                var item = new ReceiptTableItem()
                {
                    PartitionKey = "key",
                    RowKey       = result.ItemId,
                    ExpenseId    = result.ItemId,
                    RawText      = result.Text,
                    ErrorText    = result.ErrorText,
                    ETag         = "*"
                };

                var operation = TableOperation.Merge(item);
                await receiptTable.ExecuteAsync(operation);

                // queue message to move to next step
                receiptQueue.Add(new ReceiptQueueMessage
                {
                    ExpenseId      = result.ItemId,
                    Status         = result.StatusCode == "Success" ? "Complete" : "Error",
                    ProcessingStep = 1 // set to 1 to complete processing
                });
            }

            return(req.CreateResponse(HttpStatusCode.OK));
        }
        private async static void UpdateTableStatus(CloudTable receiptsTable, string status, string id)
        {
            // update row int results table
            var item = new ReceiptTableItem()
            {
                PartitionKey = "key",
                RowKey       = id,
                Status       = status,
                ETag         = "*"
            };

            var operation = TableOperation.Merge(item);
            await receiptsTable.ExecuteAsync(operation);
        }
        private static async Task CreateTableEntry(ReceiptQueueMessage receiptQueueItem, CloudTable receiptsTable)
        {
            // create table entry
            var item = new ReceiptTableItem()
            {
                PartitionKey = "key",
                RowKey       = receiptQueueItem.ExpenseId,
                ExpenseId    = receiptQueueItem.ExpenseId,
                UserId       = receiptQueueItem.UserId,
                Status       = "Processing"
            };

            var operation = TableOperation.Insert(item);
            await receiptsTable.ExecuteAsync(operation);
        }