Skip to main content
Parkstack

Developers

API reference

Every address, field and error in version 1. The same reference is available as OpenAPI.

Basics

Address
https://api.parkstack.net/site/v1
Key
Send Authorization: Bearer pk_live_… on every request. The key alone decides the park. A park’s owner makes keys in Parkstack (Park settings → Your own website). The demo key pk_live_demoRiversideParkstackSiteApiKey reads Riverside from any website.
Browsers
Servers send no Origin and are always allowed. A browser may only call from a website address listed on the key; CORS answers for those addresses and never sends credentials.
Dates, times and money
Dates are YYYY-MM-DD and times HH:mm on the park’s clock (timezone on /park); moments such as startsAt are ISO 8601. Money is whole pence, the total the guest pays.
Text
Park-written text is Markdown with bold, links and bulleted lists only, with a plain-words copy beside it. Render it without raw HTML.

Park and content

The park

GET/park

Name, contact details, address, logo, colours, fonts, the cheapest ticket and who guests buy from. Start here: most pages need some of it.

  • Show seller beside anything that sells tickets, and link the Ticket terms (/pages/ticket-terms).
Request
curl "https://api.parkstack.net/site/v1/park" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/park", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const park = await response.json();
Example answer (lists cut short)
{
  "name": "Riverside Adventure Park",
  "tagline": "Thrills on the river. Fun for every generation.",
  "timezone": "Europe/London",
  "currency": "GBP",
  "contact": {
    "email": null,
    "phone": null
  },
  "address": {
    "lines": null,
    "postcode": null,
    "parking": null,
    "mapUrl": null
  },
  "social": [],
  "logo": {
    "url": "https://media.parkstack.net/riverside/1790686420307-78slhb.webp",
    "width": 640,
    "height": 640,
    "alt": null,
    "srcset": "https://media.parkstack.net/riverside/1790686420307-78slhb.webp?w=96 96w, https://media.parkstack.net/riverside/1790686420307-78slhb.webp?w=192 192w, https://media.parkstack.net/riverside/1790686420307-78slhb.webp?w=384 384w, https://med…"
  },
  "logoForDarkBackgrounds": null,
  "colours": {
    "main": "#0F5C4C",
    "accent": "#E3B23C"
  },
  "fonts": [
    {
      "role": "Headings",
      "name": "Fraunces",
      "url": "https://fonts.google.com/specimen/Fraunces"
    },
    {
      "role": "Text",
      "name": "Source Sans 3",
      "url": "https://fonts.google.com/specimen/Source+Sans+3"
    }
  ],
  "tickets": {
    "onSaleOnline": true,
    "fromPence": 2900,
    "fromIncludesVat": false,
    "shopUrl": "https://riverside.parkstack.net/tickets"
  },
  "seller": {
    "name": null,
    "address": null,
    "email": null,
    "phone": null,
    "vatNumber": null,
    "companyDetails": null
  },
  "parkstackUrl": "https://riverside.parkstack.net",
  "demo": true
}

Answer

namestring
The park's name as guests know it.
taglinestring or null
A short line under the name.
timezonestring
IANA time zone; every date and time in the API is on this clock.
currencystring
ISO 4217 code, "GBP". Every amount is in this currency's smallest unit (pence).
contactobject
For guests to get in touch.
emailstring or null
phonestring or null
addressobject
linesstring or null
The postal address; may hold line breaks.
postcodestring or null
parkingstring or null
The park's note on parking.
mapUrlstring or null
A Google Maps search for the address.
socialarray of object
Social media and other links, in the park's order.
labelstring
"Facebook", "Instagram", "TikTok", "X" or the park's own words.
urlstring
logoobject or null
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
logoForDarkBackgroundsobject or null
A white or light logo for dark backgrounds, when the park has one.
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
coloursobject
Hints for a matching design; the site is free to ignore them.
mainstring
A hex colour, "#0f5c4c".
accentstring
A hex colour.
fontsarray of object
The fonts the park chose; the site is free to use others.
role"Headings" | "Text" | "Headings and text"
namestring
A Google Fonts family name.
urlstring
Its Google Fonts stylesheet.
ticketsobject
onSaleOnlineboolean
Whether guests can buy tickets online now. Hide ticket links while false.
fromPenceinteger or null
The cheapest ticket on sale, in pence: show it as the total price ("From £12").
fromIncludesVatboolean or null
Whether the "from" price includes VAT ("From £12 inc. VAT"); null when there is no "from" price.
shopUrlstring
Parkstack's ticket shop, until the site sells tickets itself.
sellerobject
Who guests buy tickets from; show it with the ticket terms. Null fields are not set.
namestring or null
addressstring or null
emailstring or null
phonestring or null
vatNumberstring or null
companyDetailsstring or null
For a limited company: name, where registered, number and registered office, in one sentence.
parkstackUrlstring
Parkstack's own address for the park's guest pages (ticket confirmations and legal pages live there).
demoboolean
A demonstration park: checkout takes no payment and its tickets are not valid.

Cache-Control: public, max-age=60, stale-while-revalidate=300

Opening hours

GET/hours

Opening times day by day, with special dates and the names of events on each day. Today when no dates are given; up to 62 days a request.

  • A day with status not_set has no hours from the park: say nothing about it rather than "closed".
Request
curl "https://api.parkstack.net/site/v1/hours?from=2026-11-01&to=2026-11-30" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/hours?from=2026-11-01&to=2026-11-30", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const hours = await response.json();
Example answer (lists cut short)
{
  "days": [
    {
      "date": "2026-10-29",
      "status": "open",
      "opens": "10:00",
      "closes": "21:00",
      "lastEntry": "19:30",
      "label": "Halloween late opening · Halloween Trail"
    },
    {
      "date": "2026-10-30",
      "status": "open",
      "opens": "10:00",
      "closes": "21:00",
      "lastEntry": "19:30",
      "label": "Halloween late opening · Halloween Trail"
    },
    {
      "date": "2026-10-31",
      "status": "open",
      "opens": "10:00",
      "closes": "21:00",
      "lastEntry": "19:30",
      "label": "Halloween late opening · Halloween Trail · Halloween Fireworks"
    }
  ]
}

Parameters

fromquery, optional
First day, YYYY-MM-DD. Today when left out.
toquery, optional
Last day, YYYY-MM-DD. The same as from when left out.

Answer

daysarray of object
datestring
YYYY-MM-DD on the park's clock.
status"open" | "closed" | "not_set"
"not_set" means the park has not given hours for that day: say nothing rather than "closed".
opensstring or null
HH:mm, or null.
closesstring or null
lastEntrystring or null
labelstring or null
The day's label and the events on it ("Halloween Trail").

