Kehittäjille

Liitä järjestelmäsi Membershipiin, jotta se voi tarkistaa, kuka on organisaation jäsen – ilman että jäsentiedot kopioidaan omaan tietokantaasi.

Yleiskuva

Organisaatiot hallitsevat jäsenistöään Membershipissä. Muut järjestelmät tarvitsevat usein tiedon siitä, onko henkilö tällä hetkellä jäsen: kilpailujärjestelmä ilmoittautumisen hintaa varten, varausjärjestelmä kulkuoikeuksia varten, harjoituspäiväkirja osallistumisoikeuden tarkistamiseen. Connections-rajapinta vastaa täsmälleen tähän kysymykseen – eikä mihinkään muuhun.

Organisaation ylläpitäjä antaa järjestelmällesi luvan kertaalleen, ja sen jälkeen voit:

  • lukea yhdistetyn organisaation julkiset perustiedot (nimi, tunnus, jäsenmäärä)
  • kysyä, kuuluuko tietty sähköpostiosoite organisaation nykyiselle jäsenelle
  • lukea jäsenen jäsenlajin ja sen, onko kuluvan kauden jäsenmaksu hoidettu

Rajapinta on vain luettava ja rajattu yhteen organisaatioon. Se ei koskaan palauta nimiä, osoitteita, puhelinnumeroita tai maksusummia, eikä sillä voi muuttaa mitään Membershipissä. Jos käyttötapauksesi vaatii enemmän kuin jäsenyyden tarkistuksen, pyydä organisaatiota viemään tiedot erikseen.

Miten parittaminen toimii

Parittaminen on suunniteltu niin, ettei pitkäikäinen salaisuus kulje koskaan selaimen, sähköpostin tai keskustelusovelluksen kautta. Ylläpitäjä käsittelee vain lyhytikäistä tunnusta; varsinainen API-avain vaihdetaan palvelimesi ja meidän palvelimen välillä.

  1. Organisaation omistaja tai ylläpitäjä avaa organisaation asetukset Membershipissä ja luo paritustunnuksen. Se on muodossa ABCD-EFGH, voimassa 15 minuuttia ja käytettävissä kertaalleen.
  2. Ylläpitäjä syöttää tunnuksen järjestelmääsi, sinne minne olet sijoittanut integraatioasetukset.
  3. Palvelimesi – ei selainsovelluksesi – kutsuu POST /ext/connections/claim ja kertoo samalla, mikä järjestelmä on kyseessä ja mitä kohdetta ollaan liittämässä.
  4. Membership tarkistaa tunnuksen, luo yhteyden ja palauttaa API-avaimen sekä organisaation perustiedot. Avain näytetään vain tämän yhden kerran.
  5. Tallennat avaimen salattuna ja käytät sitä kaikissa myöhemmissä kutsuissa. Ylläpitäjä näkee järjestelmäsi organisaation yhteyslistassa ja voi poistaa yhteyden milloin tahansa.

Koska ylläpitäjä luo tunnuksen Membershipin sisällä, voimassa olevan tunnuksen hallussapito osoittaa, että yhteyden hyväksyvä henkilö todella ylläpitää kyseistä organisaatiota. Et koskaan kysy käyttäjältä Membershipin tunnuksia, eikä Membershipin tarvitse tietää käyttäjiesi salasanoja.

Osoite ja tunnistautuminen

Kaikki päätepisteet ovat osoitteen https://api.membership.fi/api/v1 alla. Lähetä API-avain bearer-tokenina jokaisessa kutsussa lukuun ottamatta itse parituskutsua:

Authorization: Bearer mepk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

Avaimet alkavat etuliitteellä mepk_, sisältävät 256 bittiä satunnaisuutta ja on rajattu yhteen organisaatioon ja yhteen liitettyyn kohteeseen. Tämä on palvelinten välinen rajapinta: selainkutsut estetään CORS-säännöillä, ja avaimen välittäminen selaimeen antaisi hyökkääjälle lukuoikeuden organisaation jäsenyystietoihin. Pidä avain palvelimella ja salattuna.

