Custom Integrations Improvement 1 - Officially support writable fields

Custom Integrations Feature request (1 of 2): Officially support writable fields

TLDR

Two major feature requests for Custom Integrations to enable robust bi-directional sync, based on the existing Jira integration.

  1. Improve and document how the Jira integration editable fields work.
  2. Add the ability to create in Custom Integration DBs and extend some of the Jira functionality.

This proposal would not require the Fibery team to make a bi-directional sync engine or API. See part 2 here: Custom Integrations Improvement 2 - Allow creates and emit posts for creates and deletes

If you do happen to read this, thanks! I’ve spent a ton of time thinking about this problem and even taught myself a bit of programming to try to make it a reality!

Disclaimer: I did have some LLM assistance for the generation and review of this request, however I have done significant testing around this issue and feel confident in my proposal.

Summary

This is a two-part feature request intended to give a concrete path for Fibery to support bi-directional sync by improving the current Custom Integrations API, without having to build a bi-directional sync engine. The general intention is for Fibery to provide a few additional features that would make it easier for developers to implement their own bi-directional sync. Request 1 asks for official support of the writable fields used in the Jira integration, with expanded type support and improvements to the /api/v1/synchronizer/execute endpoint. Request 2 adds record creation and deletion for Custom Integrations, sent through the same /api/v1/synchronizer/execute endpoint.

Rationale

Fibery can replace a lot of software, but almost every company still runs some it can’t replace. Some systems are required by someone else: my accountants require QuickBooks for accounting and payroll. Others serve a specialized field, where rebuilding them in a general-purpose tool isn’t realistic, or isn’t a risk a company is willing to take.

The people working in Fibery still need that data. Custom Integrations bring it in, but only one way. To change anything, users leave Fibery, make the edit in the other system, and wait for the next sync to bring it back. Fibery becomes a place to look at that data, not to work with it.

That gap matters most in a big part of the small and medium business software market: project and inventory management tools that sync both ways with accounting software like QuickBooks or Xero. Fibery’s flexibility makes it a natural fit there, but it’s an area I don’t think Fibery has addressed well yet.

Bi-directional sync is one of the oldest and most requested features. I’m not asking Fibery to build a sync engine, or an integration for every system. A write-back path already exists, undocumented, behind the Jira beta. I’m asking Fibery to support it, so integration developers can opt in field by field and handle the other system’s rules themselves. Even the first tier alone would make everyday fields, like status, assignee and dates, safe to edit in both directions.

I’ve also built this on the regular API and the Custom Integration API. Both technically work, but the regular API gives up read-only fields and the managed schema, which are the reasons to use a Custom Integration. The Custom Integration implementation uses editable dbs that mirror the integration dbs using automations. This works OK, but requires 6-8 automations per bi-directional sync and is fairly slow since it relies on the single threaded automation executor.

The end goal

With Requests 1 and 2 in place, a Custom Integration could run a full bi-directional sync with an outside system without Fibery becoming a sync engine. Fibery stays the transport and the interface: it reports every change made in Fibery, waits for the integration’s answer, and shows the result. The integration keeps owning everything about the outside system: mapping, conflicts, its rules, and the source of truth.

Proposal

Support writable fields as a documented, stable part of the Custom Integration API. I set up a test integration to validate the current behavior. It already works for simple fields: text, numbers, dates, checkboxes, single-selects and single links. Before an integration could rely on it, a few gaps would need closing:

  • Some edits are never sent: lists (linked records, multi-selects, file lists), rich text, and clearing a single-select (O4, O5).
  • A failed delivery disappears. It’s retried for about 33 seconds and then dropped, and the edit stays in Fibery with no message to anyone (O3).
  • One slow reply blocks everything. Edits to other records wait behind it, for up to about 9.5 minutes (O3).
  • Nothing says who made an edit, or what it replaced, so an integration can’t tell a user’s change from a rule reacting to the integration’s own sync, or check it against the outside system for conflicts (O6).
