Hey there, fellow JavaScript dev! Ready to supercharge your Xero integration with real-time updates? Webhooks are your new best friend. They'll keep your app in sync with Xero data faster than you can say "asynchronous callback". Let's dive in and get those webhooks humming!
Before we jump into the code, make sure you've got:
First things first, let's get your app set up in the Xero Developer Portal:
Now, let's create a simple Express.js server to handle those incoming webhooks:
const express = require('express'); const app = express(); app.use(express.json()); app.post('/webhook', (req, res) => { console.log('Webhook received:', req.body); res.sendStatus(200); }); app.listen(3000, () => console.log('Webhook server running on port 3000'));
Easy peasy, right? This sets up a basic endpoint that'll receive POST requests from Xero.
Xero's webhook payloads are pretty straightforward. Here's how you can parse and validate them:
app.post('/webhook', (req, res) => { const { events, firstEventSequence, lastEventSequence } = req.body; if (!events || !Array.isArray(events)) { return res.status(400).send('Invalid payload'); } // Process events here events.forEach(event => { console.log(`Received event: ${event.eventType} for ${event.resourceType}`); }); res.sendStatus(200); });
Time to tell Xero what events you're interested in. Here's how you can create a webhook subscription:
const axios = require('axios'); async function createWebhookSubscription(accessToken) { try { const response = await axios.post('https://api.xero.com/connections/webhooks/subscriptions', { url: 'https://your-webhook-url.com/webhook', events: ['invoices.created', 'contacts.updated'] }, { headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' } }); console.log('Webhook subscription created:', response.data); } catch (error) { console.error('Error creating webhook subscription:', error.response.data); } }
Now that you're receiving events, let's handle them like a pro:
function handleEvent(event) { switch(event.eventType) { case 'invoices.created': console.log('New invoice created:', event.resourceId); // Add your invoice handling logic here break; case 'contacts.updated': console.log('Contact updated:', event.resourceId); // Add your contact update logic here break; default: console.log('Unhandled event type:', event.eventType); } }
Security first! Always verify those webhook signatures:
const crypto = require('crypto'); function verifyWebhookSignature(payload, signature, webhookKey) { const hmac = crypto.createHmac('sha256', webhookKey); const computedSignature = hmac.update(payload).digest('base64'); return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(computedSignature)); } app.post('/webhook', (req, res) => { const signature = req.headers['x-xero-signature']; const payload = JSON.stringify(req.body); if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_KEY)) { return res.status(401).send('Invalid signature'); } // Process the webhook... });
Sometimes things go wrong. Be prepared with a retry mechanism:
async function processWebhook(event, retries = 3) { try { // Your webhook processing logic here } catch (error) { if (retries > 0) { console.log(`Retrying... Attempts left: ${retries - 1}`); await new Promise(resolve => setTimeout(resolve, 1000)); return processWebhook(event, retries - 1); } else { console.error('Failed to process webhook after retries:', error); } } }
Before you go live, give your webhook a test drive with Xero's webhook simulator:
const mockWebhook = { events: [ { resourceType: 'invoices', eventType: 'created', resourceId: 'mock-invoice-id' } ] }; // Simulate a webhook POST request axios.post('http://localhost:3000/webhook', mockWebhook, { headers: { 'Content-Type': 'application/json', 'X-Xero-Signature': 'your-mocked-signature' } }).then(response => { console.log('Test webhook sent, response:', response.status); }).catch(error => { console.error('Test webhook error:', error); });
And there you have it! You're now ready to rock the world of Xero webhooks. Remember, this is just the beginning – there's so much more you can do with real-time data. Keep exploring, keep coding, and most importantly, have fun with it!
Got questions? Hit up the Xero API docs or join the developer community. Happy coding!