Redemption

Redeem tickets and bookings by reference or barcode

To use this capability add octo/redemption to your Octo-Capabilities header.

This capability allows a supplier to redeem tickets using a barcode or reference number. It's not enabled by default and not available or intended for resellers.

Products

GET https://api.ventrata.com/octo/products

This endpoint isn't specific to this capability as it's part of the OCTO core, but worth mentioning as it will return a list of products that the redemption lookup and redeem endpoints might return. This is important if you need to know what products, options and units to expect and map them in advance.

[
  {
    "id": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
    "internalName": "Walking Tour of Barcelona",
    "reference": "BRC-WALK",
    "locale": "en",
    "timeZone": "Europe/Madrid",
    "allowFreesale": true,
    "availabilityType": "START_TIME",
    "deliveryFormats": ["PDF_URL", "QRCODE"],
    "deliveryMethods": ["TICKET", "VOUCHER"],
    "redemptionMethod": "DIGITAL",
    "capabilities": [
      {
        "id": "octo/content",
        "revision": 1,
        "required": false,
        "dependencies": []
      },
      {
        "id": "octo/cart",
        "revision": 1,
        "required": false,
        "dependencies": []
      },
      {
        "id": "octo/pricing",
        "revision": 1,
        "required": false,
        "dependencies": []
      },
      {
        "id": "octo/offers",
        "revision": 1,
        "required": false,
        "dependencies": ["octo/pricing"]
      },
      {
        "id": "octo/card-payment",
        "revision": 1,
        "required": false,
        "dependencies": []
      }
    ],
    "options": [
      {
        "id": "DEFAULT",
        "default": true,
        "internalName": "DEFAULT",
        "reference": null,
        "restrictions": {
          "minUnits": 0,
          "maxUnits": null
        },
        "units": [
          {
            "id": "adult",
            "internalName": "Adult",
            "reference": "adult",
            "type": "ADULT",
            "restrictions": {
              "minAge": 18,
              "maxAge": 99,
              "idRequired": false,
              "minQuantity": null,
              "maxQuantity": null,
              "paxCount": 1,
              "accompaniedBy": []
            }
          },
          {
            "id": "child",
            "internalName": "Child",
            "reference": "child",
            "type": "CHILD",
            "restrictions": {
              "minAge": 0,
              "maxAge": 17,
              "idRequired": false,
              "minQuantity": null,
              "maxQuantity": null,
              "paxCount": 1,
              "accompaniedBy": ["adult"]
            }
          }
        ]
      }
    ]
  }
  // ...rest of the products
]

You can see a full description of the endpoint and documentation on each field here.

Lookup

GET https://api.ventrata.com/octo/redemption/lookup

Finds all matching bookings given a scanned code (reference). This can either be a barcode or reference number. From the input we'll attempt to locate all matching bookings and return them in the response.

Query Parameters

