1.0.6 • Published 1 month ago

@code4recovery/spec v1.0.6

Weekly downloads
-
License
MIT
Repository
-
Last release
1 month ago

Meeting Guide API

The goal of the Meeting Guide API is help sync information about AA meetings. It was developed for the Meeting Guide app, but it is non-proprietary and other systems are encouraged to make use of it.

If you have feedback, please put an issue on this repository.

Usage

To implement the API on your server, create a file that can take information from your database and format it in the correct specification (see below).

For security, your script should not accept any parameters. It should be read-only.

Your data must not break anyone's anonymity. No last names should be used in meeting notes, and no one's face should be pictured in meeting images.

You may test your feed with the Meeting Guide JSON Feed Validator. Once it's ready, or if you have questions, see How to Connect to Meeting Guide.

If you would like to share your script, we'll include a copy in this repository so that it might help future users.

Specification

The JSON file is expected to contain a simple array of meetings. Here is an example of a live JSON feed.

[
	{
		"name": "Sunday Serenity",
		"slug": "sunday-serenity-14",
		"day": 0,
		"time": "18:00",
		"end_time": "19:30",
		"location": "Alano Club",
		"group": "The Serenity Group",
		"notes": "Ring buzzer. Meeting is on the 2nd floor.",
		"updated": "2014-05-31 14:32:23",
		"url": "https://district123.org/meetings/sunday-serenity",
		"types": [
			"O",
			"T",
			"LGBTQ"
		],
		"address": "123 Main Street",
		"city": "Anytown",
		"state": "CA",
		"postal_code": "98765",
		"country": "US",
		"approximate": "no",
		"entity": "District 123",
		"entity_email": "info@district123.org",
		"entity_feedback_emails": [
			"meetingupdates@district123.org"
		],
		"entity_location": "Example County, California",
		"entity_logo": "https://district123.org/images/logo.svg",
		"entity_phone": "+1-123-456-7890",
		"entity_url": "https://district123.org"
	},
	...
]

name is a required string. It should be the meeting name, where possible. Some areas use group names instead, although that's more abiguous. 255 characters max.

slug is required, and must be unique to your data set. It should preferably be a string, but integer IDs are fine too.

day is required and may be an integer or an array of integers 0-6, representing Sunday (0) through Saturday (6).

time is a required five-character string in the HH:MM 24-hour time format.

end_time is an optional five-character string in the HH:MM 24-hour time format.

timezone is an optional string in tz database format e.g. America/New_York.

types is an optional array of standardized meeting types. See the types section below.

notes is an optional long text field to hold additional details about the meeting. Line breaks are ok, but HTML will be stripped.

conference_url is an optional URL to a specific public videoconference meeting. This should be a common videoconferencing service such as Zoom or Google Hangouts. It should launch directly into the meeting and not link to an intermediary page.

conference_url_notes is an optional string which contains metadata about the conference_url (eg meeting password in plain text for those groups unwilling to publish a one-tap URL).

conference_phone is telephone number to dial into a specific meeting. Should be numeric, except a + symbol may be used for international dialers, and ,, *, and # can be used to form one-tap phone links.

conference_phone_notes is an optional string with metadata about the conference_phone (eg a numeric meeting password or other user instructions).

location is an optional string and should be a recognizable building or landmark name.

location_notes is an optional long text field with notes applying to all meetings at the location.

formatted_address either this or the address / city / state / postal_code / country combination are required.

address, city, state, postal_code, and country are all optional strings, but together they must form an address that Google can identify. address and city are suggested. Take special care to strip extra information from the address, such as 'upstairs' or 'around back,' since this is the primary cause of geocoding problems. (That information belongs in the notes field.) Intersections are usually ok, but approximate addresses, such as only a city or route, do not have enough precision to be listed in the app.

latitude and longitude are optional numeric values indicating the geoposition of the meeting. Only five decimal places of precision are necessary here (1.11m). These values are ignored by the Meeting Guide importer.

approximate is an optional stringified boolean value, that, when present, indicates whether the address is an approximate location ("yes") or a specific point on a map such as a street address ("no"). This is ignored by the Meeting Guide importer.