Can also answer BAD_REQUEST. Cache-Control: public, max-age=60, stale-while-revalidate=300

Attractions

GET/attractions

Every published attraction guests can see, in the park's order. Unlisted ones are left out.

Request
curl "https://api.parkstack.net/site/v1/attractions" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/attractions", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const attractions = await response.json();
Example answer (lists cut short)
{
  "items": [
    {
      "slug": "halloween-trail",
      "name": "Halloween Trail",
      "summary": "A lantern-lit family trail through Pioneer Woods, on for Halloween.",
      "type": "trail",
      "typeLabel": "Trail",
      "status": {
        "code": "operating",
        "label": "Available",
        "note": null
      },
      "isNew": true,
      "height": null,
      "minAge": null,
      "photo": null,
      "updatedAt": "2026-10-20T18:57:33.077Z"
    },
    {
      "slug": "iron-fall",
      "name": "Iron Fall",
      "summary": "Our new for 2028 B&M Dive Coaster.",
      "type": "ride",
      "typeLabel": "Ride",
      "status": {
        "code": "coming_soon",
        "label": "Coming soon",
        "note": "Coming soon"
      },
      "isNew": false,
      "height": {
        "minCm": 140,
        "maxCm": null,
        "label": "140 cm and over"
      },
      "minAge": null,
      "photo": {
        "url": "https://media.parkstack.net/riverside/1787448412512-b7kk9w.webp",
        "width": 1872,
        "height": 1056,
        "alt": null,
        "srcset": "https://media.parkstack.net/riverside/1787448412512-b7kk9w.webp?w=96 96w, https://media.parkstack.net/riverside/1787448412512-b7kk9w.webp?w=192 192w, https://media.parkstack.net/riverside/1787448412512-b7kk9w.webp?w=384 384w, https://med…"
      },
      "updatedAt": "2026-08-23T01:27:09.817Z"
    }
  ]
}

Answer

itemsarray of object
slugstring
The entry's part of its address, as in /explore/attractions/{slug}. Changes when the park renames it: see GET /redirects.
namestring
summarystring or null
One or two plain sentences for cards and lists.
type"ride" | "roller_coaster" | "flat_ride" | "show" | "animal" | "exhibit" | "play" | "walk" | "trail" | "other"
What kind of attraction it is; walk and trail have a distance and terrain.
typeLabelstring
The type in words ("Rollercoaster").
statusobject
code"operating" | "closed" | "seasonal" | "coming_soon" | "refurbishment" | "unlisted"
Whether guests can use it now. Unlisted entries are left out of lists but still have their own page.
labelstring
The code in words for guests: "Available", "Unavailable", "Seasonal"…
notestring or null
The park's note for guests, or a plain reason, while it is not available.
isNewboolean
Show a "New" badge.
heightobject or null
Height limits, inclusive; null when there are none.
minCminteger or null
Riders must be at least this tall.
maxCminteger or null
Riders must be no taller than this.
labelstring
Both limits in words: "110 cm and over", "Up to 130 cm", "100 to 140 cm".
minAgeinteger or null
The youngest age allowed, in years, when the park set one.
photoobject or null
The first photo: the one for cards and lists.
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
updatedAtstring
When it last changed, as an ISO 8601 time in UTC. Useful for sitemaps and caches.

Cache-Control: public, max-age=60, stale-while-revalidate=300

One attraction

GET/attractions/{slug}

An attraction's full details, photos, accessibility and the events held there.

  • On NOT_FOUND, ask /redirects?path= before showing your own 404: the park may have renamed it.
Request
curl "https://api.parkstack.net/site/v1/attractions/halloween-trail" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/attractions/halloween-trail", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const attraction = await response.json();
Example answer (lists cut short)
{
  "slug": "halloween-trail",
  "name": "Halloween Trail",
  "summary": "A lantern-lit family trail through Pioneer Woods, on for Halloween.",
  "type": "trail",
  "typeLabel": "Trail",
  "status": {
    "code": "operating",
    "label": "Available",
    "note": null
  },
  "isNew": true,
  "height": null,
  "minAge": null,
  "photo": null,
  "updatedAt": "2026-10-20T18:57:33.077Z",
  "description": "Follow the lanterns through Pioneer Woods and collect stamps at six spooky stops, then swap your card for a treat bag at the end.\n\nThe daytime path has mild frights and no jump scares, so it suits younger explorers. It runs on weekends t…",
  "descriptionText": "Follow the lanterns through Pioneer Woods and collect stamps at six spooky stops, then swap your card for a treat bag at the end. The daytime path has mild frights and no jump scares, so it suits younger explorers. It runs on weekends th…",
  "photos": [],
  "thrillLevel": null,
  "durationMinutes": null,
  "distanceMetres": null,
  "terrain": null,
  "wheelchairAccess": null,
  "events": [
    {
      "slug": "halloween-trail",
      "name": "Halloween Trail",
      "when": "Weekends, 3 October to 1 November, plus 26 to 30 October, during opening hours"
    }
  ],
  "seo": {
    "title": null,
    "description": null
  }
}

Parameters

slugin the path
The attraction's web address name, from its list.

Answer

slugstring
The entry's part of its address, as in /explore/attractions/{slug}. Changes when the park renames it: see GET /redirects.
namestring
summarystring or null
One or two plain sentences for cards and lists.
type"ride" | "roller_coaster" | "flat_ride" | "show" | "animal" | "exhibit" | "play" | "walk" | "trail" | "other"
What kind of attraction it is; walk and trail have a distance and terrain.
typeLabelstring
The type in words ("Rollercoaster").
statusobject
code"operating" | "closed" | "seasonal" | "coming_soon" | "refurbishment" | "unlisted"
Whether guests can use it now. Unlisted entries are left out of lists but still have their own page.
labelstring
The code in words for guests: "Available", "Unavailable", "Seasonal"…
notestring or null
The park's note for guests, or a plain reason, while it is not available.
isNewboolean
Show a "New" badge.
heightobject or null
Height limits, inclusive; null when there are none.
minCminteger or null
Riders must be at least this tall.
maxCminteger or null
Riders must be no taller than this.
labelstring
Both limits in words: "110 cm and over", "Up to 130 cm", "100 to 140 cm".
minAgeinteger or null
The youngest age allowed, in years, when the park set one.
photoobject or null
The first photo: the one for cards and lists.
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
updatedAtstring
When it last changed, as an ISO 8601 time in UTC. Useful for sitemaps and caches.
descriptionstring or null
The full description as Markdown: bold, links and bulleted lists only.
descriptionTextstring or null
The same description as plain words, for search results and meta tags.
photosarray of object
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
thrillLevelinteger or null
1 (gentle) to 5 (most intense), when the park set one.
durationMinutesinteger or null
How long it lasts or takes.
distanceMetresinteger or null
A walk or trail's length.
terrain"easy" | "moderate" | "challenging"
How hard a walk or trail's ground is.
wheelchairAccessobject or null
Null when the park has not said.
code"full" | "partial" | "none"
labelstring
The code in words for guests.
eventsarray of object
Published events held here that have not ended.
slugstring
namestring
whenstring
When it is on, in words.
seoobject
The park's own wording for search results and link previews; when null, use the name and summary.
titlestring or null
descriptionstring or null