[
  {
    "redemptionCode": "connect_9VWRHNASD|2aa894f0-2faa-403b-8b4e-9416854b4ba8,booking_,include_6622032d-840c-43c1-bdc2-111b1801174a",
    "redeemable": true,
    "uuid": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "testMode": true,
    "resellerReference": "VOUCHER-0123",
    "supplierReference": "X749G9",
    "status": "CONFIRMED",
    "utcExpiresAt": null,
    "utcConfirmedAt": "2020-06-07T18:36:29Z",
    "productId": "1a7213eb-3a33-4cbb-b114-64d771c201ac",
    "optionId": "DEFAULT",
    "cancellable": true,
    "cancellation": null,
    "freesale": false,
    "notes": "Optional notes on the booking",
    "availability": {
      "id": "2020-06-27T00:00:00+02:00",
      "localDateTimeStart": "2020-06-27T00:00:00+02:00",
      "localDateTimeEnd": "2020-06-28T00:00:00+02:00",
      "allDay": true,
      "openingHours": []
    },
    "contact": {
      "fullName": "Oliver Morgan",
      "emailAddress": "ollym@me.com",
      "phoneNumber": "+447840739436",
      "locales": ["en-GB", "en-US", "en"],
      "country": "GB"
    },
    "deliveryMethods": [
      "VOUCHER",
      "TICKET"
    ],
    "voucher": {
      "redemptionMethod": "DIGITAL",
      "utcRedeemedAt": null,
      "deliveryOptions": [
        {
          "deliveryFormat": "QRCODE",
          "deliveryValue": "!1|zmEIG9t4f8x4qyhYcMkV8oPCQcZhgcOfKc1cJcvcl|mwhjfBi9hZlRDzAsjLkz5m|Zar+nrHcNn/CR1Gp"
        },
        {
          "deliveryFormat": "PDF_URL",
          "deliveryValue": "https://api.ventrata.com/octo/pdf?booking=50a54a87-3fe3-4a1b-8409-15d4de0e7d41"
        }
      ]
    },
    "unitItems": [
      {
        "uuid": "eeddd74e-88e6-4dab-84e9-14f7af18935f",
        "resellerReference": null,
        "supplierReference": "408H44",
        "unitId": "child",
        "ticket": {
          "redemptionMethod": "DIGITAL",
          "utcRedeemedAt": null,
          "deliveryOptions": [
            {
              "deliveryFormat": "QRCODE",
              "deliveryValue": "!1|y8DI7kHZfKB3qNiBc8oAVLpsDfyflcmcKcBc6cJcg|mwhjfBi9hZlRDzAsjLkz5m|cS1MkoKTmFnBwT6B"
            },
            {
              "deliveryFormat": "PDF_URL",
              "deliveryValue": "https://api.ventrata.com/octo/pdf?booking=50a54a87-3fe3-4a1b-8409-15d4de0e7d41&ticket=3def6f63-3d7c-4f66-b2a1-32d202493a52"
            }
          ]
        }
      },
      {
        "uuid": "ec1e2622-1359-437b-83f8-15182759d605",
        "resellerReference": null,
        "supplierReference": "BSDYM4",
        "unitId": "adult",
        "ticket": {
          "redemptionMethod": "DIGITAL",
          "utcRedeemedAt": null,
          "deliveryOptions": [
            {
              "deliveryFormat": "QRCODE",
              "deliveryValue": "!1|zmEIG9t4f8x4qyhYcMkV8oPCPhDfgcJcKc1cJcvcl|mwhjfBi9hZlRDzAsjLkz5m|VgmSJOhfTnAeO7pt"
            },
            {
              "deliveryFormat": "PDF_URL",
              "deliveryValue": "https://api.ventrata.com/octo/pdf?booking=50a54a87-3fe3-4a1b-8409-15d4de0e7d41&ticket=9bcc82c9-4c75-4a86-aa1f-b25f397953a1"
            }
          ]
        }
      },
      {
        "uuid": "de9855fd-8176-4551-9ba9-ae8c997cb2bb",
        "resellerReference": null,
        "supplierReference": "E5K92G",
        "unitId": "adult",
        "ticket": {
          "redemptionMethod": "DIGITAL",
          "utcRedeemedAt": null,
          "deliveryOptions": [
            {
              "deliveryFormat": "QRCODE",
              "deliveryValue": "!1|An2IZ2hGfxpwlXCkcWRZ5A8flimcqc2fncmcAcKcl|mwhjfBi9hZlRDzAsjLkz5m|aTDanPYLWocA94cw"
            },
            {
              "deliveryFormat": "PDF_URL",
              "deliveryValue": "https://api.ventrata.com/octo/pdf?booking=50a54a87-3fe3-4a1b-8409-15d4de0e7d41&ticket=34cda40a-0807-4e03-9968-22b7e20b0561"
            }
          ]
        }
      }
    ]
  },
  // ...maybe more
]

The response is an array of bookings, the schema of which is described here. The only addition are two fields:

redemptionCode which you'll need to redeem that booking. redeemable which is true or false depending whether this booking can be redeemed.

The first thing to note is the endpoint may return multiple results, when this happens it is because the scanned code might be that of a package which contains more than one bookings that you must chose which you want to redeem.

Redeem

POST https://api.ventrata.com/octo/redemption/redeem

Once you've chosen a booking to redeem, this endpoint performs the redemption.

Request Body

