Bouw met onze beschikbaarheidsgegevens

Plek in de Veste API

Gebruik de opgeslagen beschikbaarheid van FC Twente thuiswedstrijden in je eigen website, overzicht of analyse.

Openbaar · geen API-keyAlleen lezen · JSONPer wedstrijd circa elke 6 uur

De API combineert vrije verkoop en extra plaatsen via de kaartenmarkt. Je leest de opgeslagen stand: een verzoek haalt geen nieuwe gegevens op bij de ticketshop. Kaarten kopen gaat via FC Twente.

Basis-URL

HTTPS
https://plekindeveste.net/local-api

Begin met /season-availability voor aantallen van alle wedstrijden in één verzoek. Gebruik /events om wedstrijd-ID’s te vinden en /history voor het verloop door de tijd.

Gebruik vanuit je eigen website

Vraag de API aan vanuit je eigen backend en bewaar het antwoord daar tijdelijk. Rechtstreekse JavaScript-verzoeken vanuit een ander domein worden momenteel niet ondersteund: deze API stuurt geen CORS-toestemming mee. cURL, Python en server-side JavaScript hebben die browserbeperking niet.

Een eerste verzoek

Codevoorbeelden

Deze voorbeelden lezen alleen opgeslagen gegevens. De veldnamen zijn hoofdlettergevoelig.

cURL
curl --fail --max-time 20 -H "Accept: application/json" \
  "https://plekindeveste.net/local-api/season-availability"
JavaScript · Node.js 18+
JavaScript
// Node.js 18+ (server-side)
const response = await fetch(
  'https://plekindeveste.net/local-api/season-availability',
  { headers: { Accept: 'application/json' }, signal: AbortSignal.timeout(20000) }
);
if (!response.ok) throw new Error('HTTP ' + response.status);
const matches = await response.json();
for (const match of matches.filter(m => m.isCurrent)) {
  const stand = match.availability;
  console.log(match.Name, stand?.availableCount ?? 'Nog geen meting',
    stand?.capturedAt, stand?.complete);
}
Python 3
Python
# Python 3, zonder extra pakketten
import json
from urllib.request import Request, urlopen

request = Request(
    'https://plekindeveste.net/local-api/season-availability',
    headers={'Accept': 'application/json'}
)
with urlopen(request, timeout=20) as response:
    matches = json.load(response)
for match in matches:
    if match['isCurrent']:
        stand = match['availability']
        print(match['Name'], stand if stand is not None else 'Nog geen meting')

Importeer openapi.json in bijvoorbeeld een API-client. De voorbeelden hieronder zijn illustratief; aantallen en tijdstippen zijn geen live stand.

GET/season-history

Verloop van alle wedstrijden

Alle opgeslagen wedstrijden met hun volledige metingen in history. Filter op de wedstrijddatum voor het gewenste seizoen. Bevat alleen tellingen, geen stoelen.

Verzoek
curl --fail --max-time 20 "https://plekindeveste.net/local-api/season-history"
Voorbeeldantwoord
JSON
[
  {
    "EventId": 371,
    "Name": "FC Twente - PSV",
    "EventStartDateTime": "2026-09-20T12:30:00",
    "isCurrent": true,
    "firstSeen": "2026-09-15T01:00:00.000Z",
    "lastSeen": "2026-09-16T10:00:00.000Z",
    "removedAt": null,
    "lastCapturedAt": "2026-09-16T10:01:00.000Z",
    "measurementCount": 12,
    "history": [
      {
        "id": 123,
        "started_at": "2026-09-16T10:00:00.000Z",
        "captured_at": "2026-09-16T10:01:00.000Z",
        "complete": 1,
        "marketplace_status": "loaded",
        "interval_minutes": 360,
        "total_count": 28292,
        "available_count": 120,
        "regular_count": 80,
        "marketplace_count": 45,
        "marketplace_extra_count": 40
      }
    ]
  }
]
GET/events

Wedstrijden

Alle opgeslagen wedstrijden, inclusief archief. Filter zelf op isCurrent voor het huidige aanbod. Activiteiten en vrouwenwedstrijden zijn uitgesloten. Er is geen paginering.