Can also answer NOT_FOUND. Cache-Control: public, max-age=60, stale-while-revalidate=300

Food and drink

GET/food-and-drink

Restaurants, cafés, kiosks and bars, with dietary options and price bands.

Request
curl "https://api.parkstack.net/site/v1/food-and-drink" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/food-and-drink", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const foodAndDrink = await response.json();
Example answer (lists cut short)
{
  "items": [
    {
      "slug": "the-mill-restaurant",
      "name": "The Mill Restaurant",
      "summary": "Table-service British cooking in the old mill, with a terrace over the race.",
      "type": "restaurant",
      "typeLabel": "Restaurant",
      "status": {
        "code": "operating",
        "label": "Available",
        "note": null
      },
      "cuisine": "British",
      "location": "Mill courtyard",
      "priceBand": 3,
      "mealPeriods": "Lunch, dinner",
      "hoursNote": "12:00–15:00 and 17:00–20:00",
      "dietary": {
        "vegetarian": true,
        "vegan": true,
        "glutenFree": true
      },
      "reservations": true,
      "servesAlcohol": true,
      "photo": {
        "url": "https://media.parkstack.net/riverside/1787457896122-e66mt0.webp",
        "width": 1408,
        "height": 768,
        "alt": null,
        "srcset": "https://media.parkstack.net/riverside/1787457896122-e66mt0.webp?w=96 96w, https://media.parkstack.net/riverside/1787457896122-e66mt0.webp?w=192 192w, https://media.parkstack.net/riverside/1787457896122-e66mt0.webp?w=384 384w, https://med…"
      },
      "updatedAt": "2026-08-23T04:04:59.224Z"
    },
    {
      "slug": "rapids-cafe",
      "name": "Rapids Café",
      "summary": "Counter-service café next to the water ride. Jacket potatoes, toasties and cake.",
      "type": "cafe",
      "typeLabel": "Café",
      "status": {
        "code": "operating",
        "label": "Available",
        "note": null
      },
      "cuisine": "Café",
      "location": "River Rapids",
      "priceBand": 2,
      "mealPeriods": "Breakfast, lunch, snacks",
      "hoursNote": "Opens with the park; kitchen until one hour before close",
      "dietary": {
        "vegetarian": true,
        "vegan": true,
        "glutenFree": true
      },
      "reservations": false,
      "servesAlcohol": true,
      "photo": {
        "url": "https://media.parkstack.net/riverside/1790631494156-2n0am3.webp",
        "width": 1600,
        "height": 1200,
        "alt": null,
        "srcset": "https://media.parkstack.net/riverside/1790631494156-2n0am3.webp?w=96 96w, https://media.parkstack.net/riverside/1790631494156-2n0am3.webp?w=192 192w, https://media.parkstack.net/riverside/1790631494156-2n0am3.webp?w=384 384w, https://med…"
      },
      "updatedAt": "2026-09-28T21:38:57.050Z"
    }
  ]
}

Answer

itemsarray of object
slugstring
The entry's part of its address, as in /explore/attractions/{slug}. Changes when the park renames it: see GET /redirects.
namestring
summarystring or null
One or two plain sentences for cards and lists.
type"restaurant" | "cafe" | "kiosk" | "bar" | "food_truck" | "other"
What kind of place it is.
typeLabelstring
The type in words ("Café").
statusobject
code"operating" | "closed" | "seasonal" | "coming_soon" | "refurbishment" | "unlisted"
Whether guests can use it now. Unlisted entries are left out of lists but still have their own page.
labelstring
The code in words for guests: "Available", "Unavailable", "Seasonal"…
notestring or null
The park's note for guests, or a plain reason, while it is not available.
cuisinestring or null
The park's words ("Pizza and pasta").
locationstring or null
Where it is in the park, in the park's words ("Next to the main entrance").
priceBandinteger or null
1 to 4: show as £ to ££££.
mealPeriodsstring or null
The meals it serves, in the park's words ("Lunch and snacks").
hoursNotestring or null
The park's note on when it is open ("Weekends only"), shown as written.
dietaryobject
Options it offers; false means the park has not said it does.
vegetarianboolean
veganboolean
glutenFreeboolean
reservationsboolean
Whether guests can book a table.
servesAlcoholboolean
photoobject or null
The first photo: the one for cards and lists.
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
updatedAtstring
When it last changed, as an ISO 8601 time in UTC. Useful for sitemaps and caches.

Cache-Control: public, max-age=60, stale-while-revalidate=300

One food or drink place

GET/food-and-drink/{slug}

A food or drink place's full details and photos.

Request
curl "https://api.parkstack.net/site/v1/food-and-drink/the-mill-restaurant" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/food-and-drink/the-mill-restaurant", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const foodPlace = await response.json();
Example answer (lists cut short)
{
  "slug": "the-mill-restaurant",
  "name": "The Mill Restaurant",
  "summary": "Table-service British cooking in the old mill, with a terrace over the race.",
  "type": "restaurant",
  "typeLabel": "Restaurant",
  "status": {
    "code": "operating",
    "label": "Available",
    "note": null
  },
  "cuisine": "British",
  "location": "Mill courtyard",
  "priceBand": 3,
  "mealPeriods": "Lunch, dinner",
  "hoursNote": "12:00–15:00 and 17:00–20:00",
  "dietary": {
    "vegetarian": true,
    "vegan": true,
    "glutenFree": true
  },
  "reservations": true,
  "servesAlcohol": true,
  "photo": {
    "url": "https://media.parkstack.net/riverside/1787457896122-e66mt0.webp",
    "width": 1408,
    "height": 768,
    "alt": null,
    "srcset": "https://media.parkstack.net/riverside/1787457896122-e66mt0.webp?w=96 96w, https://media.parkstack.net/riverside/1787457896122-e66mt0.webp?w=192 192w, https://media.parkstack.net/riverside/1787457896122-e66mt0.webp?w=384 384w, https://med…"
  },
  "updatedAt": "2026-08-23T04:04:59.224Z",
  "description": "A sit-down restaurant for longer meals. Sunday roast in season, children's portions, and a short wine list.\n\nReservations recommended after 17:00 on Fridays and Saturdays.",
  "descriptionText": "A sit-down restaurant for longer meals. Sunday roast in season, children's portions, and a short wine list. Reservations recommended after 17:00 on Fridays and Saturdays.",
  "photos": [
    {
      "url": "https://media.parkstack.net/riverside/1787457896122-e66mt0.webp",
      "width": 1408,
      "height": 768,
      "alt": null,
      "srcset": "https://media.parkstack.net/riverside/1787457896122-e66mt0.webp?w=96 96w, https://media.parkstack.net/riverside/1787457896122-e66mt0.webp?w=192 192w, https://media.parkstack.net/riverside/1787457896122-e66mt0.webp?w=384 384w, https://med…"
    }
  ],
  "seo": {
    "title": null,
    "description": null
  }
}