# Change Tier
A1 Support and document writable fields and the execute callback 1: support what already exists
A2 Send clears consistently 1
A3 Make failed edits visible 1
A4 Say who made an edit, how, and what it replaced 1
A5 Send list and rich-text edits, and allow writable workflow fields 2: complete the update path
A6 A reply contract: an error undoes the edit and shows a message, in the reply or later 2
A7 Queue per record, not per integration 2
A8 Files: a download link, and claiming an upload 2
A9 Apply only the fields a push carries 2
N1 Fields the integration requires Nice to have
N2 Closed select fields Nice to have

Tier 1 makes the existing path a supported feature, with small changes that make it safe to rely on. Tier 2 extends the callback to the edits it misses today, and stops pushes from overwriting edits. Scheduled syncs into Fibery don’t change, and integrations without writable fields are unaffected.

For Fibery end-users

  • A synced database works like a native one, for whatever the integration allows. People edit fields, link records, tag them, write notes and attach files, from any view, and through automations or the API. With Request 2, they can also create and delete records. Fields the integration doesn’t allow stay read-only.
  • An accepted change looks like any other edit. Values the outside system adds or adjusts, such as a generated number or a rounded amount, appear right away.
  • A rejected change is undone, and the person who made it sees why, on the record and in a notification: “A customer with this name already exists.” Nothing is lost silently.
  • A new record shows as pending until the outside system confirms it (Request 2). If it can’t be created, it stays, marked failed, with Retry and Discard.

For people building integrations

  • Opt in per field and per type. Mark fields writable in the schema, and declare update, create or delete in the sync config. Optionally, mark fields the sync depends on as required, and select fields as closed.
  • One callback for every change. Each change made in Fibery reaches execute once, however it was made. It carries only what changed: plain values, null for clears, added and removed items for lists, rich text once editing pauses, and a download link for files.
  • Every change says who, how, and what it replaced: the user; whether a person, a rule, a button or the API made it, including whether a rule was reacting to the integration’s own sync; and each field’s previous value. Echoes are easy to skip, conflicts are easy to check, and the outside system’s audit trail gets real names.
  • The reply decides the outcome. A success, optionally with final values that Fibery applies and keeps as its baseline. An error with a message, which undoes the change and shows the message. For a create, the outside ID, which Fibery stores on the record. Work that finishes after the reply can report the same results later.
  • Sync on every edit, or on save. An integration can send each change straight on, or stage changes and send them when someone clicks a button (see Anticipated questions).
  • Predictable delivery. A documented timeout and retry schedule, a correlation ID to use as an idempotency key, and changes kept in order per record, so one slow record never holds up the rest.
  • Files make the round trip. The integration downloads an upload without a Fibery API token, then claims it with its own file key, so the next sync neither duplicates nor replaces it. Alternatively, Fibery could give the integration a regular API token, so it can sync files through the regular API.

One record’s life

A job in an outside system, synced into a Fibery database whose integration opts into all of the above:

  1. Create. Someone creates an “Install panel” job in Fibery and links it to a customer they created a minute earlier. Both show as pending. The integration receives the customer’s create, then the job’s, with the link pointing at the customer’s Fibery ID. It creates both in the outside system and replies with their IDs and the job’s generated number, J-0042. Both records are confirmed. (Request 2: B1)
  2. Lists and files. Someone tags the job “Urgent” and attaches a spec sheet. The integration receives {"added": ["Urgent"]} and the file with a download link. It uploads the file to the outside system and claims the Fibery copy with the outside key. (A5, A8)
  3. Who and how. A rule sets Priority to High when a job is tagged Urgent. That edit arrives marked as coming from the rule, and the integration passes it on. Later, a rename made in the outside system syncs in, and a rule reacting to it edits the job. That edit arrives marked triggeredBySync, and the integration skips it. (A4)
  4. Rejection. Someone moves the job’s start date past its due date, which the outside system refuses. The integration replies 400 with “Start date is after the due date.” Fibery restores the old date and tells them why. (A3, A6)
  5. Outage. The outside system is down for a minute during an edit. Fibery retries that record’s change with the same correlation ID, while edits to other records keep flowing. If the retries ran out, the edit would be marked failed instead of disappearing. (A3, A7)
  6. Clear. Someone clears the job’s assignee. The integration receives null and unassigns it. (A2)
  7. Delete. Someone deletes the job. The outside system archives jobs rather than deleting them, so the integration replies keep with active: false, and the job stays in Fibery as inactive. (Request 2: B2)

