Skip to Content
ReferenceData exportOverview

Data export

A copy of everything your organization holds on plugsync, as one ZIP package: connector configurations, plugins and their storage, identity mappings, sync history, recorded payloads, agent conversations, event source samples, conflicts, the outcomes of bulk imports and verifications, the reports of file sources with the rows they discarded, and usage figures. Use it to keep your own archive, to audit what the platform stores about your records, or to take your data with you. What a package leaves out is listed in its manifest, with the reason (see What is not in the package).

An export is asked for, prepared in the background, and then downloaded through a signed link:

  1. POST /api/data-exports answers 202 with the export and its id.
  2. GET /api/data-exports/{id} shows its status. Preparation usually starts within a minute; how long it takes depends on how much data the organization holds.
  3. Once the status is completed, GET /api/data-exports/{id}/download returns a signed link to the ZIP.

The same flow is in the dashboard under Settings > Organization > Data export.

Who can export

The owners of the organization, and the organization’s API keys. A member gets 403. An export, like a connector, belongs to one organization: the id of an export or of a connector of another organization answers 404.

A package holds payloads, plugin code and agent conversations, exactly as you wrote or sent them (see Secrets you wrote yourself). Treat the package, and a key that can ask for one, like a credential.

Scope

Request bodyWhat is exported
{} or no bodyThe whole organization: every connector, every plugin, every agent conversation
{"connector_id": "<id>"}One connector: its configuration, mappings, history, recorded payloads, plugin storage, source samples, conflicts, bulk imports, verifications, file source reports, daily usage and the agent conversations about it. Plugins belong to the organization, so all of them are included. The monthly event count belongs to the organization, so usage/monthly_events.jsonl is empty

One export per scope can be in preparation at a time: asking again while one is queued or running answers 409 data_export_in_progress with the export_id of the one in progress. An organization can ask for 10 exports per 24 hours; past that the answer is 429 data_export_limit_reached.

AnswerWhen
404 connector_not_foundThe connector does not exist in this organization, or was deleted while the request was being handled
409 data_export_in_progressAn export of the same scope is queued or running
409 organization_closedThe organization was closed and its recovery period is over
429 data_export_limit_reached10 exports were requested in the last 24 hours

The API error catalog collects these codes with the errors of every other public route.

API

All routes take Authorization: Bearer <token or API key>.

POST /api/data-exports

curl -X POST https://app.plugsync.com/api/data-exports \ -H "Authorization: Bearer $PLUGSYNC_API_KEY" \ -H "Content-Type: application/json" \ -d '{}'
{ "id": "5b0e6a52-7a0f-4d53-9c1e-2f4f0a1f7c11", "scope": "organization", "connector_id": null, "status": "queued", "requested_by": "api-key:backup", "created_at": "2026-10-08T09:00:00Z", "completed_at": null, "expires_at": null, "size_bytes": null, "error": null, "categories": [] }

GET /api/data-exports and GET /api/data-exports/{id}

The list returns the 20 most recent exports of the organization, newest first, as {"exports": [...]}. Each has the shape above.

FieldMeaning
statusqueued, running, completed, failed or expired
requested_byThe email of the owner, or api-key:<label>
completed_atWhen the package was ready
expires_atUntil when the package can be downloaded: 7 days after completed_at
size_bytesSize of the ZIP
errorOn a failed export, why (see below); otherwise null
categoriesOn a completed export, the categories and files of the package with their record counts (the same list as in manifest.json)
StatusWhat it meansWhat to do
queuedWaiting to be preparedPoll
runningBeing preparedPoll
completedThe package is ready until expires_atDownload
failedThe export stopped for goodRead error
expiredThe package has been deletedAsk for a new export
errorWhat happenedWhat to do
export_failedPreparation failed three times. The attempts are spaced out: the second starts 2 minutes after the first failure, the third 10 minutes after the secondAsk for a new export
scope_not_foundThe connector of the export was deleted before the package was readyNothing: its data is gone
organization_closedThe organization reached the end of its recovery period before the package was readyNothing