Parameters

slugin the path
The food or drink place's web address name, from its list.

Answer

slugstring
The entry's part of its address, as in /explore/attractions/{slug}. Changes when the park renames it: see GET /redirects.
namestring
summarystring or null
One or two plain sentences for cards and lists.
type"restaurant" | "cafe" | "kiosk" | "bar" | "food_truck" | "other"
What kind of place it is.
typeLabelstring
The type in words ("Café").
statusobject
code"operating" | "closed" | "seasonal" | "coming_soon" | "refurbishment" | "unlisted"
Whether guests can use it now. Unlisted entries are left out of lists but still have their own page.
labelstring
The code in words for guests: "Available", "Unavailable", "Seasonal"…
notestring or null
The park's note for guests, or a plain reason, while it is not available.
cuisinestring or null
The park's words ("Pizza and pasta").
locationstring or null
Where it is in the park, in the park's words ("Next to the main entrance").
priceBandinteger or null
1 to 4: show as £ to ££££.
mealPeriodsstring or null
The meals it serves, in the park's words ("Lunch and snacks").
hoursNotestring or null
The park's note on when it is open ("Weekends only"), shown as written.
dietaryobject
Options it offers; false means the park has not said it does.
vegetarianboolean
veganboolean
glutenFreeboolean
reservationsboolean
Whether guests can book a table.
servesAlcoholboolean
photoobject or null
The first photo: the one for cards and lists.
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
updatedAtstring
When it last changed, as an ISO 8601 time in UTC. Useful for sitemaps and caches.
descriptionstring or null
The full description as Markdown: bold, links and bulleted lists only.
descriptionTextstring or null
The same description as plain words, for search results and meta tags.
photosarray of object
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
seoobject
The park's own wording for search results and link previews; when null, use the name and summary.
titlestring or null
descriptionstring or null

Can also answer NOT_FOUND. Cache-Control: public, max-age=60, stale-while-revalidate=300

Shops and facilities

GET/shops-and-facilities

Shops, toilets, first aid, lockers and the like. `isShop` separates shops from the rest.

Request
curl "https://api.parkstack.net/site/v1/shops-and-facilities" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/shops-and-facilities", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const shopsAndFacilities = await response.json();
Example answer (lists cut short)
{
  "items": [
    {
      "slug": "first-aid",
      "name": "First aid",
      "summary": "Trained first aiders, open whenever the park is.",
      "type": "first_aid",
      "typeLabel": "First aid",
      "isShop": false,
      "status": {
        "code": "operating",
        "label": "Available",
        "note": null
      },
      "location": "Next to Guest Services, by the main entrance",
      "hoursNote": "Open whenever the park is",
      "photo": null,
      "updatedAt": "2026-10-20T09:12:44.000Z"
    }
  ]
}

Answer

itemsarray of object
slugstring
The entry's part of its address, as in /explore/attractions/{slug}. Changes when the park renames it: see GET /redirects.
namestring
summarystring or null
One or two plain sentences for cards and lists.
type"shop" | "toilets" | "accessible_toilets" | "baby_change" | "first_aid" | "guest_services" | "lockers" | "cash_machine" | "picnic_area" | "other"
What kind of shop or facility it is.
typeLabelstring
The type in words ("Baby changing").
isShopboolean
Shops are listed apart from other facilities on our site.
statusobject
code"operating" | "closed" | "seasonal" | "coming_soon" | "refurbishment" | "unlisted"
Whether guests can use it now. Unlisted entries are left out of lists but still have their own page.
labelstring
The code in words for guests: "Available", "Unavailable", "Seasonal"…
notestring or null
The park's note for guests, or a plain reason, while it is not available.
locationstring or null
Where it is in the park, in the park's words ("Next to the main entrance").
hoursNotestring or null
The park's note on when it is open ("Weekends only"), shown as written.
photoobject or null
The first photo: the one for cards and lists.
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
updatedAtstring
When it last changed, as an ISO 8601 time in UTC. Useful for sitemaps and caches.

Cache-Control: public, max-age=60, stale-while-revalidate=300

One shop or facility

GET/shops-and-facilities/{slug}

A shop or facility's full details and photos.

Request
curl "https://api.parkstack.net/site/v1/shops-and-facilities/first-aid" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/shops-and-facilities/first-aid", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const facility = await response.json();
Example answer (lists cut short)
{
  "slug": "first-aid",
  "name": "First aid",
  "summary": "Trained first aiders, open whenever the park is.",
  "type": "first_aid",
  "typeLabel": "First aid",
  "isShop": false,
  "status": {
    "code": "operating",
    "label": "Available",
    "note": null
  },
  "location": "Next to Guest Services, by the main entrance",
  "hoursNote": "Open whenever the park is",
  "photo": null,
  "updatedAt": "2026-10-20T09:12:44.000Z",
  "description": "Our first aid team can help with **cuts, bumps and anything else**. Ask any member of staff and they will call them.",
  "descriptionText": "Our first aid team can help with cuts, bumps and anything else. Ask any member of staff and they will call them.",
  "photos": [],
  "seo": {
    "title": null,
    "description": null
  }
}

Parameters

slugin the path
The shop or facility's web address name, from its list.

Answer