Veld / parameterBetekenis
EventIdGebruik dit nummer als eventId bij de andere endpoints.
isCurrenttrue = aanwezig in de laatst opgehaalde wedstrijdlijst. Dit zegt niet of de aftrap al is geweest.
lastCapturedAt / measurementCountLaatste meting (kan onvolledig zijn) en aantal opgeslagen metingen. null betekent nog geen meting.
firstSeen / lastSeen / removedAtEerste en laatste keer gezien in het aanbod; tijdstip van archivering of null.
HasTicketsAvailable / CurrentlyOnSaleForUserOptionele verkoopvlaggen uit de bron. Gebruik availability of totals voor de getelde beschikbare plaatsen.
Verzoek
curl --fail --max-time 20 "https://plekindeveste.net/local-api/events"
Voorbeeldantwoord
JSON
[
  {
    "EventId": 371,
    "Name": "FC Twente - PSV",
    "EventStartDateTime": "2026-09-20T12:30:00",
    "isCurrent": true,
    "firstSeen": "2026-09-15T01:00:00.000Z",
    "lastSeen": "2026-09-16T10:00:00.000Z",
    "removedAt": null,
    "lastCapturedAt": "2026-09-16T10:01:00.000Z",
    "measurementCount": 12
  }
]
GET/season-availability

Beschikbaarheid van alle wedstrijden

De lichtste keuze voor een overzicht met actuele aantallen. Eén antwoord met de wedstrijden en hun laatst bewaarde stand. Bevat ook archiefwedstrijden. Een seizoen loopt van juli tot en met juni; groepeer zelf op de Nederlandse aftrapdatum. Er is geen season-parameter.

Veld / parameterBetekenis
availabilitynull als er nog geen meting is. Anders een object met capturedAt, complete en aantallen.
totalCountGetelde capaciteit bij deze stand; niet automatisch de officiële stadioncapaciteit. Dit endpoint bevat geen capacityKnown-vlag. Gebruik voor een betrouwbaar percentage het dashboard en controleer data.capacityKnown.
availableCountTotaal unieke beschikbare standaardplaatsen.
regularCountBeschikbaar via vrije verkoop.
marketplaceExtraCountExtra beschikbare plaatsen via de kaartenmarkt, zonder overlap met vrije verkoop.
completetrue als de benodigde bronnen geladen zijn. Een expliciet gesloten kaartenmarkt hoeft niet te worden opgehaald. Bij voorkeur wordt een volledige meting teruggegeven, ook als een recentere poging onvolledig is.
Verzoek
curl --fail --max-time 20 "https://plekindeveste.net/local-api/season-availability"
Voorbeeldantwoord
JSON
[
  {
    "EventId": 371,
    "Name": "FC Twente - PSV",
    "EventStartDateTime": "2026-09-20T12:30:00",
    "isCurrent": true,
    "firstSeen": "2026-09-15T01:00:00.000Z",
    "lastSeen": "2026-09-16T10:00:00.000Z",
    "removedAt": null,
    "lastCapturedAt": "2026-09-16T10:01:00.000Z",
    "measurementCount": 12,
    "availability": {
      "capturedAt": "2026-09-16T10:01:00.000Z",
      "complete": true,
      "marketplaceStatus": "loaded",
      "marketplaceInferredZero": false,
      "totalCount": 28292,
      "availableCount": 120,
      "regularCount": 80,
      "marketplaceExtraCount": 40
    }
  }
]
GET/events/{eventId}/dashboard

Vakken en stoelen

Uitgebreid antwoord met stadionindeling, vakken, stoelen en tellingen. Gebruik dit alleen als je die details nodig hebt. Geeft bij voorkeur de laatste volledige meting; zonder volledige meting de laatste onvolledige. HTTP 404 als er geen opgeslagen meting is.

