Hello @Troy Tessalone, @ken.a and @gloheating
Sorry it’s taken me a while to get back on this, I’m working it out in my off hours. I think I’ve figured out how this integration works, and why it’s failing to do what we want.
I think that Zapier’s updated integration with Xero uses Xero’s webhooks, which means that Xero is now sending a notification every time an invoice is created or updated. However, the webhook payload only tells us that an "update" occurred without any specific details (like "Approved" or "Unsent").
The webhook payload looks like this:
{
"events": [
{
"resourceUrl": "https://api.xero.com/api.xro/2.0/Invoices/717f2bfc-c6d4-41fd-b238-3f2f0c0cf777",
"resourceId": "717f2bfc-c6d4-41fd-b238-3f2f0c0cf777",
"eventDateUtc": "2017-06-21T01:15:39.902",
"eventType": "Update",
"eventCategory": "INVOICE",
"tenantId": "c2cc9b6e-9458-4c7d-93cc-f02b81b0594f",
"tenantType": "ORGANISATION"
}
],
"lastEventSequence": 1,
"firstEventSequence": 1,
"entropy": "S0m3r4Nd0mt3xt"
}
As you can see, it doesn't specify the exact action, just that an update happened.
The problem is, when an invoice is marked as "Approved" in Xero, it triggers multiple actions (like "Edited," "Approved," and sometimes "Invoice Unsent"). Zapier receives an "Update" for each of these but doesn't get specific details, only that an update occurred.
It seems like Zapier then queries the invoice’s action history to determine the last action taken. Since these actions often happen at the same time, Zapier can end up reading the most recent status, which might not reflect the full sequence. This also explains why Zapier sometimes runs the workflow 2 or 3 times for the same invoice.
It’s also good to note, events can be bundled if they’re created in quick succession, which I found in this devblog. It states:
A final note about Xero webhooks, they can be batched meaning that if events occurred near the same time. The JSON body will contain an array of events (up to 200) within a single notification.
Workaround:
It’s not the perfect solution, but to work around this, I'm thinking of using a Zapier Table to track invoice IDs:
- When an invoice is created, it’s logged in the table.
- For each update, we check if the invoice ID is in the table:
- If change history shows any “Approved” action, we process it and delete it from the table.
- If change history shows any “Voided” action, we simply delete it from the table.
I may also need to manually add a delay to manage API rate limits. I also need to make sure that the invoice is created in the table before handling the rest if it’s created and approved at the same time.
It's a really long, unnecessary workaround for something that used to work perfectly. I think the Zapier team need to revert to the way it worked before, until they figure this out.