slugstring
The entry's part of its address, as in /explore/attractions/{slug}. Changes when the park renames it: see GET /redirects.
namestring
summarystring or null
One or two plain sentences for cards and lists.
type"shop" | "toilets" | "accessible_toilets" | "baby_change" | "first_aid" | "guest_services" | "lockers" | "cash_machine" | "picnic_area" | "other"
What kind of shop or facility it is.
typeLabelstring
The type in words ("Baby changing").
isShopboolean
Shops are listed apart from other facilities on our site.
statusobject
code"operating" | "closed" | "seasonal" | "coming_soon" | "refurbishment" | "unlisted"
Whether guests can use it now. Unlisted entries are left out of lists but still have their own page.
labelstring
The code in words for guests: "Available", "Unavailable", "Seasonal"…
notestring or null
The park's note for guests, or a plain reason, while it is not available.
locationstring or null
Where it is in the park, in the park's words ("Next to the main entrance").
hoursNotestring or null
The park's note on when it is open ("Weekends only"), shown as written.
photoobject or null
The first photo: the one for cards and lists.
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
updatedAtstring
When it last changed, as an ISO 8601 time in UTC. Useful for sitemaps and caches.
descriptionstring or null
The full description as Markdown: bold, links and bulleted lists only.
descriptionTextstring or null
The same description as plain words, for search results and meta tags.
photosarray of object
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
seoobject
The park's own wording for search results and link previews; when null, use the name and summary.
titlestring or null
descriptionstring or null

Can also answer NOT_FOUND. Cache-Control: public, max-age=60, stale-while-revalidate=300

Events

GET/events

Current and upcoming events first, then past ones newest first (`past: true`), with when they are on in words.

  • Show past events apart, as an archive, or leave them out.
Request
curl "https://api.parkstack.net/site/v1/events" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/events", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const events = await response.json();
Example answer (lists cut short)
{
  "items": [
    {
      "slug": "halloween-trail",
      "name": "Halloween Trail",
      "summary": "A family scare trail through the woods. Mild frights, no jump scares on the daytime path.",
      "when": "Weekends, 3 October to 1 November, plus 26 to 30 October, during opening hours",
      "startsAt": "2026-10-02T23:00:00.000Z",
      "endsAt": "2026-11-01T23:59:00.000Z",
      "nextStart": "2026-10-30T10:00:00.000Z",
      "past": false,
      "location": "Pioneer Woods",
      "attraction": {
        "name": "Halloween Trail",
        "slug": "halloween-trail"
      },
      "photo": null,
      "updatedAt": "2026-10-20T21:06:58.561Z"
    },
    {
      "slug": "halloween-fireworks",
      "name": "Halloween Fireworks",
      "summary": "A Halloween fireworks display over the lake to close the season.",
      "when": "Saturday 31 October at 20:00",
      "startsAt": "2026-10-31T20:00:00.000Z",
      "endsAt": "2026-10-31T21:00:00.000Z",
      "nextStart": "2026-10-31T20:00:00.000Z",
      "past": false,
      "location": "Lakeside lawn",
      "attraction": null,
      "photo": null,
      "updatedAt": "2026-10-20T21:07:08.197Z"
    }
  ]
}

Answer

