Skip to content

Reference

Catalogue

The agenda: public data, the same for every token. Needs read.

GET/events

List events

Access
Token with read
operationId
listEvents

Every approved event in the agenda for NL and BE, soonest first. Defaults to today onwards. Needs a token with the read scope. A read token is free: create one in the organiser portal under API. Browsing the site itself needs nothing.

Parameters

NameInTypeDefaultDescription
city optionalquerystring-Only events in this city. Matched case-insensitively against the venue's city.
genre optionalquerystring-Only events carrying this genre, exactly as /v1/genres spells it.
from optionalquerystring (date)-First date, yyyy-mm-dd. Defaults to today in Europe/Amsterdam.
to optionalquerystring (date)-Last date, yyyy-mm-dd, inclusive.
venue_id optionalquerystring-Only events in this venue.
artist_id optionalquerystring-Only events this artist is billed on.
organisation_id optionalquerystring-Only events from this organisation.
q optionalquerystring-Free text over the title and the venue name.
has_tickets optionalqueryboolean-True: only events you can buy a ticket for right now. False: only events you cannot.
max_price optionalquerynumber>= 0-Only events whose cheapest ticket is at most this, in euros. 0 means free entry only.
min_price optionalquerynumber>= 0-Only events whose cheapest ticket is at least this, in euros. Free entry and an unknown price never pass a floor above 0.
lat optionalquerynumber-90..90-Latitude of the centre for a radius search, with lng. Only venues with coordinates can match.
lng optionalquerynumber-180..180-Longitude of the centre for a radius search, with lat.
radius_km optionalqueryinteger1..200-How far from lat,lng a venue may be, in kilometres. Needs lat and lng. Defaults to 25.
limit optionalqueryinteger1..10025Items per page, 1 to 100.
cursor optionalquerystring-Opaque cursor from meta.next_cursor of the previous page. Do not build one yourself.

Example request

curl
curl -s "https://api.partyppl.nl/v1/events?city=Amsterdam&limit=25" \
  -H "Authorization: Bearer $PPL_TOKEN"
