app.zeens.event
{
"$type": "com.atproto.lexicon.schema",
"defs": {
"itineraryItem": {
"properties": {
"location": {
"description": "Optional location for this item. Only meaningful for events with mode 'in_person' or 'hybrid'. Items with lat/lng are plotted on the event map.",
"ref": "#location",
"type": "ref"
},
"text": {
"description": "What happens at this point in the event (e.g. 'Meet at the park entrance', 'Darkroom demo', 'Q&A with the curator').",
"maxLength": 500,
"type": "string"
},
"time": {
"description": "Free-text time label for this item (e.g. '9:00 AM', 'Lunch'). Stored as text, not a datetime, so it renders verbatim without timezone handling.",
"maxLength": 50,
"type": "string"
}
},
"required": [
"text"
],
"type": "object"
},
"link": {
"properties": {
"label": {
"maxLength": 100,
"type": "string"
},
"uri": {
"format": "uri",
"type": "string"
}
},
"required": [
"uri"
],
"type": "object"
},
"location": {
"properties": {
"address": {
"description": "Human-readable street address.",
"maxLength": 500,
"type": "string"
},
"lat": {
"description": "Latitude in microdegrees (degrees x 1e7). ATProto rejects non-integer numbers, so coordinates are scaled to integers.",
"type": "integer"
},
"lng": {
"description": "Longitude in microdegrees (degrees x 1e7).",
"type": "integer"
},
"name": {
"description": "Venue / place name.",
"maxLength": 200,
"type": "string"
}
},
"type": "object"
},
"main": {
"description": "An event: a photowalk, workshop, meetup, exhibition or talk. Written to the organiser's own PDS. Others RSVP via app.zeens.rsvp (ATProto handle) or via an email address tracked off-protocol in PocketBase. The app does NOT collect payment: paid events carry free-text paymentInstructions and any URL/link in that field is rejected at write time. Carries the app.zeens.v marker so firehose + Lua filters recognise it. NOTE: the record id stays 'app.zeens.event' and the app.zeens.* namespace is network plumbing — it is not renamed when the product is. Two orthogonal axes describe an event: `mode` (WHERE it happens — in person, online, or both) and `categories` (WHAT it is — one or more of photowalk/workshop/meetup/exhibition/talk/other). The `hostedBy` field is DEPRECATED (the organiser is the record owner); kept for back-compat with old records.",
"key": "tid",
"record": {
"properties": {
"app.zeens.v": {
"description": "Zeens version marker (always 1).",
"type": "integer"
},
"approvalRequired": {
"description": "When true, an RSVP is pending until the organiser approves it; only approved RSVPs count toward the cap and the attendee list. Approval state is tracked off-protocol (the organiser cannot mutate another user's rsvp record). Default false.",
"type": "boolean"
},
"capacityMode": {
"description": "Behaviour when maxParticipants is reached. 'hard' = block new going RSVPs. 'waitlist' = overflow goes on a waitlist, promoted in RSVP order. Only meaningful when maxParticipants is set. Default 'hard'.",
"knownValues": [
"hard",
"waitlist"
],
"type": "string"
},
"categories": {
"description": "WHAT the event is. One or more (max 3) — an event can be both a photowalk and a meetup. Drives browse/filter, which OR-matches any element. Orthogonal to `mode`. The legacy value 'online_meetup' is tolerated on read and means mode 'online' + category 'meetup'.",
"items": {
"knownValues": [
"photowalk",
"workshop",
"meetup",
"exhibition",
"talk",
"other"
],
"type": "string"
},
"maxLength": 3,
"minLength": 1,
"type": "array"
},
"coverImage": {
"accept": [
"image/jpeg",
"image/png",
"image/webp"
],
"description": "Wide cover image shown on the event header and share previews.",
"maxSize": 4000000,
"type": "blob"
},
"createdAt": {
"format": "datetime",
"type": "string"
},
"createdBy": {
"description": "Display text for the event creator/organiser (the account that owns this record).",
"maxLength": 200,
"type": "string"
},
"description": {
"description": "Long-form event description.",
"maxLength": 3000,
"type": "string"
},
"endsAt": {
"description": "Optional event end instant.",
"format": "datetime",
"type": "string"
},
"facets": {
"description": "Rich-text facets (links, mentions) over the description, reusing the Bluesky richtext lexicon.",
"items": {
"ref": "app.bsky.richtext.facet",
"type": "ref"
},
"type": "array"
},
"hostedBy": {
"description": "DEPRECATED. Display text for who is hosting. The organiser is the record owner, so this is no longer written; kept so old records still read.",
"maxLength": 200,
"type": "string"
},
"itinerary": {
"description": "Ordered agenda for the event: a list of items, each with optional time, descriptive text, and an optional location. Works for any event type — a photowalk's route, a workshop's schedule, an exhibition's programme. Items that carry coordinates are drawn on the event map as numbered pins in order; an event whose items have no coordinates simply renders the list with no map.",
"items": {
"ref": "#itineraryItem",
"type": "ref"
},
"maxLength": 30,
"type": "array"
},
"links": {
"description": "Social / website links for the event.",
"items": {
"ref": "#link",
"type": "ref"
},
"maxLength": 5,
"type": "array"
},
"location": {
"description": "Physical location. Expected for mode 'in_person' and 'hybrid'; absent for 'online'.",
"ref": "#location",
"type": "ref"
},
"maxParticipants": {
"description": "Optional cap on confirmed (going) participants. Absent = unlimited.",
"minimum": 1,
"type": "integer"
},
"mode": {
"description": "WHERE the event happens, and one of exactly three values. 'in_person' needs a location; 'online' needs a virtualUrl and has no location; 'hybrid' needs both. Orthogonal to `categories` — an online workshop is mode 'online' + categories ['workshop']. Records written before this field carried meaning default to 'in_person' on read. The legacy value 'virtual' is tolerated on read and means 'online'.",
"knownValues": [
"in_person",
"online",
"hybrid"
],
"type": "string"
},
"paid": {
"description": "Whether the event costs money. The app never processes payment.",
"type": "boolean"
},
"paymentInstructions": {
"description": "Free-text explanation of how the organiser collects payment out of band. MUST NOT contain a URL/link; rejected at write time client- and server-side.",
"maxLength": 1000,
"type": "string"
},
"photoCategories": {
"description": "Photography genre tags (Street, Landscape, Portrait, ...). Up to 3, optional. Drawn from the shared category list used by posts. Distinct from `categories`, which is the event type.",
"items": {
"maxLength": 100,
"type": "string"
},
"maxLength": 3,
"type": "array"
},
"rsvpPolicy": {
"description": "Who may RSVP. 'atmosphere' = any ATProto account. 'photosky' = members only. 'anyone_email' = anyone, including non-ATProto people via an email address. Enforcement is soft (obscurity-level), like collection visibility.",
"knownValues": [
"atmosphere",
"photosky",
"anyone_email"
],
"type": "string"
},
"startsAt": {
"description": "Event start, as an absolute instant. Render in `timezone`.",
"format": "datetime",
"type": "string"
},
"timezone": {
"description": "IANA timezone name (e.g. 'America/New_York'). Stored separately from startsAt so calendar export (.ics DTSTART;TZID) and the displayed local time are correct.",
"maxLength": 100,
"type": "string"
},
"title": {
"description": "Event title.",
"maxGraphemes": 150,
"maxLength": 300,
"type": "string"
},
"virtualUrl": {
"description": "Join link for events with mode 'online' or 'hybrid'. Required for those modes. Shown only to RSVP'd users in the client.",
"format": "uri",
"type": "string"
}
},
"required": [
"title",
"startsAt",
"timezone",
"mode",
"rsvpPolicy",
"categories",
"createdAt",
"app.zeens.v"
],
"type": "object"
},
"type": "record"
}
},
"id": "app.zeens.event",
"lexicon": 1
}
Metadata
- DID
-
did:plc:pwpuqwge6g7xrjmfbw73uycw - CID
-
bafyreib7avfkz7tzud2bhhqcbl5e2n4xoix6icaa2ndhlbc2ccq6iucxau - Indexed At
- 2026-10-22 16:31 UTC
- AT-URI
-
at://did:plc:pwpuqwge6g7xrjmfbw73uycw/com.atproto.lexicon.schema/app.zeens.event
Referenced Schemas (1)
Similar Lexicons
Lexicons whose schemas describe something close to this one. Check them before publishing a new one that overlaps.
-
An independently addressable public event appearance for a Craftsky business.
-
Optional fields that can be used to provide less pertinent information about the event
-
org.devcon.event record
-
org.devcon.event.vone record
Optional fields that can be used to provide less pertinent information about the event
-
org.devcon.event.testcache record