File & Link Subscriptions

Stream file and link changes over WebSocket — scope by organization, workspace, or folder, and react to batch deletions in real time.


Keep attachment lists and link rails live without polling. The subscribeToFile, subscribeToLink, and onDeleteFiles subscriptions push file (File) and link (Link) changes to your client the moment they happen on the server.

These are streamed over WebSocket using the graphql-ws protocol at wss://api.blue.cc/graphql — the same path as the HTTP GraphQL endpoint. Open and authenticate the connection first; see Connect & Authenticate for the handshake and credential forms. The examples below show only the subscription documents.

Like the other entity change-feeds, subscribeToFile and subscribeToLink use the shared payload shape { mutation, node, previousValues, updatedFields } described on the Real-time overview. onDeleteFiles is an imperative batch event that returns the deleted files directly as a list.

subscribeToFile

Stream create, update, and delete events for files. A file is a File object — an uploaded attachment that lives under a workspace and, optionally, a folder. Scope the stream by organization (companyId), workspace (projectId), and optionally folder (folderId).

Request

subscription OnFileChange {
  subscribeToFile(companyId: "company_123", projectId: "project_123") {
    mutation
    node {
      id
      name
      extension
      size
      status
      folder {
        id
        title
      }
    }
    updatedFields
  }
}

Pass folderId to narrow the stream to a single folder — you then only receive events for files in that folder:

subscription OnFolderFileChange {
  subscribeToFile(companyId: "company_123", projectId: "project_123", folderId: "folder_123") {
    mutation
    node {
      id
      name
      folder {
        id
      }
    }
  }
}

Parameters

ParameterTypeRequiredDescription
companyIdStringNoOrganization ID or slug. Only events whose file belongs to this organization are delivered.
projectIdStringNoWorkspace ID or slug. Only events whose file belongs to this workspace are delivered.
folderIdStringNoFolder ID. When provided, only events for files in this folder are delivered. Omit to receive events for all files in the workspace.
Scope to a workspace you can access

Each event is delivered only if you are a member of the file’s workspace. Pass the same companyId and projectId you scope the rest of your client to. Company and workspace arguments accept an ID or a slug.

Response

subscribeToFile returns a FileSubscriptionPayload per event.

{
  "data": {
    "subscribeToFile": {
      "mutation": "CREATED",
      "node": {
        "id": "clm4n8qwx000008l0g4oxdqn7",
        "name": "Q3-report.pdf",
        "extension": "pdf",
        "size": 482113,
        "status": "CONFIRMED",
        "folder": {
          "id": "clm4n8qwx000108l0abcd1234",
          "title": "Reports"
        }
      },
      "updatedFields": null
    }
  }
}

FileSubscriptionPayload

FieldTypeDescription
mutationMutationType!The kind of change: CREATED, UPDATED, or DELETED.
nodeFileThe file after the change. null on a DELETED event — read previousValues instead.
previousValuesFilePreviousValuesThe file’s scalar values before the change. Populated on UPDATED and DELETED events.
updatedFields[String!]Names of the scalar fields that changed on an UPDATED event. null otherwise.

File

The most useful fields on the node. A File also exposes its parent objects (company, project, folder, comment, discussion, statusUpdate, customField, document, todo, user); select only what you render.

FieldTypeDescription
idID!The file’s unique identifier.
uidString!Storage-layer identifier used to build download URLs.
nameString!Display file name.
sizeFloat!File size in bytes.
typeString!MIME type.
extensionString!File extension without the dot (e.g. pdf).
sharedBoolean!Whether the file is shared publicly.
statusFileStatusUpload lifecycle state: PENDING until the upload is confirmed, then CONFIRMED.
positionFloatSort position within its container.
folderFolderThe folder the file lives in, if any.
createdAtDateTime!When the file was created.
updatedAtDateTime!When the file was last modified.

FilePreviousValues

FieldTypeDescription
idID!The file’s identifier.
uidString!Storage-layer identifier.
nameString!Previous file name.
sizeFloat!Previous size in bytes.
typeString!Previous MIME type.
extensionString!Previous extension.
sharedBooleanPrevious shared flag.
createdAtDateTime!When the file was created.
updatedAtDateTime!When the file was last modified.