JavaScript
const res = await fetch("https://api.partyppl.nl/v1/events?city=Amsterdam&limit=25", {
  headers: {
    Authorization: `Bearer ${process.env.PPL_TOKEN}`,
  },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
Python
import os
import requests

res = requests.get(
    "https://api.partyppl.nl/v1/events?city=Amsterdam&limit=25",
    headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
    timeout=30,
)
res.raise_for_status()
payload = res.json()
Show the example response
200 · Example response
{
  "data": [
    {
      "id": "oost-sat",
      "slug": "oost-hard-techno-night",
      "title": "OOST: Hard Techno Night",
      "date": "2026-10-03",
      "end_date": null,
      "start": "23:00",
      "end": "06:00",
      "timezone": "Europe/Amsterdam",
      "status": "approved",
      "cancelled": false,
      "cancel_reason": null,
      "postponed_to": null,
      "genres": [
        "Hard techno",
        "Techno"
      ],
      "price": 18,
      "price_max": 25,
      "currency": "EUR",
      "age": 18,
      "ticket_url": null,
      "artwork_url": "https://partyppl.nl/media/imports/oost/oost-sat.jpg",
      "venue": {
        "id": "oost",
        "name": "OOST",
        "city": "Amsterdam",
        "address": "Zeeburgerpad 1, 1018 AJ Amsterdam",
        "lat": 52.3701,
        "lng": 4.9412
      },
      "organisation": {
        "id": "oost-collective",
        "name": "OOST Collective"
      },
      "url": "https://partyppl.nl/e/oost-hard-techno-night",
      "updated_at": 1758499200
    }
  ],
  "meta": {
    "request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33",
    "count": 1,
    "limit": 25,
    "next_cursor": null,
    "attribution": {
      "text": "Event data from PartyPPL. Link back to the event page on partyppl.nl.",
      "url": "https://partyppl.nl",
      "terms": "https://api.partyppl.nl/v1/terms"
    }
  }
}

Statuses

  • 200List events
  • 400The request is wrong. error.details.params names every bad parameter.
  • 401No token, or a token we do not know.
  • 403The token is valid but does not carry the read scope, or the organisation is suspended.
  • 429Over the per-minute limit or the daily quota. Retry-After says how long to wait.
  • 500Something went wrong on our side. Quote request_id.

GET/events/{id}

Get one event

Access
Token with read
operationId
getEvent

One event by its id or by its slug, with the bill, the set times when there are any and the festival maps. Needs a token with the read scope. A read token is free: create one in the organiser portal under API. Browsing the site itself needs nothing.

Parameters

NameInTypeDefaultDescription
id requiredpathstring-The id of the resource. Events also accept their slug.

Example request

curl
curl -s "https://api.partyppl.nl/v1/events/oost-sat" \
  -H "Authorization: Bearer $PPL_TOKEN"
JavaScript
const res = await fetch("https://api.partyppl.nl/v1/events/oost-sat", {
  headers: {
    Authorization: `Bearer ${process.env.PPL_TOKEN}`,
  },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
Python
import os
import requests

res = requests.get(
    "https://api.partyppl.nl/v1/events/oost-sat",
    headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
    timeout=30,
)
res.raise_for_status()
payload = res.json()
Show the example response
200 · Example response
{
  "data": {
    "id": "oost-sat",
    "slug": "oost-hard-techno-night",
    "title": "OOST: Hard Techno Night",
    "date": "2026-10-03",
    "end_date": null,
    "start": "23:00",
    "end": "06:00",
    "timezone": "Europe/Amsterdam",
    "status": "approved",
    "cancelled": false,
    "cancel_reason": null,
    "postponed_to": null,
    "genres": [
      "Hard techno",
      "Techno"
    ],
    "price": 18,
    "price_max": 25,
    "currency": "EUR",
    "age": 18,
    "ticket_url": null,
    "artwork_url": "https://partyppl.nl/media/imports/oost/oost-sat.jpg",
    "venue": {
      "id": "oost",
      "name": "OOST",
      "city": "Amsterdam",
      "address": "Zeeburgerpad 1, 1018 AJ Amsterdam",
      "lat": 52.3701,
      "lng": 4.9412
    },
    "organisation": {
      "id": "oost-collective",
      "name": "OOST Collective"
    },
    "url": "https://partyppl.nl/e/oost-hard-techno-night",
    "updated_at": 1758499200,
    "description": "Twee vloeren, hard techno tot zes uur.",
    "lineup": [
      {
        "id": "amelie-lens",
        "name": "Amelie Lens",
        "order": 0
      },
      {
        "id": "vril",
        "name": "Vril",
        "order": 1
      }
    ],
    "timetable": {
      "Main": [
        [
          "23:00",
          "Vril"
        ],
        [
          "01:00",
          "Amelie Lens"
        ]
      ]
    },
    "maps": [
      {
        "label": "Plattegrond",
        "image_url": "https://partyppl.nl/media/imports/oost/plattegrond.png",
        "source": null
      }
    ],
    "rules": [
      "18+, legitimatie verplicht",
      "Geen fotos op de dansvloer"
    ],
    "dress": null,
    "source": "partyflock",
    "source_url": "https://partyflock.nl/party/498065"
  },
  "meta": {
    "request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33",
    "attribution": {
      "text": "Event data from PartyPPL. Link back to the event page on partyppl.nl.",
      "url": "https://partyppl.nl",
      "terms": "https://api.partyppl.nl/v1/terms"
    }
  }
}

Statuses

  • 200Get one event
  • 400The request is wrong. error.details.params names every bad parameter.
  • 401No token, or a token we do not know.
  • 403The token is valid but does not carry the read scope, or the organisation is suspended.
  • 404No such resource.
  • 429Over the per-minute limit or the daily quota. Retry-After says how long to wait.
  • 500Something went wrong on our side. Quote request_id.

GET/events/{id}/token-prices

What a token costs at this festival

Access
Token with read
operationId
getTokenPrices

Dutch and Belgian festivals sell drinks in munten, and what that costs is worked out here from what visitors reported: euros per token at the till and in advance, tokens per drink and therefore the price of a beer, whether unspent tokens are refunded, what the previous edition cost, and how it sits against the rest of the season. Nothing in the answer was checked by us. verified is always false and reports and last_report_at are always there, so anything you build with it can say who said so and when. 404 for an event that is not a festival. Needs a token with the read scope. A read token is free: create one in the organiser portal under API. Browsing the site itself needs nothing.

Parameters

NameInTypeDefaultDescription
id requiredpathstring-The id of the resource. Events also accept their slug.

Example request

curl
curl -s "https://api.partyppl.nl/v1/events/oost-sat/token-prices" \
  -H "Authorization: Bearer $PPL_TOKEN"
JavaScript
const res = await fetch("https://api.partyppl.nl/v1/events/oost-sat/token-prices", {
  headers: {
    Authorization: `Bearer ${process.env.PPL_TOKEN}`,
  },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
Python
import os
import requests

res = requests.get(
    "https://api.partyppl.nl/v1/events/oost-sat/token-prices",
    headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
    timeout=30,
)
res.raise_for_status()
payload = res.json()
Show the example response
200 · Example response
{
  "data": {
    "event_id": "awakenings-2027",
    "festival_key": "awakenings",
    "season": 2027,
    "verified": false,
    "reports": 11,
    "last_report_at": 1782000000,
    "confidence": "good",
    "token_price": 3.6,
    "token_price_channel": "onsite",
    "presale": 3.4,
    "onsite": 3.6,
    "saving": 0.2,
    "drink_tokens": 2,
    "drink_price": 7.2,
    "refund": "no",
    "outliers": 1,
    "example": {
      "paid": 18,
      "tokens": 5
    },
    "previous_edition": {
      "event_id": "awakenings-2026",
      "title": "Awakenings Festival 2026",
      "date": "2026-07-04",
      "season": 2026,
      "token_price": 3.4,
      "drink_price": 6.8,
      "reports": 8
    },
    "season_compare": {
      "season": 2027,
      "median": 3.4,
      "festivals": 14,
      "diff": 0.2
    },
    "url": "https://partyppl.nl/e/awakenings-festival-2027#munten"
  },
  "meta": {
    "request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33",
    "attribution": {
      "text": "Event data from PartyPPL. Link back to the event page on partyppl.nl.",
      "url": "https://partyppl.nl",
      "terms": "https://api.partyppl.nl/v1/terms"
    }
  }
}

Statuses

  • 200What a token costs at this festival
  • 400The request is wrong. error.details.params names every bad parameter.
  • 401No token, or a token we do not know.
  • 403The token is valid but does not carry the read scope, or the organisation is suspended.
  • 404No such resource.
  • 429Over the per-minute limit or the daily quota. Retry-After says how long to wait.
  • 500Something went wrong on our side. Quote request_id.

GET/events/{id}/token-reports

The token reports behind that price

Access
Token with read
operationId
listTokenReports

The individual reports the price above is built from, newest first, so the working can be checked. Anonymous by design: each report carries what was paid and how close the reporter stood to the night (tier, which is what their weight is built from), and never who they are. Needs a token with the read scope. A read token is free: create one in the organiser portal under API. Browsing the site itself needs nothing.

Parameters

NameInTypeDefaultDescription
id requiredpathstring-The id of the resource. Events also accept their slug.
limit optionalqueryinteger1..10025Items per page, 1 to 100.
cursor optionalquerystring-Opaque cursor from meta.next_cursor of the previous page. Do not build one yourself.

Example request

curl
curl -s "https://api.partyppl.nl/v1/events/oost-sat/token-reports?limit=25" \
  -H "Authorization: Bearer $PPL_TOKEN"
JavaScript
const res = await fetch("https://api.partyppl.nl/v1/events/oost-sat/token-reports?limit=25", {
  headers: {
    Authorization: `Bearer ${process.env.PPL_TOKEN}`,
  },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
Python
import os
import requests

res = requests.get(
    "https://api.partyppl.nl/v1/events/oost-sat/token-reports?limit=25",
    headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
    timeout=30,
)
res.raise_for_status()
payload = res.json()
Show the example response
200 · Example response
{
  "data": [
    {
      "id": "tp_8cQ2fR",
      "paid": 18,
      "tokens": 5,
      "token_price": 3.6,
      "drink_tokens": 2,
      "channel": "onsite",
      "refund": "no",
      "tier": "ticket",
      "weight": 5,
      "created_at": 1782000000
    }
  ],
  "meta": {
    "request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33",
    "count": 1,
    "limit": 25,
    "next_cursor": null,
    "attribution": {
      "text": "Event data from PartyPPL. Link back to the event page on partyppl.nl.",
      "url": "https://partyppl.nl",
      "terms": "https://api.partyppl.nl/v1/terms"
    }
  }
}

Statuses

  • 200The token reports behind that price
  • 400The request is wrong. error.details.params names every bad parameter.
  • 401No token, or a token we do not know.
  • 403The token is valid but does not carry the read scope, or the organisation is suspended.
  • 404No such resource.
  • 429Over the per-minute limit or the daily quota. Retry-After says how long to wait.
  • 500Something went wrong on our side. Quote request_id.

GET/venues

List venues

Access
Token with read
operationId
listVenues

Clubs, concert halls and festival sites, by name. Needs a token with the read scope. A read token is free: create one in the organiser portal under API. Browsing the site itself needs nothing.

Parameters

NameInTypeDefaultDescription
city optionalquerystring-Only venues in this city.
q optionalquerystring-Free text over the name.
with_events optionalqueryboolean-True: only venues with at least one event from today on.
limit optionalqueryinteger1..10025Items per page, 1 to 100.
cursor optionalquerystring-Opaque cursor from meta.next_cursor of the previous page. Do not build one yourself.

Example request

curl
curl -s "https://api.partyppl.nl/v1/venues?city=Rotterdam&limit=25" \
  -H "Authorization: Bearer $PPL_TOKEN"
JavaScript
const res = await fetch("https://api.partyppl.nl/v1/venues?city=Rotterdam&limit=25", {
  headers: {
    Authorization: `Bearer ${process.env.PPL_TOKEN}`,
  },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
Python
import os
import requests

res = requests.get(
    "https://api.partyppl.nl/v1/venues?city=Rotterdam&limit=25",
    headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
    timeout=30,
)
res.raise_for_status()
payload = res.json()
Show the example response
200 · Example response
{
  "data": [
    {
      "id": "oost",
      "name": "OOST",
      "city": "Amsterdam",
      "area": "Oost",
      "address": "Zeeburgerpad 1, 1018 AJ Amsterdam",
      "lat": 52.3701,
      "lng": 4.9412,
      "website": "https://clubooost.nl",
      "tags": [
        "club",
        "techno"
      ],
      "rating": 4.4,
      "reviews_count": 128,
      "image_url": "https://partyppl.nl/media/venues/oost.jpg",
      "url": "https://partyppl.nl/locatie/oost"
    }
  ],
  "meta": {
    "request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33",
    "count": 1,
    "limit": 25,
    "next_cursor": null,
    "attribution": {
      "text": "Event data from PartyPPL. Link back to the event page on partyppl.nl.",
      "url": "https://partyppl.nl",
      "terms": "https://api.partyppl.nl/v1/terms"
    }
  }
}

Statuses

  • 200List venues
  • 400The request is wrong. error.details.params names every bad parameter.
  • 401No token, or a token we do not know.
  • 403The token is valid but does not carry the read scope, or the organisation is suspended.
  • 429Over the per-minute limit or the daily quota. Retry-After says how long to wait.
  • 500Something went wrong on our side. Quote request_id.

GET/venues/{id}

Get one venue

Access
Token with read
operationId
getVenue

One venue with its practical profile: capacity, lockers, payment, smoking, accessibility and the rest of what a visitor asks before they go. Needs a token with the read scope. A read token is free: create one in the organiser portal under API. Browsing the site itself needs nothing.

Parameters

NameInTypeDefaultDescription
id requiredpathstring-The id of the resource. Events also accept their slug.

Example request

curl
curl -s "https://api.partyppl.nl/v1/venues/oost" \
  -H "Authorization: Bearer $PPL_TOKEN"
JavaScript
const res = await fetch("https://api.partyppl.nl/v1/venues/oost", {
  headers: {
    Authorization: `Bearer ${process.env.PPL_TOKEN}`,
  },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
Python
import os
import requests

res = requests.get(
    "https://api.partyppl.nl/v1/venues/oost",
    headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
    timeout=30,
)
res.raise_for_status()
payload = res.json()
Show the example response
200 · Example response
{
  "data": {
    "id": "oost",
    "name": "OOST",
    "city": "Amsterdam",
    "area": "Oost",
    "address": "Zeeburgerpad 1, 1018 AJ Amsterdam",
    "lat": 52.3701,
    "lng": 4.9412,
    "website": "https://clubooost.nl",
    "tags": [
      "club",
      "techno"
    ],
    "rating": 4.4,
    "reviews_count": 128,
    "image_url": "https://partyppl.nl/media/venues/oost.jpg",
    "url": "https://partyppl.nl/locatie/oost",
    "info": "Ingang aan de waterkant, garderobe verplicht.",
    "accessibility": "Rolstoeltoegankelijk, aangepast toilet aanwezig.",
    "rules": [
      "18+, legitimatie verplicht"
    ],
    "rules_url": "https://clubooost.nl/huisregels",
    "facts": {
      "capacity": 1200,
      "rooms": "2 zalen",
      "lockers": "app",
      "cashless": "pin",
      "smoking": "buiten"
    },
    "upcoming_events": 7
  },
  "meta": {
    "request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33",
    "attribution": {
      "text": "Event data from PartyPPL. Link back to the event page on partyppl.nl.",
      "url": "https://partyppl.nl",
      "terms": "https://api.partyppl.nl/v1/terms"
    }
  }
}

Statuses

  • 200Get one venue
  • 400The request is wrong. error.details.params names every bad parameter.
  • 401No token, or a token we do not know.
  • 403The token is valid but does not carry the read scope, or the organisation is suspended.
  • 404No such resource.
  • 429Over the per-minute limit or the daily quota. Retry-After says how long to wait.
  • 500Something went wrong on our side. Quote request_id.

GET/artists

List artists

Access
Token with read
operationId
listArtists

Performers, by name. Most of these profiles are built from the line-ups we import. Needs a token with the read scope. A read token is free: create one in the organiser portal under API. Browsing the site itself needs nothing.

Parameters

NameInTypeDefaultDescription
q optionalquerystring-Free text over the name.
genre optionalquerystring-Only artists whose primary genre is this.
country optionalquerystring-Only artists from this country, as the profile spells it.
limit optionalqueryinteger1..10025Items per page, 1 to 100.
cursor optionalquerystring-Opaque cursor from meta.next_cursor of the previous page. Do not build one yourself.

Example request

curl
curl -s "https://api.partyppl.nl/v1/artists?q=lens&limit=25" \
  -H "Authorization: Bearer $PPL_TOKEN"
JavaScript
const res = await fetch("https://api.partyppl.nl/v1/artists?q=lens&limit=25", {
  headers: {
    Authorization: `Bearer ${process.env.PPL_TOKEN}`,
  },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
Python
import os
import requests

res = requests.get(
    "https://api.partyppl.nl/v1/artists?q=lens&limit=25",
    headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
    timeout=30,
)
res.raise_for_status()
payload = res.json()
Show the example response
200 · Example response
{
  "data": [
    {
      "id": "amelie-lens",
      "name": "Amelie Lens",
      "genre": "Techno",
      "country": "BE",
      "city": "Antwerpen",
      "verified": true,
      "image_url": "https://partyppl.nl/media/artists/amelie-lens.jpg",
      "links": {
        "spotify": "https://open.spotify.com/artist/0",
        "instagram": "https://instagram.com/amelielens"
      },
      "url": "https://partyppl.nl/artiest/amelie-lens"
    }
  ],
  "meta": {
    "request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33",
    "count": 1,
    "limit": 25,
    "next_cursor": null,
    "attribution": {
      "text": "Event data from PartyPPL. Link back to the event page on partyppl.nl.",
      "url": "https://partyppl.nl",
      "terms": "https://api.partyppl.nl/v1/terms"
    }
  }
}

Statuses

  • 200List artists
  • 400The request is wrong. error.details.params names every bad parameter.
  • 401No token, or a token we do not know.
  • 403The token is valid but does not carry the read scope, or the organisation is suspended.
  • 429Over the per-minute limit or the daily quota. Retry-After says how long to wait.
  • 500Something went wrong on our side. Quote request_id.

GET/artists/{id}

Get one artist

Access
Token with read
operationId
getArtist

One artist with their biography, their links, their discography and their next dates in NL and BE. Needs a token with the read scope. A read token is free: create one in the organiser portal under API. Browsing the site itself needs nothing.

Parameters

NameInTypeDefaultDescription
id requiredpathstring-The id of the resource. Events also accept their slug.

Example request

curl
curl -s "https://api.partyppl.nl/v1/artists/amelie-lens" \
  -H "Authorization: Bearer $PPL_TOKEN"
JavaScript
const res = await fetch("https://api.partyppl.nl/v1/artists/amelie-lens", {
  headers: {
    Authorization: `Bearer ${process.env.PPL_TOKEN}`,
  },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
Python
import os
import requests

res = requests.get(
    "https://api.partyppl.nl/v1/artists/amelie-lens",
    headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
    timeout=30,
)
res.raise_for_status()
payload = res.json()
Show the example response
200 · Example response
{
  "data": {
    "id": "amelie-lens",
    "name": "Amelie Lens",
    "genre": "Techno",
    "country": "BE",
    "city": "Antwerpen",
    "verified": true,
    "image_url": "https://partyppl.nl/media/artists/amelie-lens.jpg",
    "links": {
      "spotify": "https://open.spotify.com/artist/0",
      "instagram": "https://instagram.com/amelielens"
    },
    "url": "https://partyppl.nl/artiest/amelie-lens",
    "bio": "Belgische techno-dj en producer, oprichter van Lenske.",
    "aliases": [],
    "agency": null,
    "releases": [
      {
        "title": "Hypnotized",
        "year": 2020
      }
    ],
    "upcoming_events": [
      {
        "id": "oost-sat",
        "slug": "oost-hard-techno-night",
        "title": "OOST: Hard Techno Night",
        "date": "2026-10-03",
        "end_date": null,
        "start": "23:00",
        "end": "06:00",
        "timezone": "Europe/Amsterdam",
        "status": "approved",
        "cancelled": false,
        "cancel_reason": null,
        "postponed_to": null,
        "genres": [
          "Hard techno",
          "Techno"
        ],
        "price": 18,
        "price_max": 25,
        "currency": "EUR",
        "age": 18,
        "ticket_url": null,
        "artwork_url": "https://partyppl.nl/media/imports/oost/oost-sat.jpg",
        "venue": {
          "id": "oost",
          "name": "OOST",
          "city": "Amsterdam",
          "address": "Zeeburgerpad 1, 1018 AJ Amsterdam",
          "lat": 52.3701,
          "lng": 4.9412
        },
        "organisation": {
          "id": "oost-collective",
          "name": "OOST Collective"
        },
        "url": "https://partyppl.nl/e/oost-hard-techno-night",
        "updated_at": 1758499200
      }
    ]
  },
  "meta": {
    "request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33",
    "attribution": {
      "text": "Event data from PartyPPL. Link back to the event page on partyppl.nl.",
      "url": "https://partyppl.nl",
      "terms": "https://api.partyppl.nl/v1/terms"
    }
  }
}

Statuses

  • 200Get one artist
  • 400The request is wrong. error.details.params names every bad parameter.
  • 401No token, or a token we do not know.
  • 403The token is valid but does not carry the read scope, or the organisation is suspended.
  • 404No such resource.
  • 429Over the per-minute limit or the daily quota. Retry-After says how long to wait.
  • 500Something went wrong on our side. Quote request_id.

GET/organisations

List organisations

Access
Token with read
operationId
listOrganisations

Promoters and the programming teams of clubs, by name. Needs a token with the read scope. A read token is free: create one in the organiser portal under API. Browsing the site itself needs nothing.

Parameters

NameInTypeDefaultDescription
q optionalquerystring-Free text over the name.
verified optionalqueryboolean-True: only organisations we have checked.
limit optionalqueryinteger1..10025Items per page, 1 to 100.
cursor optionalquerystring-Opaque cursor from meta.next_cursor of the previous page. Do not build one yourself.

Example request

curl
curl -s "https://api.partyppl.nl/v1/organisations?q=oost&limit=25" \
  -H "Authorization: Bearer $PPL_TOKEN"
JavaScript
const res = await fetch("https://api.partyppl.nl/v1/organisations?q=oost&limit=25", {
  headers: {
    Authorization: `Bearer ${process.env.PPL_TOKEN}`,
  },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
Python
import os
import requests

res = requests.get(
    "https://api.partyppl.nl/v1/organisations?q=oost&limit=25",
    headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
    timeout=30,
)
res.raise_for_status()
payload = res.json()
Show the example response
200 · Example response
{
  "data": [
    {
      "id": "oost-collective",
      "name": "OOST Collective",
      "verified": true,
      "since": 2014,
      "bio": "Hard techno in Amsterdam Oost.",
      "website": "https://clubooost.nl",
      "events_count": 42,
      "url": "https://partyppl.nl/organisatie/oost-collective"
    }
  ],
  "meta": {
    "request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33",
    "count": 1,
    "limit": 25,
    "next_cursor": null,
    "attribution": {
      "text": "Event data from PartyPPL. Link back to the event page on partyppl.nl.",
      "url": "https://partyppl.nl",
      "terms": "https://api.partyppl.nl/v1/terms"
    }
  }
}

Statuses

  • 200List organisations
  • 400The request is wrong. error.details.params names every bad parameter.
  • 401No token, or a token we do not know.
  • 403The token is valid but does not carry the read scope, or the organisation is suspended.
  • 429Over the per-minute limit or the daily quota. Retry-After says how long to wait.
  • 500Something went wrong on our side. Quote request_id.

GET/organisations/{id}

Get one organisation

Access
Token with read
operationId
getOrganisation

One organisation. Needs a token with the read scope. A read token is free: create one in the organiser portal under API. Browsing the site itself needs nothing.

Parameters

NameInTypeDefaultDescription
id requiredpathstring-The id of the resource. Events also accept their slug.

Example request

curl
curl -s "https://api.partyppl.nl/v1/organisations/oost-collective" \
  -H "Authorization: Bearer $PPL_TOKEN"
JavaScript
const res = await fetch("https://api.partyppl.nl/v1/organisations/oost-collective", {
  headers: {
    Authorization: `Bearer ${process.env.PPL_TOKEN}`,
  },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
Python
import os
import requests

res = requests.get(
    "https://api.partyppl.nl/v1/organisations/oost-collective",
    headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
    timeout=30,
)
res.raise_for_status()
payload = res.json()
Show the example response
200 · Example response
{
  "data": {
    "id": "oost-collective",
    "name": "OOST Collective",
    "verified": true,
    "since": 2014,
    "bio": "Hard techno in Amsterdam Oost.",
    "website": "https://clubooost.nl",
    "events_count": 42,
    "url": "https://partyppl.nl/organisatie/oost-collective"
  },
  "meta": {
    "request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33",
    "attribution": {
      "text": "Event data from PartyPPL. Link back to the event page on partyppl.nl.",
      "url": "https://partyppl.nl",
      "terms": "https://api.partyppl.nl/v1/terms"
    }
  }
}

Statuses

  • 200Get one organisation
  • 400The request is wrong. error.details.params names every bad parameter.
  • 401No token, or a token we do not know.
  • 403The token is valid but does not carry the read scope, or the organisation is suspended.
  • 404No such resource.
  • 429Over the per-minute limit or the daily quota. Retry-After says how long to wait.
  • 500Something went wrong on our side. Quote request_id.

GET/genres

List genres

Access
Token with read
operationId
listGenres

The fixed list of genres an event can carry, with the family each belongs to. These are the only values ?genre= accepts. Needs a token with the read scope. A read token is free: create one in the organiser portal under API. Browsing the site itself needs nothing.

Parameters

NameInTypeDefaultDescription
limit optionalqueryinteger1..10025Items per page, 1 to 100.
cursor optionalquerystring-Opaque cursor from meta.next_cursor of the previous page. Do not build one yourself.

Example request

curl
curl -s "https://api.partyppl.nl/v1/genres?limit=25" \
  -H "Authorization: Bearer $PPL_TOKEN"
JavaScript
const res = await fetch("https://api.partyppl.nl/v1/genres?limit=25", {
  headers: {
    Authorization: `Bearer ${process.env.PPL_TOKEN}`,
  },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
Python
import os
import requests

res = requests.get(
    "https://api.partyppl.nl/v1/genres?limit=25",
    headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
    timeout=30,
)
res.raise_for_status()
payload = res.json()
Show the example response
200 · Example response
{
  "data": [
    {
      "name": "Hard techno",
      "group": "Hard",
      "slug": "hard-techno"
    }
  ],
  "meta": {
    "request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33",
    "count": 1,
    "limit": 25,
    "next_cursor": null,
    "attribution": {
      "text": "Event data from PartyPPL. Link back to the event page on partyppl.nl.",
      "url": "https://partyppl.nl",
      "terms": "https://api.partyppl.nl/v1/terms"
    }
  }
}

Statuses

  • 200List genres
  • 400The request is wrong. error.details.params names every bad parameter.
  • 401No token, or a token we do not know.
  • 403The token is valid but does not carry the read scope, or the organisation is suspended.
  • 429Over the per-minute limit or the daily quota. Retry-After says how long to wait.
  • 500Something went wrong on our side. Quote request_id.

GET/radar

List new releases

Access
Token with read
operationId
listRadar

Radar: new singles, EPs and albums from the artists in the agenda, newest first, from the last one to four weeks. Read only. Needs a token with the read scope. A read token is free: create one in the organiser portal under API. Browsing the site itself needs nothing.

Parameters

NameInTypeDefaultDescription
genre optionalquerystring-Only records by artists of this genre, one of /v1/genres.
weeks optionalqueryinteger1..44How many weeks back: 1, 2 or 4.
limit optionalqueryinteger1..10025Items per page, 1 to 100.
cursor optionalquerystring-Opaque cursor from meta.next_cursor of the previous page. Do not build one yourself.

Example request

curl
curl -s "https://api.partyppl.nl/v1/radar?genre=Techno&limit=25" \
  -H "Authorization: Bearer $PPL_TOKEN"
JavaScript
const res = await fetch("https://api.partyppl.nl/v1/radar?genre=Techno&limit=25", {
  headers: {
    Authorization: `Bearer ${process.env.PPL_TOKEN}`,
  },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
Python
import os
import requests

res = requests.get(
    "https://api.partyppl.nl/v1/radar?genre=Techno&limit=25",
    headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
    timeout=30,
)
res.raise_for_status()
payload = res.json()
Show the example response
200 · Example response
{
  "data": [
    {
      "title": "The Resistance EP",
      "type": "ep",
      "release_date": "2026-09-24",
      "genre": "Techno",
      "artists": [
        {
          "id": "charlotte-de-witte",
          "name": "Charlotte de Witte",
          "url": "https://partyppl.nl/artiest/charlotte-de-witte"
        }
      ],
      "spotify_url": null,
      "deezer_url": "https://www.deezer.com/album/123456789",
      "cover_url": "https://partyppl.nl/media/artists/charlotte-de-witte-rel-1a2b3c4d.jpg",
      "next_event": {
        "id": "ev_7k2m",
        "title": "Awakenings Upclose",
        "date": "2026-10-17",
        "city": "Amsterdam",
        "url": "https://partyppl.nl/e/awakenings-upclose-2026"
      }
    }
  ],
  "meta": {
    "request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33",
    "count": 1,
    "limit": 25,
    "next_cursor": null,
    "attribution": {
      "text": "Event data from PartyPPL. Link back to the event page on partyppl.nl.",
      "url": "https://partyppl.nl",
      "terms": "https://api.partyppl.nl/v1/terms"
    }
  }
}

Statuses

  • 200List new releases
  • 400The request is wrong. error.details.params names every bad parameter.
  • 401No token, or a token we do not know.
  • 403The token is valid but does not carry the read scope, or the organisation is suspended.
  • 429Over the per-minute limit or the daily quota. Retry-After says how long to wait.
  • 500Something went wrong on our side. Quote request_id.

GET/badges

The badge catalogue

Access
Token with read
operationId
listBadges

Every badge somebody can earn on PartyPPL, with its family, its rung and what it takes, in Dutch and English. Every rule is checked against what a person has actually been to or contributed: nights that have happened, cities, rooms, genres attended, festivals, friends, corrections the agenda team applied, answers somebody else found useful. Nothing here is read from a setting somebody ticked, and nothing rewards volume of posting or money spent. Needs a token with the read scope. A read token is free: create one in the organiser portal under API. Browsing the site itself needs nothing.

Parameters

NameInTypeDefaultDescription
limit optionalqueryinteger1..10025Items per page, 1 to 100.
cursor optionalquerystring-Opaque cursor from meta.next_cursor of the previous page. Do not build one yourself.

Example request

curl
curl -s "https://api.partyppl.nl/v1/badges?limit=25" \
  -H "Authorization: Bearer $PPL_TOKEN"
JavaScript
const res = await fetch("https://api.partyppl.nl/v1/badges?limit=25", {
  headers: {
    Authorization: `Bearer ${process.env.PPL_TOKEN}`,
  },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
Python
import os
import requests

res = requests.get(
    "https://api.partyppl.nl/v1/badges?limit=25",
    headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
    timeout=30,
)
res.raise_for_status()
payload = res.json()
Show the example response
200 · Example response
{
  "data": [
    {
      "id": "nacht-25",
      "family": "nights",
      "tier": 25,
      "mark": "25",
      "name": {
        "nl": "25 nachten",
        "en": "25 nights"
      },
      "description": {
        "nl": "Vijfentwintig nachten geweest",
        "en": "Twenty-five nights out"
      },
      "counts": "nights",
      "needs": 25
    }
  ],
  "meta": {
    "request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33",
    "count": 1,
    "limit": 25,
    "next_cursor": null,
    "attribution": {
      "text": "Event data from PartyPPL. Link back to the event page on partyppl.nl.",
      "url": "https://partyppl.nl",
      "terms": "https://api.partyppl.nl/v1/terms"
    }
  }
}

Statuses

  • 200The badge catalogue
  • 400The request is wrong. error.details.params names every bad parameter.
  • 401No token, or a token we do not know.
  • 403The token is valid but does not carry the read scope, or the organisation is suspended.
  • 429Over the per-minute limit or the daily quota. Retry-After says how long to wait.
  • 500Something went wrong on our side. Quote request_id.

GET/users/{id}/badges

The badges one person has

Access
Token with read
operationId
listUserBadges

The badges of one public profile, addressed by handle or by id, with the date each one was earned and the number behind it at that moment. Badges are personal data and this follows the profile exactly: a private account, a suspended account and an account that does not exist all answer 404, because saying which of the three it is would itself be telling you something about somebody. Nothing in the answer says what they have not earned.

Parameters

NameInTypeDefaultDescription
id requiredpathstring-The id of the resource. Events also accept their slug.
limit optionalqueryinteger1..10025Items per page, 1 to 100.
cursor optionalquerystring-Opaque cursor from meta.next_cursor of the previous page. Do not build one yourself.

Example request

curl
curl -s "https://api.partyppl.nl/v1/users/oost-sat/badges?limit=25" \
  -H "Authorization: Bearer $PPL_TOKEN"
JavaScript
const res = await fetch("https://api.partyppl.nl/v1/users/oost-sat/badges?limit=25", {
  headers: {
    Authorization: `Bearer ${process.env.PPL_TOKEN}`,
  },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
Python
import os
import requests

res = requests.get(
    "https://api.partyppl.nl/v1/users/oost-sat/badges?limit=25",
    headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
    timeout=30,
)
res.raise_for_status()
payload = res.json()
Show the example response
200 · Example response
{
  "data": [
    {
      "id": "nacht-25",
      "family": "nights",
      "tier": 25,
      "name": {
        "nl": "25 nachten",
        "en": "25 nights"
      },
      "description": {
        "nl": "Vijfentwintig nachten geweest",
        "en": "Twenty-five nights out"
      },
      "value": 27,
      "earned_at": 1789654255
    }
  ],
  "meta": {
    "request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33",
    "count": 1,
    "limit": 25,
    "next_cursor": null,
    "user": {
      "id": "u_noor",
      "handle": "noor",
      "name": "Noor",
      "url": "https://partyppl.nl/u/noor"
    },
    "catalogue": 40
  }
}

Statuses

  • 200The badges one person has
  • 400The request is wrong. error.details.params names every bad parameter.
  • 401No token, or a token we do not know.
  • 403The token is valid but does not carry the read scope, or the organisation is suspended.
  • 404No such resource.
  • 429Over the per-minute limit or the daily quota. Retry-After says how long to wait.
  • 500Something went wrong on our side. Quote request_id.

GET/cities

List cities

Access
Token with read
operationId
listCities

Every city with at least one event coming up, busiest first, with the number of events and the middle of that city's venues. Needs a token with the read scope. A read token is free: create one in the organiser portal under API. Browsing the site itself needs nothing.

Parameters

NameInTypeDefaultDescription
country optionalqueryNL | BE-Only cities in this country.
limit optionalqueryinteger1..10025Items per page, 1 to 100.
cursor optionalquerystring-Opaque cursor from meta.next_cursor of the previous page. Do not build one yourself.

Example request

curl
curl -s "https://api.partyppl.nl/v1/cities?country=NL&limit=25" \
  -H "Authorization: Bearer $PPL_TOKEN"
JavaScript
const res = await fetch("https://api.partyppl.nl/v1/cities?country=NL&limit=25", {
  headers: {
    Authorization: `Bearer ${process.env.PPL_TOKEN}`,
  },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
Python
import os
import requests

res = requests.get(
    "https://api.partyppl.nl/v1/cities?country=NL&limit=25",
    headers={"Authorization": f"Bearer {os.environ['PPL_TOKEN']}"},
    timeout=30,
)
res.raise_for_status()
payload = res.json()
Show the example response
200 · Example response
{
  "data": [
    {
      "name": "Amsterdam",
      "country": "NL",
      "upcoming_events": 312,
      "lat": 52.3702,
      "lng": 4.8952,
      "url": "https://partyppl.nl/stad/amsterdam"
    }
  ],
  "meta": {
    "request_id": "9f1c2b4a-7e3d-4a10-9c2f-6b8d1e5a0c33",
    "count": 1,
    "limit": 25,
    "next_cursor": null,
    "attribution": {
      "text": "Event data from PartyPPL. Link back to the event page on partyppl.nl.",
      "url": "https://partyppl.nl",
      "terms": "https://api.partyppl.nl/v1/terms"
    }
  }
}

Statuses

  • 200List cities
  • 400The request is wrong. error.details.params names every bad parameter.
  • 401No token, or a token we do not know.
  • 403The token is valid but does not carry the read scope, or the organisation is suspended.
  • 429Over the per-minute limit or the daily quota. Retry-After says how long to wait.
  • 500Something went wrong on our side. Quote request_id.

The specification as JSON