developers · Aug 12, 2025

A Developer's Take on How to Build Two-Way Sync with Quire API

Quire two-way sync architecture diagram showing bidirectional data flow between Quire and external applications

Last updated: October 30, 2026

TL;DR

Two-way sync between Quire and another app requires a middle-layer server that receives webhooks from both sides and calls each API to mirror the change. Architecture: Quire ↔ Your App ↔ Other App. Four implementation steps: stand up the webhook server, register it with Quire (add as project follower), register it with the other app, then handle events using activity types from the Quire API docs. Two safety rules: tag the origin of each change to avoid infinite loops, and keep an ID mapping between Quire task IDs and the other app's item IDs. The Google Calendar Two-Way Sync app is a working example.

The calendar says the design review is on the 14th. The task board says it moved to the 18th. Both were right at some point, and now someone spends a morning finding out which one is right today.

When the same fact lives in two apps, every change gets made twice or gets made once and lost. Two-way sync fixes that by letting the apps tell each other. Quire's Open API and webhooks were built for the pattern, and the Google Calendar Two-Way Sync app is a working example of it. This post shows how to build the same thing against any other app's API.

The cost of the manual version is measurable. McKinsey's 2012 report on the social economy found that knowledge workers spend about a fifth of their week looking for internal information or tracking down colleagues, and estimated that better-connected tools could raise their productivity by 20 to 25 percent. A sync that works is a small piece of that.

Google Calendar Two-Way Sync is made for Premium and higher subscription tiers. More information can be found on our Pricing page.

Components of a Quire two-way sync

Component Role
Quire app Provides API credentials; registered as project follower for webhooks
Middle-layer server (your app) Receives webhooks from both sides; calls each API to mirror the change
Other app (e.g. Google Calendar) Source of events on its side; target of API writes
Webhook URL in Quire app settings Where Quire POSTs activity events
ID mapping table Maps Quire task IDs ↔ other app's item IDs
Origin tag on each change Prevents infinite update loops

What is the two-way sync workflow?

A conversation between two apps. When you change a task in Quire, Quire tells the other app. When something changes in the other app, it tells Quire. Neither side has to be reminded, and the fact you read is the same in both places.

Two-way sync workflow diagram illustrating event flow between Quire, middleware, and external app

What do you need before you start?

A Quire app, first. It holds the credentials your code uses to reach a Quire project through the API.

For a step-by-step guide on how to create your own app with Quire API, please visit our blog post.

Then a middle-layer app of your own, sitting between Quire and the target app. It's a translator. It takes an event from one side, works out what it means, and sends the right command to the other side. The flow is Quire ↔ Your App ↔ Other App, and the translator is the only part you have to write.

How do you build it step by step?

1. Prepare an app for handling events

Your server is the middle layer, and its job is to receive webhook POST requests from both Quire and the other app. It needs to do three things.

  • Accept incoming HTTP POST requests (webhook events) from Quire and the other app.
  • Parse each payload and decide what action it calls for.
  • Use the respective APIs to update Quire or the other app.

Any stack works. Node.js, Python, Ruby, whatever your team already runs. The examples below use Node.js.

The one hard requirement is that the server is reachable from the internet, or the webhooks have nowhere to go.

Here's the smallest Express server that qualifies.

const express = require('express');
const app = express();
app.use(express.json());

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

2. Set up a webhook in Quire to send task updates to your app

Add a route that receives Quire's events.

app.post('/webhook', (req, res) => {
  console.log('Received webhook event:', req.body);
  // TODO: Handle the event and update Quire or other app via API
  res.status(200).send('Event received');
});

The route is /webhook, so the full URL is ${your-host}/webhook.

Paste that webhook URL into the Quire app settings. That's how Quire learns where to send event notifications.

Quire app settings displaying webhook URL configuration field

One more step, and it's the one people forget. Register your Quire app as a follower of the project you want to sync. A follower gets notified. An app that isn't following hears nothing and looks broken.

For a step-by-step guide on how to receive notifications via Quire API, please visit our guide.

3. Set up a webhook in the other app to send its updates to your app

Same idea in the other direction. Add a second route for the other app's events, then configure that app to send its notifications to your endpoint. The registration steps differ by app, but the shape is the one you've already built.

4. Handle incoming events and update data in both Quire and the other app

Now your server hears both sides, and the sync logic goes in the middle. For each event, the handler does four things.

  • Parse the payload to find what changed (task created, updated, or deleted), using the Quire API Document - Notification Events for the event structure.
  • Decide which API calls reflect that change on the other side.
  • Send those requests to Quire or the other app.
  • Record the link between the Quire task ID and the other app's item ID, so the next update lands on the right record.