region is an optional string that represents a geographical subset of meeting locations. Usually this is a neighborhood or city. District numbers are discouraged because they require special program knowledge to be understood.

updated is an optional UTC timestamp in the format YYYY-MM-DD HH:MM:SS and indicates when the listing was last updated.

image is an optional url that should point to an image representing the location. We recommend an image of the building's facade. Ideally this is a JPG image 1080px wide by 540px tall.

group is an optional string representing the name of the group providing the meeting. Groups can hold meetings in multiple locations.

group_notes is an optional long text field. Line breaks are ok, but HTML will be stripped.

venmo is an optional string and should be a Venmo handle, eg @AAGroupName. This is understood to be the address for 7th Tradition contributions to the meeting, and not any other entity.

square is an optional string and should be a Square Cash App cashtag, eg $AAGroupName. This is understood to be the address for 7th Tradition contributions to the meeting, and not any other entity.

paypal is an optional string and should be a PayPal.me username, eg AAGroupName. This is understood to be the address for 7th Tradition contributions to the meeting, and not any other entity.

url is optional and should point to the meeting's listing on the area website.

edit_url is an optional string URL that trusted servants can use to edit the specific meeting's listing.

feedback_url is an optional string URL that can be used to provide feedback about the meeting. These can be on-site or off-site absolute URLs, eg https://example.org/feedback?meeting=meeting-slug-1 or https://typeform.com/to/23904203?meeting=meeting-slug-1, or email links, eg mailto:webservant@domain.org?subject=meeting-slug-1.

entity is the name of the service entity responsible for the listing. entity info is optional, but entity is required if any of the other entity fields are present.

entity_email is a public email address for the service entity responsible for the listing.

entity_feedback_emails an array of feedback addresses for the service entity responsible for the listing.

entity_location is a human-readable physical description of the service area of the entity, eg Whatcom County, Washington.

entity_logo is the URL of the logo of the service entity responsible for the listing. should begin with https://. ideally the image this points to is a vector-based SVG so it can be scaled to any size. Additionally, the image should be square, and have a transparent background. Finally, colors should be specified using currentColor so that they can adapt to the color mode (light, dark) of the app.

entity_phone is the phone number of the service entity responsible for the listing. Should be in the format +1-123-456-7890 and start with country code for international dialing.

entity_website_url is the URL of the website homepage of the service entity responsible for the listing. should begin with https://

Common Questions & Concerns

We use different meeting codes!

That's ok. App users don't actually see the codes, just the types they translate to.

Our meeting type isn't listed!

Types have to be consistent across the app to make a good user experience. It's common that a user might see meeting results from several areas at a time (this happens in small areas, and near borders). The set of meeting types we use is a mutually-agreed-upon set of names across 70+ areas. If you have a request to edit the list, we will bring it up at our steering committee meeting.

Meeting Guide requirements

Some applications have requirements about what content needs to be in the feed. Meeting Guide, for example, requires slug, day, time, as well as geographic information to be present for it to be imported.

Why is slug necessary?

Slug is a required unique field because there is an app feature where users may 'favorite' a meeting, and in order for that to persist across sessions we must attach it to a unique field. It might seem intuitive that meeting location + time would be a unique combination, but in practice we see cases where there are in fact simultaneous meetings at the same location.

Why are day and time required?

It's perfectly fine for meetings to be 'by appointment' and this often happens in places where there are not many meetings. The app, however, needs this information to present useful information to the user.

Why is geographic information necessary for online-only meetings?

Meeting Guide has far too many meetings in its database to expose them all to individual users. To present only the most relevant information, Meeting Guide selects meetings that are "nearby" - even if that meeting is online. In these cases, the location can be thought of as a point of origin for the meeting, or a geographic affinity.

Use approximate locations for these meetings. formatted_address is the most flexible field for this, and values can be things like: Wicker Park, Chicago, IL, USA (neighborhood), Chicago, IL, USA (city), or Illinois, USA (state). It's also fine to use country, city, and state fields atomically.

