UltimateBookings

API-handleiding

Voor een ontwikkelaar of technisch helper van een klant. Met de API laat je je website, CRM of boekhouder gegevens uit Ultimate Bookings lezen. Vragen? info@ultimate-bookings.com.

Wat is het

Een API waarmee je alleen kunt lezen. Schrijven, aanpassen of verwijderen kan niet. Elke sleutel hoort bij een organisatie en ziet alleen de gegevens van die organisatie. Waar de grens ligt is geen afspraak in onze code die iemand kan vergeten: elke vraag loopt via de database, die de sleutel toetst en alleen rijen van die organisatie teruggeeft.

Er zijn twee soorten sleutels:

Een sleutel maken

  1. Ga in Ultimate Bookings naar Instellingen, API-sleutels. Alleen de eigenaar van de organisatie kan hier sleutels maken, pauzeren en verwijderen.
  2. Geef de sleutel een naam (tot 80 tekens), bijvoorbeeld Website of CRM.
  3. Kies het soort: website-sleutel of volledige sleutel.
  4. Bij een volledige sleutel vink je aan wat hij mag lezen: Shows (altijd aan), Agenda, Contacten, Artiesten en Geld. Geld staat standaard uit: pas als je dat aanvinkt ziet de sleutel gages en facturen.
  5. Kies Sleutel maken. De sleutel staat daarna een keer in beeld. Kopieer hem meteen. Wij bewaren alleen een afgeleide waarde (een hash), dus we kunnen hem je niet opnieuw laten zien. Kwijt? Verwijder hem en maak een nieuwe.

Een sleutel kun je pauzeren: hij werkt dan meteen niet meer en je kunt hem later weer aanzetten. Verwijderen is definitief. In de lijst zie je per sleutel wanneer hij voor het laatst is gebruikt en hoe vaak.

Een show komt pas in de website-sleutel als je hem zelf hebt aangevinkt bij Op je website tonen in het boekingsformulier. Standaard staat dat uit, zodat een privefeest of een optie nooit vanzelf openbaar wordt.

Inloggen met je sleutel

Stuur de sleutel mee in de kop van elk verzoek:

Authorization (HTTP-kop)
Authorization: Bearer ub_live_JOUW_SLEUTEL

Een website-sleutel mag ook in het adres, als ?sleutel=ub_web_.... Dat is bedoeld voor een browser: die bron is voor elke website bereikbaar (CORS staat open), zodat je vanuit je eigen pagina rechtstreeks kunt ophalen. Dit werkt alleen voor openbare-shows. Een volledige sleutel in het adres wordt genegeerd; die moet altijd in de kop en hoort alleen op een server.

De zes bronnen

Alle adressen zijn GET en beginnen met https://ultimate-bookings.com/api/v1. Een volledige sleutel heeft het genoemde recht nodig; Shows heeft elke volledige sleutel. Velden zonder waarde ontbreken in het antwoord in plaats van null te zijn.

De bronnen van de API met het recht dat ze vragen en hun parameters
AdresRechtParametersWat je krijgt
/showsShows (altijd aan)van, tot, limiet, vanafAlle shows, ook opties en geannuleerde
/agendaAgendavan, tot, limiet, vanafBlokkades, reizen en notities
/contactenContactenlimiet, vanafJe adresboek, zonder notities
/artiestenArtiestengeen (alle artiesten in een keer)Je artiesten, zonder factuurgegevens
/facturenGeldvan, tot, limiet, vanafVerstuurde facturen (geen concepten)
/openbare-showsWebsite-sleutellimiet (1 tot en met 200, standaard 100), artiest (id van een artiest, optioneel)Aankomende openbare shows, voor je website

Parameters

Een parameter die een bron niet gebruikt wordt wel gecontroleerd op geldigheid, maar doet verder niets.

GET /api/v1/shows

Recht: Shows (altijd aan). Parameters: van, tot, limiet, vanaf.

Alle shows van je organisatie, gesorteerd op begintijd, met elke status (van aanvraag tot betaald, en geannuleerd). Filter zelf op het veld status als je alleen bevestigde shows wilt. van en tot gaan over de begintijd van de show.

Velden

id
titel
status
inquiry, quote, option, confirmed, performed, invoiced, paid, cancelled of no_show
soort
start
einde
hele_dag
zaal
stad
land
landcode
artiest_id
artiest
naam van de artiest
openbaar
staat de show op Op je website tonen?

Alleen met het recht Geld