What stays the same

  • Fibery doesn’t map fields, resolve conflicts or decide which side is right. The integration does.
  • Fibery’s permissions decide who can edit what, including locking records the outside system treats as final, such as a billed invoice. The protocol doesn’t need locks of its own, and the integration can still reject an edit as a backstop (A6).
  • Scheduled syncs into Fibery work as they do today.
  • Integrations that don’t opt in see no change.

What this request delivers on its own

Request 2 completes the picture, but this request is worth doing without it. In the walkthrough above, every step except create (1) and delete (7) needs only Request 1.

Bi-directional editing for records the outside system owns. In many integrations, records are born in the outside system: jobs, tickets, orders. Fibery is where people plan, coordinate and update them. That pattern needs edits to flow back, but creation and deletion can stay in the outside system. The Jira beta follows the same pattern.

Concretely, with Request 1 alone:

  • Every Custom Integration can offer what the Jira beta offers, on a documented contract, with the gaps closed.
  • Integration builders can rely on it. Today, anyone who ships editable fields is building on an internal detail that could change without notice.
  • No silent data loss. An edit either reaches the outside system or is visibly marked failed and, with A6, undone.

Tier 1 is useful on its own, too. With A1–A4 alone, an integration can safely offer the field types that work today, which cover the everyday fields of a typical work record: name, status, assignee, priority and dates. Clears arrive, failures are visible, echoes can be skipped, and conflicts can be checked. Tier 2 then adds links between records, tags, notes and files, keeps one slow record from holding up the rest, and stops pushes from overwriting edits.

What still needs Request 2: creating records from Fibery and deleting them.


Changes in detail

Each change cites the observations behind it (O1–O10, under Background).

Tier 1: support what already exists

A1. Support and document writable fields and execute. Treat writable fields, the actions declaration and the execute callback like the rest of the Custom Integration API: documented, kept stable, and changed only with notice. The documentation would cover what makes a field editable (O1), the execute request, replies, retries, timeout and queueing (O1–O3), the value sent for each field type (O4), file fields and the resource endpoint (O5), whole-record application (O7), field selection (O8), and the undocumented protocol fields (O9).

A2. Send clears consistently. Clearing any writable field sends null, including single-selects (which send nothing today) and relations (O4).

A3. Make failed edits visible. When an edit is rejected with a 4xx, or its retries run out, mark it on the record, notify the person who made it, and list it in the integration’s settings (O3).

A4. Say who made an edit, how, and what it replaced. Add the acting user, the origin and each changed field’s previous value to each execute record, including whether an automation was reacting to the integration’s own sync:

{ "id": "t-1", "fields": { "flagged": true }, "previous": { "flagged": false },
  "editedBy": { "id": "5af2db22-…", "email": "…" },
  "origin": { "type": "automation", "ruleId": "6ae63de1…", "triggeredBySync": true } }

Without the editor and origin, the outside system can’t attribute changes to people, and an integration can’t recognize echoes of its own data, which is how sync loops start (O6). Without the previous value, it can’t check for a conflict (does the outside system still hold what the user changed?) unless it keeps its own copy of every record. Fibery’s activity history already records all of this (O6).

Tier 2: complete the update path

A5. Send list and rich-text edits, and allow writable workflow fields (O4).

  • Lists (many-to-many relations, multi-selects, file lists) as added and removed items, the shape Fibery’s webhooks use, so two quick edits can’t overwrite each other: "tags": {"added": ["Bug"], "removed": []}.
  • Rich text as Markdown or HTML, matching the schema, once editing pauses.
  • Workflow fields honor writable: true, like single-selects.

A6. A reply contract, in the reply or later. An error reply carries a message, such as {"message": "A customer with this name already exists"}. When retries stop, Fibery undoes the edit and shows the message (A3). A success reply can carry the record’s final values, such as a rounded amount or a generated number, which Fibery applies right away and keeps as its baseline. An integration that replies first and finishes the work later, as rate limits often require, can report the same results afterwards for the record, with the same effect (O2).

A7. Queue per record, not per integration. Keep each record’s edits in order, but don’t hold other records behind a slow or failing call (O3).