Päätepisteet

POST /ext/connections/claim

Vaihtaa paritustunnuksen API-avaimeen. Ei vaadi tunnistautumista – tunnus itse on valtuutus – ja on rajoitettu 20 yritykseen 15 minuutissa IP-osoitetta kohden. Järjestelmäsi kertoo tässä, kuka se on.

KenttäTyyppiKuvaus
codemerkkijonoYlläpitäjän antama paritustunnus. Kirjainkoko ja erotinmerkit normalisoidaan, joten sekä abcd-efgh että ABCDEFGH toimivat.
systemKeymerkkijonoPysyvä pienaakkosinen tunniste järjestelmällesi, 2–50 merkkiä ja muodossa ^[a-z0-9][a-z0-9-]*$. Älä koskaan muuta sitä: se tunnistaa yhteyden uudelleenparituksessa.
systemNamemerkkijonoJärjestelmäsi näyttönimi, joka näytetään organisaation ylläpidolle. Enintään 100 merkkiä.
externalIdmerkkijonoOma pysyvä tunnisteesi liitettävälle kohteelle – seura, joukkue tai osasto omassa järjestelmässäsi. Enintään 100 merkkiä.
externalNamemerkkijonoKohteen näyttönimi, joka näytetään ylläpidolle. Enintään 200 merkkiä.
externalUrlmerkkijono, valinnainenLinkki kohteeseen, jotta ylläpitäjä näkee mihin yhteys muodostettiin. Enintään 500 merkkiä.

Onnistunut paritus palauttaa HTTP 201:

{
  "success": true,
  "data": {
    "apiKey": "mepk_...",
    "organization": {
      "id": "clx...",
      "slug": "esimerkkiseura",
      "name": "Esimerkkiseura ry",
      "shortName": "ES",
      "profileImageUrl": null,
      "membershipPolicy": "APPROVAL_REQUIRED"
    }
  }
}

Kaikki virhetilanteet – väärä, vanhentunut tai jo käytetty tunnus – palauttavat saman HTTP 400 -vastauksen viestillä Invalid or expired pairing code, joten päätepisteellä ei voi selvittää, mitkä tunnukset ovat olemassa. Pyydä ylläpitäjältä uusi tunnus ja yritä uudelleen.

GET /ext/organization

Palauttaa yhdistetyn organisaation ja yhteenvedon yhteydestä. Käytä tätä varmistamaan, että avain toimii yhä, ja näyttämään liitetyn organisaation omissa asetuksissasi.

{
  "success": true,
  "data": {
    "organization": {
      "id": "clx...",
      "slug": "esimerkkiseura",
      "name": "Esimerkkiseura ry",
      "shortName": "ES",
      "profileImageUrl": null,
      "membershipPolicy": "APPROVAL_REQUIRED",
      "memberCount": 120
    },
    "connection": {
      "externalId": "oma-seura-id",
      "externalName": "Esimerkkiseura",
      "connectedAt": "2026-08-08T09:12:00.000Z"
    }
  }
}

POST /ext/members/verify

Tärkein päätepiste. Lähetä yksi sähköpostiosoite ja saat vastauksena jäsenyystilanteen. Tunnistus tapahtuu sähköpostiosoitteella, kirjainkoosta riippumatta. Rajoitus on 120 kutsua minuutissa.

// Pyyntö
{ "email": "henkilo@example.com" }

// Vastaus
{
  "success": true,
  "data": {
    "isMember": true,
    "membershipType": "Aikuinen",
    "memberSince": "2024-01-15T00:00:00.000Z",
    "currentSeason": {
      "id": "clx...",
      "name": "2026",
      "feeStatus": "PAID",
      "feePaid": true
    }
  }
}