{
  "redemptionCode": "connect_9VWRHNASD|2aa894f0-2faa-403b-8b4e-9416854b4ba8,booking_,include_6622032d-840c-43c1-bdc2-111b1801174a",
  "redeemable": false,
  "uuid": "463ab84c-06b2-4f58-8220-dd7cba0330f3",
  "testMode": false,
  "resellerReference": null,
  "supplierReference": "XHSNK2",
  "status": "REDEEMED",
  "utcCreatedAt": "2021-05-07T08:59:37Z",
  "utcUpdatedAt": "2021-05-08T18:41:58Z",
  "utcExpiresAt": null,
  "utcRedeemedAt": "2021-05-08T18:41:57Z",
  "utcConfirmedAt": "2021-05-07T08:59:50Z",
  "productId": "1ba8b5fd-a061-42a6-8af8-ee46bb1a5660",
  "product": {
    "id": "1ba8b5fd-a061-42a6-8af8-ee46bb1a5660",
    "internalName": "London River Cruise Return",
    "reference": null,
    "locale": "en",
    "timeZone": "Europe/London",
    "allowFreesale": false,
    "instantConfirmation": true,
    "instantDelivery": true,
    "availabilityRequired": true,
    "availabilityType": "OPENING_HOURS",
    "deliveryFormats": [
      "PDF_URL",
      "QRCODE"
    ],
    "deliveryMethods": [
      "VOUCHER",
      "TICKET"
    ],
    "redemptionMethod": "DIGITAL",
    "options": [
      {
        "id": "DEFAULT",
        "default": true,
        "internalName": "DEFAULT",
        "reference": null,
        "availabilityLocalStartTimes": ["11:30", "14:00"],
        "cancellationCutoff": "0 hours",
        "cancellationCutoffAmount": 0,
        "cancellationCutoffUnit": "hour",
        "restrictions": {
          "minUnits": 0,
          "maxUnits": null
        },
        "units": [
          {
            "id": "adult",
            "internalName": "Adult",
            "reference": "adult",
            "type": "ADULT",
            "restrictions": {
              "minAge": 16,
              "maxAge": 100,
              "idRequired": false,
              "minQuantity": null,
              "maxQuantity": null,
              "paxCount": 1,
              "accompaniedBy": []
            }
          },
          {
            "id": "child",
            "internalName": "Child",
            "reference": "child",
            "type": "CHILD",
            "restrictions": {
              "minAge": 5,
              "maxAge": 15,
              "idRequired": false,
              "minQuantity": null,
              "maxQuantity": null,
              "paxCount": 1,
              "accompaniedBy": []
            }
          },
          {
            "id": "family",
            "internalName": "Family",
            "reference": "family",
            "type": "FAMILY",
            "restrictions": {
              "minAge": 0,
              "maxAge": 100,
              "idRequired": false,
              "minQuantity": 2,
              "maxQuantity": null,
              "paxCount": 4,
              "accompaniedBy": []
            }
          }
        ]
      }
    ]
  },
  "optionId": "DEFAULT",
  "option": {
    "id": "DEFAULT",
    "default": true,
    "internalName": "DEFAULT",
    "reference": null,
    "availabilityLocalStartTimes": ["11:30", "14:00"],
    "cancellationCutoff": "0 hours",
    "cancellationCutoffAmount": 0,
    "cancellationCutoffUnit": "hour",
    "restrictions": {
      "minUnits": 0,
      "maxUnits": null
    },
    "units": [
      {
        "id": "adult",
        "internalName": "Adult",
        "reference": "adult",
        "type": "ADULT",
        "restrictions": {
          "minAge": 16,
          "maxAge": 100,
          "idRequired": false,
          "minQuantity": null,
          "maxQuantity": null,
          "paxCount": 1,
          "accompaniedBy": []
        }
      },
      {
        "id": "child",
        "internalName": "Child",
        "reference": "child",
        "type": "CHILD",
        "restrictions": {
          "minAge": 5,
          "maxAge": 15,
          "idRequired": false,
          "minQuantity": null,
          "maxQuantity": null,
          "paxCount": 1,
          "accompaniedBy": []
        }
      },
      {
        "id": "family",
        "internalName": "Family",
        "reference": "family",
        "type": "FAMILY",
        "restrictions": {
          "minAge": 0,
          "maxAge": 100,
          "idRequired": false,
          "minQuantity": 2,
          "maxQuantity": null,
          "paxCount": 4,
          "accompaniedBy": []
        }
      }
    ]
  },
  "cancellable": true,
  "cancellation": null,
  "freesale": false,
  "availabilityId": "2021-05-07T00:00:00+01:00",
  "availability": {
    "id": "2021-05-07T00:00:00+01:00",
    "localDateTimeStart": "2021-05-07T00:00:00+01:00",
    "localDateTimeEnd": "2021-05-08T00:00:00+01:00",
    "allDay": true,
    "openingHours": []
  },
  "contact": {
    "fullName": null,
    "firstName": null,
    "lastName": null,
    "emailAddress": null,
    "phoneNumber": null,
    "locales": [],
    "country": null,
    "notes": null
  },
  "notes": null,
  "deliveryMethods": [
    "VOUCHER",
    "TICKET"
  ],
  "voucher": {
    "redemptionMethod": "DIGITAL",
    "utcRedeemedAt": "2021-05-08T18:41:57Z",
    "deliveryOptions": [
      {
        "deliveryFormat": "QRCODE",
        "deliveryValue": "!1|VPrcXmH4ckjXzxUrc51jNwWIgcJfBcxcNcpcYc7cL|Xrunh3cRIl1xQVNsO8R1Ww|yCneQi16Yd3OXGgc"
      },
      {
        "deliveryFormat": "PDF_URL",
        "deliveryValue": "http://api.ventrata.localhost:3000/octo/pdf?booking=463ab84c-06b2-4f58-8220-dd7cba0330f3"
      }
    ]
  },
  "unitItems": [
    {
      "uuid": "629ec991-aa56-4a8a-8def-d0e88b135ac9",
      "resellerReference": null,
      "supplierReference": "9498BW",
      "unitId": "adult",
      "unit": {
        "id": "adult",
        "internalName": "Adult",
        "reference": "adult",
        "type": "ADULT",
        "restrictions": {
          "minAge": 16,
          "maxAge": 100,
          "idRequired": false,
          "minQuantity": null,
          "maxQuantity": null,
          "paxCount": 1,
          "accompaniedBy": []
        }
      },
      "status": "REDEEMED",
      "utcRedeemedAt": "2021-05-08T18:41:57Z",
      "ticket": {
        "redemptionMethod": "DIGITAL",
        "utcRedeemedAt": "2021-05-08T18:41:57Z",
        "deliveryOptions": [
          {
            "deliveryFormat": "QRCODE",
            "deliveryValue": "!1|W7vTxZhVcDXGOqh6c0nK2vyUpfvflc4cqcOcBcmcV|Xrunh3cRIl1xQVNsO8R1Ww|cGse+mMihBA7Iz/X"
          },
          {
            "deliveryFormat": "PDF_URL",
            "deliveryValue": "http://api.ventrata.localhost:3000/octo/pdf?booking=463ab84c-06b2-4f58-8220-dd7cba0330f3&ticket=629ec991-aa56-4a8a-8def-d0e88b135ac9"
          }
        ]
      }
    }
  ]
}