Veld / parameterBetekenis
eventId · verplichtEventId uit GET /events. Het voorbeeld 371 is geen vaste standaard.
snapshotId · optioneelID van een eerdere meting uit de history-route van deze wedstrijd. Zonder deze parameter krijg je de laatste beschikbare stand.
Veld / parameterBetekenis
snapshot / latestAttemptsnapshot beschrijft de getoonde stand. latestAttempt beschrijft de nieuwste opgeslagen poging; die kan nieuwer en onvolledig zijn.
data.totalsGecombineerde tellingen: availableCount = regularAvailableCount + marketplaceExtraCount. marketplaceAvailableCount kan overlap bevatten.
data.sectionsVakgegevens. VenueBuildingBlockId is het vak-ID; Name is de zichtbare vaknaam. Gebruik de naam niet als ID.
data.sectionAvailabilityObject met vak-ID’s als sleutels. Elk vak bevat tellingen, section en seatMap.Rows[].Columns[] met stoelen.
PlacementTypeId / IsAvailableForSaleTel uitsluitend stoelen met PlacementTypeId === 1. IsAvailableForSale geeft de gecombineerde beschikbaarheid aan. Andere types en X/Y-indelingsmarkeringen tellen niet mee.
RegularAvailable / MarketplaceAvailablePer stoel de beschikbaarheid per bron. Tel een stoel die in beide voorkomt maar één keer.
capacityKnown / availabilityRateBij capacityKnown === false is de capaciteit niet volledig bekend. Gebruik dan geen percentage vrij. availabilityRate is een percentage van 0–100.
AvailableSeats / HasMarketplaceTicketsAvailableBronvelden voor het ophalen, geen gecombineerde telling. AvailableSeats kan op de kaartenmarkt 0 zijn terwijl er wel aanbod is.
Verzoek
curl --fail --max-time 20 "https://plekindeveste.net/local-api/events/371/dashboard"
Voorbeeldantwoord · verkort
JSON
{
  "snapshot": {
    "id": 123,
    "startedAt": "2026-09-16T10:00:00.000Z",
    "capturedAt": "2026-09-16T10:01:00.000Z",
    "complete": true
  },
  "latestAttempt": {
    "capturedAt": "2026-09-16T10:01:00.000Z",
    "complete": true
  },
  "data": {
    "eventMeta": {
      "EventId": 371,
      "Name": "FC Twente - PSV",
      "EventStartDateTime": "2026-09-20T12:30:00"
    },
    "totals": {
      "availableCount": 120,
      "regularAvailableCount": 80,
      "marketplaceAvailableCount": 45,
      "marketplaceExtraCount": 40
    },
    "marketplace": {
      "status": "loaded",
      "channelId": 7,
      "message": "Beide bronnen geladen"
    }
  }
}
GET/events/{eventId}/history-sections

Vak-ID’s voor historie

De beschikbare vakken voor historische selectie, met naam en tribune. Gebruik id als sectionId of in sectionIds. Geeft [] als er geen vakgegevens zijn.

Veld / parameterBetekenis
eventId · verplichtEventId uit GET /events. Het voorbeeld 371 is geen vaste standaard.
Verzoek
curl --fail --max-time 20 "https://plekindeveste.net/local-api/events/371/history-sections"
Voorbeeldantwoord
JSON
[
  {
    "id": 391427,
    "name": "Vak 134",
    "tribune": "Lange zijde"
  }
]
GET/events/{eventId}/history

Historische metingen

Chronologisch gesorteerde metingen, oudste eerst. Zonder parameters: het hele stadion, alleen volledige metingen. Geeft [] bij ontbrekende historie. Geen datumfilter of paginering; filter en bewaar het resultaat zelf.

Veld / parameterBetekenis
eventId · verplichtEventId uit GET /events. Het voorbeeld 371 is geen vaste standaard.
includeIncomplete · optioneelGebruik 1 om ook onvolledige metingen te ontvangen. Standaard uitgesloten, behalve bij sectionIds.
sectionId · optioneelEén vak-ID. Bevat ook section_id, snapshot_id, name en aanvullende tellingen. Niet combineren met sectionIds.
sectionIds · optioneelMaximaal 200 komma-gescheiden vak-ID’s. Dubbele ID’s tellen eenmaal. Geeft opgetelde tellingen per meting. Bevat altijd ook onvolledige metingen, ongeacht includeIncomplete. complete=1 alleen als alle geselecteerde vakken aanwezig zijn en de snapshot volledig is. Niet combineren met sectionId.
Veld / parameterBetekenis
captured_at / started_atEind- en begintijd van deze meting, in UTC.
complete1 = volledig, 0 = onvolledig. Anders dan de boolean complete bij dashboard en seizoenoverzicht.
available_countTotaal beschikbaar = regular_count + marketplace_extra_count.
marketplace_countAlle beschikbare kaartenmarktplaatsen, inclusief mogelijke overlap. Niet optellen bij regular_count.
total_countGetelde capaciteit, niet automatisch de volledige officiële stadioncapaciteit.
interval_minutesGeplande tijd tussen metingen; voor nieuwe hostingmetingen 360. Oudere metingen kunnen een andere waarde hebben.
sectionIds met ontbrekende vakkenTellingen kunnen gedeeltelijk zijn, of 0 als niets gevonden is. Gebruik alleen complete === 1 voor een volledige vergelijking; een onvolledige 0 betekent niet uitverkocht.
Verzoek
curl --fail --max-time 20 "https://plekindeveste.net/local-api/events/371/history"
Voorbeelden van vakselecties · gebruik ID’s uit history-sections
/events/371/history?includeIncomplete=1
/events/371/history?sectionId=391427&includeIncomplete=1
/events/371/history?sectionIds=391427,390337
Voorbeeldantwoord
JSON
[
  {
    "id": 123,
    "started_at": "2026-09-16T10:00:00.000Z",
    "captured_at": "2026-09-16T10:01:00.000Z",
    "complete": 1,
    "marketplace_status": "loaded",
    "interval_minutes": 360,
    "total_count": 28292,
    "available_count": 120,
    "regular_count": 80,
    "marketplace_count": 45,
    "marketplace_extra_count": 40
  }
]
GET/status