GET /api/data-exports/{id}/download

{ "url": "https://...", "filename": "plugsync-export-20261008-5b0e6a52.zip", "expires_in_seconds": 300 }

url is a signed link valid for 5 minutes: fetch it right away, without the Authorization header. Ask for a new link whenever you need one, for as long as the package exists.

AnswerWhen
409 data_export_not_readyThe export is still queued or running
410 data_export_expiredThe package is past expires_at, or was deleted earlier (see below)
410 data_export_failedThe export failed
503 data_export_unavailableData export is temporarily unavailable; retry later

How long a package is kept

A package can be downloaded for 7 days after it is ready, then it is deleted and the export shows as expired.

Deleting a connector expires every package of its organization, because a package may hold that connector’s data: the exports show as expired and their download answers 410 as soon as the connector is deleted, and the files are removed right after. An export that was still being prepared at that moment is prepared again without the deleted connector, so it can take longer than usual; a package requested after the deletion is not affected.

Closing the organization deletes the packages with everything else at the end of the recovery period; until then exports can still be requested and downloaded. At the end of the period an export still in preparation fails with organization_closed.

A package is a snapshot taken while syncs keep running. Each file is read once, front to back; records written while it is being read may or may not be in it.

The package

manifest.json connectors.jsonl configuration/versions.jsonl configuration/drafts.jsonl plugins/plugins.jsonl plugins/storage.jsonl plugins/<plugin name>/source.ts plugins/<plugin name>/bundle.js identity_mappings.jsonl sync_history.jsonl recorded_payloads.jsonl agent_conversations.jsonl source_samples.jsonl conflicts.jsonl bulk_imports/jobs.jsonl bulk_imports/rows.jsonl verifications/jobs.jsonl verifications/rows.jsonl file_sources/files.jsonl file_sources/discarded_rows.jsonl usage/monthly_events.jsonl usage/daily_counters.jsonl

Every category is always present: a file with no records is an empty file, and its entry in the manifest says "records": 0.

.jsonl files are JSON Lines : UTF-8, one JSON object per line, no enclosing array. Read them line by line; the larger files (identity_mappings.jsonl, sync_history.jsonl, bulk_imports/rows.jsonl) can hold millions of lines. Timestamps are ISO 8601 in UTC. A field with no value is null.

The ZIP uses the ZIP64 extensions when it needs them (a file over 4 GB, or a package over 4 GB). Current versions of unzip, 7-Zip, Python’s zipfile and the archive tools of macOS and Windows read it.

manifest.json

The index of the package. Start here.

{ "format_version": 1, "export_id": "5b0e6a52-7a0f-4d53-9c1e-2f4f0a1f7c11", "organization_id": "0d0c9a3e-3a67-4b0e-b1a5-1f1f6a2b9d10", "scope": "organization", "connector_ids": ["9c7f0b5e-0a55-4b71-8f3b-6f1c2b7a4e02"], "generated_at": "2026-10-08T09:01:12.412301+00:00", "categories": [ { "name": "identity_mappings", "files": [ { "path": "identity_mappings.jsonl", "format": "jsonl", "records": 18304 } ] }, { "name": "plugins", "files": [ { "path": "plugins/plugins.jsonl", "format": "jsonl", "records": 1 }, { "path": "plugins/bank-check/source.ts", "format": "typescript", "plugin": "bank-check", "bytes": 2210 }, { "path": "plugins/bank-check/bundle.js", "format": "javascript", "plugin": "bank-check", "bytes": 48113 } ] } ], "exclusions": [ { "name": "credentials", "description": "The credentials saved on the platform: connector credentials (OAuth tokens, API keys, passwords), the secrets of the event sources (such as webhook signing secrets) and the API keys of the organization.", "reason": "They are secrets. They are stored encrypted and never leave the platform; the configuration refers to them by name, and the name is exported." } ] }
FieldMeaning
format_versionVersion of the layout described on this page. It changes only when a file is removed or renamed, or a field changes meaning. New files and new fields can appear without a new version: ignore what you do not know
scopeorganization or connector
connector_idsThe connectors the package covers
categories[].nameconnectors, configuration, plugins, plugin_storage, identity_mappings, sync_history, recorded_payloads, agent_conversations, source_samples, conflicts, bulk_imports, verifications, file_sources, usage
categories[].files[]path in the ZIP and format; records for a .jsonl file; bytes and plugin for a plugin code file
exclusions[]What the package leaves out: a stable name, a description of what is left out and the reason. The list is the same for every package (see What is not in the package)