These locations should standardized (can you find it with Google Maps?), and imply the time zone. For this reason, don't use a broad geographic area like United States that spans multiple time zones.

Why can't we have HTML in meeting notes?

Data should be portable across a range of devices, some of which might not display HTML.

What about business meetings or other monthly meetings?

This API is for weekly recovery meetings.

Meeting Types

The codes below are only used for transmitting meeting data. App users will only see the full definitions.

The codes below should be considered 'reserved.' In your implementation, it's ok to alter the description (for example "Topic Discussion" rather than "Discussion") so long as the intent is the same. For example, "Child Care Available" is a common substitute for "Babysitting Available." It's also ok to add types, they will be ignored by the importer, but be careful not to use any existing or proposed codes.

CodeEnglishEspañolFrançais日本語SvenskaSlovenčina
1111th Step MeditationMeditación del Paso 11Méditation sur la 11e Étapeステップ11 黙想11th Stegs MeditationMeditácia 11. kroku
12x1212 Steps & 12 Traditions12 Pasos y 12 Tradiciones12 Étapes et 12 Traditions12のステップと12の伝統12 Steg & 12 Traditioner12 Krokov & 12 Tradícií
ASecularSecularSéculier無宗教SekulärtSvetské
ABSIAs Bill Sees ItComo lo ve BillRéflexions de Billビルはこう思うSom Bill Ser DetAko to vidí Bill
ALConcurrent with AlateenConcurrente con AlateenEn même temps qu’Alateenアラティーンと同時進行Tillsammans med AlateenSúbežne s Alateen
AL-ANConcurrent with Al-AnonConcurrente con Al-AnonEn même temps qu’Al-Anonアラノンと同時進行Tillsammans med Al-AnonSúbežne s Al-Anon
AMAmharicAmáricoAmhariqueアムハラ語AmhariskaAmharčina
ASLAmerican Sign LanguageLenguaje por señasLangage des Signesアメリカ手話Amerikanskt teckenspråkAmerický posunkový jazyk
BBig BookLibro GrandeGros LivreビッグブックStora BokenVeľká Kniha
BABabysitting AvailableGuardería disponibleGarderie d’enfants disponibleベビーシッターありBarnvakt FinnsDostupné opatrovanie detí
BENewcomerPrincipiantesNouveau/nouvelleビギナーズNykomlingNováčikovia
BIBisexualBisexualBisexuelバイセクシャルBisexuelltBisexuálne
BRKBreakfastDesayunoPetit déjeuner朝食FrukostRaňajky
CClosedCerradaFerméクローズドSlutetUzatvorené
CANCandlelightLuz de una velaÀ la chandelleキャンドルTända LjusSviečky
CFChild-FriendlyNiño amigableEnfants acceptésお子さま歓迎BarnvänligtPriateľský k deťom
DDiscussionDiscusiónDiscussionディスカッションDiskussionDiskusia
DADanishDanésDanoisデンマーク語DanskaDánsky
DBDigital BasketCanasta digitalPanier numérique電子献金Digital KorgDigitálny košík
DDDual DiagnosisDiagnóstico dualDouble diagnostic重複診断Dubbel DiagnosDuálna diagnóza
DEGermanAlemánAllemandドイツ語TyskaNemecké
DRDaily ReflectionsReflexiones DiariasRéflexions quotidiennes今日を新たにDagliga ReflektionerDenné úvahy
ELGreekGriegoGrecギリシャ語GrekiskaGrécke
ENEnglishInglésAnglais英語EngelskaAnglické
FAPersianPersaPersanペルシア語PersiskaPerzské
FFFragrance FreeSin fraganciaSans parfum香水なしParfym FrittBez vône
FRFrenchFrancésFrançaisフランス語FranskaFrancúzsky
GGayGayGaiゲイGayGay
GRGrapevineLa ViñaGrapevineグレープバインGrapevineGrapevine
HBirthdayCumpleañosAnniversaireバースデーFödelsedagNarodeniny
HEHebrewHebreoHébreuヘブライ語HebreiskaHebrejské
HIHindiHindiHindiヒンディー語HindiHindi
HRCroatianCroataCroateクロアチア語KroatiskaChorvátsky
HUHungarianHúngaroHongroisハンガリー語UngerskaMaďarské
ITAItalianItalianoItalienイタリア語ItalienskaTaliansky
JAJapaneseJaponésJaponais日本語JapanskaJaponské
KORKoreanCoreanoCoréen韓国語KoreanskaKórejske
LLesbianLesbianasLesbienneレズビアンLesbisktLesbické
LGBTQLGBTQLGBTQLGBTQLGBTQHBTQLGBTQ
LITLiteratureLiteraturaPublications書籍LitteraturLiteratúra
LSLiving SoberViviendo SobrioVivre… Sans alcoolリビングソーバーLeva NyktertTriezvy život
LTLithuanianLituanoLituanienリトアニア語LitauiskaLitovské
MMenHombresHommes男性MansmöteMuži
MEDMeditationMeditaciónMéditation黙想MeditationsmöteMeditácia
MLMalayalamMalayalamMalayalamマラヤーラム語MalayalamMalajálamsky
NNative AmericanNativo AmericanoAutochtoneネイティブアメリカンUr-amerikansktDomorodí Američania
NDGIndigenousIndígenaIndigène先住民UrfolkligtDomorodé
NONorwegianNoruegoNorvégienノルウェー語NorskaNórsky
OOpenAbiertaOuvert(e)オープンÖppetOtvorené
OUTOutdoorAl aire libreEn plein airアウトドアUtomhusVonkajšie
PProfessionalsProfesionalesProfessionnels職業人ProfessionellaProfesionáli
POCPeople of ColorGente de colorGens de couleur有色人種FärgadeFarební ľudia
POLPolishPolacoPolonaisポーランド語PolskaPoľské
PORPortuguesePortuguésPortugaisポルトガル語PortugisiskaPortugalské
PUNPunjabiPunjabiPendjabiパンジャブ語PunjabiPandžábske
RUSRussianRusoRusseロシア語RyskaRuské
SSpanishEspañolEspagnolスペイン語SpanskaŠpanielské
SENSeniorsPersonas mayoresSéniorsシニアSeniorerSeniori
SKSlovakEslovacoSlovaqueスロバキア語SlovakiskaSlovenské
SMSmoking PermittedSe permite fumarPermis de fumer喫煙可Rökning TillåtenFajčenie povolené
SPSpeakerOradorConférencierスピーカーTalareSpíker
STStep StudyEstudio de pasosSur les ÉtapesステップStegmöteŠtúdium Krokov
SVSwedishSuecoSuédoisスウェーデン語SvenskaŠvédske
TTransgenderTransgéneroTransgenreトランスジェンダーTranspersonerTransgender
TCLocation Temporarily ClosedUbicación temporalmente cerradaEmplacement temporairement fermé一時的休止中Tillfälligt StängtMiesto dočasne zatvorené
THThaiTailandésThaïタイ語ThailändskaThajské
TLTagalogTagaloTagalogタガログ語TagalogTagalské
TRTradition StudyEstudio de tradicionÉtude des Traditions伝統TraditionsmöteTradičné štúdium
UKUkrainianUcranianoUkrainienウクライナ語UkrainskaUkrajinské
WWomenMujerFemmes女性KvinnomöteŽeny
XWheelchair AccessAcceso en silla de ruedasAccès aux fauteuils roulants車いすアクセスHandikappanpassatPrístup pre vozíčkarov
XBWheelchair-Accessible BathroomBaño accesible para sillas de ruedasToilettes accessibles aux fauteuils roulants車いす使用者用トイレHandikappanpassad WCBezbariérová kúpeľňa
XTCross Talk PermittedSe permite opinarConversation croisée permiseクロストーク可能Kommentarer TilltåtnaCross Talk povolený
YYoung PeopleGente jovenJeunesヤングYoung PeopleMladí ľudia