Status van het ophalen

Informatie over de automatische ophaalplanning. Een GET start nooit een nieuwe ophaalronde. De publieke API kan alleen opgeslagen gegevens lezen.

Veld / parameterBetekenis
intervalMinutes360: geplande tussenpoos per wedstrijd op de hosting.
nextRunAtVolgende uurbeurt voor de planning; niet noodzakelijk de volgende meting van jouw gekozen wedstrijd.
running / cooldownUntilOf er een ronde actief is en of er een API-pauze geldt. Een poging kan mislukken of later afronden.
lastRunLaatste ronde met status, startedAt, finishedAt en result, of null. Extra diagnosevelden kunnen aanwezig zijn.
manualSyncAllowedOp de openbare website altijd false. POST /sync is niet beschikbaar voor afnemers en geeft 403.
Verzoek
curl --fail --max-time 20 "https://plekindeveste.net/local-api/status"
Voorbeeldantwoord
JSON
{
  "running": false,
  "nextRunAt": "2026-09-16T11:00:00.000Z",
  "intervalMinutes": 360,
  "snapshotCount": 120,
  "cooldownUntil": null,
  "manualSyncAllowed": false,
  "progress": null,
  "lastRun": null
}

Tellingen en tijdstippen

Gegevens begrijpen

Eén stoel telt één keer

vrije verkoop + extra kaartenmarkt = totaal beschikbaar. Het volledige kaartenmarktaantal kan stoelen bevatten die ook vrije verkoop worden aangeboden. Tel daarom alleen het extra kaartenmarktaantal op bij vrije verkoop. De tellingen omvatten standaardplaatsen, geen X/Y-markeringen of andere plaatssoorten.

Een gesloten kaartenmarkt is geen gemeten nul

ShowMarketplaceForEvent in de wedstrijdlijst geeft de huidige openingsstatus aan. Voor historische metingen gebruik je marketplace_status; in het seizoenoverzicht heet dit availability.marketplaceStatus. closed betekent dat de kaartenmarkt expliciet niet beschikbaar was en niet is opgehaald. loaded betekent dat de kaartenmarkt geladen is; nul is dan een geldige waarneming. unavailable is een ophaalfout. unknown betekent dat de openingsstatus niet werd vastgelegd.

De numerieke kaartenmarkttellingen blijven 0 bij een gesloten markt, zodat de totaaltelling blijft kloppen. Zonder eerder aangetoonde opening toon je ‘Nog niet geopend’ in plaats van 0 en teken je geen kaartenmarktmeetpunt. Voor een nul na een eerdere opening geldt de afgeleide markering hieronder. Leid uit oudere nulmetingen met unknown geen openingsdatum af. Gebruik de huidige wedstrijdvlag niet om oude metingen achteraf als gesloten te bestempelen.

Volledigheid en actualiteit

Controleer altijd complete en het tijdstip van de stand. Een ontbrekende meting (null of een lege lijst) is iets anders dan nul beschikbare plaatsen. Het dashboard en seizoenoverzicht geven bij voorkeur de laatste volledige stand. Een nieuwere onvolledige poging kan daardoor een later tijdstip hebben dan de getoonde stand.

Iedere wedstrijd is ongeveer eens per zes uur aan de beurt. Wedstrijden worden over de uren verdeeld. Bij zes wedstrijden wordt elk uur één wedstrijd opgehaald. Fouten, pauzes of wijzigingen in het wedstrijdprogramma kunnen de tussenpoos verlengen of verschuiven.

Tijdzones

Metingen gebruiken ISO 8601 met Z (UTC). EventStartDateTime kan geen tijdzone bevatten: behandel die waarde als UTC. Toon tijden met Europe/Amsterdam om zomer- en wintertijd mee te nemen. Zo is 2026-09-20T12:30:00 in Nederland 14:30.

Een nul na een eerdere opening

Een volledige meting met marketplace_status === 'closed' en nul kaartenmarktaanbod na een eerdere waargenomen opening wordt op de website als afgeleide nul weergegeven. Het seizoenendpoint geeft hiervoor availability.marketplaceInferredZero: true terug. Dit is geen gemeten nul: gebruik deze waarde niet als bewijs van verkochte kaarten of een gemeten daling.

