{
  "openapi": "3.0.0",
  "info": {
    "title": "Paragon Sync API",
    "description": "API for managing Syncs and permissions for Connected Users",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://sync.useparagon.com",
      "description": "Production server"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Paragon User Token. Add to the Authorization header of your requests."
      }
    },
    "schemas": {
      "EnableSyncRequest": {
        "type": "object",
        "required": ["integration", "pipeline"],
        "properties": {
          "integration": {
            "type": "string",
            "description": "The integration to use for the sync",
            "example": "googledrive"
          },
          "pipeline": {
            "type": "string",
            "description": "The type of Synced Object to sync from the integration. You can find the list of supported values in [Synced Objects](/managed-sync/synced-objects).",
            "example": "files"
          },
          "configuration": {
            "type": "object",
            "description": "The configuration for this sync. For example, the [folder ID](/managed-sync/integrations/googledrive) to sync from Google Drive. Learn more about the configuration options supported for each integration in the [Integrations Reference](/managed-sync/integrations/amazons3).",
            "additionalProperties": true
          },
          "configurationName": {
            "type": "string",
            "description": "A unique name for this sync configuration. Set this field to a unique value when creating multiple syncs for the same integration and pipeline."
          },
          "credentialId": {
            "type": "string",
            "description": "The ID of the credential to use for syncing data. Use this when your user has connected multiple accounts for the same integration (Multi-Account Authorization). See [Multi-Account Authorization](/apis/api-reference/multi-account-authorization) for details on retrieving credential IDs.\n\nIf not provided, the default credential (oldest active credential) will be used."
          },
          "incrementalAccumulatorFrequency": {
            "type": "string",
            "enum": ["1m", "5m", "10m", "30m", "1h", "3h", "6h", "24h"],
            "description": "Controls how often Paragon checks for incremental changes from the integration for this sync. If not provided, the default frequency is used.\n\nUse a lower frequency (for example, `1h`) when freshness is less important than reducing API calls to the integration.",
            "example": "1m"
          }
        }
      },
      "SyncConflictResponse": {
        "type": "object",
        "required": ["statusCode", "message", "id"],
        "properties": {
          "statusCode": {
            "type": "integer",
            "description": "HTTP status code",
            "example": 409
          },
          "message": {
            "type": "string",
            "description": "Human-readable error message",
            "example": "Sync instance already exists"
          },
          "id": {
            "type": "string",
            "description": "ID of the existing Sync that conflicts with the create request. Use this ID to retrieve, update, disable, or delete the existing Sync.",
            "example": "a11347bd-d510-5489-9068-e5fded55a28c"
          }
        }
      },
      "NewSyncResponse": {
        "type": "object",
        "required": [
          "id",
          "userId",
          "integration",
          "pipeline",
          "projectId",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the sync",
            "example": "a11347bd-d510-5489-9068-e5fded55a28c"
          },
          "userId": {
            "type": "string",
            "description": "ID of the Connected User who enabled the Sync",
            "example": "your-user-id"
          },
          "integration": {
            "type": "string",
            "description": "The integration to use for the sync",
            "example": "googledrive"
          },
          "pipeline": {
            "type": "string",
            "description": "The type of Synced Object being used in this Sync",
            "example": "files"
          },
          "projectId": {
            "type": "string",
            "description": "ID of the Paragon Project that this Sync is associated with",
            "example": "1ea8024c-23a7-4885-b925-c50d0faf9318"
          },
          "status": {
            "$ref": "#/components/schemas/StatusField"
          }
        }
      },
      "StatusField": {
        "type": "string",
        "enum": ["INITIALIZING", "ACTIVE", "IDLE", "RATE_LIMITED", "DISABLED", "ERRORED", "DELETING"],
        "description": "Current state of Sync activity.\nPossible values:\n- `INITIALIZING`: The Sync has just been created and is pending its first run.\n- `ACTIVE`: The Sync is actively fetching new data.\n- `IDLE`: The Sync has completed and is watching for updates to synced data.\n\t- Check `summary.lastSyncedAt` to see if the sync has successfully completed.\n- `RATE_LIMITED`: The Sync is backing off because the third-party API's rate limit was reached. Check `rateLimitBackoffMs` for the back-off duration. The Sync resumes automatically once the back-off period passes.\n- `DISABLED`: The Sync has been paused temporarily by the [Disable a Sync](/managed-sync/api/disable-sync) endpoint.\n- `ERRORED`: The Sync has been suspended due to an error. Check the `errorCode`, `reason`, and `httpStatusCode` fields on the Sync status for details, or [Webhook Events](/managed-sync/webhooks) for the `sync_errored` event.\n- `DELETING`: The Sync is being deleted and its synced data is being removed."
      },
      "SyncStatus": {
        "type": "object",
        "required": ["status", "summary"],
        "properties": {
          "status": {
            "$ref": "#/components/schemas/StatusField"
          },
          "credentialId": {
            "type": "string",
            "description": "The ID of the credential used to authenticate this Sync"
          },
          "incrementalAccumulatorFrequency": {
            "type": "string",
            "enum": ["1m", "5m", "10m", "30m", "1h", "3h", "6h", "24h"],
            "description": "The configured incremental sync frequency for this Sync. Only present when explicitly set on the Sync.",
            "example": "1m"
          },
          "summary": {
            "type": "object",
            "required": ["totalRecords", "syncedRecordsCount"],
            "description": "Metrics on the sync progress and last seen record timestamps",
            "properties": {
              "totalRecords": {
                "type": "integer",
                "description": "Total number of records in the Sync"
              },
              "syncedRecordsCount": {
                "type": "integer",
                "description": "Number of records that have been synced"
              },
              "lastSyncedAt": {
                "type": "string",
                "format": "date-time",
                "description": "Timestamp of when the Sync was last completed"
              },
              "lastPeriodicFullSyncedAt": {
                "type": "string",
                "format": "date-time",
                "description": "Timestamp of when the Sync last completed a [periodic full sync](/managed-sync/sync-api#sync-lifecycle). Only present once the Sync has completed at least one periodic full sync."
              },
              "latestCursor": {
                "type": "string",
                "description": "A paging cursor pointing to records that will be created, updated, or deleted after the `lastSyncedAt` timestamp. This value can change after a full or incremental sync detects new updates; persist your own `paging.cursor` from Pull Synced Records to resume from a specific point."
              }
            }
          },
          "rateLimitBackoffMs": {
            "type": "integer",
            "description": "If the sync status is `RATE_LIMITED`, the duration (in milliseconds) that the Sync is backing off before it resumes fetching data, in response to the third-party API's rate limit.\n\nThe Sync resumes automatically once this back-off period has passed. We recommend waiting at least this long before polling the Sync status again.",
            "example": 30000
          },
          "errorCode": {
            "type": "string",
            "description": "If the sync status is `ERRORED`, a stable code identifying the error that suspended the Sync. Use this field for programmatic handling. See the [error code reference](/managed-sync/webhooks#error-codes) for the full list of codes and suggested actions.",
            "example": "PROXY_7300"
          },
          "reason": {
            "type": "string",
            "description": "If the sync status is `ERRORED`, this field will be populated with a message explaining why the sync failed. The message is captured at the time of failure and reflects the exact error the Sync encountered.",
            "example": "Credential ID [id] is no longer valid or has been deleted."
          },
          "httpStatusCode": {
            "type": "integer",
            "description": "If the sync status is `ERRORED` and the failure came from a third-party API request, the HTTP status code returned by that API (for example, `401` or `403`). Only present when an HTTP status was captured at the time of failure.",
            "example": 401
          }
        }
      },
      "SyncedRecordsResponse": {
        "type": "object",
        "required": ["data", "paging"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Array of synced records. See schemas in [**Synced Objects**](https://docs.useparagon.com/managed-sync/synced-objects) for the available fields.",
            "example": "[/* See schema in Synced Objects */]"
          },
          "paging": {
            "type": "object",
            "required": [
              "totalRecords",
              "totalActiveRecords",
              "remainingRecords",
              "cursor",
              "lastSeen"
            ],
            "properties": {
              "totalRecords": {
                "type": "integer",
                "description": "Total number of records in this Sync"
              },
              "totalActiveRecords": {
                "type": "integer",
                "description": "Total number of non-deleted records tracked by this Sync"
              },
              "remainingRecords": {
                "type": "integer",
                "description": "Number of records remaining to be synced after the current cursor"
              },
              "cursor": {
                "type": "string",
                "description": "Pagination cursor for the last record on this page. Pass it as the `cursor` query parameter to fetch subsequent records. Remains valid for resume after full or incremental syncs."
              },
              "lastSeen": {
                "type": "integer",
                "description": "UNIX timestamp (in milliseconds) of when the last record was synced"
              }
            }
          }
        }
      },
      "PermissionsCheckRequest": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "description": "UUID of the Synced Object, returned from the [Pull Synced Records](/managed-sync/api/pull-synced-records) endpoint.",
            "example": "a657df3b-17e2-5989-bc5f-13ddb7fdab41"
          },
          "user": {
            "type": "string",
            "description": "The email of the user to check permissions for.",
            "example": "email@example.com"
          },
          "role": {
            "type": "string",
            "description": "The role to use for the access check.",
            "enum": ["can_read", "can_write", "is_owner"]
          }
        },
        "required": ["object", "user", "role"]
      },
      "PermissionsCheckResponse": {
        "type": "object",
        "required": ["hasAccess"],
        "properties": {
          "hasAccess": {
            "type": "boolean",
            "description": "Returns `true` if the user has access to the Synced Object with the specified role."
          }
        }
      },
      "BatchCheckRequest": {
        "type": "object",
        "properties": {
          "checks": {
            "type": "array",
            "description": "A list of access checks to perform between users and Synced Objects.",
            "items": {
              "$ref": "#/components/schemas/BatchCheckItem"
            }
          }
        },
        "required": ["checks"]
      },
      "BatchCheckItem": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "description": "UUID of the Synced Object, returned from the [Pull Synced Records](/managed-sync/api/pull-synced-records) endpoint.",
            "example": "a657df3b-17e2-5989-bc5f-13ddb7fdab41"
          },
          "user": {
            "type": "string",
            "description": "The user identifier to check permissions for, prefixed with the type (*note that this prefix is specific to Batch Check*)",
            "example": "user:email@example.com"
          },
          "role": {
            "type": "string",
            "description": "The role to use for the access check.",
            "enum": ["can_read", "can_write", "is_owner"]
          }
        },
        "required": ["object", "role", "user"]
      },
      "BatchCheckResponse": {
        "type": "object",
        "properties": {
          "result": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchCheckResultItem"
            }
          }
        },
        "required": ["result"]
      },
      "BatchCheckResultItem": {
        "type": "object",
        "properties": {
          "allowed": {
            "type": "boolean",
            "description": "Returns `true` if the user has access to the Synced Object with the specified role."
          },
          "request": {
            "$ref": "#/components/schemas/BatchCheckItem",
            "description": "The original request item that was checked"
          },
          "error": {
            "type": "string",
            "description": "Error message if the check failed"
          }
        },
        "required": ["allowed", "request"]
      },
      "ListUsersRequest": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "description": "UUID of the Synced Object, returned from the [Pull Synced Records](/managed-sync/api/pull-synced-records) endpoint.",
            "example": "a657df3b-17e2-5989-bc5f-13ddb7fdab41"
          },
          "role": {
            "type": "string",
            "description": "The role to filter related users by.",
            "enum": ["can_read", "can_write", "is_owner"]
          }
        },
        "required": ["object", "role"]
      },
      "ListUsersResponse": {
        "type": "object",
        "required": ["users"],
        "properties": {
          "users": {
            "type": "array",
            "description": "List of user emails that have access to the Synced Object with the specified role.",
            "items": {
              "type": "string",
              "example": "email@example.com"
            }
          }
        }
      },
      "ListObjectsRequest": {
        "type": "object",
        "properties": {
          "objectType": {
            "type": "string",
            "description": "The type of object to list.",
            "enum": ["file", "folder"],
            "example": "file"
          },
          "user": {
            "type": "string",
            "description": "The email of the user to list accessible objects for.",
            "example": "email@example.com"
          },
          "role": {
            "type": "string",
            "description": "The role to use for identifying accessible objects.",
            "enum": ["can_read", "can_write", "is_owner"],
            "example": "can_read"
          }
        },
        "required": ["user", "objectType", "role"]
      },
      "ListObjectsResponse": {
        "type": "object",
        "required": ["objects"],
        "properties": {
          "objects": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "UUID of a Synced Object, which can be referenced in the [Get Synced Record](/managed-sync/api/get-synced-record) endpoint.",
              "example": "a657df3b-17e2-5989-bc5f-13ddb7fdab41"
            }
          }
        }
      },
      "SyncsResponse": {
        "type": "object",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["id", "integration", "pipeline", "status"],
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Unique identifier for the Sync"
                },
                "integration": {
                  "type": "string",
                  "description": "The integration this Sync uses"
                },
                "pipeline": {
                  "type": "string",
                  "description": "The type of Synced Object being synced"
                },
                "status": {
                  "$ref": "#/components/schemas/StatusField"
                },
                "reason": {
                  "type": "string",
                  "description": "If the sync status is `ERRORED`, this field will be populated with a message explaining why the sync failed.",
                  "example": "Credential ID [id] is no longer valid or has been deleted."
                },
                "configurationName": {
                  "type": "string",
                  "description": "The name of the Sync configuration as provided when the Sync was created"
                },
                "dateCreated": {
                  "type": "string",
                  "format": "date-time",
                  "description": "The date and time the Sync was created"
                },
                "dateUpdated": {
                  "type": "string",
                  "format": "date-time",
                  "description": "The date and time the Sync was last updated"
                },
                "credentialId": {
                  "type": "string",
                  "description": "The ID of the credential used to authenticate this Sync"
                },
                "lastPeriodicFullSyncedAt": {
                  "type": "string",
                  "format": "date-time",
                  "description": "Timestamp of when the Sync last completed a periodic full sync. Only present once the Sync has completed at least one periodic full sync."
                }
              }
            }
          }
        }
      },
      "WebhookResponse": {
        "type": "object",
        "properties": {
          "preserve": {
            "type": "string",
            "format": "date-time",
            "description": "Date until which data should be preserved"
          }
        }
      },
      "File": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the file in Paragon"
          },
          "externalId": {
            "type": "string",
            "description": "ID of the file in the source integration (e.g., Google Drive ID)"
          },
          "name": {
            "type": "string",
            "description": "Name of the file, including file extension"
          },
          "mimeType": {
            "type": "string",
            "description": "MIME type of the file"
          },
          "size": {
            "type": "integer",
            "description": "Size of the file in bytes"
          },
          "url": {
            "type": "string",
            "description": "URL reference for this file in the integration"
          },
          "thumbnailUrl": {
            "type": "string",
            "description": "URL to a thumbnail of the file (may not be available for all integrations)"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the file was created"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the file was last updated"
          },
          "hash": {
            "type": "object",
            "description": "Hash information for the file",
            "properties": {
              "type": {
                "type": "string",
                "description": "Type of hash algorithm used",
                "example": "MD5"
              },
              "value": {
                "type": "string",
                "description": "Hash value"
              }
            }
          },
          "parentFolderId": {
            "type": "string",
            "description": "ID of the parent folder"
          },
          "customFields": {
            "type": "object",
            "additionalProperties": true,
            "description": "Additional integration-specific metadata for the file. The shape of this object varies by integration. For example, Notion populates this with page properties extracted from databases, and SharePoint populates this with the file's `fullPath` and (when enabled) list item `metadata`."
          }
        }
      },
      "Folder": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the folder in Paragon"
          },
          "externalId": {
            "type": "string",
            "description": "ID of the folder in the source integration (e.g., Google Drive ID)"
          },
          "name": {
            "type": "string",
            "description": "Name of the folder"
          },
          "parentFolderId": {
            "type": "string",
            "description": "ID of the parent folder"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the folder was created"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the folder was last updated"
          }
        }
      },
      "Contact": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the contact in Paragon"
          },
          "externalId": {
            "type": "string",
            "description": "External identifier for the contact in the source integration"
          },
          "firstName": {
            "type": "string",
            "description": "First name of the contact"
          },
          "lastName": {
            "type": "string",
            "description": "Last name of the contact"
          },
          "fullName": {
            "type": "string",
            "description": "Full name of the contact"
          },
          "companyName": {
            "type": "string",
            "description": "Company name associated with the contact"
          },
          "jobTitle": {
            "type": "string",
            "description": "Job title of the contact"
          },
          "emails": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ContactEmail" },
            "description": "List of email addresses for the contact"
          },
          "phoneNumbers": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ContactPhoneNumber" },
            "description": "List of phone numbers for the contact"
          },
          "addresses": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ContactAddress" },
            "description": "List of addresses for the contact"
          },
          "socialProfiles": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ContactSocialProfile" },
            "description": "List of social profiles for the contact"
          },
          "type": {
            "type": "string",
            "enum": ["lead", "customer", "prospect", "partner", "other"],
            "description": "Type of contact"
          },
          "status": {
            "type": "string",
            "enum": ["active", "inactive", "new", "qualified", "unqualified"],
            "description": "Status of the contact"
          },
          "ownerId": {
            "type": "string",
            "description": "External ID of the User who owns/manages this contact in the source integration"
          },
          "createdAt": {
            "type": "integer",
            "format": "string",
            "description": "Timestamp when the contact was created"
          },
          "updatedAt": {
            "type": "integer",
            "format": "string",
            "description": "Timestamp when the contact was last updated"
          },
          "lastActivityAt": {
            "type": "integer",
            "format": "string",
            "description": "Timestamp of the last activity for the contact"
          },
          "lifecycleStage": {
            "type": "string",
            "description": "Lifecycle stage of the contact"
          },
          "leadSource": {
            "type": "string",
            "description": "Lead source for the contact"
          },
          "tags": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Tags associated with the contact"
          },
          "notes": {
            "type": "string",
            "description": "Notes about the contact"
          },
          "website": {
            "type": "string",
            "description": "Website associated with the contact"
          },
          "customFields": {
            "type": "object",
            "additionalProperties": true,
            "description": "All other fields for the contact, synced as-is from the source integration"
          }
        },
        "required": ["id", "externalId", "createdAt", "updatedAt"]
      },
      "ContactPhoneNumber": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": ["primary", "work", "home", "mobile", "other"]
          },
          "number": {
            "type": "string"
          }
        },
        "required": ["type", "number"]
      },
      "ContactAddress": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "primary",
              "work",
              "home",
              "mailing",
              "billing",
              "shipping",
              "other"
            ]
          },
          "street1": { "type": "string" },
          "street2": { "type": "string" },
          "city": { "type": "string" },
          "state": { "type": "string" },
          "postalCode": { "type": "string" },
          "country": { "type": "string" }
        },
        "required": ["type", "street1", "city"]
      },
      "ContactSocialProfile": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": ["linkedin", "twitter", "facebook", "instagram", "other"]
          },
          "url": { "type": "string" },
          "username": { "type": "string" }
        },
        "required": ["type", "url"]
      },
      "ContactEmail": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": ["primary", "work", "personal", "other"]
          },
          "email": { "type": "string" }
        },
        "required": ["type", "email"]
      },
      "DealStatus": {
        "type": "string",
        "enum": ["open", "closed_lost", "closed_won"],
        "description": "The type of status that the `status` field represents in the source CRM"
      },
      "Deal": {
        "type": "object",
        "required": [
          "id",
          "externalId",
          "createdAt",
          "updatedAt",
          "amount",
          "statusType",
          "status",
          "accountId",
          "ownerId",
          "closeDate"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the deal in Paragon"
          },
          "externalId": {
            "type": "string",
            "description": "External identifier for the deal in the source integration"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of when the deal was created"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of when the deal was last updated"
          },
          "name": {
            "type": "string",
            "description": "Name or title of the deal",
            "example": "Enterprise Software License Deal"
          },
          "description": {
            "type": "string",
            "description": "Description of the deal",
            "example": "Annual enterprise software license renewal for Q1 2024"
          },
          "nextStep": {
            "type": "string",
            "description": "Next step in the deal process",
            "example": "Schedule demo with technical team"
          },
          "amount": {
            "type": "number",
            "description": "Monetary value/amount of the deal",
            "example": 50000.0
          },
          "statusType": {
            "$ref": "#/components/schemas/DealStatus"
          },
          "status": {
            "type": "string",
            "description": "Current status of the deal, as labeled by the source integration",
            "example": "Proposal Sent"
          },
          "accountId": {
            "type": "string",
            "description": "External ID of the associated account in the source integration"
          },
          "ownerId": {
            "type": "string",
            "description": "External ID of the User who is assigned as Owner in the source integration"
          },
          "closeDate": {
            "type": "string",
            "format": "date",
            "description": "Date when the deal was closed or expected to be closed"
          },
          "probability": {
            "type": "integer",
            "description": "Values from 0-100; 80 means 80% probability",
            "example": 75,
            "minimum": 0,
            "maximum": 100
          },
          "customFields": {
            "type": "object",
            "description": "All other fields for the deal, synced as-is from the source integration",
            "additionalProperties": true
          }
        }
      },
      "Company": {
        "type": "object",
        "required": ["id", "externalId", "createdAt", "updatedAt", "name"],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the company in Paragon"
          },
          "externalId": {
            "type": "string",
            "description": "External identifier for the company in the source integration"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of when the company was created"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of when the company was last updated"
          },
          "name": {
            "type": "string",
            "description": "Company name",
            "example": "Acme Corporation"
          },
          "description": {
            "type": "string",
            "description": "Company description or notes"
          },
          "website": {
            "type": "string",
            "format": "uri",
            "description": "Primary website URL",
            "example": "https://www.acme.com"
          },
          "addresses": {
            "type": "array",
            "description": "Addresses associated with the company",
            "items": {
              "$ref": "#/components/schemas/CompanyAddress"
            }
          },
          "phoneNumbers": {
            "type": "array",
            "description": "Phone numbers associated with the company",
            "items": {
              "$ref": "#/components/schemas/CompanyPhoneNumber"
            }
          },
          "annualRevenue": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ],
            "description": "Annual revenue amount"
          },
          "numberOfEmployees": {
            "type": "integer",
            "description": "Number of employees"
          },
          "parentCompanyId": {
            "type": "string",
            "description": "External ID of the parent company in the source integration"
          },
          "timezone": {
            "type": "string",
            "description": "Company timezone",
            "example": "America/New_York"
          },
          "type": {
            "type": "string",
            "description": "Type of company, e.g. Prospect, Partner, Vendor, Competitor",
            "example": "Prospect"
          },
          "industry": {
            "type": "string",
            "description": "Industry classification",
            "example": "Technology"
          },
          "ownerId": {
            "type": "string",
            "description": "External ID of the User who owns/manages this company in the source integration"
          },
          "customFields": {
            "type": "object",
            "description": "All other fields for the company, synced as-is from the source integration",
            "additionalProperties": true
          }
        }
      },
      "CompanyAddress": {
        "type": "object",
        "required": ["type"],
        "properties": {
          "type": {
            "$ref": "#/components/schemas/UnifiedAddressType"
          },
          "street1": {
            "type": "string",
            "nullable": true,
            "description": "Primary street address",
            "example": "123 Main Street"
          },
          "street2": {
            "type": "string",
            "nullable": true,
            "description": "Secondary street address",
            "example": "Suite 100"
          },
          "city": {
            "type": "string",
            "nullable": true,
            "description": "City name",
            "example": "New York"
          },
          "state": {
            "type": "string",
            "nullable": true,
            "description": "State or province",
            "example": "NY"
          },
          "postalCode": {
            "type": "string",
            "nullable": true,
            "description": "Postal or ZIP code",
            "example": "10001"
          },
          "country": {
            "type": "string",
            "nullable": true,
            "description": "Country name or code",
            "example": "United States"
          }
        }
      },
      "CompanyPhoneNumber": {
        "type": "object",
        "required": ["type", "number"],
        "properties": {
          "type": {
            "type": "string",
            "enum": ["primary", "fax", "other"],
            "description": "Type of phone number"
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Description of the phone number",
            "example": "Main office line"
          },
          "number": {
            "type": "string",
            "description": "E.164 formatted phone number",
            "pattern": "^\\+[1-9]\\d{1,14}$",
            "example": "+1234567890"
          }
        }
      },
      "UnifiedAddressType": {
        "type": "string",
        "enum": [
          "primary",
          "work",
          "home",
          "mailing",
          "billing",
          "shipping",
          "other"
        ],
        "description": "Type of address"
      },
      "CustomObject": {
        "type": "object",
        "required": [
          "id",
          "externalId",
          "createdAt",
          "updatedAt",
          "objectType"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the record in Paragon"
          },
          "externalId": {
            "type": "string",
            "description": "External identifier for the record in the source integration"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of when the record was created"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of when the record was last updated"
          },
          "objectType": {
            "type": "string",
            "description": "The object type identifier (e.g., `Product_Catalog__c`, `feedback_submissions`, etc.)",
            "example": "Product_Catalog__c"
          },
          "customFields": {
            "type": "object",
            "description": "All fields for the record, synced as-is from the source integration",
            "additionalProperties": true,
            "example": {
              "product_name": "Enterprise License",
              "price": 99.99,
              "category": "Software",
              "is_active": true,
              "tags": ["enterprise", "software", "license"]
            }
          }
        }
      },
      "Ticket": {
        "type": "object",
        "required": [
          "id",
          "externalId",
          "title",
          "status",
          "priority",
          "type",
          "assignees",
          "originalRecord"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the record in Paragon."
          },
          "externalId": {
            "type": "string",
            "description": "The ID of the ticket in the origin system."
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "description": "The body of the original ticket, normalized from domain-specific formats (e.g. HTML or ADF) to Markdown."
          },
          "status": {
            "type": "object",
            "required": ["type", "name"],
            "properties": {
              "type": {
                "type": "string",
                "enum": ["open", "in_progress", "pending", "on_hold", "closed"]
              },
              "name": {
                "type": "string",
                "description": "The name of the status as used in the integration, e.g. 'Open' or 'Pending'."
              }
            }
          },
          "priority": {
            "type": "string",
            "enum": ["low", "normal", "high", "urgent"],
            "description": "The priority of the ticket. For custom priorities lower than these levels, `'low'` is used."
          },
          "type": {
            "type": "string",
            "description": "The name of the ticket type as used in the origin system."
          },
          "assignees": {
            "type": "array",
            "description": "A list of users that are assignees to the ticket.",
            "items": {
              "type": "object",
              "required": ["externalId"],
              "properties": {
                "externalId": {
                  "type": "string",
                  "description": "The ID of the user that is assigned to a ticket"
                },
                "email": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              }
            }
          },
          "createdBy": {
            "type": "object",
            "description": "The user that originally created this ticket.",
            "properties": {
              "externalId": {
                "type": "string",
                "description": "The ID of the user that originally created this ticket."
              },
              "email": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "A list of tag names that were applied to this ticket."
          },
          "dueAt": {
            "type": "string",
            "format": "date-time",
            "description": "ISO timestamp of the due date of this ticket."
          },
          "resolvedAt": {
            "type": "string",
            "format": "date-time",
            "description": "ISO timestamp of the resolution date of this ticket."
          },
          "externalUrl": {
            "type": "string",
            "description": "A link reference to this ticket in the origin system."
          },
          "project": {
            "type": "object",
            "description": "For Project Management integrations, the project where this ticket was created.",
            "properties": {
              "externalId": {
                "type": "string",
                "description": "The ID of the project where this ticket was created."
              },
              "name": {
                "type": "string"
              }
            }
          },
          "originalRecord": {
            "type": "object",
            "additionalProperties": true,
            "description": "The original ticket as synced from the API, without any normalization applied."
          }
        }
      },
      "ExpandResponse": {
        "type": "object",
        "required": ["tree"],
        "properties": {
          "tree": {
            "$ref": "#/components/schemas/UsersetTree"
          }
        }
      },
      "UsersetTree": {
        "type": "object",
        "properties": {
          "root": {
            "$ref": "#/components/schemas/Node"
          }
        }
      },
      "Node": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "leaf": {
            "$ref": "#/components/schemas/Leaf"
          },
          "difference": {
            "$ref": "#/components/schemas/UsersetTreeDifference"
          },
          "union": {
            "$ref": "#/components/schemas/Nodes"
          },
          "intersection": {
            "$ref": "#/components/schemas/Nodes"
          }
        }
      },
      "Leaf": {
        "type": "object",
        "properties": {
          "users": {
            "$ref": "#/components/schemas/Users"
          },
          "computed": {
            "$ref": "#/components/schemas/Computed"
          },
          "tupleToUserset": {
            "$ref": "#/components/schemas/UsersetTreeTupleToUserset"
          }
        }
      },
      "Users": {
        "type": "object",
        "properties": {
          "users": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Computed": {
        "type": "object",
        "properties": {
          "userset": {
            "type": "string"
          }
        }
      },
      "UsersetTreeTupleToUserset": {
        "type": "object",
        "properties": {
          "tupleset": {
            "type": "string"
          },
          "computed": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Computed"
            }
          }
        }
      },
      "UsersetTreeDifference": {
        "type": "object",
        "properties": {
          "base": {
            "$ref": "#/components/schemas/Node"
          },
          "subtract": {
            "$ref": "#/components/schemas/Node"
          }
        }
      },
      "Nodes": {
        "type": "object",
        "properties": {
          "nodes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Node"
            }
          }
        }
      },
      "PermissionChangesResponse": {
        "type": "object",
        "required": ["changes"],
        "properties": {
          "changes": {
            "type": "array",
            "description": "Permission changes in chronological order. An empty array indicates that you have reached the end of the feed.",
            "items": {
              "$ref": "#/components/schemas/PermissionChange"
            }
          },
          "continuationToken": {
            "type": "string",
            "description": "Token to pass on the next request to read the next page. Repeated unchanged when there are no new changes, so detect the end of the feed by an empty `changes` array rather than by an absent token."
          }
        }
      },
      "PermissionChange": {
        "type": "object",
        "required": ["tupleKey", "operation", "timestamp"],
        "properties": {
          "tupleKey": {
            "$ref": "#/components/schemas/PermissionChangeTupleKey"
          },
          "operation": {
            "type": "string",
            "enum": ["write", "delete"],
            "description": "Whether the permission relationship was added (`write`) or removed (`delete`)."
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "Time at which the change occurred."
          }
        }
      },
      "PermissionChangeTupleKey": {
        "type": "object",
        "required": ["user", "relation", "object"],
        "properties": {
          "user": {
            "type": "string",
            "description": "The user or group that the permission relationship applies to (e.g. `user:email@example.com`)."
          },
          "relation": {
            "type": "string",
            "description": "The role or relation that changed (e.g. `can_read`, `can_write`, `is_owner`)."
          },
          "object": {
            "type": "string",
            "description": "The object that the permission relationship applies to (e.g. `file:[File UUID]`)."
          },
          "condition": {
            "type": "object",
            "description": "Condition attached to the permission relationship, if any.",
            "required": ["name"],
            "properties": {
              "name": {
                "type": "string",
                "description": "Name of the condition."
              },
              "context": {
                "type": "object",
                "description": "Context values associated with the condition."
              }
            }
          }
        }
      },
      "PermissionChangesError": {
        "type": "object",
        "required": ["statusCode", "error", "message"],
        "properties": {
          "statusCode": {
            "type": "integer",
            "example": 400
          },
          "error": {
            "type": "string",
            "example": "Bad Request"
          },
          "code": {
            "type": "string",
            "enum": ["PERMISSION_CHANGES_CURSOR_INVALID", "PERMISSION_CHANGES_CURSOR_TYPE_MISMATCH"],
            "description": "Stable code identifying a rejected continuation token. `PERMISSION_CHANGES_CURSOR_INVALID` means the token is not valid for this Sync; read again from the beginning or from a `startTime`. `PERMISSION_CHANGES_CURSOR_TYPE_MISMATCH` means the `type` filter does not match the one the token was issued under."
          },
          "message": {
            "type": "string"
          }
        }
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/api/syncs": {
      "get": {
        "summary": "List Syncs",
        "description": "List all Syncs for a Connected User",
        "parameters": [
          {
            "name": "credentialId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter syncs by credential UUID. Use this to list syncs for a specific credential when you have multiple credentials for the same integration.",
            "example": "0aea7d3a-b5f7-4488-890e-d51a5cf4f8f1"
          }
        ],
        "responses": {
          "200": {
            "description": "List of Syncs",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SyncsResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Enable a Sync",
        "description": "Start a Sync for a Connected User with a specific configuration",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnableSyncRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sync successfully enabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NewSyncResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Source not found"
          },
          "409": {
            "description": "A Sync already exists for this Connected User with the same integration, pipeline, credential, and configuration name. The response body includes the `id` of the existing Sync so you can resume working with it instead of creating a new one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SyncConflictResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/syncs/{syncId}": {
      "get": {
        "summary": "Get Sync Status",
        "description": "Get the status of a Sync for a Connected User",
        "parameters": [
          {
            "name": "syncId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the sync to get the status of"
          }
        ],
        "responses": {
          "200": {
            "description": "Sync status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SyncStatus"
                },
                "examples": {
                  "Idle": {
                    "summary": "Idle",
                    "value": {
                      "status": "IDLE",
                      "credentialId": "0aea7d3a-b5f7-4488-890e-d51a5cf4f8f1",
                      "summary": {
                        "totalRecords": 1000,
                        "syncedRecordsCount": 1000,
                        "lastSyncedAt": "2026-08-20T19:00:00.000Z"
                      }
                    }
                  },
                  "Errored": {
                    "summary": "Errored",
                    "value": {
                      "status": "ERRORED",
                      "credentialId": "0aea7d3a-b5f7-4488-890e-d51a5cf4f8f1",
                      "errorCode": "PROXY_7300",
                      "reason": "Credential ID 0aea7d3a-b5f7-4488-890e-d51a5cf4f8f1 is no longer valid or has been deleted.",
                      "httpStatusCode": 401,
                      "summary": {
                        "totalRecords": 1000,
                        "syncedRecordsCount": 820,
                        "lastSyncedAt": "2026-08-20T19:00:00.000Z"
                      }
                    }
                  },
                  "Rate limited": {
                    "summary": "Rate limited",
                    "value": {
                      "status": "RATE_LIMITED",
                      "credentialId": "0aea7d3a-b5f7-4488-890e-d51a5cf4f8f1",
                      "rateLimitBackoffMs": 30000,
                      "summary": {
                        "totalRecords": 1000,
                        "syncedRecordsCount": 820
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Sync not found"
          }
        }
      },
      "patch": {
        "summary": "Update a Sync",
        "description": "Update an existing Sync for a Connected User",
        "parameters": [
          {
            "name": "syncId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the sync to update"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Provide at least one field to update. All fields are optional, but the request body must contain at least one updatable property.",
                "properties": {
                  "credentialId": {
                    "type": "string",
                    "description": "The ID of the credential to associate with this sync. Must be a valid UUID.\n\nUpdating this field will trigger a full re-sync."
                  },
                  "incrementalAccumulatorFrequency": {
                    "type": "string",
                    "enum": ["1m", "5m", "10m", "30m", "1h", "3h", "6h", "24h"],
                    "description": "Update how often Paragon checks for incremental changes for this sync.\n\nUpdating only this field will not trigger a full re-sync. The new frequency takes effect on the next scheduled run.",
                    "example": "1m"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sync successfully updated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["id", "data", "message"],
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "ID of the updated sync"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "credentialId": {
                          "type": "string"
                        },
                        "incrementalAccumulatorFrequency": {
                          "type": "string"
                        }
                      }
                    },
                    "message": {
                      "type": "string",
                      "example": "Update request accepted and is being processed"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Sync not found"
          }
        }
      },
      "delete": {
        "summary": "Delete a Sync",
        "description": "Delete a Sync for a Connected User, including all associated Synced Objects",
        "parameters": [
          {
            "name": "syncId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the sync to delete"
          }
        ],
        "responses": {
          "200": {
            "description": "Sync successfully deleted"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Sync not found"
          }
        }
      }
    },
    "/api/syncs/{syncId}/disable": {
      "post": {
        "summary": "Disable a Sync",
        "description": "Disable an active Sync for a Connected User",
        "parameters": [
          {
            "name": "syncId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the sync to disable"
          }
        ],
        "responses": {
          "202": {
            "description": "Sync successfully disabled"
          }
        }
      }
    },
    "/api/syncs/{syncId}/reenable": {
      "post": {
        "summary": "Re-enable a Sync",
        "description": "Re-enable an inactive Sync for a Connected User",
        "parameters": [
          {
            "name": "syncId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the sync to re-enable"
          }
        ],
        "responses": {
          "200": {
            "description": "Sync successfully re-enabled"
          }
        }
      }
    },
    "/api/syncs/{syncId}/records": {
      "get": {
        "summary": "Pull Synced Records",
        "description": "Get records from a Sync",
        "parameters": [
          {
            "name": "syncId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the sync"
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Number of records to return per page",
            "example": 100
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Pagination cursor returned in `paging.cursor` from a previous response. Pass it to resume from that point in the change log of synced records.",
            "example": "Y3Vyc29yOjEyMQ=="
          }
        ],
        "responses": {
          "200": {
            "description": "Synced records",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SyncedRecordsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Sync not found"
          }
        }
      }
    },
    "/api/syncs/{syncId}/records/{recordId}": {
      "get": {
        "summary": "Get Synced Record",
        "description": "Get metadata for a specific record in a Sync",
        "parameters": [
          {
            "name": "syncId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" },
            "description": "ID of the sync"
          },
          {
            "name": "recordId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" },
            "description": "ID (Sync-generated UUID, not external ID) of the record"
          }
        ],
        "responses": {
          "200": {
            "description": "Synced record data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "description": "The data of the record, e.g. File Metadata or CRM Contact properties. See schemas in [**Synced Objects**](https://docs.useparagon.com/managed-sync/synced-objects) for the available fields.",
                      "properties": {},
                      "example": "{ /* See schema in Synced Objects */ }"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/syncs/{syncId}/records/{recordId}/content": {
      "get": {
        "summary": "Download Content",
        "description": "Download the file associated with a File-type Synced Object.",
        "parameters": [
          {
            "name": "syncId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the Sync"
          },
          {
            "name": "recordId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID (Sync-generated UUID, not external ID) of the file to download"
          }
        ],
        "responses": {
          "200": {
            "description": "The response will be the binary content of the file. The `Content-Type` response header will vary based on the MIME type of the file."
          }
        }
      }
    },
    "/api/permissions/{syncId}/check": {
      "post": {
        "summary": "Check Access",
        "description": "Check if a user has access to a specific Synced Object",
        "parameters": [
          {
            "name": "syncId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "UUID of the Sync to query, returned from the [Enable Sync](/managed-sync/api/enable-a-sync) endpoint."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PermissionsCheckRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Access check result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionsCheckResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/permissions/{syncId}/list-users": {
      "post": {
        "summary": "List Users",
        "description": "List users that have access to a Synced Object by a specific role",
        "parameters": [
          {
            "name": "syncId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" },
            "description": "UUID of the Sync to query, returned from the [Enable Sync](/managed-sync/api/enable-a-sync) endpoint."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListUsersRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListUsersResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/permissions/{syncId}/list-objects": {
      "post": {
        "summary": "List Objects",
        "description": "List all accessible objects for a user",
        "parameters": [
          {
            "name": "syncId",
            "description": "UUID of the Sync to query, returned from the [Enable Sync](/managed-sync/api/enable-a-sync) endpoint.",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListObjectsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "List of Synced Objects that the user has access to with the specified role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListObjectsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/permissions/streamed-list-objects": {
      "post": {
        "summary": "Streamed List Objects (All Syncs)",
        "description": "List all accessible objects across syncs for a user as a streamed response.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListObjectsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A newline-delimited JSON stream. Each line is a JSON object tagged with `syncInstanceId` and `integration`. Success lines include an `object` field with the UUID of a Synced Object the user has access to. If a specific sync fails to enumerate, a line with an `error` field is emitted for that sync instead, and the stream continues with the remaining syncs.",
            "content": {
              "application/x-ndjson": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/permissions/{syncId}/streamed-list-objects": {
      "post": {
        "summary": "Streamed List Objects",
        "description": "List all accessible objects for a user as a streamed response.",
        "parameters": [
          {
            "name": "syncId",
            "description": "UUID of the Sync to query, returned from the [Enable Sync](/managed-sync/api/enable-a-sync) endpoint.",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListObjectsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A newline-delimited JSON stream. Each line is a JSON object of the form `{ \"object\": \"<uuid>\" }`, where `object` is the UUID of a Synced Object the user has access to with the specified role.",
            "content": {
              "application/x-ndjson": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/permissions/{syncId}/batch-check": {
      "post": {
        "summary": "Batch Check Access",
        "description": "Check access for a list of users and Synced Objects",
        "parameters": [
          {
            "name": "syncId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" },
            "description": "UUID of the Sync to query, returned from the [Enable Sync](/managed-sync/api/enable-a-sync) endpoint."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchCheckRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Batch access check result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchCheckResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/api/permissions/{syncId}/expand": {
      "post": {
        "summary": "Expand Relationships",
        "description": "Get all users and group relationships associated with an object by role",
        "parameters": [
          {
            "name": "syncId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" },
            "description": "UUID of the Sync to query, returned from the [Enable Sync](/managed-sync/api/enable-a-sync) endpoint."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "object": {
                    "type": "string",
                    "description": "The UUID of the file object that you are querying relationships for."
                  },
                  "relation": {
                    "type": "string",
                    "description": "The role (e.g. `can_read`, `can_write`, `is_owner`) or other relation to query on for this file."
                  }
                },
                "required": ["object", "relation"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Expanded relationships tree showing all users and groups related to the object",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExpandResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/permissions/{syncId}/changes": {
      "get": {
        "summary": "Permission Changes",
        "description": "Read a chronological list of permission changes (writes and deletes) for a Sync",
        "parameters": [
          {
            "name": "syncId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" },
            "description": "UUID of the Sync to query, returned from the [Enable Sync](/managed-sync/api/enable-a-sync) endpoint."
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "schema": { "type": "string" },
            "description": "Object type to filter changes by (e.g. `file`). A continuation token is issued against the `type` that produced it, so this value must stay identical for every page of a paginated read, including when it is omitted."
          },
          {
            "name": "startTime",
            "in": "query",
            "required": false,
            "schema": { "type": "string", "format": "date-time" },
            "description": "Only return changes that occurred at or after this time. Must be a full RFC 3339 timestamp with a time component (e.g. `2026-07-16T00:00:00Z`); a date-only value is rejected with a 400. Ignored when `continuationToken` is supplied.",
            "example": "2026-07-16T00:00:00Z"
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 },
            "description": "Number of changes to return per page, from 1 to 100. Defaults to 50."
          },
          {
            "name": "continuationToken",
            "in": "query",
            "required": false,
            "schema": { "type": "string" },
            "description": "Token from a previous response, used to read the next page of changes. Takes precedence over `startTime` when both are supplied."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of permission changes in chronological order",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionChangesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error or a rejected continuation token. A rejected continuation token includes a stable `code` of `PERMISSION_CHANGES_CURSOR_INVALID` or `PERMISSION_CHANGES_CURSOR_TYPE_MISMATCH`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionChangesError"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    }
  }
}