Proposed New Types

The following types are proposed for future use. They are not currently in use in the app.

CodeEnglishEspañolFrançais日本語SvenskaSlovenčina
BV-IBlind / Visually ImpairedCiego / Discapacidad VisualAveugle / Malvoyant視覚障害者Blind / SynskadadNevidiaci / Zrakovo postihnutí
D-HOHDeaf / Hard of HearingSordo / Duro de OídoSourd / Malentendant聴覚障害者Döv / HörselskadadNepočujúci / Nedoslýchaví
LO-ILoners / IsolationistsSolitarios / AislacionistasSolitaires / Isolationnistes孤独 / 孤立主義者Ensamvargar / IsolationisterSamotári / Izolacionisti
POAProof of AttendancePrueba de AsistenciaPreuve de Présence出席証明NärvarobevisDoklad o účasti
QSLQuebec Sign LanguageLengua de Señas de QuebecLangue des Signes Québécoiseケベック手話Quebecskt TeckenspråkQuebecký posunkový jazyk
RSLRussian Sign LanguageLengua de Señas RusaLangue des Signes Russeロシア手話Ryskt TeckenspråkRuský posunkový jazyk

Proposed Changed Types

The following types being considered for a name change.

CodeEnglishEspañolFrançais日本語SvenskaSlovenčina
LGBTQLGBTQIAA+LGBTQIAA+LGBTQIAA+LGBTQIAA+HBTQIAA+LGBTQIAA+

