accessoticketing-mcp

Read accesso-powered mobile ticket links (accessoticketing.com media-engine URLs from confirmation emails) — order number, per-ticket product, participant, date/time, barcodes, Google Wallet passes — with curl.

Install

openclaw skills install @chrischall/accessoticketing-mcp

accesso tickets

For accesso Passport mobile-ticket links, which look like:

text
https://media-engine.<region>.accessoticketing.com/tickets/v1/<island>?oToken=A1:…&cToken=A1:…&merchant_id=<n>

Many venues deliver tickets this way (US National Whitewater Center, theme parks, festivals). The link arrives in the order-confirmation email, often behind a click-tracker — resolve that first with curl -sSIL <tracking-url> | grep -i ^location.

No login, no browser bridge. The oToken in the URL is the credential, and the page is plain-curl reachable server-side. Treat the URL as a secret: it grants anyone the order's tickets and barcodes. Never paste one into a file, a commit, or an issue.

Core pattern

references/parse-tickets.mjs is dependency-free (no node_modules) and takes a URL, a file, or - for stdin:

bash
P=~/.claude/skills/accesso-tickets/references/parse-tickets.mjs
node "$P" "$TICKET_URL" | jq .

Useful flags:

  • --barcodes <dir> — write each ticket's barcode as a PNG (ticket-<idx>-<ticketId>.png) and add barcodeFile to the output.
  • --terms — include the (long, boilerplate, per-ticket-identical) termsAndConditions. Omitted by default.
  • --url <original-url> — supply the source URL when parsing a saved file, so googleWalletUrl can be built.

Exit codes: 3 no tickets parsed (expired link, or layout drift — the message says which), 4 HTTP error fetching, 64 bad usage.

Output

Top level: orderNumber, island, merchantId, merchantLogo, ticketCount, declaredTicketCount, tickets[].

Per ticket: index, ticketId, packageName, participant, additionalGuests[], date, time (absent on all-day items), barcodeText, barcodeIsDataUrl, instructions, googleWalletUrl, plus any other label/value pair the merchant rendered (commonly guestNumber, webSalesId).

Extra fields are harvested generically from the page's label/value markup rather than hardcoded, so a merchant with different detail rows still comes through. See references/recipes.md for jq recipes and the verified request shapes.

Gotchas

  • An expired or invalid link returns HTTP 200, not 4xx — the body just says "no tickets available to print on this order." Status alone never tells you the link is dead; the parser checks the body and says so.
  • Every ticket is rendered twice (a mobile ticket-item-container<N> grouping and a desktopTicketGrouping one) sharing barcode element ids. Parse only the mobile blocks or you get doubles.
  • ticketId lives in neither rendering — it is in the trailing "Register this ticket" modal section, one hidden input per ticket in ticket order. The parser maps it positionally and omits it (with a warning) if the counts disagree, rather than guessing.
  • date/time are the merchant's local wall-clock strings (MM/DD/YYYY, 9:00 AM) with no timezone. Don't convert them.
  • Barcodes are inline base64 PNGs of the same order-level code (%RC<order>), not per-ticket unique on every merchant.