A8. Files: a download link, and claiming an upload (O5).

  • Send file changes as added and removed files (A5), each with its name, type, size and a short-lived download link that works without a Fibery API token. An endpoint authenticated with the integration’s account credentials would work too.
  • Let the integration claim an upload. A file value like {"fiberyId": "01a19333-…", "fileKey": "src-778"}, in a sync or an execute reply, attaches the outside system’s key to the existing file instead of adding a copy.

A9. Apply only the fields a push carries. As an opt-in, for example a flag on the push, apply only the fields in a webhook push (O7). Otherwise a push that arrives while an edit is still on its way out overwrites the edit in Fibery while the outside system receives the new value, and the two stay out of step until something else changes.

Nice to have

  • N1. Required fields: a schema flag for fields the sync depends on, so users can’t turn them off and they’re never deleted with a field selection (O8).
  • N2. Closed selects: a schema option that stops users creating options the outside system doesn’t have (O4).

Background: what I observed

All observations come from a self-hosted probe: a configurable Custom Integration server that logs every request Fibery makes. Testing ran from 2026-09-06 to 2026-10-31 and captured 1,224 requests in a live workspace. Where an edit sent “nothing”, Fibery’s activity history shows the edit happened and no request reached the integration.

O1. An undocumented write-back path already exists

I found it in the Jira integration’s configuration, whose writable type declares "actions": {"update": {}} next to its writable fields. Copied into my own integration, it worked. With responsibleFor.dataProviding: true in the app config, writable: true on a schema field, and "actions": {"update": {}} on the type, the field becomes editable and every edit is POSTed to an undocumented endpoint. Without the actions declaration, the field is still editable but nothing is sent.

POST {basePath}/api/v1/synchronizer/execute

{
  "account": { "_id": "…", "auth": "token", "token": "…", "…": "…" },
  "action": { "update": { "task": [
    { "id": "t-2", "fields": { "statusId": { "id": "s-done", "name": "Done" } } }
  ] } },
  "filter": { "enable_sync_source": true },
  "types": ["task", "status", "user"]
}

Only changed fields are sent, keyed by action, then type. Scalars are plain values, and relations arrive as {id, name}.

O2. The reply body is ignored

Only the status code matters, and only for retries (O3). An integration can’t reject an edit visibly or confirm the values it saved.

O3. Delivery: retries, a timeout, and one queue

execute reply What Fibery did
500 or 502 5 retries over about 33 s (+1.3, +2.3, +4.4, +8.8, +16.4 s) with the same correlation ID, then dropped
400 no retry
200 after 30 s accepted
200 after 90 s treated as failed and retried
  • Failed edits are silently lost. The edited value stays in Fibery, with no error, toast or marker.
  • One queue for the whole integration. While one call was slow, edits to other records waited behind it and arrived about 85 s late. A hung reply can block every edit for about 9.5 minutes before it’s dropped.

O4. Which field types are sent

Writable field Edit Sent to execute
Text, number, checkbox, URL, email, date, date-time set / clear the value / null
Many-to-one relation set / clear {"id", "name"} / {"id": null, "name": null}
Single-select set the option name, even for an option a user just created in Fibery
Single-select clear nothing
Many-to-many relation, multi-select add or remove nothing
Rich text edit nothing
Workflow — can’t be edited, despite writable: true

O5. Files

subType: "file" gives a single-file field or a file list, and both can be writable. Files from the integration arrive as app://resource?…&__file-key=… URLs, which Fibery fetches through POST /api/v1/synchronizer/resource, and fetches again only when the key changes.

  • Uploading to a single-file field sends only {"fibery/id": "…"}, and reading the file then takes a Fibery API token. Uploading to or removing from a file list sends nothing.
  • The round trip breaks. Sync only reconciles files the integration supplied, and a returned fibery/id is ignored. So sending back the outside system’s copy replaces the upload in a single-file field and duplicates it in a list, and a file removed from a list comes back at the next sync.

O6. Every edit path reaches execute, including echoes

The entity view, tables, board drags, buttons, automations, the API, bulk edits (one call per record, sharing one correlation ID), undo and history reverts all send ordinary updates.

