Open Evnt Specification
Version: 0.1: DRAFT Last updated: 2026-06-12
1. Introduction
This document defines the Open Evnt data format for describing events.
1.1 Scope
This specification defines:
- The data model for representing events, venues, instances, and components
- The partial date string format
- The extension mechanism for custom component and venue types
- Conformance requirements for producers and consumers
This specification does not define:
- Transport protocols, APIs, storage, or recurrence rules
- How events should be displayed or rendered
1.2 Conformance
The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in RFC 2119.
For readability, these keywords appear in lowercase in this document.
1.3 Terminology
| Term | Definition |
|---|---|
| Event | A planned happening, represented as an OpenEvnt object |
| Producer | Software that creates or emits Open Evnt documents |
| Consumer | Software that reads or processes Open Evnt documents |
| Instance | A single continuous occurrence of an event with its own time and venue references |
| Component | A typed piece of additional event metadata, extensible by $type |
| Partial Date | A string representing a date and/or time with varying precision and an explicit timezone |
2. Data Model
2.1 OpenEvnt
The root object representing a single event.
OpenEvnt
$type: "directory.evnt.event"? OPTIONAL
v: "0.1" REQUIRED
name: Translations REQUIRED
label: Translations? OPTIONAL
status: EventStatus? OPTIONAL
venues: Venue[]? OPTIONAL
instances: EventInstance[]? OPTIONAL
components: EventComponent[]? OPTIONAL
Additional properties: NOT ALLOWED$type: An optional type identifier for AT Protocol record wrapping. When present, MUST be "directory.evnt.event".
v: A string literal "0.1" identifying the format version. See Versioning for version semantics.
name: The event name as a Translations object. MUST have at least one entry.
label: A Translations object for representing an additional name for the event, for distinguishing it from similarly named events. Producers SHOULD use this field when the event has a name that might be ambiguous (e.g. "SomeCon") to provide a more specific label (e.g. "SomeCon 2025"). Consumers MAY display this label alongside the main name.
status: An EventStatus value describing the current planning state. When absent, consumers MUST treat the event as "planned".
venues: An array of Venue objects. Each venue MUST have a unique id within this array.
instances: An array of EventInstance objects representing occurrences of the event.
components: An array of EventComponent objects representing additional metadata.
2.2 Translations
An object mapping BCP47 language tags to strings.
Translations
[language: string]: string
Constraints:
Keys MUST be valid BCP47 language tags
Values MUST be non-empty strings
At least one entry REQUIREDResolution algorithm
When a consumer needs a single string for a user's preferred language, the following algorithm is RECOMMENDED:
- Exact match against the user's preferred BCP47 tag
- Match without region subtag (e.g.
zh-Hans-CN→zh-Hans) - Match on primary language subtag only (e.g.
zh-Hans-CN→zh) - Fallback to
en - Any available entry
- Empty string or placeholder
2.3 EventStatus
An enum representing the planning state of an event or instance.
EventStatus: "planned" | "uncertain" | "postponed" | "cancelled" | "suspended"| Variant | Description | Dates valid? |
|---|---|---|
planned | Event is scheduled as described (default) | Yes |
uncertain | Event may be rescheduled or cancelled | Unknown |
postponed | Event moved to a later, unknown date | No |
cancelled | Event will not take place | No |
suspended | Event paused; future unknown | No |
plannedis the initial state and the default whenstatusis absent.cancelledis a terminal state - it MUST NOT transition to any other status.- Any non-terminal status MAY return to
planned.
When status is not "planned", consumers SHOULD treat associated dates as potentially invalid.
2.4 Media
A media asset (image, video) with one or more sources.
Media
sources: MediaSource[] REQUIRED
alt: Translations? OPTIONAL
presentation: PresentationInfo? OPTIONALsources: One or more sources for the same media in different formats or resolutions. MUST NOT contain semantically different content in the same Media object.
alt: Alternative text for accessibility.
presentation: Visual hints for rendering.
PresentationInfo
blurhash: string? OPTIONAL
dominantColor: string? OPTIONALblurhash: A BlurHash string representing a placeholder image.
dominantColor: A hex color code (e.g. #1a1a2e) representing the dominant color in the media.
MediaSource
MediaSource
url: string? OPTIONAL
blob: object? OPTIONAL
mimeType: string? OPTIONAL
dimensions: { width: number, height: number }? OPTIONAL
Either url OR blob MUST be presenturl: A publicly accessible URL for the media source.
blob: An inline blob reference, as defined by the enclosing transport layer (e.g. AT Protocol BlobRef).
mimeType: The MIME type of the media (e.g. image/jpeg, video/mp4). When blob is used, MAY be inferred from the blob's metadata.
dimensions: The native width and height of the media in pixels.
Either url or blob MUST be present.
3. Partial Date
A PartialDate is a string that represents a date and/or time with varying precision and an explicit timezone.
3.1 Grammar
partialdate = year [ "-" month [ "-" day [ "T" time ] ] ] "[" timezone "]"
time = hour ":" minute
year = 4DIGIT
month = 2DIGIT ; 01–12
day = 2DIGIT ; 01–31
hour = 2DIGIT ; 00–23
minute = 2DIGIT ; 00–59
timezone = 1*( ALPHA / DIGIT / "-" / "_" / "/" / "+" )The grammar is adapted from RFC 9557 (which extends RFC 3339) but is not compatible with RFC 3339 or ISO 8601.
3.2 Precision levels
| Level | Pattern | Example |
|---|---|---|
| Year | 2025[Europe/London] | Only the year is known |
| Month | 2025-11[Europe/London] | Year and month known |
| Day | 2025-11-12[Europe/London] | Full date known |
| Time | 2025-11-12T11:00[Europe/London] | Date and time (without seconds) known |
3.3 Constraints
- Precision levels MUST be provided in order. Skipping a level (e.g. year to day without month) is NOT ALLOWED.
- A time component MUST NOT appear without a day.
- A day MUST NOT appear without a month.
- A month MUST NOT appear without a year.
- Seconds MUST NOT be included.
3.4 Timezone
Every PartialDate MUST include an IANA timezone identifier in square brackets at the end of the string.
- UTC offsets (
Z,+02:00) are NOT ALLOWED. - Only IANA timezone identifiers (e.g.
Europe/London,America/New_York,UTC) are valid.
When precision is year-only or month-only, the timezone carries no semantic meaning but MUST still be provided. [UTC] is a conventional choice.
3.5 Semantics
- A
PartialDaterepresents a range of possible instants, not a single instant. - At year precision, the value covers the entire calendar year in the specified timezone.
- At month precision, the value covers the entire calendar month.
- At day precision, the value covers the entire calendar day.
- At time precision, the value is a specific instant (subject to timezone rules such as DST).
3.6 Comparison
Two PartialDate values MAY be compared only when they share the same precision and timezone. Cross-precision comparison (e.g. year vs month) is NOT RECOMMENDED without explicit resolution rules.
3.7 Invalid examples
| Value | Reason |
|---|---|
2025-11-12T11:00Z | UTC offset, not timezone bracket |
2025-11-12T11:00+02:00 | UTC offset, not timezone bracket |
2025-11-12T11:00[Europe/London | Missing closing bracket |
2025-11-12T11:00:00[Europe/London] | Seconds not allowed |
2025-11-12T11[Europe/London] | Time must include minutes |
2025-11T11:00[Europe/London] | Time without day |
2025T11:00[Europe/London] | Time without month and day |
4. Venues
A venue represents a location where an event takes place. Venues are defined at the event level and referenced by instances via their id field.
4.1 Venue (base)
Venue (base)
id: string REQUIRED
$type: string REQUIRED
name: Translations REQUIREDid: A locally unique identifier within the event's venues array. Two different events MAY use the same venue IDs. Within a single event, venue IDs MUST be unique.
$type: A reverse-domain string identifying the venue variant. Determines the structure of the venue object.
name: A human-readable name as a Translations object.
4.2 PhysicalVenue
$type: directory.evnt.venue.physical
A real-world location.
PhysicalVenue extends Venue
$type: "directory.evnt.venue.physical"
address: Address? OPTIONAL
maps: MapReferences? OPTIONALAddress
Address
addr: string? OPTIONAL
countryCode: string? OPTIONALaddr: The full address as a single free-form string.
countryCode: An ISO 3166-1 alpha-2 country code (e.g. LT, US). SHOULD be uppercase.
MapReferences
A record of identifiers for the venue in external map services.
MapReferences
[nsid: string]: string | string[]Keys are reverse-domain NSIDs. Values are the identifier(s) assigned by that service.
| NSID | Service | Entity |
|---|---|---|
org.openstreetmap.node | OpenStreetMap | Node (POI) |
org.openstreetmap.way | OpenStreetMap | Way (building) |
org.openstreetmap.relation | OpenStreetMap | Relation (area) |
com.google.places | Google Places | Place ID |
com.foursquare | Foursquare | Venue ID |
com.what3words | what3words | 3-word address |
org.geonames | GeoNames | Feature ID |
org.wikidata.entity | Wikidata | Entity QID |
4.3 OnlineVenue
$type: directory.evnt.venue.online
A virtual or web-based location.
OnlineVenue extends Venue
$type: "directory.evnt.venue.online"
url: string? OPTIONALurl: The URL where the event can be accessed online.
4.4 UnknownVenue
$type: directory.evnt.venue.unknown
This represents a location with a name but does not make any guarantees about whether it is physical or online. Recommended for automated data collection when the venue type cannot be determined.
UnknownVenue extends Venue
$type: "directory.evnt.venue.unknown"If an instance has no known venue at all, use an empty venueIds array rather than creating an UnknownVenue.
4.5 Custom venue types
Producers MUST NOT define custom venue types. Consumers MUST ignore venues with unknown $type values and MUST preserve them when re-saving.
If a venue is ignored due to unknown $type, its id is no longer available for instance references. Consumers SHOULD treat references to ignored venues as unresolvable.
5. Instances
An instance represents a single continuous occurrence of an event. If an event happens multiple times (e.g. a conference with multiple days), each occurrence is a separate instance.
5.1 EventInstance
EventInstance
id: string? OPTIONAL
venueIds: string[] REQUIRED
start: PartialDate? OPTIONAL
end: PartialDate? OPTIONAL
status: EventStatus? OPTIONAL
components:EventComponent[]? OPTIONAL
Additional properties: NOT ALLOWEDid: An optional local identifier for the instance.
activities: An array of Activity objects representing scheduled sub-items within this instance (e.g. conference talks, workshops, performances). See Activity for the full definition.
components: An array of EventComponent objects representing additional metadata specific to this instance.
venueIds: References to Venues defined in the parent OpenEvnt.venues. MUST be an array (possibly empty). Duplicate values MUST NOT appear. Each value MUST match the id field of a venue in venues. If a value does not match any venue, consumers SHOULD treat it as an error.
When displaying venue information, consumers SHOULD use the venueIds of each instance rather than listing all event-level venues directly. This prevents displaying venues that are not relevant to a specific instance.
Producers SHOULD warn if a venue in venues is not referenced by any instance.
start: The start date and/or time as a PartialDate.
end: The end date and/or time as a PartialDate. When both start and end are present, end MUST have the same or lower precision than start (e.g. if start specifies a day, end cannot specify a time).
status: The planning state of this instance. Overrides the event-level EventStatus for this instance. When absent, inherits from the event-level status.
An event with no instances has no scheduled occurrences. This is valid for placeholder or template events.
5.2 Multiple instances
When an event has multiple occurrences with different times or venues, each occurrence SHOULD be represented as a separate instance.
{
"instances": [
{
"venueIds": ["hall"],
"start": "2026-06-15T09:00[Europe/Vilnius]",
"end": "2026-06-15T18:00[Europe/Vilnius]"
},
{
"venueIds": ["hall"],
"start": "2026-06-16T10:00[Europe/Vilnius]",
"end": "2026-06-16T17:00[Europe/Vilnius]"
}
]
}5.3 Multi-day events
A single event spanning multiple consecutive days (e.g. a festival, a game jam) SHOULD be represented as a single instance with start and end dates. The criterion is whether attendance is continuous (one instance) vs. discrete separate sessions (multiple instances).
5.4 Instance status
Each instance MAY have its own status, independent of the event-level status.
{
"status": "planned",
"instances": [
{ "venueIds": ["hall"], "status": "planned", "start": "2026-06-15[Europe/Vilnius]" },
{ "venueIds": ["hall"], "status": "uncertain", "start": "2026-06-16[Europe/Vilnius]" }
]
}Instance-level status overrides the event-level status for that instance only.
5.5 Activity
An activity is a scheduled sub-item within an instance: a conference talk, workshop, performance, or social hour.
Activity
name: Translations REQUIRED
slot: ActivitySlot? OPTIONAL
location: ActivityLocation? OPTIONAL
components: EventComponent[]? OPTIONALname: The activity name as a Translations object. MUST have at least one entry.
slot: When the activity takes place within the instance's time window.
location: A label for the room, stage, or area within the venue where this activity takes place. Not a Venue reference - use ActivityLocation for sub-venue naming.
components: Activity-specific metadata. See Components.
ActivitySlot
ActivitySlot
time?: "hh:mm" OPTIONAL
duration?: "hh:mm" OPTIONALtime: Clock time in 24h format. Hours 00–23, minutes 00–59. Represents unanchored clock time - inherits timezone context from the parent instance's PartialDate.
duration: Duration in hours:minutes. Minutes limited to 00–59; hours are unbounded.
| Slot shape | Meaning |
|---|---|
{} | Untimed |
{ "time": "15:00" } | Starts 15:00 |
{ "time": "15:00", "duration": "1:00" } | 15:00–16:00 |
ActivityLocation
ActivityLocation
name: Translations REQUIREDname: A label for the room or area, e.g. { "en": "Janson" }, { "en": "Main Stage" }, { "en": "Workshop Tent" }.
Example
{
"instances": [
{
"venueIds": ["campus"],
"start": "2026-02-07[Europe/Brussels]",
"end": "2026-02-07T19:00[Europe/Brussels]",
"activities": [
{
"name": { "en": "Opening Keynote" },
"slot": { "time": "09:30", "duration": "0:50" },
"location": { "name": { "en": "Janson" } }
},
{
"name": { "en": "Rust for Linux" },
"slot": { "time": "13:00", "duration": "0:50" },
"location": { "name": { "en": "Janson" } }
},
{
"name": { "en": "LLVM Workshop" },
"slot": { "time": "10:30", "duration": "8:30" },
"location": { "name": { "en": "K.3.201" } }
}
]
}
]
}6. Components
Components carry additional metadata about an event that is not tied to a specific venue or instance. They are the primary extension mechanism of Open Evnt.
6.1 EventComponent (base)
EventComponent
$type: string REQUIRED
Additional properties: ALLOWED$type: A reverse-domain string identifying the component type. Determines the structure and semantics of the remaining fields.
6.2 Component processing rules
- Consumers MUST ignore components with unknown
$typevalues. - Consumers MUST preserve unknown components and their properties when re-saving event data.
- Producers MAY define custom component types using any reverse-domain string.
- Custom
$typevalues SHOULD use a namespace the producer controls (e.g.com.example.component.metadata).
7. Defined component types
directory.evnt.component.link
A link related to the event (website, ticketing, social media, etc.).
directory.evnt.component.link
$type: "directory.evnt.component.link"
url: string REQUIRED
name: Translations? OPTIONAL
disabled: boolean? OPTIONAL
opensAt: PartialDate? OPTIONAL
closesAt: PartialDate? OPTIONALdisabled: When true, the link is temporarily unavailable.
opensAt: The link becomes active at this time.
closesAt: The link becomes inactive at this time.
directory.evnt.component.source
A source of information about the event (news article, announcement, etc.).
directory.evnt.component.source
$type: "directory.evnt.component.source"
url: string REQUIREDProducers SHOULD use this component when the event data was sourced from an external announcement or publication. It is not needed when the event itself is the primary source.
directory.evnt.component.splashMedia
A media item for visual representation of the event (cover image, poster, etc.).
directory.evnt.component.splashMedia
$type: "directory.evnt.component.splashMedia"
media: Media REQUIRED
roles: string[] REQUIREDroles: Usage roles such as "background", "thumbnail", "poster". Applications MAY define their own roles.
directory.evnt.component.languages
Languages the event is available in.
directory.evnt.component.languages
$type: "directory.evnt.component.languages"
languages: LanguageInfo[] REQUIREDlanguages: An array of language entries.
LanguageInfo
code: string REQUIREDcode: A BCP47 language tag (e.g. "en", "lt", "zh-Hans").
directory.evnt.richtext.bluesky
Rich text content in the Bluesky Rich Text format.
directory.evnt.richtext.bluesky
$type: "directory.evnt.richtext.bluesky"
text: string REQUIRED
facets: Facet[]? OPTIONALThe facets field uses the same format as Bluesky Rich Text Facets. Facet is defined by the Bluesky AT Protocol and is not part of this specification.
directory.evnt.richtext.markdown
Markdown content with an optional language hint.
directory.evnt.richtext.markdown
$type: "directory.evnt.richtext.markdown"
content: string REQUIRED
language: string? OPTIONAL
flavor: string? OPTIONALlanguage: A BCP47 language tag for the markdown content. Producers SHOULD populate this field when the language is known.
flavor: A string indicating the markdown flavor. Producers SHOULD populate this field when the flavor is known.
8. Serialization
Open Evnt documents are serialized as JSON.
8.1 JSON representation
An OpenEvnt object MUST be represented as a JSON object conforming to the data model defined in this specification.
{
"v": "0.1",
"name": {
"en": "Example Event"
}
}8.2 Field ordering
Consumers MUST NOT depend on JSON object key order.
8.3 Unknown fields
At the OpenEvnt level, consumers MUST reject objects with properties not defined in the data model.
At the component level, additional properties beyond $type are PERMITTED. Consumers MUST preserve them when re-saving.
8.4 File extension
The RECOMMENDED file extension for Open Evnt files is .evnt.json. This distinguishes Open Evnt files from generic JSON while keeping standard tooling (syntax highlighting, validators) working.
meetup.evnt.json
fosdem-2026.evnt.json8.5 MIME type
The RECOMMENDED MIME type is application/evnt+json.
Optional version parameter:
application/evnt+json; v=0.19. Versioning
9.1 Version scheme
Versions follow a MAJOR.MINOR scheme.
Exception for 0.x versions: All 0.* versions may introduce breaking changes. This follows the ZeroVer convention while the format is in development. Starting from 1.0, the rules below apply.
- MINOR changes (e.g.
1.0→1.1): Additive only. New optional fields, new component types. Existing documents remain valid. - MAJOR changes (e.g.
1.0→2.0): May break backward compatibility. Fields may be removed, required fields may change, serialization format may change.
9.2 Current version
The current version is "0.1". All published documents MUST set v to "0.1".
The 0. prefix indicates the format is in development. Producers and consumers SHOULD expect breaking changes between any 0.x versions.
9.3 Producer requirements
- Producers MUST set
vto the version of the spec they conform to. - Producers MUST NOT produce documents with a
vvalue that does not match the spec they implement.
9.4 Consumer requirements
- Consumers MUST accept documents with a
vvalue equal to or lower than the highest version they support. - Consumers MAY accept documents with a higher minor version (e.g. a
1.0consumer MAY accept1.1documents, ignoring unrecognized fields). - Consumers MUST reject documents with a higher major version they do not support.
Appendix A: Complete example
{
"v": "0.1",
"name": {
"en": "Tech Conference 2026",
"lt": "Tech Konferencija 2026"
},
"label": {
"en": "The premier tech event in Vilnius",
"lt": "Pagrindinis technologijų renginys Vilniuje"
},
"status": "planned",
"venues": [
{
"id": "main-hall",
"$type": "directory.evnt.venue.physical",
"name": { "en": "Vilnius Convention Centre" },
"address": {
"addr": "123 Konstitucijos pr., Vilnius",
"countryCode": "LT"
}
},
{
"id": "stream",
"$type": "directory.evnt.venue.online",
"name": { "en": "Livestream" },
"url": "https://live.example.com/techconf-2026"
}
],
"instances": [
{
"venueIds": ["main-hall", "stream"],
"start": "2026-06-15T09:00[Europe/Vilnius]",
"end": "2026-06-15T18:00[Europe/Vilnius]"
},
{
"venueIds": ["main-hall", "stream"],
"start": "2026-06-16T10:00[Europe/Vilnius]",
"end": "2026-06-16T17:00[Europe/Vilnius]"
}
],
"components": [
{
"$type": "directory.evnt.component.link",
"url": "https://example.com/tickets",
"name": { "en": "Get Tickets" }
},
{
"$type": "directory.evnt.component.splashMedia",
"media": {
"sources": [
{
"url": "https://example.com/banner.jpg",
"mimeType": "image/jpeg",
"dimensions": { "width": 1200, "height": 600 }
}
],
"alt": { "en": "Tech Conference 2026 banner" },
"presentation": {
"dominantColor": "#1a1a2e"
}
},
"roles": ["background"]
}
]
}Appendix B: JSON Schema
The machine-validatable JSON Schema for this specification is published at https://evnt.directory/openevnt.schema.json.
Appendix C: Changelog
0.1: 2026-06-12
- Initial draft of the Open Evnt specification.