project.resource.updated

A resource's title, description or on/off switch changes, or a recovery moves it onto another place.

There are no project.resource.activated / deactivated events. Switching a resource on or off arrives here, as changes.active, alongside title and description edits. One save is one event, and it lists only what changed.

When this fires

A creator changes one of the three editable fields on a resource — title, description or active — and at least one of them is actually different afterwards. Every surface that can make that change raises it:

  • Dashboard — the resource editor on the project's Resources page, and the on/off switch on each resource row.
  • RESTPATCH /v1/projects/{project}/resources/{resource} for title and description edits, and POST /v1/projects/{project}/resources/{resource}/activate / deactivate for the switch.
  • MCP — the update_resource, activate_resource and deactivate_resource tools.

It also fires when the place behind a resource is swapped: a Disaster Recovery replacement, an automatic failover to a standby, Swap & Grant Resource from the resources list, or the undo of any of those. That event carries changes.space_id with the previous and the new space, changes.kind when the platform upgraded the place in the same move (a Telegram group that became a supergroup), and resource.space already reads the new place.

It does not fire when:

  • Nothing changed. A PATCH that re-sends the stored values, or an activate call on a resource that is already active, writes nothing and emits nothing.
  • The place is linked for the first time or removed. That is the connector's link (project.resource.linked) or an unlink (project.resource.unlinked).
  • The resource is deleted. That is project.resource.deleted, and no updated event precedes it.

Required ability

project-resource:view — token must carry this at mint time to subscribe an endpoint to this event.

Payload

{
  "id": "evt_01HX...",
  "type": "project.resource.updated",
  "created_at": "2026-09-06T09:14:00Z",
  "api_version": "2026-05-01",
  "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13",
  "data": {
    "resource": {
      "id": "b73c5f21-9d80-4a6e-8215-4f70ce13a9d6",
      "title": "Members lounge (VIP)",
      "kind": "telegram:supergroup",
      "connector": "telegram",
      "space": {
        "id": "3c1f7a58-2b6e-4d90-8f41-6a2e9c5d7b10",
        "external_id": "-1001234567890",
        "title": "Members lounge"
      },
      "active": true
    },
    "changes": {
      "title": {
        "from": "Members lounge",
        "to": "Members lounge (VIP)"
      }
    }
  }
}

Field reference

FieldTypeNotes
idstring ULIDUnique event id, prefixed evt_. Use for idempotent processing.
typestringAlways project.resource.updated for this event.
created_atISO 8601 timestampServer-side emission time.
api_versionstringWebhook API contract version.
project_idstring UUIDProject this event belongs to.
data.resourceobjectPost-update snapshot — id, title, kind, connector, space, active only.
data.resource.idstring UUIDResource identifier.
data.resource.titlestringDisplay title after the change.
data.resource.kindstringmanual, or the connector's kind spelled connector:kind. Shown so a consumer can branch without a lookup; changes only when a swap upgraded the place, and then changes.kind says so.
data.resource.connectorstring, nullableThe connector the place is on; null for a manual perk.
data.resource.spaceobject, nullableThe place after the change: id, the platform's external_id, title. null for a manual perk and for an unlinked row.
data.resource.activebooleanSwitch position after the change.
data.changesobject<string, {from,to}>Map of the fields that changed. Keys are one or more of title, description, active, space_id, kind; values are before/after pairs. Never empty — an empty map means no event.
data.changes.title.fromstringPrevious title. Present only when the title changed.
data.changes.title.tostringNew title.
data.changes.description.fromstring, nullablePrevious description. Present only when the description changed. null when there was none.
data.changes.description.tostring, nullableNew description — up to 1000 characters of well-formed HTML, or null when it was cleared.
data.changes.active.frombooleanPrevious switch position. Present only when the switch flipped.
data.changes.active.tobooleanNew switch position.
data.changes.space_id.fromstring UUID, nullableThe space the resource pointed at before a swap. Present only when a recovery, a failover, a manual swap or an undo moved the place.
data.changes.space_id.tostring UUID, nullableThe space it points at now; resource.space.id reads the same value.
data.changes.kind.fromstringThe kind before a swap that upgraded the place. Present only then.
data.changes.kind.tostringThe kind after it (telegram:supergroup for a group Telegram converted).

Caveats

  • The description is not in the resource snapshot, matching every other project.resource.* event — but when the description is what changed, changes.description.to carries the new text in full. Read it from there rather than following up with GET /v1/projects/{project}/resources/{resource}.
  • Switching a resource off does not touch the plans that sell it. The connector stops granting that one place while the plans keep selling everything else, so a changes.active flip to false is "this perk is paused", not "this plan changed". No plan.updated follows.
  • An activate / deactivate call and a PATCH that sets active produce the same event with the same changes.active shape. The payload does not say which route was used.
  • A swap that also switches an inactive resource back on carries changes.active beside changes.space_id, because the swap reactivates what it repairs.
  • changes contains only the fields that mutated. A PATCH carrying all three fields where only one differs reports one key.

How is this guide?

On this page

Subscriby is a product designed by you — for you.

No boardroom full of executives deciding what we ships next. Our roadmap always shaped by you with your feedback.

Share feedback or a request