Here's an example using Node.js and axios.

const axios = require('axios');

app.post('/webhook', (req, res) => {
  const { type } = req.body.data;
  // Reference of activity types: 
  // https://github.com/quire-api/quire-api/blob/master/docs/activity_types.md
  switch (type) {
    case 0: //Quire task created
      onQuireTaskCreate();
      break; 
    case 1: //Quire task deleted
      onQuireTaskDelete();
      break;
  }
  res.status(200).send('Event received');
});

// Route for handling events from another app to Quire
app.post('/anotherwebhook', async (req, res) => {
  const { isCreate, id, name, projectId } = req.body;
  if (isCreate) {
    // Create a task in the Quire project
    await axios.post(`https://quire.io/api/task/${projectId}`, { name });
    // Optionally, store the mapping between your app's id and Quire's task id
  } else {
    // Retrieve the corresponding Quire task id using your mapping logic
    const taskOid = getTaskIdByAppEventId(id, projectId);
    // Delete the task from the Quire project
    await axios.delete(`https://quire.io/api/task/${taskOid}`);
  }
  res.status(200).send('Event processed successfully');
});

This handles create and delete events from another app and mirrors them into Quire. Add error handling, and treat the ID mapping as the heart of the sync rather than an afterthought. Lose the mapping and every later update creates a duplicate.

What are the key considerations?

Two rules cover the failures that bite every first implementation.

Track the origin of each change. Tag the updates your sync triggered, and ignore them when they come back as a webhook. Without the tag, Quire pushes to the other app, the other app fires a webhook back, your server pushes again, and the loop runs until someone pulls the plug.

Keep data formats consistent. A field that means one thing in Quire, like a Markdown description, may need explicit conversion before it lands as a calendar event description, a plain-text issue note, or whatever the target expects. Decide the conversion once and apply it on every hop.

A third rule, now that Quire supports it: lock the Custom Fields your sync owns, so a hand edit never fights the next sync. See how to lock a Custom Field.

What goes wrong in the first week?

The loop and the format mismatch are the famous failures. What breaks once real users touch the sync? Four quieter things.

The same event arrives twice. Webhook senders retry when they don't get a fast 200, and a slow handler can be retried mid-work. Record each event's ID when you process it, and skip any ID you've seen. Respond 200 first, then do the work, if the sender's timeout is short.

Events arrive out of order. A rename and a delete can land in the wrong sequence under load. Compare timestamps before applying a change, and never apply an older state over a newer one.

The mapping table disappears. It was in memory, the server restarted, and now nothing matches. Put the mapping in a database from day one. It's the only state the sync owns, and it's the whole sync.

A record is deleted on one side only. Decide the policy before it happens. Delete the twin, archive it, or flag it for a human, but decide, because the default (do nothing) leaves an orphan on one side that a later update will try to find.

None of these needs clever code. They need a decision written down before the first user hits the edge case, which is the kind of decision that's hard to make at 2 a.m. and easy to make now.

What's the next step?

Start with the smallest sync that can work. One event type, one direction. Create a task in Quire, watch it appear in the other app, and confirm nothing bounces back. Then add the reverse direction, then the second event type.

Open API plus webhooks turns Quire and your other tools into one record instead of two competing ones. Build it in that order and the loop never gets a chance to start.

Related: Integrate External Tools with Quire via Quire API, Using n8n as an Example, a worked example if you'd rather start with a no-code automation tool than a custom server.

A two-way sync sits near the top of the automation ladder. For the rungs below it, see what to automate first in Quire, from recurring tasks to Zapier recipes.

Task management software to break big goals into the next small step

Frequently Asked Questions

What is two-way sync between Quire and another app?

A bidirectional connection where updates flow both ways: changes in Quire push to the other app, and changes there push back to Quire. The Google Calendar Two-Way Sync app is a working example.

What do I need to build a two-way sync with the Quire API?

A Quire app with API credentials, a middle-layer server reachable from the internet to receive webhooks, and logic to translate events between the two APIs. Any backend language works.

What role does the middle-layer app play?

It acts as a translator between Quire and the other service, receiving webhook events, deciding what API calls to make, and maintaining the mapping between Quire task IDs and the other app's item IDs.

How do I prevent infinite sync loops?

Track where each change originated and ignore updates triggered by your own sync process. Without this safeguard, every update ping-pongs between the two apps forever.

Which Quire plan is required for Google Calendar Two-Way Sync?

Premium and up. Check the current tier limits on the pricing page.

Whiter
Software Engineer