gage
bedrag in de munt van het veld munt, met twee decimalen
munt

GET /api/v1/agenda

Recht: Agenda. Parameters: van, tot, limiet, vanaf.

De agenda-items die geen show zijn: blokkades, reizen en notities, gesorteerd op begintijd. van en tot gaan over de begintijd.

Velden

id
soort
blokkade, reis of notitie
reis_soort
titel
start
einde
hele_dag
plaats
artiest_id
show_id
de show waar dit bij hoort, als die er is

GET /api/v1/contacten

Recht: Contacten. Parameters: limiet, vanaf.

Je adresboek, gesorteerd op naam. Geanonimiseerde contacten komen niet mee. van en tot doen hier niets.

Velden

id
naam
bedrijf
soort
email
email_2
telefoon
straat
postcode
stad
land
landcode
btw_nummer

Notities, reisprofiel, allergieen en afmeldsleutel zitten er bewust niet in.

GET /api/v1/artiesten

Recht: Artiesten. Parameters: geen (alle artiesten in een keer).

Al je artiesten, gesorteerd op naam, in een keer. Hier is geen paginering: limiet, vanaf, van en tot doen niets.

Velden

id
naam
soort
kleur
actief
thuisstad
thuisland

IBAN, KvK-nummer en btw-nummer zitten er bewust niet in.

GET /api/v1/facturen

Recht: Geld. Parameters: van, tot, limiet, vanaf.

Je facturen, gesorteerd op factuurdatum, zonder concepten. van en tot gaan hier over de factuurdatum (beide dagen tellen mee). Bedragen zijn in hele euro's met twee decimalen, niet in centen.

Velden

id
nummer
status
soort
factuurdatum
vervaldatum
betaald_op
excl_btw
btw
totaal
munt
btw_verlegd
artiest_id
show_id
klant
bedrijfsnaam van het contact
contact
naam van het contact

GET /api/v1/openbare-shows

Recht: Website-sleutel. Parameters: limiet (1 tot en met 200, standaard 100), artiest (id van een artiest, optioneel).

Alleen shows waarbij je het vinkje "Op je website tonen" hebt aangezet, die bevestigd zijn (of al gespeeld, gefactureerd of betaald) en die vandaag of later plaatsvinden, op datum. Dit is de enige bron voor een website-sleutel, en de enige die een website-sleutel mag lezen. Heeft elke artiest een eigen site, geef dan artiest mee met de artiest_id uit het antwoord: dan krijg je alleen de shows van die artiest. van, tot en vanaf doen hier niets.

Velden

datum
JJJJ-MM-DD, in Amsterdamse tijd
start
ontbreekt bij een show die de hele dag duurt
zaal
stad
land
landcode
artiest
artiest_id
voor het filter artiest

Antwoord, fouten en limieten

Een gelukt verzoek geeft een data-lijst en een meta-blok terug. aantal is het aantal rijen in dit antwoord, limiet en vanaf zijn de waarden die we gebruikt hebben.

Antwoord van GET /shows (JSON)
{
  "data": [
    {
      "id": "0b6f1c1e-...",
      "titel": "Zaterdagavond Paradiso",
      "status": "confirmed",
      "soort": "show",
      "start": "2026-10-10T20:00:00+00:00",
      "hele_dag": false,
      "zaal": "Paradiso",
      "stad": "Amsterdam",
      "land": "NL",
      "artiest_id": "5d0c9a52-...",
      "artiest": "Afro Bros",
      "openbaar": true
    }
  ],
  "meta": { "aantal": 1, "limiet": 50, "vanaf": 0 }
}

Bij een fout krijg je een error-blok met een vaste code (waar je op kunt controleren) en een message (leesbaar, kan veranderen):

Voorbeeld van een fout (JSON)
{
  "error": {
    "code": "geen_recht",
    "message": "Deze sleutel mag dit onderdeel niet lezen. Zet het vinkje aan bij Instellingen, API-sleutels."
  }
}
Foutcodes met HTTP-status en betekenis
StatusCodeBetekenis
400ongeldige_datumvan of tot is geen datum als 2026-10-01 (jaar 1900 tot en met 2100), of van ligt na tot.
400ongeldige_limietlimiet is geen heel getal van 1 tot en met 500 (bij openbare-shows 200).
400ongeldige_artiestartiest is geen id van een artiest.
400ongeldige_vanafvanaf is geen heel getal van 0 of meer.
401sleutel_ontbreektEr is geen sleutel meegestuurd.
401sleutel_ongeldigDe sleutel bestaat niet, is gepauzeerd of is verwijderd.
402geen_api_in_pakketEen volledige sleutel werkt alleen met de API in het pakket (zie hierboven).
403geen_rechtDe sleutel heeft dit recht niet, of is van het verkeerde soort voor deze bron.
403geen_pakketDe organisatie heeft geen lopend pakket of is opgeheven.
404onbekende_bronDit adres na /api/v1/ bestaat niet.
429te_veel_verzoekenJe zit boven de limiet. De kop Retry-After zegt hoeveel seconden je moet wachten.
500storingEr ging iets mis aan onze kant. Probeer het zo opnieuw.