The echo loop. A rename synced in from the outside system triggered an automation, whose edit came back through execute about 7 s later, indistinguishable from a user’s edit. Nothing in the call identifies the editor, and the account’s owner is just whoever connected the integration. Fibery’s activity history does know: it records the author, fromService: "automations" with the rule ID, fromService: "vizydrop_data_sync" with the integration ID, and each field’s before and after values.

O7. Synced records are re-applied whole

Fibery applies a synced record only when it differs from the last values the integration sent, and then applies all of it. Fields left out of a full sync are emptied. So an edit the outside system never accepted survives while that system is quiet, then is overwritten when any other field of the record changes there. Webhook pushes behave the same way.

O8. Field selection is Fibery’s, and changes are silent

A field added to an already-synced database arrives turned off, whatever the schema says. Clearing an integration’s field selection deleted the fields, breaking every formula and auto-link that used them.

O9. Undocumented or inert protocol fields

Data requests carry lastFullSynchronizedAt and lastSynchronizationCheckpoint, and the checkpoint was always null. verifyEntitiesExist, set on Jira’s writable type, had no visible effect. Across 34 manual sync clicks, data was requested 0–97 s later (median 22 s).

O10. Why not the regular API

I built the same bi-directional sync on the regular API with webhooks. It worked, with changes reaching the other system in 4–8 s, but it lacks what a Custom Integration provides:

Need Regular API Custom Integration
Read-only fields no; access is per database non-writable fields can’t be edited
Schema stays intact users can delete or retype fields Fibery manages the schema
Telling its own writes from users’ edits no its own writes never arrive on execute (rules reacting to them do, O6)
Safe concurrent writes no conditional writes one call per edit, with only the changed fields

Hard parts, and how I’d solve them in implementation

  • Undoing after a newer edit (A6): whether the error comes in the reply or later, undo a field only if it still holds the rejected value; otherwise just show the message.
  • Rich text (A5): send it once editing pauses, in alignment with upcoming tracked changes and webhooks.
  • Lists under concurrency (A5): added and removed items, delivered in order per record, can’t overwrite each other.
  • Related records (A7): keep each record’s edits in order, and deliver across records in edit order. Integrations handle cross-record dependencies from syncs and webhooks the same way.
  • Retries and duplicates: the correlation ID that retries reuse (O3), paired with the record ID, works as an idempotency key once it’s documented.
  • Loops (A4): Fibery doesn’t need to prevent them. The origin lets the integration skip its own echoes.
  • Call volume: these changes add calls only for edits that are dropped today.

The integration takes care of the rest: conflicts with its own source, echoes, retries into the outside system and its rate limits, and which fields are writable at all.

Anticipated questions

Doesn’t this make Fibery responsible for sync correctness? No. Fibery reports each change once and honors the reply. Conflicts, retries into the outside system and source-of-truth decisions stay in the integration.

What about integrations that don’t opt in? Nothing changes for them.

Does every edit have to sync immediately? No. An integration can stage edits and send them when someone is ready, using an external Action button or an HTTP request automation, with the result reported through A6. That suits records that should be reviewed before they reach the outside system, such as an invoice, and records the outside system needs in one call (Request 2). I prototyped the staging half with the probe: the first edit flips a read-only “Edited” checkbox through a push, later edits accumulate, and saving or reverting releases them. A9 would make this simpler, since each push currently has to repeat the staged values.

Out of scope

  • Creating and deleting records in synced databases: see Request 2.
  • A native bi-directional sync engine, field mapping, or conflict resolution.
  • Any change to scheduled syncs into Fibery.

Open questions I couldn’t answer from outside

  1. Is dataProviding still required once fields are writable? I only ever removed both together.
  2. Must the Jira-style sync filter be on for execute to fire? Mine always was.
  3. Is there a configuration under which list and rich-text edits reach execute?
  4. Is the queue (O3) per account, per app or per workspace, and what is the exact timeout?
  5. Can a data response return a lastSynchronizationCheckpoint?

Appendix: test setup

A self-hosted Custom Integration probe (Go) in a live workspace, configurable per test (writable fields, declared actions, sync type, deletion markers, and how it answers execute), logging every request and reply. It captured 1,224 requests between 2026-09-06 and 2026-10-31, including 54 execute calls on 2026-10-31. I can share sanitized logs or run further tests on request, including against a beta.