Näin vastaus tulkitaan:

  • isMember on tosi, kun henkilöllä on hyväksytty ja voimassa oleva jäsenyys yhdistetyssä organisaatiossa. Tuntematon sähköpostiosoite sekä hylätty, estetty, käsittelyä odottava tai poistettu jäsenyys palauttavat kaikki false – päätepiste ei kerro, mistä on kyse.
  • membershipType on organisaation oma jäsenlajin nimi, esimerkiksi "Aikuinen" tai "Juniori". Organisaatiot määrittelevät ne vapaasti, joten käsittele arvoa nimikkeenä, ei kiinteänä luettelona.
  • currentSeason kuvaa organisaation käynnissä olevaa jäsenyyskautta, tai on null, jos kausi ei ole käynnissä.
  • feeStatus on yksi arvoista UNBILLED, INVOICED, PAID, WAIVED tai NONE, kun jäsenelle ei ole vielä muodostettu maksua. feePaid on apulippu, joka on tosi arvoilla PAID ja WAIVED.

Päätä tietoisesti, mitä näistä toimintosi vaatii. "On jäsen" ja "on jäsen, joka on maksanut kuluvan kauden" ovat eri sääntöjä, ja organisaatiot laskuttavat hyvin eri aikatauluilla – feePaid-ehto tammikuussa voi sulkea ulos jäseniä, joiden laskuja ei ole vielä lähetetty.

DELETE /ext/connection

Mitätöi sen avaimen, jolla kutsu tehdään, ja palauttaa HTTP 204. Kutsu tätä, kun käyttäjä katkaisee integraation omalla puolellasi, jottei käyttökelpoista avainta jää jäljelle – ja poista oma tallennettu kopiosi.

Vastaukset ja virheet

Jokainen JSON-vastaus on kuoritettu. Onnistuneet kutsut palauttavat { "success": true, "data": ... } ja virheet { "success": false, "error": { "code", "message" } }.

TilaMerkitysMitä tehdä
400Virheellinen paritustunnus tai kenttä ei läpäisyt tarkistustaPyydä uusi tunnus tai korjaa pyyntö. Älä yritä uudelleen samoilla tiedoilla.
401Avain puuttuu, on tuntematon, vaihdettu tai mitätöityLopeta kutsut, merkitse yhteys korjausta vaativaksi ja pyydä uutta paritustunnusta.
429Kutsurajoitus ylittyiHidasta ja yritä myöhemmin; välimuistita tulokset turhien kutsujen välttämiseksi.
5xxMembership ei ole käytettävissäYritä uudelleen porrastetusti ja käytä dokumentoitua varasuunnitelmaasi. Älä jätä käyttäjää odottamaan tätä kutsua loputtomiin.

Avaimen elinkaari

Avain lakkaa toimimasta täsmälleen kahdesta syystä, ja molemmat näkyvät HTTP 401 -virheenä:

  • Uudelleenparitus. Uuden tunnuksen lunastaminen samalla systemKey- ja externalId-yhdistelmällä vaihtaa olemassa olevan yhteyden avaimen. Edellinen avain lakkaa toimimasta heti, joten uudelleenparitus ei jätä ylimääräistä voimassa olevaa avainta. Näin käyttäjä korjaa rikkoutuneen yhteyden.
  • Mitätöinti. Organisaation ylläpitäjä voi poistaa käyttöoikeutesi asetuksistaan milloin tahansa, ja voit mitätöidä oman avaimesi kutsulla DELETE /ext/connection.

Käsittele 401 normaalina tilana, ei kaatumisena. Näytä käyttäjälle, että yhteys on muodostettava uudelleen ja miten se tehdään, ja lopeta kutsuminen siihen asti – uudelleenyrityssilmukka mitätöidyllä avaimella vain kuluttaa kutsurajasi.