Limieten

Voorbeelden

Shows van oktober ophalen met curl

Volledige sleutel, 50 shows per keer, vanaf de eerste.

curl (shell)
curl -H "Authorization: Bearer ub_live_JOUW_SLEUTEL" \
  "https://ultimate-bookings.com/api/v1/shows?van=2026-10-01&tot=2026-10-31&limiet=50&vanaf=0"

Aankomende shows op je website

Met een website-sleutel. Dit vult een lijst op je pagina en zet de gegevens als tekst neer, niet als HTML, zodat vreemde tekens in een zaalnaam niets kapot kunnen maken. Wil je het eerst proberen:

curl met een website-sleutel (shell)
curl "https://ultimate-bookings.com/api/v1/openbare-shows?limiet=10&sleutel=ub_web_JOUW_SLEUTEL"
Lijst op een website (HTML en JavaScript)
<ul id="ub-shows"></ul>
<script>
  var SLEUTEL = "ub_web_JOUW_SLEUTEL";
  var ADRES = "https://ultimate-bookings.com/api/v1/openbare-shows?limiet=10&sleutel=" + SLEUTEL;
  var lijst = document.getElementById("ub-shows");

  fetch(ADRES)
    .then(function (antwoord) {
      if (!antwoord.ok) throw new Error("HTTP " + antwoord.status);
      return antwoord.json();
    })
    .then(function (uitkomst) {
      if (uitkomst.data.length === 0) {
        lijst.textContent = "Nog geen shows aangekondigd.";
        return;
      }
      uitkomst.data.forEach(function (show) {
        // datum is een kale dag (JJJJ-MM-DD); in UTC lezen, dan schuift hij nergens een dag op.
        var datum = new Date(show.datum + "T12:00:00Z").toLocaleDateString("nl-NL", {
          day: "numeric", month: "long", year: "numeric", timeZone: "UTC"
        });
        var plaats = [show.zaal, show.stad].filter(Boolean).join(", ");
        var regel = document.createElement("li");
        regel.textContent = datum + ": " + plaats + (show.artiest ? " (" + show.artiest + ")" : "");
        lijst.appendChild(regel);
      });
    })
    .catch(function () {
      lijst.textContent = "De showlijst kon niet worden geladen.";
    });
</script>

Alles ophalen met paginering

Vraag telkens een pagina en verhoog vanaf met limiet, tot een antwoord minder rijen heeft dan de limiet. De volgorde is vast (op begintijd en dan id), dus een pagina komt niet dubbel of overgeslagen terug zolang er niets verandert tijdens het ophalen. Dit werkt voor shows, agenda, contacten en facturen.

Paginering met wachten bij 429 (JavaScript)
// Node 18 of nieuwer. Haalt alle shows op, 500 per keer.
const SLEUTEL = process.env.UB_SLEUTEL; // ub_live_...
const LIMIET = 500;

async function haalAlleShows() {
  const alles = [];
  let vanaf = 0;

  while (true) {
    const adres = "https://ultimate-bookings.com/api/v1/shows?limiet=" + LIMIET + "&vanaf=" + vanaf;
    const antwoord = await fetch(adres, { headers: { Authorization: "Bearer " + SLEUTEL } });

    if (antwoord.status === 429) {
      const wacht = Number(antwoord.headers.get("Retry-After")) || 60;
      await new Promise((klaar) => setTimeout(klaar, wacht * 1000));
      continue; // dezelfde pagina nog een keer
    }
    if (!antwoord.ok) {
      const { error } = await antwoord.json();
      throw new Error(error.code + ": " + error.message);
    }

    const { data, meta } = await antwoord.json();
    alles.push(...data);
    if (meta.aantal < LIMIET) return alles; // laatste pagina
    vanaf += LIMIET;
  }
}

Wat het (nog) niet kan