itemsarray of object
slugstring
The entry's part of its address, as in /explore/attractions/{slug}. Changes when the park renames it: see GET /redirects.
namestring
summarystring or null
One or two plain sentences for cards and lists.
whenstring
"Weekends, 3 October to 1 November, during opening hours": on the park's clock.
startsAtstring
First start and last end, as ISO times.
endsAtstring
nextStartstring or null
The next start (a showtime, or the day's opening), or null once it is over.
pastboolean
Over: our site shows these in a separate archive, newest first.
locationstring or null
Where it is in the park, in the park's words ("Next to the main entrance").
attractionobject or null
The attraction it happens at, when the park chose one.
slugstring
namestring
photoobject or null
The first photo: the one for cards and lists.
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
updatedAtstring
When it last changed, as an ISO 8601 time in UTC. Useful for sitemaps and caches.

Cache-Control: public, max-age=60, stale-while-revalidate=300

One event

GET/events/{slug}

An event's full details, every date it is on and its showtimes.

Request
curl "https://api.parkstack.net/site/v1/events/halloween-trail" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/events/halloween-trail", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const event = await response.json();
Example answer (lists cut short)
{
  "slug": "halloween-trail",
  "name": "Halloween Trail",
  "summary": "A family scare trail through the woods. Mild frights, no jump scares on the daytime path.",
  "when": "Weekends, 3 October to 1 November, plus 26 to 30 October, during opening hours",
  "startsAt": "2026-10-02T23:00:00.000Z",
  "endsAt": "2026-11-01T23:59:00.000Z",
  "nextStart": "2026-10-30T10:00:00.000Z",
  "past": false,
  "location": "Pioneer Woods",
  "attraction": {
    "name": "Halloween Trail",
    "slug": "halloween-trail"
  },
  "photo": null,
  "updatedAt": "2026-10-20T21:06:58.561Z",
  "description": "Collect stamps at six points and swap them for a treat bag. An after-dark trail for ages 12 and over runs from 18:30 on late-opening days, 24 October to 1 November.",
  "descriptionText": "Collect stamps at six points and swap them for a treat bag. An after-dark trail for ages 12 and over runs from 18:30 on late-opening days, 24 October to 1 November.",
  "photos": [],
  "dates": [
    "2026-10-03",
    "2026-10-04"
  ],
  "showtimes": [],
  "seo": {
    "title": null,
    "description": null
  }
}

Parameters

slugin the path
The event's web address name, from its list.

Answer

slugstring
The entry's part of its address, as in /explore/attractions/{slug}. Changes when the park renames it: see GET /redirects.
namestring
summarystring or null
One or two plain sentences for cards and lists.
whenstring
"Weekends, 3 October to 1 November, during opening hours": on the park's clock.
startsAtstring
First start and last end, as ISO times.
endsAtstring
nextStartstring or null
The next start (a showtime, or the day's opening), or null once it is over.
pastboolean
Over: our site shows these in a separate archive, newest first.
locationstring or null
Where it is in the park, in the park's words ("Next to the main entrance").
attractionobject or null
The attraction it happens at, when the park chose one.
slugstring
namestring
photoobject or null
The first photo: the one for cards and lists.
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
updatedAtstring
When it last changed, as an ISO 8601 time in UTC. Useful for sitemaps and caches.
descriptionstring or null
The full description as Markdown: bold, links and bulleted lists only.
descriptionTextstring or null
The same description as plain words, for search results and meta tags.
photosarray of object
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
datesarray of string
Every date it is on, YYYY-MM-DD, at most a year's worth.
showtimesarray of string
Showtimes (HH:mm) when it has them, else empty.
seoobject
The park's own wording for search results and link previews; when null, use the name and summary.
titlestring or null
descriptionstring or null

Can also answer NOT_FOUND. Cache-Control: public, max-age=60, stale-while-revalidate=300

Questions and answers

GET/faq

The park's FAQ in its groups and order.

Request
curl "https://api.parkstack.net/site/v1/faq" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/faq", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const faq = await response.json();
Example answer (lists cut short)
{
  "groups": [
    {
      "heading": "Visit",
      "questions": [
        {
          "question": "What time do the gates open?",
          "answer": "Most days we open at 10:00. Sunday is our planned closed day, except during school holidays. Always check opening hours before you travel.",
          "answerText": "Most days we open at 10:00. Sunday is our planned closed day, except during school holidays. Always check opening hours before you travel."
        }
      ]
    },
    {
      "heading": "Rides",
      "questions": [
        {
          "question": "Do you have height restrictions?",
          "answer": "Yes. Each ride page lists a minimum height. Thunder Run is 1.20 m and Sky Drop is 1.30 m. Measuring posts are at the entrance to every ride.",
          "answerText": "Yes. Each ride page lists a minimum height. Thunder Run is 1.20 m and Sky Drop is 1.30 m. Measuring posts are at the entrance to every ride."
        }
      ]
    }
  ]
}

Answer

groupsarray of object
In the order guests see them; questions with no group come first, with a null heading.
headingstring or null
questionsarray of object
questionstring
answerstring
Markdown: bold, links and bulleted lists only.
answerTextstring
The same answer as plain words.

Cache-Control: public, max-age=60, stale-while-revalidate=300

A page

GET/pages/{slug}

A page's words, photos and files: about, accessibility, privacy, ticket-terms and the park's own pages.

  • Show every entry in notices after the page's own words: Privacy and Ticket terms carry parts the law needs that the park does not write itself.
Request
curl "https://api.parkstack.net/site/v1/pages/ticket-terms" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/pages/ticket-terms", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const page = await response.json();
Example answer (lists cut short)
{
  "slug": "about",
  "title": "About Riverside",
  "text": "Riverside Adventure Park opened in 1984 on the site of a Victorian mill. We are an independently run park on the edge of the river valley, with a mix of thrill rides, family coasters and quiet gardens.\n\nOur aim is simple: a clean, well-r…",
  "photos": [],
  "files": [],
  "notices": [],
  "seo": {
    "title": "About Riverside",
    "description": null
  },
  "updatedAt": "2026-08-22T23:38:35.161Z"
}

Parameters

slugin the path
The page's web address name, such as about, privacy or ticket-terms.

Answer

slugstring
The page's address, as in /{slug} ("about", "privacy", "ticket-terms").
titlestring
textstring
The page's words as Markdown (blocks such as galleries and videos are left out in v1).
photosarray of object
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
filesarray of object
Files to download (PDFs and the like).
urlstring
namestring
mimestring
noticesarray of object
Parts Parkstack adds that the page must show after its own words (Privacy and Ticket terms).
headingstring
paragraphsarray of string
seoobject
The park's own wording for search results and link previews; when null, use the name and summary.
titlestring or null
descriptionstring or null
updatedAtstring
When it last changed, as an ISO 8601 time in UTC. Useful for sitemaps and caches.

Can also answer NOT_FOUND. Cache-Control: public, max-age=60, stale-while-revalidate=300

Attraction closures

GET/closures

Attractions unavailable today, and those closed for the season or for refurbishment.

Request
curl "https://api.parkstack.net/site/v1/closures" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/closures", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const closures = await response.json();
Example answer (lists cut short)
{
  "shown": true,
  "temporary": [],
  "scheduled": [
    {
      "slug": "sky-drop",
      "name": "Sky Drop",
      "summary": "A 40-metre drop tower currently closed for winter work.",
      "type": "ride",
      "typeLabel": "Ride",
      "status": {
        "code": "refurbishment",
        "label": "Refurbishment",
        "note": "Closed for refurbishment"
      },
      "isNew": false,
      "height": {
        "minCm": 130,
        "maxCm": null,
        "label": "130 cm and over"
      },
      "minAge": null,
      "photo": {
        "url": "https://media.parkstack.net/riverside/1790631023188-xeqohj.webp",
        "width": 1600,
        "height": 900,
        "alt": null,
        "srcset": "https://media.parkstack.net/riverside/1790631023188-xeqohj.webp?w=96 96w, https://media.parkstack.net/riverside/1790631023188-xeqohj.webp?w=192 192w, https://media.parkstack.net/riverside/1790631023188-xeqohj.webp?w=384 384w, https://med…"
      },
      "updatedAt": "2026-09-28T21:31:43.910Z"
    }
  ]
}

Answer

shownboolean
Whether the park shows this list on its own Parkstack site (Attraction availability switched on).
temporaryarray of object
Unavailable now.
slugstring
The entry's part of its address, as in /explore/attractions/{slug}. Changes when the park renames it: see GET /redirects.
namestring
summarystring or null
One or two plain sentences for cards and lists.
type"ride" | "roller_coaster" | "flat_ride" | "show" | "animal" | "exhibit" | "play" | "walk" | "trail" | "other"
What kind of attraction it is; walk and trail have a distance and terrain.
typeLabelstring
The type in words ("Rollercoaster").
statusobject
code"operating" | "closed" | "seasonal" | "coming_soon" | "refurbishment" | "unlisted"
Whether guests can use it now. Unlisted entries are left out of lists but still have their own page.
labelstring
The code in words for guests: "Available", "Unavailable", "Seasonal"…
notestring or null
The park's note for guests, or a plain reason, while it is not available.
isNewboolean
Show a "New" badge.
heightobject or null
Height limits, inclusive; null when there are none.
minCminteger or null
Riders must be at least this tall.
maxCminteger or null
Riders must be no taller than this.
labelstring
Both limits in words: "110 cm and over", "Up to 130 cm", "100 to 140 cm".
minAgeinteger or null
The youngest age allowed, in years, when the park set one.
photoobject or null
The first photo: the one for cards and lists.
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
updatedAtstring
When it last changed, as an ISO 8601 time in UTC. Useful for sitemaps and caches.
scheduledarray of object
Seasonal or closed for refurbishment.
slugstring
The entry's part of its address, as in /explore/attractions/{slug}. Changes when the park renames it: see GET /redirects.
namestring
summarystring or null
One or two plain sentences for cards and lists.
type"ride" | "roller_coaster" | "flat_ride" | "show" | "animal" | "exhibit" | "play" | "walk" | "trail" | "other"
What kind of attraction it is; walk and trail have a distance and terrain.
typeLabelstring
The type in words ("Rollercoaster").
statusobject
code"operating" | "closed" | "seasonal" | "coming_soon" | "refurbishment" | "unlisted"
Whether guests can use it now. Unlisted entries are left out of lists but still have their own page.
labelstring
The code in words for guests: "Available", "Unavailable", "Seasonal"…
notestring or null
The park's note for guests, or a plain reason, while it is not available.
isNewboolean
Show a "New" badge.
heightobject or null
Height limits, inclusive; null when there are none.
minCminteger or null
Riders must be at least this tall.
maxCminteger or null
Riders must be no taller than this.
labelstring
Both limits in words: "110 cm and over", "Up to 130 cm", "100 to 140 cm".
minAgeinteger or null
The youngest age allowed, in years, when the park set one.
photoobject or null
The first photo: the one for cards and lists.
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
updatedAtstring
When it last changed, as an ISO 8601 time in UTC. Useful for sitemaps and caches.

Cache-Control: public, max-age=60, stale-while-revalidate=300

Old addresses

GET/redirects

Where an old address now goes, after the park renamed or removed something.

  • Ask with your own path. Both path and to are Parkstack guest-site addresses, such as /explore/attractions/{slug}; answer with a permanent redirect (308) to to.
Request
curl "https://api.parkstack.net/site/v1/redirects?path=%2Fexplore%2Fattractions%2Fold-name" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/redirects?path=%2Fexplore%2Fattractions%2Fold-name", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const redirects = await response.json();
Example answer (lists cut short)
{
  "to": "/explore/attractions/dragon-flight"
}

Parameters

pathquery
The old path, starting with /.

Answer

tostring
The path to send the guest to with a permanent redirect.

Can also answer NOT_FOUND. Cache-Control: public, max-age=60, stale-while-revalidate=300

Tickets and checkout

List the tickets, show which days can be booked, start a checkout and send the guest to the payment page. After paying, the guest lands on Parkstack’s confirmation page, or on your returnUrl with ?order=…&t=… for GET /orders/{orderNumber}.

Tickets

GET/tickets

Tickets on sale online with their prices, VAT wording, days covered and re-entry.

  • Prices are in pence and are the total the guest pays. Show them as they are; never add VAT or fees.
  • Show priceOnTheDayPence only as what it is: the price for a dated ticket bought for today.
  • While onSaleOnline is false, offer nothing to buy.
Request
curl "https://api.parkstack.net/site/v1/tickets" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/tickets", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const tickets = await response.json();
Example answer (lists cut short)
{
  "onSaleOnline": true,
  "maxPerOrder": 20,
  "items": [
    {
      "id": "cmt50rksr001uuvf8hycjp0qj",
      "name": "Dated Entry Ticket",
      "description": null,
      "photo": null,
      "pricePence": 2900,
      "priceOnTheDayPence": null,
      "includesVat": false,
      "dated": true,
      "days": 1,
      "dayMode": "consecutive",
      "daysLine": null,
      "validFrom": null,
      "validTo": null,
      "reentryLine": null
    }
  ]
}

Answer

onSaleOnlineboolean
False: tickets are not on sale online now. Hide ticket links and offer nothing to buy.
maxPerOrderinteger
The most tickets one online order may hold, across every line.
itemsarray of object
idstring
Send this in checkout lines.
namestring
descriptionstring or null
Plain words (not Markdown).
photoobject or null
urlstring
The full-size file.
widthinteger or null
In pixels, when known: set width and height on the <img> so the page does not jump.
heightinteger or null
In pixels, when known.
altstring or null
Null means decorative: give it alt="".
srcsetstring or null
For an <img srcset>, when the file can be served at smaller sizes.
pricePenceinteger
What the guest pays, VAT included when charged: show it as the total.
priceOnTheDayPenceinteger or null
Charged instead for a dated ticket bought for today; null when the ticket has one price.
includesVatboolean
Say "inc. VAT" beside the price.
datedboolean
A visit date must be chosen (send visitDate in the checkout line).
daysinteger
Days the ticket covers.
dayMode"consecutive" | "any"
"consecutive" (days in a row from the visit date) or "any" (any days within its valid dates).
daysLinestring or null
"2-day ticket: the day you choose and the day after", or null for a one-day ticket.
validFromstring or null
On sale for visits from and until (YYYY-MM-DD), when limited.
validTostring or null
reentryLinestring or null
"You can leave and come back on the same day.", when the park chose to say so.

Cache-Control: public, max-age=60, stale-while-revalidate=300

Ticket availability

GET/tickets/availability

A month of days: which can be booked for each dated ticket, which are sold out, closed or too late, and when few places are left.

Request
curl "https://api.parkstack.net/site/v1/tickets/availability?month=2026-11" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/tickets/availability?month=2026-11", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const availability = await response.json();
Example answer (lists cut short)
{
  "from": "2026-10-29",
  "to": "2026-10-31",
  "todayCutOff": "19:30",
  "days": [
    {
      "date": "2026-10-29",
      "status": "too_late",
      "label": "Halloween late opening",
      "tickets": [
        {
          "id": "cmt50rksr001uuvf8hycjp0qj",
          "available": false,
          "fewLeft": null
        }
      ]
    },
    {
      "date": "2026-10-30",
      "status": "available",
      "label": "Halloween late opening",
      "tickets": [
        {
          "id": "cmt50rksr001uuvf8hycjp0qj",
          "available": true,
          "fewLeft": null
        }
      ]
    },
    {
      "date": "2026-10-31",
      "status": "available",
      "label": "Halloween late opening",
      "tickets": [
        {
          "id": "cmt50rksr001uuvf8hycjp0qj",
          "available": true,
          "fewLeft": null
        }
      ]
    }
  ]
}

Parameters

monthquery, optional
YYYY-MM; this month when left out. Past months are refused.

Answer

fromstring
tostring
todayCutOffstring or null
Today's last time to buy for today (HH:mm), when the park has one.
daysarray of object
datestring
status"available" | "sold_out" | "closed" | "too_late"
"available", "sold_out", "closed" or "too_late" (today, after the cut-off).
labelstring or null
ticketsarray of object
Each dated ticket on this day. Undated tickets need no day.
idstring
availableboolean
fewLeftinteger or null
Places left when 10 or fewer, else null.

Can also answer BAD_REQUEST. Cache-Control: public, max-age=60, stale-while-revalidate=300

Start a checkout

POST/checkout

Checks the order exactly as Parkstack's own ticket page does, holds the places and answers with Stripe's payment page. Up to 20 tickets an order.

  • Send the guest to url. Card details are only ever typed on Stripe's page: never collect them yourself.
  • Show the refusal's message to the guest as it is: it is written for them.
  • Before the button, link the Ticket terms and say who the guest is buying from (seller on /park).
  • Keep orderNumber and linkToken: with them GET /orders/{orderNumber} shows the tickets, with no return address needed. A phone app leaves out returnUrl and cancelUrl and reads the order when the guest closes Stripe's page.
Request
curl -X POST https://api.parkstack.net/site/v1/checkout \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey" \
  -H "Content-Type: application/json" \
  -d '{"email":"guest@example.com","lines":[{"ticketId":"cmt50rksr001uuvf8hycjp0qj","quantity":2,"visitDate":"2026-10-30"}]}'
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/checkout", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "email": "guest@example.com",
    "lines": [
      {
        "ticketId": "cmt50rksr001uuvf8hycjp0qj",
        "quantity": 2,
        "visitDate": "2026-10-30"
      }
    ]
  }),
});
const answer = await response.json();
if (!response.ok) throw new Error(answer.message); // written for the guest
// Keep answer.orderNumber and answer.linkToken, then send the guest to answer.url.
Example answer (lists cut short)
{
  "url": "https://checkout.stripe.com/c/pay/cs_live_a1B2c3…",
  "demo": false,
  "orderNumber": "RIV-2026-000123",
  "linkToken": "q8Zt3VnK0wXyR5mJ2hLc7PbD"
}