Note if your application groups multiple redemption codes together it's also possible to send redemptionCode parameter as an array of codes you want to redeem. If this parameter is sent as an array then the response body will also be an array of each redemption response. For example:

POST /redemption/redeem HTTP/1.1
Content-Type: application/json
Authorization: Bearer 5bd1629a-323e-4edb-ac9b-327ef51e6136

{
  "redemptionCode": [
    "a",
    "b",
    "c"
  ]
}

Will redeem codes "a", "b" and "c" together.

The redemptionCode parameter is taken from the lookup response. The response will return the booking object, now with a status altered to "REDEEMED".

Redemption Credentials

POST https://api.ventrata.com/octo/redemption/credentials

In some cases where you might have multiple credentials on the same system that you redeem for, this endpoint is un-authenticated where you send the reference/barcode and a list of credentials, and we will return the most appropriate.

Request Body

{
  "apiKey": "5bd1629a-323e-4edb-ac9b-327ef51e6136"
}

An example request might be like:

POST /redemption/credentials HTTP/1.1
Content-Type: application/json

{
  "reference": "HTA89203",
  "apiKeys": [
    "5bd1629a-323e-4edb-ac9b-327ef51e6136",
    "84ea621d-b3c3-4cee-be5f-8cfdf00666cc",
    "29e13da7-f5fa-45fa-be74-16f55af24c90"
  ]
}

