Skip to main content
All Docs
FeaturesagentOS Block ManagerUpdated April 13, 2026

Communications Centre

Communications Centre

The Communications Centre provides a structured outbound messaging system for block managers to send and track communications to leaseholders. All communications are logged with a full audit trail covering who sent what, to whom, and when.

Communication Types

TypeDescription
circularGeneral information sent to all leaseholders in a block
noticeFormal notices (e.g. Section 20 consultation, insurance renewal)
demand_letterService charge demands, ground rent demands, arrears letters
agm_noticeAnnual General Meeting invitations and agendas

Lifecycle

Communications follow a one-way status progression:

draft → scheduled → sent
             ↓
           failed
  • draft — Created but not yet sent. Can be edited or deleted.
  • scheduled — Has a future scheduledAt timestamp. Can still be edited.
  • sent — Marked as sent with a sentAt timestamp. Immutable — cannot be edited or deleted.
  • failed — Delivery failed before sending completed.

Audit trail: Once a communication is marked as sent, it becomes a permanent record. The platform enforces this — the update and delete procedures will reject any request targeting a sent communication.

Scoping

Each communication can be scoped to:

  • A block — for block-wide circulars sent to all units
  • A specific unit — for individual notices to a single leaseholder
  • Neither — for organisation-level drafts

The block or unit must belong to the calling organisation; the API validates this on creation.

Delivery Channels

The channel field records how the communication was sent. Supported values include email, post, portal, or any custom string up to 50 characters. Defaults to email.

Recipient Tracking

Recipients are added to a communication using the addRecipients procedure. Each recipient maps to a leaseholder unit.

At the time of adding, the system snapshots:

  • recipientName — the leaseholder's name at that moment
  • recipientEmail — the leaseholder's email at that moment

This snapshot is preserved even if the leaseholder's details change later, ensuring the audit record is accurate.

Delivery Status

Each recipient record tracks an independent delivery status:

StatusMeaning
pendingAdded but not yet delivered
deliveredSuccessfully delivered; deliveredAt timestamp recorded
bouncedDelivery attempted but bounced
failedDelivery failed; failureReason field populated
openedRecipient opened/read the communication; openedAt timestamp recorded

API Reference

All procedures are on the communication tRPC router.

communication.list

Paginated list of communications for the organisation.

Access: Org member

Filters:

  • blockId — scope to a specific block
  • unitId — scope to a specific unit
  • communicationType — filter by type
  • status — filter by lifecycle status

communication.getById

Fetch a single communication by ID. Returns the communication record plus a recipientCount.

Access: Org member


communication.create

Create a new communication as a draft.

Access: Admin

Input:

{
  communicationType: "circular" | "notice" | "demand_letter" | "agm_notice";
  subject: string;           // max 500 chars
  bodyHtml?: string;         // HTML content for email/PDF rendering
  blockId?: string;          // must belong to org
  unitId?: string;           // must belong to org
  channel?: string;          // default: "email"
  scheduledAt?: string;      // ISO datetime — sets status to "scheduled"
  notes?: string;            // internal reference notes
}

If scheduledAt is provided, the communication is created with status scheduled; otherwise it is draft.


communication.update

Edit a draft or scheduled communication. Sent communications cannot be edited.

Access: Admin

Editable fields: subject, bodyHtml, channel, scheduledAt, notes

Setting scheduledAt to null moves the status back to draft. Setting it to a datetime moves it to scheduled.


communication.markSent

Transition a communication to sent status. Records sentAt timestamp. The communication becomes immutable after this call.

Access: Admin


communication.delete

Delete a draft or scheduled communication. Also removes all associated recipient records.

Access: Admin

Sent communications cannot be deleted — they are part of the audit trail.


communication.addRecipients

Bulk-add leaseholder units as recipients. Snapshots name and email from each unit at the time of the call.

Access: Admin

Input:

{
  communicationId: string;
  unitIds: string[];  // at least 1
}

Unit IDs that do not belong to the organisation are silently skipped. If none are valid, the call returns a BAD_REQUEST error.

Cannot add recipients to a sent communication.


communication.listRecipients

Paginated list of recipients for a given communication.

Access: Org member

Filters: deliveryStatus


communication.updateRecipientStatus

Update the delivery status of a single recipient record. Automatically records deliveredAt or openedAt timestamps where applicable.

Access: Admin

Input:

{
  id: string;
  deliveryStatus: "pending" | "delivered" | "bounced" | "failed" | "opened";
  failureReason?: string;  // populated when status is "bounced" or "failed"
}