Request body (JSON)

emailstring
The guest's email address: their tickets are sent there.
namestring or null, optional
Required when the park asks for it at checkout; the refusal says so.
phonestring or null, optional
postcodestring or null, optional
linesarray of object
ticketIdstring
A ticket's id from GET /tickets.
quantityinteger
visitDatestring or null, optional
YYYY-MM-DD, for a dated ticket; leave out for an undated one.
discountCodestring or null, optional
A discount code the guest typed; refused with a plain message when it does not apply.
voucherCodestring or null, optional
A gift voucher code; its balance pays first and Stripe takes the rest.
returnUrlstring or null, optional
Where the guest lands after paying, on one of the key's own website addresses; it gains ?order=…&t=… for GET /orders/{orderNumber}. Leave out to use Parkstack's confirmation page.
cancelUrlstring or null, optional
Where "Back" on the payment page goes; one of the key's own addresses. Leave out for Parkstack's ticket page.

Answer

urlstring
Send the guest here: Stripe's payment page, or the confirmation page when nothing is to pay.
demoboolean
A demonstration park: no payment, and the tickets are not valid.
orderNumberstring or null
The order this checkout made. With linkToken, read it from GET /orders/{orderNumber}?t=… until its status is PAID. Null on a demonstration park, which makes no order.
linkTokenstring or null
The order's private link code, for GET /orders/{orderNumber}?t=…. Keep it with the order on the guest's device only: it opens their tickets.