The system will then search through each API key to find the one most appropriate for the given code and return it, for example:

{ "apiKey": "5bd1629a-323e-4edb-ac9b-327ef51e6136" }

However if the code is not recognised from any of the apiKeys then null will be returned instead, for example:

{ "apiKey": null }

In which case you should assume the reference does not belong to any of the provided apiKeys.

Redemption Validation

POST https://api.ventrata.com/octo/redemption/validate

Request Body

{
  "redemptionCode": "connect_9VWRHNASD|2aa894f0-2faa-403b-8b4e-9416854b4ba8,booking_,include_6622032d-840c-43c1-bdc2-111b1801174a",
  "redeemable": false,
  "uuid": "463ab84c-06b2-4f58-8220-dd7cba0330f3",
  "testMode": false,
  "resellerReference": null,
  "supplierReference": "XHSNK2",
  "status": "REDEEMED",
  "utcCreatedAt": "2021-05-07T08:59:37Z",
  "utcUpdatedAt": "2021-05-08T18:41:58Z",
  "utcExpiresAt": null,
  "utcRedeemedAt": "2021-05-08T18:41:57Z",
  "utcConfirmedAt": "2021-05-07T08:59:50Z",
  "productId": "1ba8b5fd-a061-42a6-8af8-ee46bb1a5660",
  "product": {
    "id": "1ba8b5fd-a061-42a6-8af8-ee46bb1a5660",
    "internalName": "London River Cruise Return",
    "reference": null,
    "locale": "en",
    "timeZone": "Europe/London",
    "allowFreesale": false,
    "instantConfirmation": true,
    "instantDelivery": true,
    "availabilityRequired": true,
    "availabilityType": "OPENING_HOURS",
    "deliveryFormats": [
      "PDF_URL",
      "QRCODE"
    ],
    "deliveryMethods": [
      "VOUCHER",
      "TICKET"
    ],
    "redemptionMethod": "DIGITAL",
    "options": [
      {
        "id": "DEFAULT",
        "default": true,
        "internalName": "DEFAULT",
        "reference": null,
        "availabilityLocalStartTimes": ["11:30", "14:00"],
        "cancellationCutoff": "0 hours",
        "cancellationCutoffAmount": 0,
        "cancellationCutoffUnit": "hour",
        "restrictions": {
          "minUnits": 0,
          "maxUnits": null
        },
        "units": [
          {
            "id": "adult",
            "internalName": "Adult",
            "reference": "adult",
            "type": "ADULT",
            "restrictions": {
              "minAge": 16,
              "maxAge": 100,
              "idRequired": false,
              "minQuantity": null,
              "maxQuantity": null,
              "paxCount": 1,
              "accompaniedBy": []
            }
          },
          {
            "id": "child",
            "internalName": "Child",
            "reference": "child",
            "type": "CHILD",
            "restrictions": {
              "minAge": 5,
              "maxAge": 15,
              "idRequired": false,
              "minQuantity": null,
              "maxQuantity": null,
              "paxCount": 1,
              "accompaniedBy": []
            }
          },
          {
            "id": "family",
            "internalName": "Family",
            "reference": "family",
            "type": "FAMILY",
            "restrictions": {
              "minAge": 0,
              "maxAge": 100,
              "idRequired": false,
              "minQuantity": 2,
              "maxQuantity": null,
              "paxCount": 4,
              "accompaniedBy": []
            }
          }
        ]
      }
    ]
  },
  "optionId": "DEFAULT",
  "option": {
    "id": "DEFAULT",
    "default": true,
    "internalName": "DEFAULT",
    "reference": null,
    "availabilityLocalStartTimes": ["11:30", "14:00"],
    "cancellationCutoff": "0 hours",
    "cancellationCutoffAmount": 0,
    "cancellationCutoffUnit": "hour",
    "restrictions": {
      "minUnits": 0,
      "maxUnits": null
    },
    "units": [
      {
        "id": "adult",
        "internalName": "Adult",
        "reference": "adult",
        "type": "ADULT",
        "restrictions": {
          "minAge": 16,
          "maxAge": 100,
          "idRequired": false,
          "minQuantity": null,
          "maxQuantity": null,
          "paxCount": 1,
          "accompaniedBy": []
        }
      },
      {
        "id": "child",
        "internalName": "Child",
        "reference": "child",
        "type": "CHILD",
        "restrictions": {
          "minAge": 5,
          "maxAge": 15,
          "idRequired": false,
          "minQuantity": null,
          "maxQuantity": null,
          "paxCount": 1,
          "accompaniedBy": []
        }
      },
      {
        "id": "family",
        "internalName": "Family",
        "reference": "family",
        "type": "FAMILY",
        "restrictions": {
          "minAge": 0,
          "maxAge": 100,
          "idRequired": false,
          "minQuantity": 2,
          "maxQuantity": null,
          "paxCount": 4,
          "accompaniedBy": []
        }
      }
    ]
  },
  "cancellable": true,
  "cancellation": null,
  "freesale": false,
  "availabilityId": "2021-05-07T00:00:00+01:00",
  "availability": {
    "id": "2021-05-07T00:00:00+01:00",
    "localDateTimeStart": "2021-05-07T00:00:00+01:00",
    "localDateTimeEnd": "2021-05-08T00:00:00+01:00",
    "allDay": true,
    "openingHours": []
  },
  "contact": {
    "fullName": null,
    "firstName": null,
    "lastName": null,
    "emailAddress": null,
    "phoneNumber": null,
    "locales": [],
    "country": null,
    "notes": null
  },
  "notes": null,
  "deliveryMethods": [
    "VOUCHER",
    "TICKET"
  ],
  "voucher": {
    "redemptionMethod": "DIGITAL",
    "utcRedeemedAt": "2021-05-08T18:41:57Z",
    "deliveryOptions": [
      {
        "deliveryFormat": "QRCODE",
        "deliveryValue": "!1|VPrcXmH4ckjXzxUrc51jNwWIgcJfBcxcNcpcYc7cL|Xrunh3cRIl1xQVNsO8R1Ww|yCneQi16Yd3OXGgc"
      },
      {
        "deliveryFormat": "PDF_URL",
        "deliveryValue": "http://api.ventrata.localhost:3000/octo/pdf?booking=463ab84c-06b2-4f58-8220-dd7cba0330f3"
      }
    ]
  },
  "unitItems": [
    {
      "uuid": "629ec991-aa56-4a8a-8def-d0e88b135ac9",
      "resellerReference": null,
      "supplierReference": "9498BW",
      "unitId": "adult",
      "unit": {
        "id": "adult",
        "internalName": "Adult",
        "reference": "adult",
        "type": "ADULT",
        "restrictions": {
          "minAge": 16,
          "maxAge": 100,
          "idRequired": false,
          "minQuantity": null,
          "maxQuantity": null,
          "paxCount": 1,
          "accompaniedBy": []
        }
      },
      "status": "REDEEMED",
      "utcRedeemedAt": "2021-05-08T18:41:57Z",
      "ticket": {
        "redemptionMethod": "DIGITAL",
        "utcRedeemedAt": "2021-05-08T18:41:57Z",
        "deliveryOptions": [
          {
            "deliveryFormat": "QRCODE",
            "deliveryValue": "!1|W7vTxZhVcDXGOqh6c0nK2vyUpfvflc4cqcOcBcmcV|Xrunh3cRIl1xQVNsO8R1Ww|cGse+mMihBA7Iz/X"
          },
          {
            "deliveryFormat": "PDF_URL",
            "deliveryValue": "http://api.ventrata.localhost:3000/octo/pdf?booking=463ab84c-06b2-4f58-8220-dd7cba0330f3&ticket=629ec991-aa56-4a8a-8def-d0e88b135ac9"
          }
        ]
      }
    }
  ]
}

Finally the POST /redemption/validate endpoint allows you to validate a ticket against the validation rules stored in our system. Use this if you want to rely on our system to define the validation rules beyond redemption and not have to manage the validity state yourself.

Note if the ticket is not already redeemed the validate endpoint will automatically redeem it first, so it's suggested that you you should use either redemption/redeem or redemption/validate but not both at the same time.

Last updated