connectors.jsonl

One line per connector.

FieldMeaning
id, nameThe connector
statusIts status when the export was taken
modelive or test
default_store_idThe default store of a multi-store connector
created_at, updated_at

The credentials of a connector are never exported: the tokens, API keys and passwords you saved for it are not in the package in any form.

configuration/versions.jsonl

One line per published version of each connector, the full history.

FieldMeaning
connector_id, versionWhich connector, which version number
is_activetrue on the version that is running
published_at, published_byWhen, and who: the email of the member who published, or a fixed name such as agent, system or api-key@system when the agent, the platform or an API key did it
change_summaryThe note attached at publish, if any
configThe whole configuration of that version, as in Config V3

configuration/drafts.jsonl

One line per connector: the draft being edited, published or not.

FieldMeaning
connector_id
base_versionThe published version the draft started from
updated_at, updated_byWhen, and who last saved it (same values as published_by)
configThe draft configuration

plugins/plugins.jsonl and the code files

One line per plugin of the organization.

FieldMeaning
id, nameThe plugin
statusIts lifecycle status (see Plugins)
capabilitiesThe capabilities it declares
staging_version, live_versionThe promoted versions
bundle_sha256SHA-256 of the bundle
has_source, has_bundleWhether source.ts and bundle.js are in the package for this plugin
last_deployed_at, created_at, updated_at

The code is next to it: plugins/<plugin name>/source.ts is the TypeScript you pushed, plugins/<plugin name>/bundle.js the bundle built from it. Take the exact paths from the manifest: characters that are not letters, digits, ., _ or - are replaced with _ in the folder name.

plugins/storage.jsonl

One line per key in the key-value store of a plugin on a connector (see the store capability).

FieldMeaning
connector_id, pluginWhose storage
key
valueThe stored value, as JSON
updated_at
expires_atWhen the key expires, or null. Keys already expired are not exported

identity_mappings.jsonl

One line per record the platform has linked: the id in your system and the id of the HubSpot object.

FieldMeaning
connector_id
entity_typeThe entity of your configuration
store_idThe store, on a multi-store connector; otherwise null
external_idThe id in your system
hubspot_idThe id of the HubSpot object
hubspot_object_typeThe HubSpot object type
metadataExtra data kept with the mapping, if any
last_synced_at, created_at, updated_at

Other fields can be present on some lines (for example the timestamps used to resolve conflicts on bidirectional connectors).

sync_history.jsonl

One line per synced record, as listed by GET /api/connectors/{connector_id}/sync-events. Lines are in no particular order: sort on created_at if you need one.

FieldMeaning
id, connector_id
entity_name, event_type, actionWhat was synced
directioninbound or outbound
statusThe outcome (see Reliability)
source_id, external_id, hubspot_id, store_idThe record
occurred_atWhen the event happened in the source system
retry_count
error_detail, errorThe last error, as text and structured
step_traceThe steps the flow executed
payloadThe payload of the event, kept only when the event did not succeed (so that it can be replayed). null for an event that succeeded, and once the payload has been pruned
payload_pruned_atWhen the payload was pruned, if it was
created_at, updated_at

Only the history still kept is exported: rows and payloads already removed by data retention are not in the package.

recorded_payloads.jsonl

One line per event archived by record mode, with the payload exactly as it was received. Empty when record mode was never enabled.

FieldMeaning
connector_id, event_id
directioninbound or outbound
source_name, event_type, external_id
occurred_at, recorded_at
payloadThe raw payload

agent_conversations.jsonl