Can also answer BAD_REQUEST, SALES_CLOSED. Cache-Control: no-store

An order

GET/orders/{orderNumber}

An order after checkout, with a QR code per ticket once paid. Needs the link token the guest returned with.

  • While status is PENDING the payment is still being confirmed: ask again every few seconds. Never offer to pay again.
Request
curl "https://api.parkstack.net/site/v1/orders/RIV-2026-000123" \
  -H "Authorization: Bearer pk_live_demoRiversideParkstackSiteApiKey"
JavaScript
const response = await fetch("https://api.parkstack.net/site/v1/orders/RIV-2026-000123", {
  headers: { Authorization: `Bearer ${process.env.PARKSTACK_SITE_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).message);
const order = await response.json();
Example answer (lists cut short)
{
  "orderNumber": "RIV-2026-000123",
  "status": "PAID",
  "totalPence": 5800,
  "currency": "GBP",
  "lines": [
    {
      "name": "Dated Entry Ticket",
      "quantity": 2,
      "unitPence": 2900,
      "visitDate": "2026-10-30",
      "lastVisitDate": "2026-10-30"
    }
  ],
  "tickets": [
    {
      "ticketNumber": "RIV-2026-000123-1",
      "name": "Dated Entry Ticket",
      "visitDate": "2026-10-30",
      "refunded": false,
      "qrPayload": "PARKSTACK:TICKET:RIV-2026-000123-1:K7QF2M9XWD4H"
    },
    {
      "ticketNumber": "RIV-2026-000123-2",
      "name": "Dated Entry Ticket",
      "visitDate": "2026-10-30",
      "refunded": false,
      "qrPayload": "PARKSTACK:TICKET:RIV-2026-000123-2:P3RN8VTC6JYB"
    }
  ],
  "confirmationUrl": "https://riverside.parkstack.net/tickets/success?order=RIV-2026-000123&t=…"
}

Parameters

orderNumberin the path
`orderNumber` from POST /checkout, or ?order= on the address the guest returned to.
tquery
`linkToken` from POST /checkout, or &t= on the address the guest returned to.

Answer

orderNumberstring
status"PENDING" | "PAID" | "PARTIALLY_REFUNDED" | "REFUNDED" | "CANCELLED" | "FAILED"
PENDING: payment not confirmed yet, ask again. PAID or PARTIALLY_REFUNDED: show the tickets. CANCELLED or FAILED: not paid (the guest left the payment page, or it expired).
totalPenceinteger
What the guest paid, in pence.
currencystring
linesarray of object
namestring
The ticket's name.
quantityinteger
unitPenceinteger
The price paid for each, after any discount code.
visitDatestring or null
YYYY-MM-DD for a dated ticket.
lastVisitDatestring or null
The last day a multi-day ticket covers.
ticketsarray of object
One per guest once paid. Draw qrPayload as a QR code; null once refunded.
ticketNumberstring
Printed under the QR code; staff can type it at the gate.
namestring
The ticket's name.
visitDatestring or null
refundedboolean
A refunded ticket cannot be used: show it as refunded, without a QR code.
qrPayloadstring or null
Draw this text as a QR code, exactly as given.
confirmationUrlstring
Parkstack's confirmation page for this order, with the QR codes.

Can also answer NOT_FOUND. Cache-Control: private, no-store

Errors

A refusal is { code, message } with no-store. React to the code; show the message to guests, who it is written for. Any request can be refused with KEY_MISSING, KEY_INVALID, ORIGIN_NOT_ALLOWED, RATE_LIMITED, SITE_OFFLINE.

KEY_MISSING401
No key was sent. Send it as Authorization: Bearer pk_live_…
KEY_INVALID401
The key is not one Parkstack knows, or the park's owner has turned it off.
ORIGIN_NOT_ALLOWED403
A browser called from a website address the key does not list. Call from your server, or ask the park's owner to add the address.
RATE_LIMITED429
Too many requests this minute. Wait for Retry-After seconds, and cache what you read.
SITE_OFFLINE503
The park's website is offline (its owner took it offline, or its plan ended). Show a short holding message.
NOT_FOUND404
Nothing published at that address.
BAD_REQUEST400
Something in the request is wrong; the message says what, in words a guest can read.
SALES_CLOSED409
Tickets are not on sale online at the moment.