W2AProtocol
Specification

Operations

Every operation a member or owner can perform, in each binding.

Summary

OperationSent toAddress bindingHub response
introducejoin@—recommendation
discoverjoin@—recommendation
joinchannel<id>+join@confirm or welcome
confirmactionact+<token>@welcome (or the confirmed result)
leavechannel<id>+leave@, one-click URLnotice (optional)
infochannel<id>+info@channel-card
postchannel<id>@receipt (optional)
replyactionact+<token>@receipt (optional)
profilejoin@—profile
forgetjoin@—notice
create (Draft)join@—confirm

All JSON requests share an envelope:

{ "w2a": "2026-10-18", "op": "<operation>", "...": "operation-specific fields" }

Natural-language requests

When a request arrives in natural language, the hub interprets it. Two rules apply:

  1. Ambiguity requires confirmation. If a request could map to more than one operation, or its target is unclear, the hub MUST reply with confirm describing its interpretation instead of acting. "I don't want to leave the fishing channel" must never be read as leave.
  2. Money and inventory never move on free text. See Security.

introduce

Creates or updates the sender's profile and returns recommendations. See Onboarding.

{
  "w2a": "2026-10-18",
  "op": "introduce",
  "text": "Lives in Hangzhou, into lure fishing and badminton, looking for weekend companions."
}

A hub MUST treat the first natural-language message from an unknown sender to join@ as an introduction.

discover

Asks the discovery service for recommendations. With explicit filters, discover behaves as a search. See Discovery.

{
  "w2a": "2026-10-18",
  "op": "discover",
  "query": "something fun this weekend",
  "filters": { "geo": "Hangzhou", "kind": ["channel", "item"] }
}

join

Requests membership in a channel.

BindingForm
AddressEmpty email to fishing-hz+join@w2a.example
Natural language"Join Hangzhou Lure Fishing" sent to join@w2a.example, or a reply to a recommendation listing item numbers
JSON{"op":"join","channel":"fishing-hz"}

Processing:

  • If the message passes DMARC alignment, the hub MAY activate the membership immediately and send welcome.
  • Otherwise the hub MUST send confirm and activate only after confirmation. This prevents anyone from subscribing a mailbox they don't control.
  • If join_policy is approval, the membership is pending until the owner approves. If it is invite, the hub MUST reject joins that lack a valid invite token.

confirm

Completes a pending state change. The member sends an empty email to the action address from the confirm message. A plain reply works too, because confirm messages set Reply-To to that address.

leave

Ends membership.

BindingForm
AddressEmpty email to fishing-hz+leave@w2a.example
One-clickHTTPS POST to the List-Unsubscribe URL (RFC 8058)
Natural language"Leave this channel" in reply to a channel message
JSON{"op":"leave","channel":"fishing-hz"}
  • A hub MUST honor leave immediately, without a confirmation step, through the address and one-click bindings.
  • A hub MUST NOT let owners disable leaving.
  • A hub MUST NOT notify the owner of individual departures by default.

info

Returns the channel card. Send an empty email to fishing-hz+info@w2a.example, or use {"op":"info","channel":"fishing-hz"}.

post

Publishes to a channel. Send an email to the channel address. The subject (if any) and the body become the post.

{
  "w2a": "2026-10-18",
  "op": "post",
  "channel": "fishing-hz",
  "text": "Going Saturday morning, room for one more.",
  "data": { "@type": "Event", "name": "Qiandao Lake lure trip", "startDate": "2026-10-24T06:00+08:00" }
}

The hub checks the post policy (identity level, rate limit), screens the content, and queues the post for the next digest. Replying to a digest without using an item's action address creates a new post.

reply

Replies to a specific item. Send an email to the item's action address. Replies are threaded under the parent item in the next digest.

profile

Returns what the hub stores about the sender: profile tags, memberships, and identity level. A hub MUST support this request in natural language ("What do you know about me?").

forget

Deletes the sender's profile and all memberships. Posts remain in channel archives under a tombstoned handle unless the member also asks for their removal.

create (Draft)

Creates a channel. The hub replies with a draft channel card in a confirm message. The channel goes live once the sender confirms. The sender becomes the owner.

Owner operations (approve, remove, ban, update, announce) are Draft and will be specified in a later revision.


Errors

Errors are sent as W2A-Type: error, with a human-readable explanation in the instruction block and a machine-readable code in the JSON part.

{ "w2a": "2026-10-18", "type": "error", "code": "not_permitted", "detail": "Posting requires L1." }
CodeMeaning
unknown_channelNo such channel on this hub
not_permittedThe sender doesn't meet the channel's policy
pending_approvalJoin recorded, waiting for owner approval
rate_limitedToo many requests. The JSON part includes retry_after in seconds.
ambiguousA natural-language request needs clarification (sent as confirm when possible)
invalid_requestMalformed JSON or unknown operation
expired_tokenThe action address has expired or was already used
unauthenticatedThe message failed DMARC alignment and the operation requires it

On this page