Toteutuksen tarkistuslista

  • Lunasta tunnukset ja tallenna avaimet vain palvelimella; älä koskaan välitä avainta selaimeen tai sovellukseen.
  • Salaa avaimet levylle ja pidä ne pois lokeista, virheraporteista ja rajapintavastauksista.
  • Rajaa parituksen ja sen purkamisen oikeus liitettävän kohteen ylläpitäjiin.
  • Käytä pysyvää systemKey-tunnistetta ja lähetä externalUrl, jotta ylläpito näkee, mihin lupa annettiin.
  • Lähetä vain sellaisen henkilön sähköpostiosoite, joka todella toimii kyseisen organisaation kohteessa. Tämä rajapinta ei ole hakupalvelu satunnaisille osoitteille.
  • Välimuistita tarkistusten tulokset lyhyeksi ajaksi – minuuteista tunteihin – sen sijaan että kutsuisit joka sivulatauksella.
  • Valitse ja dokumentoi toimintatapa Membershipin ollessa tavoittamattomissa: päästä läpi (käsittele ei-jäsenenä ja veloita normaali hinta) tai estä – mutta älä jätä valintaa sattuman varaan.
  • Kutsu DELETE /ext/connection, kun käyttäjä katkaisee yhteyden, ja poista avain.
  • Käsittele 401 pyytämällä uutta paritustunnusta sen sijaan että yrittäisit uudelleen.

Tietosuoja

Tarkistus lähettää Membershipille yhden sähköpostiosoitteen ja palauttaa jäsenyystilanteen. Molemmat osapuolet käsittelevät henkilötietoja, joten toteuttajana sinun kannattaa:

  • kertoa käyttäjille tietosuojakäytännössäsi, että jäsenyys tarkistetaan Membershipistä, ja miksi
  • tallentaa vain se, mitä toimintosi tarvitsee – totuusarvo ja aikaleima riittävät yleensä
  • pitää yhteys rajattuna siihen kohteeseen, jolle lupa annettiin; älä käytä yhden organisaation avainta muualla järjestelmässäsi

Organisaatiot ovat edelleen jäsentietojensa rekisterinpitäjiä. Niiden ylläpitäjät näkevät kaikki yhdistetyt järjestelmät ja niiden viimeisen käyttöajan, ja voivat poistaa yhteyden ilman että he ottavat sinuun yhteyttä.

Esimerkki

Paritus kerran, sen jälkeen jäsenyyden tarkistus:

# 1. Lunasta ylläpitäjän antama tunnus (palvelimella)
curl -X POST https://api.membership.fi/api/v1/ext/connections/claim \
  -H 'Content-Type: application/json' \
  -d '{
    "code": "ABCD-EFGH",
    "systemKey": "example-system",
    "systemName": "Example System",
    "externalId": "seura-42",
    "externalName": "Esimerkkiseura",
    "externalUrl": "https://example.com/seurat/esimerkkiseura"
  }'

# 2. Tallenna data.apiKey salattuna ja tarkista jäsenyys
curl -X POST https://api.membership.fi/api/v1/ext/members/verify \
  -H "Authorization: Bearer $MEMBERSHIP_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{ "email": "henkilo@example.com" }'

Sama TypeScriptillä, virhetilanteet huomioiden:

const BASE_URL = 'https://api.membership.fi/api/v1';

export async function verifyMember(apiKey: string, email: string) {
  const response = await fetch(`${BASE_URL}/ext/members/verify`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${apiKey}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ email }),
  });

  if (response.status === 401) {
    // Mitätöity tai vaihdettu: pyydä käyttäjää parittamaan uudelleen
    throw new ConnectionNeedsReconnect();
  }
  if (!response.ok) {
    // Ei tavoitettavissa tai kutsuraja ylittyi: käytä varasuunnitelmaa
    throw new MembershipUnavailable(response.status);
  }

  const { data } = await response.json();
  return data; // { isMember, membershipType, memberSince, currentSeason }
}

Palaute ja toiveet

Onko sinulla palautetta rajapinnasta tai tarvitsetko ominaisuutta, jota se ei vielä kata? Lähetä se palautelomakkeella – se vaatii Membership-tilin, ja integroijien toiveet luetaan siinä missä muutkin. Palaute näkyy vain tiimille; ominaisuustoiveet julkaistaan käsittelyn jälkeen, jotta muut voivat äänestää niitä.