FileStatus

ValueDescription
PENDINGThe upload has been initiated but not yet confirmed.
CONFIRMEDThe upload completed and the file is available.

Stream create, update, and delete events for links. A link is a Link object — a saved URL that belongs to an organization. Links are scoped at the organization level only, so subscribeToLink takes just companyId.

Request

subscription OnLinkChange {
  subscribeToLink(companyId: "company_123") {
    mutation
    node {
      id
      title
      url
      description
    }
    updatedFields
  }
}

Parameters

ParameterTypeRequiredDescription
companyIdStringNoOrganization ID or slug. Only events whose link belongs to this organization are delivered, and only if you are a member of that organization.

Response

subscribeToLink returns a LinkSubscriptionPayload per event.

{
  "data": {
    "subscribeToLink": {
      "mutation": "UPDATED",
      "node": {
        "id": "clm4n8qwx000208l0wxyz5678",
        "title": "Brand guidelines",
        "url": "https://example.com/brand",
        "description": "Logo usage and color palette"
      },
      "updatedFields": ["title", "url"]
    }
  }
}

LinkSubscriptionPayload

FieldTypeDescription
mutationMutationType!The kind of change: CREATED, UPDATED, or DELETED.
nodeLinkThe link after the change. null on a DELETED event — read previousValues instead.
previousValuesLinkPreviousValuesThe link’s scalar values before the change. Populated on UPDATED and DELETED events.
updatedFields[String!]Names of the scalar fields that changed on an UPDATED event. null otherwise.
FieldTypeDescription
idID!The link’s unique identifier.
uidString!Internal identifier.
titleString!Display title.
urlString!The target URL.
descriptionStringOptional description.
positionFloat!Sort position.
membersOnlyBooleanWhether the link is restricted to organization members.
createdByUser!The user who created the link.
companyCompany!The organization the link belongs to.
createdAtDateTime!When the link was created.
updatedAtDateTime!When the link was last modified.

LinkPreviousValues

FieldTypeDescription
idID!The link’s identifier.
uidString!Internal identifier.
titleString!Previous title.
urlString!Previous URL.
descriptionStringPrevious description.
positionFloat!Previous sort position.
membersOnlyBooleanPrevious members-only flag.
createdAtDateTime!When the link was created.
updatedAtDateTime!When the link was last modified.

onDeleteFiles

Receive a single event whenever a batch of files is deleted in a workspace. Unlike subscribeToFile — which emits one DELETED event per file — onDeleteFiles delivers all files removed in one operation as a single [File!]! list. Use it to drop several attachments from a rendered list in one update.

Request

subscription OnFilesDeleted {
  onDeleteFiles(projectId: "project_123") {
    id
    name
    folder {
      id
    }
  }
}

Parameters

ParameterTypeRequiredDescription
projectIdString!YesWorkspace ID. Events are delivered only for batch deletions in this workspace, and only if you are a member of it.

Response

onDeleteFiles returns the deleted files directly as [File!]! — there is no mutation/previousValues wrapper. See the File fields above for what you can select.

{
  "data": {
    "onDeleteFiles": [
      {
        "id": "clm4n8qwx000008l0g4oxdqn7",
        "name": "Q3-report.pdf",
        "folder": { "id": "clm4n8qwx000108l0abcd1234" }
      },
      {
        "id": "clm4n8qwx000308l0efgh9012",
        "name": "Q3-appendix.xlsx",
        "folder": { "id": "clm4n8qwx000108l0abcd1234" }
      }
    ]
  }
}

Permissions

Authentication is enforced at the WebSocket handshake — an unauthenticated connection is rejected before any subscription runs. Beyond that, delivery is gated per event:

  • subscribeToFile and onDeleteFiles deliver an event only if you are a member of the file’s workspace. subscribeToFile additionally matches on companyId/projectId (and folderId when supplied); onDeleteFiles matches on projectId.
  • subscribeToLink delivers an event only if you are a member of the link’s organization, matched on companyId.

Subscribing always succeeds; you simply receive events only for files and links you can see. See Connect & Authenticate for credentials.