websub

Model for WebSub resource subscriptions, delivery queues, and automatic imports.

Available model API paths

MethodPathResult
get/subscriptionsPaginated overview; requires use mod_websub. Payload: type (all, export, import), numeric local rsc_id, hostname, status, errors (yes/no/all), and page.
get/subscriber_count/+idNumber of unexpired incoming subscriptions; requires resource edit permission.
get/status/+idLatest import subscription status for an editable resource, or undefined when none exists.

+id is resolved through m_rsc:rid/2. The template equivalent is m.websub.status[id]; the model checks resource edit permission independently of the template or controller. Unauthorized reads return eacces. There are no public model POST or DELETE paths for starting or stopping subscriptions.

The overview includes retained expired/stopped subscriptions and renewal generations, 50 rows per page. Hostname is an exact, case-insensitive match on the incoming callback host or outgoing source host, ignoring ports and a trailing DNS dot. Status accepts active, pending, expired, or stopped; empty/all means all states. The errors filter selects rows with or without the table’s error indicator. All filters apply before pagination and counting. The overview returns a search_result record with an exact total, capped at 10,000 pages. It returns remote hostnames, never callback URLs, tokens, secrets, or authentication data. Invalid filters return is_invalid without broadening the query.

Status includes desired state (is_enabled), confirmation state (is_unsubscribed, is_active), pending_mode, lease, last_received, last_error, and credential_error. During renewal, is_active also accounts for a still-active predecessor callback. Status never exposes callback tokens, HMAC secrets, or source OAuth2 tokens.

Erlang API

  • subscribe/2 starts a durable subscription for an editable, non-authoritative resource with a remote URI. It requires a logged-in user and is idempotent for an already-enabled subscription to that source. Discovery and verification run asynchronously; ok means intent was recorded, not that the hub confirmed it.
  • unsubscribe/2 requires edit permission, immediately disables automatic imports, discards queued updates, and schedules remote unsubscription.
  • topic_url/2 generates the language-independent JSON topic URL. Use m_rsc:uri/2 for the resource's semantic /id identity instead.
ok = m_websub:subscribe(Id, Context).
ok = m_websub:unsubscribe(Id, Context).

Admin postbacks call these checked functions. The remaining exported queue, verification, export-registration, schema, and maintenance functions are internal integration APIs. They are not exposed through model paths. In particular, update_export/6 and delete_export/3 are called after the hub has verified intent; callers must not use them to bypass authorization or callback verification.

Delivery and import processing

Publisher queues coalesce resource versions, enforce lease expiry, and recheck current access within the original authentication's group restrictions. Delivery contains the complete JSON topic representation and a signature when a secret was supplied. Exhausted retries discard that notification, allowing later updates to retry delivery for the remaining lease.

Subscriber callbacks identify the subscription by capability token and validate the signed resource URI. Public imports consume the pushed JSON; credentialed imports refetch through z_fetch using the subscribing user's source credentials. Before applying content, the import transaction checks current edit permission, non-authoritative status, source identity, and version ordering. Saved import options are reused without allowing automatic updates to restart a stopped subscription. Resource identity is stored separately from the discovered WebSub topic_url, so topic migration does not change the semantic resource identifier.

See mod_websub for the two-site protocol flow and z_websub_subscription for renewal, pending intent, callback rotation, and subscriber state persistence.

Edit on GitHub