One line per conversation with the AI agent.

FieldMeaning
id
connector_idThe connector the conversation was about, or null
title, status
messagesThe messages, in order
created_at, updated_at

A connector export holds only the conversations about that connector.

source_samples.jsonl

One line per event source: the last payload that source received, the one the mapping editor shows as a sample. A source that has received nothing yet has no line.

FieldMeaning
id, connector_id
source_nameThe event source. event_api for events sent to the Event API
event_typeThe event type of the sample, if it had one
received_atWhen it was received
payloadThe payload, as received

conflicts.jsonl

One line per conflict detected on a bidirectional connector (see Loop prevention and conflicts).

FieldMeaning
id, connector_id
entity_type, external_id, store_idThe record
statuspending, resolved or expired
resolutionHow it was resolved (source_wins, target_wins or merged), or null
resolved_by, resolved_atWho or what resolved it, and when
reconciliation_statusWhether the resolved values were sent back to your system: none, pending or done
source_data, target_dataThe two versions of the conflicting properties: yours and the one on HubSpot
resolved_dataThe values kept, once resolved
source_modified_at, target_modified_atWhen each side last changed
created_atWhen the conflict was detected

bulk_imports/jobs.jsonl and bulk_imports/rows.jsonl

jobs.jsonl has one line per bulk import, including the ones a file source started.

FieldMeaning
id, connector_id, store_id
moderaw or flows
statusqueued, running, completed, partial_failure or failed
entities_total, entities_succeeded, entities_failed, entities_skippedThe totals of the import
last_errorThe last error of the import as a whole, if any
created_at, started_at, completed_at

rows.jsonl has one line per record of an import whose outcome was kept.

FieldMeaning
id
job_idThe id of the import in jobs.jsonl
referenceThe reference of the record in your request or file
statussucceeded, failed or skipped
error_category, error_messageWhy it failed, if it did
created_at

verifications/jobs.jsonl and verifications/rows.jsonl

jobs.jsonl has one line per verification: a comparison between a batch of your records and what is on HubSpot.

FieldMeaning
id, connector_id, store_id
entity_type, external_id_propertyWhat was compared, and the property that identifies a record
source_batch_idThe batch the verification refers to, if any
statusqueued, running, completed, partial_failure or failed
records_total, records_ok, records_diff, records_absent, records_errorThe totals: identical, different, not found, not checked
last_errorThe last error of the verification as a whole, if any
created_at, started_at, completed_at

rows.jsonl has one line per record whose outcome was kept.

FieldMeaning
id
job_idThe id of the verification in jobs.jsonl
referenceThe reference of the record
statusok, diff, absent or error
differencesPer property, the value expected and the actual value found
error_messageWhy the record could not be checked, if so
created_at

file_sources/files.jsonl and file_sources/discarded_rows.jsonl

files.jsonl has one line per file a file source has read (see Event sources), with the report of its last processing. The files themselves are not in the package: they are on your server.

FieldMeaning
connector_id, source_name, filenameWhich file, of which source
statusprocessed, processed_with_errors, failed or changed_blocked
size, mtime, sha256The file as it was read: size in bytes, modification time, SHA-256 of its content
processed_at
job_idThe id of the bulk import the file started, in bulk_imports/jobs.jsonl, or null
rows_total, rows_discarded, rows_repaired, rows_reconciledThe row counts of the file
entities_failedRecords that failed downstream, when known
errorWhy the file failed, if it did
post_action_pending, post_action_errorThe state of the action configured to run on the file after processing, if one is pending or failed

A field the report of a file does not carry is null.

discarded_rows.jsonl has one line per discarded row the platform has kept. It keeps the first 20 discarded rows of each file, not all of them: rows_discarded in files.jsonl is the full count. A raw longer than 2,000 characters is cut at that length. The rows are kept for the files the source still tracks: a processed file that has left the remote directory stops being tracked after 90 days, or sooner once the source tracks more than 1,000 files, and its rows go with it. When a file is processed again, the rows it discards replace the ones kept before.