Sharing Your Data

If you choose, you may make your feed discoverable by linking to it (like RSS) in your site's <HEAD>.

<link rel="alternate" type="application/json" title="Meetings Feed" href="https://example.com/etc/meetings-feed">

The script may have any name, and be in any directory, but it should be a fully qualified URL, and the title="Meetings Feed" attribute is required.

Next Steps

Some possible next steps for this format include:

  • metadata so that service entities can indicate their preferred name and URL
  • contact information for following up on issues with feed or meeting info
  • language split out into its own fields
  • indication of which language was used for geocoding

Use the Spec in your code

PHP


Code4Recovery Spec Composer Package

This package contains a class that makes the most up-to-date meeting types available to your application. Updates are released anytime new meeting types are added.

Installation

composer require code4recovery/spec

Get all available languages

Returns an array of all available languages for types can be translated into. The array is keyed by language code and has the expanded language name as the value.

$spec::getLanguages();

Example returned value

[
    'en' => 'English',
    'es' => 'Español',
    'fr' => 'Français',
    'ja' => '日本語',
    'sv' => 'Svenska',
    'sk' => 'Slovenčina',
];

Get all types

Returns an object containing all current meeeting types in every language.

$spec::getAllTypes();

Example returned value (truncated)

{
  "11": {
    "en": "11th Step Meditation",
    "es": "Meditación del Paso 11",
    "fr": "Méditation sur la 11e Étape",
    "ja": "ステップ11 黙想",
    "sv": "11th Stegs Meditation",
    "sk": "Meditácia 11. kroku"
  },
   "12x12": {
    "en": "12 Steps & 12 Traditions",
    "es": "12 Pasos y 12 Tradiciones",
    "fr": "12 Étapes et 12 Traditions",
    "ja": "12のステップと12の伝統",
    "sv": "12 Steg & 12 Traditioner",
    "sk": "12 Krokov & 12 Tradícií"
  },
  ...
};

Get types by language

Returns an array of types translated into a specified language. Pass the desired language key as a string ('en', 'es', 'fr', etc.)

$spec::getTypesByLanguage('en');

Example returned value

[
    11 => "11th Step Meditation"
    "12x12" => "12 Steps & 12 Traditions"
    "A" => "Secular"
    "ABSI" => "As Bill Sees It"
    ...
];

Typescript/Javascript


Installation

npm i @code4recovery/spec

Usage

import { getTypesForLanguage } from '@code4recovery/spec';

const types = getTypesForLanguage('en');

License

Code4Recovery Spec is made available under the MIT License (MIT). Please see License File for more information.

1.0.6

1 month ago

1.0.5

5 months ago

1.0.4

6 months ago

1.0.3

7 months ago

1.0.2

11 months ago

1.0.1

11 months ago

1.0.0

11 months ago