Quick Start¶
This page is intended as a quick introduction to pyticketswitch. As such we won’t cover all the options and things you can do, just a brief end to end transaction into a test system.
For the purposes of this example we will use the demo credentials:
user_id: demo
password: demopass
If/when you want to play with real products then drop us a line at commercial@ingresso.co.uk
Ensure that you have pyticketswitch properly installed before continuing.
The Client¶
The pyticketswitch wrapper is focused around the
Client
. Begin by importing it, and
instantiating it with your credentials:
>>> from pyticketswitch import Client
>>> client = Client('demo', 'demopass')
We will use this client for the rest of this example. If you lose it somehow (for example by closing your terminal), just instantiate a new one and continue where you left off. The client holds no relevant state other than the authentication credentials.
Finding Events¶
The top level object exposed by the API is the
Event
object and the primary way of
finding events is
list_events()
:
>>> events, meta = client.list_events()
>>> events
[
<Event 6KS: 1-Day Ticket>,
<Event 6IF: Matthew Bourne's Nutcracker TEST>,
<Event 6KT: 3-Day Hopper>
...
]
Note
list_events
is paginated, as such by default the response will only contain 50
results. See Pagination for more information.
This method will take a number of additional parameters that filter and expand the results. See Searching for an event for more information
The demo account has access to a handful of fake events and performances that should demonstrate most of the common capabilities of the system. For more information see Demo user events
For the rest of this guide we are going to focus on just a single event
6IF: Matthew Bourne's Nutcracker TEST
If you already have and event ID (the 6IF
bit) you can query it directly
with the get_event(event_id)
method:
>>> client.get_event('6IF')
<Event 6IF:Matthew Bourne's Nutcracker TEST>
Events have a number of useful attributes from geographic location to critic
reviews. See the Event
’s documentation
for more details.
For the time being all we need to know about this event is that it
is_seated
, it
has_performances
, and
it needs_performance
to book.
Performances¶
To see available performances for a given event we can use the
list_performances(event_id)
client method:
>>> performances, meta = client.list_performances('6IF')
>>> performances
[<Performance 6IF-A86: 2017-02-03T19:30:00+00:00>,
<Performance 6IF-A88: 2017-02-05T19:30:00+00:00>,
...,
<Performance 6IF-B1H: 2017-06-02T19:30:00+01:00>]
Note
list_performances
is paginated, as such by default the response will only contain 50
results. See Pagination for more information.
For the rest of this guide we will focus on the performance furthest from today
6IF-B1H
.
Like with events you can use the
get_performance(performance_id)
method to retrieve a specific performance when you have the performance ID:
>>> client.get_performance('6IF-B1H')
<Performance 6IF-B1H: 2017-06-02T19:30:00+01:00>
Warning
The performance might have passed by the time you read this, if it has then just select another event from the list. Try and make sure it is not a Saturday, as this will break (intentionally) at later stages.
See Performance
Documentation
for more information on performances. All we need for now is the
Performance.id
attribute.
Availability¶
Now that we have an Event
and a
Performance
, we need to find
out what tickets and prices are available:
>>> ticket_types, meta = client.get_availability('6IF-B1H')
>>> ticket_types
[<TicketType CIRCLE: Upper circle>,
<TicketType STALLS: Stalls>,
<TicketType BALCONY: Balcony>]
get_availability
returns
a list of TicketTypes
and an
AvailabilityMeta
object.
A ticket type can be generally considered to be a part of house, or part of a venue. Each ticket type will contain a list of one or more price bands:
>>> ticket_type = ticket_types[0]
>>> ticket_type.price_bands
[<PriceBand A/pool>, <PriceBand B/pool>, <PriceBand C/pool>]
>>> price_band = ticket_type.price_bands[0]
>>> price_band.availability
6
>>> price_band.combined_price()
35.0
Availability indicates the number of tickets available in this price band.
The combined price is made up of the seatprice (or the facevalue) and the surcharge (or booking fee) of a ticket.
The meta object contains aggregate information relevant to the ticket types and their children. For example it contains information on the currency the tickets are priced in and what are valid quantities available:
>>> meta.valid_quantities
[2, 3, 4, 5]
>>> meta.currency
<Currency gbp>
Our event is seated but we are unable to reserve individual seats. However some events do allow this, see requesting seat availability for more information.
For now all we need to continue is a
TicketType.code
and a
PriceBand.code
so pick one
of each.
Discounts¶
Tickets often have a range of discounts that can be applied to them. Usually these represent a concession that can be applied to a ticket. For example, the ticket might have reduced prices for children or students:
>>> discounts, meta = client.get_discounts(
... '6IF-B1H',
... ticket_type.code,
... price_band.code
... )
...
>>> discounts
[<Discount ADULT:Adult standard>,
<Discount CHILD:Child rate>,
<Discount STUDENT:Student rate>,
<Discount OAP:Senior citizen rate>]
Note
The default discount for a price band is usually the most expensive option and can be considered to be the standard price of the ticket inside a price band.
Each discount has the explicit price of the ticket when applied to it’s parent price band:
>>> for discount in discounts:
... print(discount.code, discount.combined_price())
...
...
ADULT 35.0
CHILD 18.0
STUDENT 26.0
OAP 28.0
In addition to the available discounts The
get_discounts()
call
will return a
meta object
that will contain
information about the currency of the prices contained in the discounts
response.
Keep the list of discounts around or make a note of the
Discount.code
for adults and
children (we will need when it comes to making a reservation).
Send Methods¶
After purchasing tickets there are often multiple ways for customers to receive
their tickets, and these may have additional costs associated with them. We
refer to this as a SendMethod
.
For example an E-Ticket might be free but posting the ticket in the mail might have an associated charge:
>>> send_methods, meta = client.get_send_methods('6IF-B1H')
>>> send_methods
[<SendMethod COBO:Collect from the venue>,
<SendMethod POST:Post (UK & Ireland only)>]
>>> for send_method in send_methods:
... print(send_method.code, send_method.cost)
...
...
COBO 1.5
POST 3.5
Warning
It’s important to check send methods before attempting a reservation as certain send methods might become unavailable as one gets closer to the performance date. For example it might take up to five working days to ship a physical ticket internationally so that send method would not be available with 2 days to go before a performance as the ticket would not get to it’s destination in time.
Some tickets may have restrictions on what countries they are available to:
>>> send_methods[1].description
'Post (UK & Ireland only)'
>>> send_methods[1].permitted_countries
[<Country ie:Ireland>, <Country uk:United Kingdom>]
Note
Send methods with additional costs apply to the whole order not indivual tickets. For example purchasing five tickets to the same show will cost the same to post as purchasing one ticket. Tickets for seperate shows by different suppliers may incur multiple send method costs; see Trollies, Bundles, Orders, and Ticket Orders for more information.
In addition to the available send methods The
get_send_methods()
call
will return a
meta object
that will contain
information about the currency of the prices contained in the send methods
response.
We now have all the information we need to make a reservation; the ticket type,
price band, discount, and a
SendMethod.code
!
Making a Reservation¶
Before making a purchase we have to reserve the tickets. Ingresso is often not the only agent connected to a ticketing system and you are almost certainly not the only user these tickets are available to. As such it’s important to put a lock on the tickets your customer is interested in so that they are not snaffled up by some other customer.
For this example we are going to attempt to reserve 3 tickets (two adults and
one child) for 6IF-B1H
. To do this we make a reservation providing the
information that we gained from the previous performance, availability,
discounts and send method calls:
>>> performance.id
'6IF-B1H'
>>> ticket_type.code
'CIRCLE'
>>> price_band.code
'A/pool'
>>> adult, child, *_ = discounts
>>> adult.code
'ADULT'
>>> child.code
'CHILD'
>>> reservation, meta = client.make_reservation(
... performance_id=performance.id,
... ticket_type_code=ticket_type.code,
... price_band_code=price_band.code,
... number_of_seats=3,
... discounts=[
... adult.code,
... adult.code,
... child.code
... ]
... )
...
Was the reservation successful? The returned reservation object contains a
Trolley object
that will give
us some information:
>>> trolley = reservation.trolley
>>> trolley
<Trolley uuid:ee39656e-ecc9-11e6-87c4-0025903268a0>
The trolley object contains three important bits of information.
The presence of a
transaction_uuid
lets
us know that we were at least somewhat successful in our reservation attempt.
It’s a unique identifier that will allow us to get the status of our
reservation/transaction going forwards:
>>> transaction_uuid = trolley.transaction_uuid
'ee39656e-ecc9-11e6-87c4-0025903268a0'
Although we have put a lock on these tickets this lock will not last forever before it’s released and become available for someone else to purchase. As such it’s import to check how long we have to make a purchase before our reservation expires:
>>> trolley.minutes_left
13.2
Note
This time varies across systems, events and performances, so be sure check this after making a reservation and ensure you make your customer aware that they are on the clock.
Lastly our trolley object will contain some
Bundles
.
Bundles
group our orders by the
ticketing system they are being made into:
>>> trolley.bundles
[<Bundle ext_test0>]
>>> bundle = trolley.bundles[0]
As we are making a single order from a single system we don’t care overly much about bundles, all we really need to know is that it contains the currency, total price, and more detailed information of our order:
>>> bundle.currency
<Currency gbp>
>>> bundle.total
89.5
>>> bundle.orders
[<Order 1>]
So what did we actually reserve? Lets inspect the
Order
:
>>> order = bundle.orders[0]
>>> order.event.id
'6IF'
>>> order.performance.id
'6IF-B1H'
>>> order.ticket_type_code
'CIRCLE'
>>> order.price_band_code
'A/pool'
>>> order.number_of_seats
3
Excellent we got the all the stuff we asked for! But wait there’s more! Our event is seated so we should have been allocated the specific seat that we will be purchasing:
>>> order.get_seats()
[<Seat ZT149>, <Seat ZT148>, <Seat ZT147>]
This is just a simple reservation, but the system can handle much more complex orders to multiple systems, in multiple currencies, and to multiple events and performances. If you are interested in package deals or up-selling then you should probably take a look at Bundling.
Note
We have glossed over a lot of information contained in the above objects with the aim of getting you purchasing quickly, if you want more information then have a read of Trollies, Bundles, Orders, and Ticket orders .
The only thing we need to carry on to the next steps is the
transaction_uuid
that
identifies our reservation, so make a note of it.
Making a Purchase¶
The final step in the transaction process is actually give us money and for us to tell the supplier to put a hold on the requested tickets permanently.
There are a number of different payment methods available but for the time being we will focus on the most common; credit. This where we take nothing from you at the time of purchase and invoice you at a later date for the amount you owe! This also happens to be the simplest payment method.
Note
There are other payment methods that you might come across. So it’s a good idea to read Taking payments before going live.
Before we can continue we need to gather some information about the customer that we are selling to:
>>> from pyticketswitch.customer import Customer
>>> customer = Customer(
... first_name='Fred',
... last_name='Flintstone',
... address_lines=['301 Cobble stone road', 'Bolder Lane'],
... country_code='us',
... email='fred@slate-rock-gravel.com',
... post_code='70777',
... town='Bedrock',
... county='LA',
... phone='0110134345'
...)
The required fields are
the customers first
and
last
name,
at least one line of a
postal address
,
the country code
for
the postal address,
a contact phone number
and unless otherwise specified by the
Reservation.needs_email_address
field a valid email address
.
You may provide additional information about the customer as you see fit, but the more information we have the easier it will be for us or the venue to contact them in case of a problem, and it also allows us to protect both you and us from fraudulent transactions. Here is our privacy policy.
You can also specify who we can send this information to with the
supplier_can_use_data
(generally recommened),
user_can_use_data
(this is your organisation, for example in reporting, or by email),
world_can_use_data
(in my opinion this should always be off), flags.
With our customer object in hand we can now make the purchase:
>>> status, callout, meta = client.make_purchase(
... transaction_uuid,
... customer,
...)
For the time being we can can ignore the callout, just check that we don’t have one:
>>> assert not callout
Assuming no errors were raised, that’s it! Your tickets are booked!
The status object should contain information about your purchase:
>>> status.status
'purchased'
>>> status.trolley.transaction_id
'T000-0000-8MU2-Z5E4'
>>> status.trolley.bundles[0].total
118.5
>>> status.trolley.bundles[0].orders[0].backend_purchase_reference
'PURCHASE-17461-1'
>>> status.trolley.bundles[0].orders[0].get_seats()
[<Seat GB506>, <Seat GB505>, <Seat GB504>]
Retrieving Transactions¶
If at any point in the process you need to retrieve the status of a transaction
or reservation you can do so using the Client.get_status
call and the transaction_uuid:
>>> status, meta = client.get_status('ee39656e-ecc9-11e6-87c4-0025903268a0')
>>> status.status
'purchased'
Ready for more? Check out the advanced section.