FieldMeaning
connector_id, source_name, filenameWhich file
lineThe line number in the file
reasonWhy the row was discarded
rawThe row, as it was in the file

usage/monthly_events.jsonl and usage/daily_counters.jsonl

monthly_events.jsonl has one line per billing month: the events counted against the plan of the organization. It is empty in a connector export.

FieldMeaning
period_start, period_endThe month
events_countEvents counted in that month

daily_counters.jsonl has one line per connector, day, outcome, entity and direction: how many records ended with that outcome that day. These are the figures behind the charts of the connector’s overview.

FieldMeaning
connector_id
dateThe day, in UTC (YYYY-MM-DD)
statusThe outcome counted
entity, directionThe entity and inbound or outbound; null when the count is not attributed to one
count

What is not in the package

Every package says this itself: exclusions in manifest.json carries the same entries under the same names, each with a description and a reason.

nameWhat is left outWhy
credentialsThe credentials you saved on the platform: connector credentials (OAuth tokens, API keys, passwords), the secrets of the event sources (such as webhook signing secrets) and the API keys of the organizationThey are secrets. They are stored encrypted and never leave the platform. A configuration refers to them by name, and only the name is exported
export_filesThe files written by export_file stepsThey are already yours to download from the connector’s Exports tab (see Scheduled exports)
account_dataAccount data of the people in the organization: members, invitations, billingIt describes the account, not the data your connectors process, and it is managed from the dashboard settings
discarded_rows_beyond_sampleThe rows discarded from a file beyond the first 20 of that fileThe platform keeps a sample of the discarded rows of each file, not all of them
data_past_retentionRecords and payloads already deleted at the end of their retention periodData is deleted periodically after its retention period ends. What the platform still holds when the export runs is included
processing_stateWorking data of the processing: the copy of each event as it was received, the values read ahead of an import, the messages held back by a limitIt is what the platform keeps while it works. The outcome of every event is in sync_history.jsonl. The payload is there only for an event that did not succeed. When record mode is on, the payloads are in recorded_payloads.jsonl
platform_logs_and_backupsThe logs and the backups of the platformThey are not kept per organization, so an export cannot package them. A request about them goes through support

The one trace of a member in a package is the email recorded where that member acted: published_by and updated_by in the configuration files, resolved_by in the conflicts.

Secrets you wrote yourself

The package is a faithful copy: nothing in it is masked or rewritten. The platform keeps the credentials you saved out of it, but it cannot tell a secret from any other text in content you wrote or sent. If one of these holds a secret, the package holds it too:

WhereWhat can be there
config in configuration/versions.jsonl and configuration/drafts.jsonlA token typed as a literal in a header, a URL or a body of a step or of an event source, instead of a reference to a saved credential. Every published version is exported, so a literal removed later is still in the older versions
error_detail, error and step_trace in sync_history.jsonlThe URL that was called and the answer of the target system, as text. A key passed in a query string, or echoed back by the target, is in that text. Output traced by a plugin is there too
payload in sync_history.jsonl, the recorded payloads and the source samplesWhatever the source system sent
source_data, target_data and resolved_data in conflicts.jsonl, differences in verifications/rows.jsonl, raw in file_sources/discarded_rows.jsonlValues of your records, as they were sent or read
error_message and last_error in the bulk import and verification files, error in file_sources/files.jsonlThe answer of the target system or of your server, as text
messages in the agent conversationsWhatever was typed or pasted in the chat
plugins/storage.jsonl and the plugin codeWhatever the plugin stored, and any constant in its source

To keep a secret out of future packages, save it as a credential and refer to it from the configuration.

Reading a package

import json, zipfile with zipfile.ZipFile("plugsync-export-20261008-5b0e6a52.zip") as package: manifest = json.loads(package.read("manifest.json")) for category in manifest["categories"]: for entry in category["files"]: print(entry["path"], entry.get("records", entry.get("bytes"))) with package.open("identity_mappings.jsonl") as lines: for line in lines: mapping = json.loads(line) ...
Last updated on