Bidirectional Sync
Outpost acts as a hub for bidirectional synchronization between your support tickets and external issue trackers. Changes flow in both directions — updates in Outpost propagate to the tracker, and changes in the tracker propagate back to Outpost.
How It Works
The sync system uses an adapter plugin pattern. Each external tracker (GitHub Issues, Linear, etc.) has a dedicated sync adapter that knows how to:
- Map Outpost ticket fields to the tracker's data model (and back)
- Receive webhook events from the tracker and apply changes to Outpost
- Push Outpost changes to the tracker via its API
- Handle conflict resolution when both sides change simultaneously
Architecture
┌─────────────────────┐
│ External Tracker │
│ (GitHub / Linear) │
└─────────┬───────────┘
│
webhooks │ ▲ API calls
▼ │
┌─────────────────────┐
│ Sync Adapter │
│ (per-tracker plugin)│
└─────────┬───────────┘
│
map fields │ ▲ map fields
▼ │
┌─────────────────────┐
│ SyncEngine │
│ (orchestrator) │
└─────────┬───────────┘
│
read/write │
▼
┌─────────────────────┐
│ Outpost Database │
│ (tickets, messages) │
└─────────────────────┘
The SyncEngine is the orchestrator that coordinates all sync operations. It processes incoming webhook events from trackers, applies field mappings, and writes changes to the Outpost database. When Outpost tickets change, the SyncEngine notifies the appropriate adapter to push updates back to the external tracker.
Adapter Plugin Pattern
Each sync adapter implements a standard interface that the SyncEngine calls. This makes it straightforward to add support for new trackers without modifying the core sync logic. An adapter is responsible for:
- Field mapping — translating between the tracker's data model and Outpost's ticket model (status, priority, assignee, labels)
- Webhook handling — parsing incoming webhook payloads from the tracker and converting them to Outpost-compatible change events
- Outbound sync — pushing Outpost ticket changes to the tracker's API
- Identity mapping — associating tracker user accounts with Outpost TeamMembers
- Bulk import — importing existing issues from the tracker into Outpost on initial setup
What Syncs
The following fields are synchronized bidirectionally:
| Field | Outpost → Tracker | Tracker → Outpost |
|---|---|---|
| Status | Mapped via status mapping config | Mapped via status mapping config |
| Priority | Mapped to tracker priority levels | Mapped to Outpost priority levels |
| Assignee | Mapped via identity mapping | Mapped via identity mapping |
| Labels / Tags | Applied as tracker labels | Applied as Outpost tags |
| Comments | Posted as tracker comments | Added as ticket messages |
| Title | Updated in tracker | Updated in Outpost |
Conflict Resolution
When the same field is changed on both sides between sync cycles, Outpost uses a last-write-wins strategy based on timestamps. Each sync event carries a timestamp, and the most recent change takes precedence. Conflict events are logged for audit purposes.
Supported Trackers
| Tracker | Status | Docs |
|---|---|---|
| GitHub Issues | Built-in (via GitHub App) | GitHub App Setup |
| Linear | Available | Linear Integration |
Adding more trackers: The adapter pattern makes it straightforward to add support for Jira, Asana, or any other issue tracker. See the Contributing guide for details on implementing a new sync adapter.