De history-endpoints geven de opgeslagen bronstatus terug en bevatten geen marketplace_inferred_zero-veld. De website berekent die markering zelf uit de chronologische historie, vóór filtering op periode. Een eerdere opening is aangetoond door loaded of positief kaartenmarktaanbod. Een mislukte of onvolledige meting levert nooit een afgeleide nul op.

Samen zitten uit stoelgegevens

Er is geen apart endpoint voor combinaties. Gebruik de dashboardstoelen voor groepen van 2, 3 of 4 beschikbare standaardplaatsen in dezelfde rij, met opeenvolgende Column-waarden. Stoelnummers bewijzen geen fysieke aansluiting. Alle stoelen van een combinatie moeten via dezelfde bron beschikbaar zijn: allemaal RegularAvailable of, bij een geladen kaartenmarkt, allemaal MarketplaceAvailable. Een combinatie met aanbod uit verschillende bronnen is niet gezamenlijk boekbaar. Sla vakken met onbekende capaciteit over en controleer eventuele MarketplaceBundled-voorwaarden in de ticketshop.

Wedstrijdmetadata en opgeslagen details

HomeImageUrl, AwayImageUrl en EventTypeLogoUrl zijn optionele bronvelden; oudere wedstrijden kunnen deze missen. De website kan ontbrekende logo's voor de weergave aanvullen. De API wijzigt daarvoor de opgeslagen metadata niet. data.eventMeta in het dashboard bevat de metadata bij die meting; /events bevat de laatst opgeslagen wedstrijdlijst.

Compatibiliteitsvelden zoals data.events, salesChannels, salesPeriods, ticketTypes en categoryPrices zijn in nieuwe opgeslagen dashboards lege lijsten; filters is een leeg object. Gebruik de getelde beschikbaarheid en stoelvelden. De gewijzigde interne databaseopslag verandert de publieke JSON-structuur niet.

Historie is geen verkoopteller

Een afname kan verkoop, een reservering of ingetrokken aanbod zijn. Vergelijk alleen volledige metingen met dezelfde getelde capaciteit en zonder te grote meetonderbreking. Voor veranderingen in kaartenmarkt en totaal moeten beide eindpunten bruikbare kaartenmarktwaarnemingen bevatten: loaded, of positief aanbod bij een oudere onbekende status. Ontbrekende brongegevens en afgeleide nullen mogen geen gemeten stijging of daling opleveren. Verandering in de vrije verkoop kan bij vergelijkbare volledige metingen wel afzonderlijk worden berekend. Uit een verschil over zes uur kun je niet afleiden in welk afzonderlijk uur kaarten zijn verkocht.

Praktische afspraken

Fouten en zorgvuldig gebruik

Veld / parameterBetekenis
200Verzoek geslaagd. Het antwoord kan een lege lijst bevatten.
400Ongeldige vakselectie, bijvoorbeeld sectionId en sectionIds samen.
403Publieke bezoekers kunnen geen ophaalronde starten via POST /sync.
404Onbekende route, niet-ondersteunde methode of geen opgeslagen dashboardmeting.
500 / 503Gegevens of hosting tijdelijk niet beschikbaar.
502 / 504De hosting kan een gatewayfout geven, eventueel als HTML in plaats van JSON.
Voorbeeld van een JSON-fout
{
  "error": "Opgeslagen gegevens zijn tijdelijk niet beschikbaar."
}
  • Bewaar antwoorden lokaal en stem verversen af op de zesuursplanning. Gebruik het lichte seizoenendpoint als je alleen totalen nodig hebt.
  • Voer verzoeken achter elkaar uit. Haal geen volledige stoeloverzichten op voor een lijst met alleen aantallen.
  • Controleer eerst de HTTP-status voordat je JSON verwerkt. Gebruik een timeout en hooguit enkele herpogingen met oplopende wachttijd bij tijdelijke fouten. Respecteer een eventuele Retry-After.
  • Er is geen vaste publieke verzoeklimiet of beschikbaarheidsgarantie vastgelegd. De hosting kan verzoeken begrenzen.
  • Toon bij hergebruik de datum van de stand. Een link naar Plek in de Veste als bron wordt gewaardeerd.

Deze website is een onafhankelijke tool. De API biedt geen reserverings- of aankoopfunctie en garandeert niet dat een getoonde stoel nog te koop is.

OpenAPI 3.1 downloaden