Sell event tickets
Put a Get a ticket button on an event page and issue a ticket only after your system has confirmed the order. This example is for a one-day workshop with an offer slug of spring-workshop-ticket.
1. Set up the ticket checkout
- Create a ticket product and price in Plandalf. Connect the intended payment integration and check whether the offer is configured for sandbox or live checkout.
- Create an offer for that ticket. Set the customer details you need for admission, check its confirmation behavior, and publish it as
spring-workshop-ticket. - Preview the offer. Check the event name, ticket price, currency, tax and any quantity or add-on options. Keep the published offer slug for your site code.
Your event page should still carry the date, venue, and admission information. The offer handles the buying flow; your ticketing system handles capacity and issuing tickets.
2. Connect the event page
Replace https://your-org.plandalf.dev with your organization's host. Pick one of these ways to open the same ticket offer.
<script defer src="https://your-org.plandalf.dev/js/plandalf-sdk.js"></script>
<button data-plandalf-present="spring-workshop-ticket">Get a ticket</button>The script binds the button. HTML has no awaited checkout result; use your server's purchase record to issue the ticket.
import { Plandalf } from '@plandalf/sdk'
const sdk = new Plandalf({ apiBase: 'https://your-org.plandalf.dev' })
const button = document.querySelector('#get-ticket')
const message = document.querySelector('#ticket-message')
button.addEventListener('click', async () => {
button.disabled = true
try {
const result = await sdk.present('spring-workshop-ticket')
message.textContent = result.status === 'complete'
? 'Checkout finished. We are confirming your ticket.'
: 'You can come back for a ticket later.'
} catch {
message.textContent = 'Checkout could not open. Please try again.'
} finally {
button.disabled = false
}
})<button id="get-ticket">Get a ticket</button>
<p id="ticket-message" role="status"></p>import { useState } from 'react'
import { PlandalfProvider, usePresent } from '@plandalf/react'
function TicketButton() {
const { present, presenting } = usePresent()
const [message, setMessage] = useState('')
async function getTicket() {
try {
const result = await present('spring-workshop-ticket')
setMessage(result.status === 'complete'
? 'Checkout finished. We are confirming your ticket.'
: 'You can come back for a ticket later.')
} catch {
setMessage('Checkout could not open. Please try again.')
}
}
return <>
<button disabled={presenting} onClick={getTicket}>Get a ticket</button>
<p role="status">{message}</p>
</>
}
export function EventPage() {
return <PlandalfProvider apiBase="https://your-org.plandalf.dev">
<TicketButton />
</PlandalfProvider>
}3. Verify the ticket handoff
- Dismiss checkout. No ticket should be issued. Confirm the page is using the intended payment environment before proceeding; a
mode: 'test'override can fall back to live for public visitors. - With an offer and integration explicitly configured for sandbox use, complete a provider-supported test payment. The JavaScript or React page can show a pending confirmation message from
status: 'complete'. - Have your server verify the purchase in your payment/order records, record the ticket against that order, and send the admission confirmation once. Test the same order arriving twice so it does not issue two tickets.
- Recheck the event page and the confirmation email or ticket in the test environment. The browser completion result alone is not a ticket record.
For an early price, add promo tiers and pass the promo slug to present(). For a complete event example, see Sell tickets to an event. Exact checkout inputs and outcomes are in present() and FlowResult.