Please make sure you read the Conventions before continuing with this guide.
Prerequisites
You will need an X-API-KEY and a Basic Access Authentication token generated by the username and password of a back-office user or a web-sales customer.
Steps to complete a ticket cancellation
1) Getting cancellable items in a transaction
First, you need to know which items are cancellable and their respective _id
and product family to make a cancellation. This endpoint will also return some basic information about each item to allow for a simple way to display the items in a list.
You will interact with the /operations/transactions/{transactionId}/cancellable-items endpoint.
This will return an array of items grouped by product family.
Response:
{
"tickets": [
{
"_id": "507f191e810c19729de860ea",
"accountId": "507f191e810c19729de86000",
"availableUses": 1,
"cancellable": true,
"channel": "backoffice",
"createdAt": {
"value": "2022-10-03T16:02:52.716Z",
"offset": 0
},
"displayTotal": 1130000,
"departureTime": "01:10",
"expirationDate": {
"value": "2022-10-11T00:00:00.000Z",
"offset": 0
},
"departureTimestamp": "2022-10-11T05:10:00.000Z",
"isExpirationDateCalculated": false,
"expire": 60,
"expireUnit": "days",
"fare": "Adult",
"firstName": "S",
"from": "Alban",
"lastName": "N",
"productFamily": "reservation",
"productType": "reservation",
"refId": "",
"status": "paid",
"ticketNumber": "A4NAG8",
"to": "Barrie",
"total": 1130000,
"trxId": "507f191e810c19729de860ee",
"expired": false
}
],
"flexPasses": [],
"reservations": [],
"parcels": [],
"fees": [],
"soldItems": [],
"insurances": [],
"redeemableItems": [],
"giftCertificates": []
}
After getting the cancellable items you only have to remember the _id
field and the product family (the key of each array) for each item as you will need it for the next step.
Possible causes for items not showing up as cancellable:
· Item is already canceled
· Item is expired (past departure date or cutoff times)
· Unpaid item
· No available uses left
· Redeemed item
· Gift certificate used at least once
· Parcel has been scanned
Note: If the query param displayAll
is set, it will return all items whether they are cancellable or not. In the case of a non-cancellable _id
being passed to the next step, it will return an error.
2) Creating a cancel set
After getting all the cancellable item _id
values and keys from the previous step, we now need to create a cancel set. This cancel set will return the item details, calculated values, applied fees and refund payment details.
For this step, you will now interact with the /sales/cancellations POST
endpoint.
When successful, a cancel set JSON object will be returned.
Response:
{
"_id": "507f191e810c19729de860ea",
"cancellation": {
"trxId": "507f191e810c19729de860ee",
"transactionId": "ABCDFG12",
"customerNumber": "123-456-789",
"tickets": [
{
"_id": "507f191e810c19729de860ea",
"trxId": "507f191e810c19729de860ee",
"accountId": "507f191e810c19729de86000",
"ticketNumber": "ABCDEF",
"ticketId": "507f191e810c19729de860ea",
"productFamily": "ticket",
"productType": "ticket",
"productId": "507f191e810c19729de860ea",
"totalRefundable": 6150000,
"displayTotalRefundable": 6150000,
"rounding": {
"policy": "default",
"decimals": "2"
},
"fareClassId": null,
"fees": [],
"taxes": [],
"status": "paid",
"ratios": [
{
"type": "cash",
"total": 6260000,
"displayTotal": 6260000,
"extraInfo": null
}
],
"cancelFees": [
{
"calculated": 615000,
"_id": "507f191e810c19729de860ea",
"userId": "507f191e810c19729de860ea",
"accountId": "507f191e810c19729de860ea",
"internalId": "Example cancel fee",
"name": "Example cancel fee",
"valueType": "%",
"value": 10000,
"taxable": true,
"isRefundable": true,
"valueToDisplay": "10",
"displayCalculated": 615000,
"taxes": [
{
"name": "ontax",
"value": 5000,
"province": "Ontario",
"calculated": 28000,
"displayCalculated": 28000
},
{
"name": "Universal all state tax",
"value": 5000,
"province": "all",
"calculated": 28000,
"displayCalculated": 28000
}
],
"taxesTotal": 56000,
"displayTaxesTotal": 56000
}
],
"expirationDate": {},
"expiryDate": null,
"price": 4590000,
"total": 6260000,
"displayPrice": 4590000,
"displayTotal": 6260000,
"subTotal": 0,
"totalTaxes": 560000,
"displaySubTotal": 0,
"displayTotalTaxes": 560000,
"flexPassOptions": {},
"currentScansPerDay": {},
"availableUses": 1,
"totalCancelFees": 615000,
"displayTotalCancelFees": 615000,
"createdFromFlexpassId": null,
"payment": [
{
"provider": "inperson",
"type": "cash",
"ticketNumber": "ABCDEF",
"amount": 5535000,
"acceptedCurrencyAmount": 5535000,
"percentage": 100
}
],
"refunded": 5535000,
"displayRefunded": 5535000,
"itemType": "reservation",
"totalRefundablePreTax": 5590000,
"displayTotalRefundablePreTax": 5590000
}
],
"reservations": [],
"soldItems": [],
"flexPasses": [],
"redeemableItems": [],
"giftCertificates": [],
"parcels": [],
"insurances": [],
"trxFees": [],
"cancelFees": [
{
"internalId": "cExample ancel fee",
"name": "Example cancel fee",
"calculated": 616000,
"displayCalculated": 616000,
"taxesTotal": 56000,
"value": 10000,
"valueType": "%"
}
],
"overridedCancelFees": [],
"displayCurrency": {
"isocode": "USD",
"symbol": "$",
"buy": 1,
"sell": 1,
"channels": [
"backoffice"
]
},
"penalty": {
"amount": 0,
"acceptedAmount": 0,
"reason": ""
},
"payments": [
{
"_id": "a1b2c3d4-abdc-abcd-1234-a1b2c3d4f555",
"method": "cash",
"provider": "inperson",
"displayName": "cash",
"firstName": "FirstName",
"lastName": "LastName",
"currency": "USD",
"card": "",
"authorization": "",
"amount": "55.44",
"acceptedCurrencyAmount": "55.44",
"feesAndPenaltyAmount": "6.16",
"displayFeesAndPenaltyAmount": "6.16",
"feesAndPenaltyAmountValue": 616000,
"displayFeesAndPenaltyAmountValue": 616000,
"amountValue": 5544000,
"acceptedCurrencyAmountValue": 5544000
}
],
"channel": "backoffice"
},
"signature": "86734655de9f997daddb61927f1a4111918d777493d748300689c0b0a55a87c899cad21b0b08c80a3c534b687cedf5ff"
}
This is a preview of what is about to get refunded among the refundable total amounts. Each item will contain all applied cancellation fees and taxes.
The cancel set is read-only and is later used to perform the cancellation of tickets and the refund of payments. If you modify the object, the next step will return an error due to the signature not matching the object sent.
If you need to change the selected items, you can simply repeat this step.
Note: When using a customer JWT, overriding cancel fees or adding penalties is not allowed.
2.1) Adding a penalty (optional)
If you need to add a penalty, you need to set the penalty amount at penalty.amount
in the current station or base currency, in this example we will add a $10 USD penalty.
Note: The user performing the cancellation must have permission to apply penalties and the account must enable arbitrary refunds.
2.2) Overriding a cancel fee (optional)
If you need to prevent one or many cancel fees from applying to this cancellation, you must provide each fee's internalId
field along with a reason text as reason
.
Note: The user performing the cancellation must have permission to override cancel fees.
3) Complete the cancellation
After getting a successful cancel set, executing the cancellation is as easy as just sending the unmodified JSON response you got in the previous step as a PUT
request.
For this step, you will now interact with the /sales/cancellations PUT
endpoint.
When successful, a new transaction
will be returned in the response.
Notes
At the moment it is only possible to refund a single online payment at a time. If there are multiple online payment methods in the same operation and no override payment was provided, the cancellation will not be performed and will return an error.
Postman resources
If you would like to use Postman to test the API, we have included a collection you can use as a starting point below.
This collection is designed to allow you to perform a cancellation, by following the steps above. To use it successfully, you will need your X-API-KEY, JWT Token, a cancellable transaction ID and data (like stations, purchases, payment types and so on) set up for your account.
After importing the collection, and the environment, make sure your collection is using the new environment, and that you have set the initial values.
On each step, each pre-script and test script will populate environment variables needed for the next step, you will only need to set the transactionId manually.
If you are going to be using our API in sandbox, please change the {{basePath}} environment variable to https://sandbox-api.betterez.com.