# Pricing

This capability supports dynamic pricing where the price of the product can be changed day by day and even at different start times. Make sure your system is able to support this level of pricing before you integrate with it.

## Product Pricing

<mark style="color:blue;">`GET`</mark> `https://octo.peek.com/integrations/octo/products/:id`

Returns top-level pricing by unit on each product.

#### Path Parameters

| Name | Type   | Description                                        |
| ---- | ------ | -------------------------------------------------- |
| id   | String | Returns top-level pricing by unit on each product. |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "id": "av_123",
  "internalName": "Rent-a-Kayak",
  "reference": "BRC-KAYAK",
  "locale": "en",
  "timeZone": "America/Los_Angeles",
  "allowFreesale": true,
  "availabilityType": "START_TIME",
  "deliveryFormats": ["QRCODE"],
  "deliveryMethods": ["VOUCHER"],
  "redemptionMethod": "DIGITAL",
  "capabilities": [
    {
      "id": "octo/pricing",
      "revision": 1,
      "required": true,
      "dependencies": []
    },
    {
      "id": "octo/webhooks",
      "revision": 1,
      "required": false,
      "dependencies": []
    }
  ],
  "defaultCurrency": "USD",
  "availableCurrencies": ["USD"],
  "pricingPer": "UNIT",
  "options": [
    {
      "id": "av_123",
      "default": true,
      "internalName": "Rent-a-Kayak",
      "reference": null,
      "restrictions": {},
      "units": [
        {
          "id": "ea5fbd4c-9c2a-42f5-80c5-251a9f04da04",
          "internalName": "1-Seater Kayak",
          "reference": "1seat",
          "type": "ADULT",
          "restrictions": {
            "minAge": 18,
            "maxAge": 99,
            "idRequired": false,
            "minQuantity": 1,
            "maxQuantity": null,
            "paxCount": 1,
            "accompaniedBy": []
          },
          "pricingFrom": [
            {
              "original": 5999,
              "retail": 5999,
              "net": null,
              "currency": "USD",
              "currencyPrecision": 2
            }
          ],
        },
        {
          "id": "582fd9d7-43fd-4685-a9b2-35b102eaec3a",
          "internalName": "2-Seater Kayak",
          "reference": "2seat",
          "type": "ADULT",
          "restrictions": {
            "minAge": 18,
            "maxAge": 99,
            "idRequired": false,
            "minQuantity": 2,
            "maxQuantity": null,
            "paxCount": 1,
            "accompaniedBy": []
          },
          "pricingFrom": [
            {
              "original": 9999,
              "retail": 9999,
              "net": null,
              "currency": "USD",
              "currencyPrecision": 2 
            }
          ]
        }
      ]
    }
  ]
}
```

{% endtab %}
{% endtabs %}

On the response the only changes from the original schema is on the Product object:

```javascript
{
  // ...rest of Product object
  "defaultCurrency": "USD",
  "availableCurrencies": ["USD", "EUR", "GBP"],
  "pricingPer": "UNIT" // "UNIT" or "BOOKING"
}
```

The `defaultCurrency` is the default currency for this product, if you omit the `currency` parameter on future endpoints this is the value Peek Pro will fallback to. `availableCurrencies` are all the possible currencies that we accept for this product.

`pricingPer` indicates whether the pricing is per unit (most common), or per booking. Pricing which is per booking is common for private charters or group booking products where the price is the same regardless of how many tickets are purchased.

Next, if `pricingPer = "UNIT"`, on each Unit (adult, child, etc.) we add the following:

```javascript
{
  // ...rest of the Unit object
  "pricingFrom": [
    {
      "original": 4500,
      "retail": 4500,
      "net": 3500,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "VAT 10",
          "retail": 800,
          "net": 500
        }
      ]
    },
    {
      "original": 4000,
      "retail": 4000,
      "net": 3000,
      "currency": "GBP",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "VAT 10",
          "retail": 700,
          "net": 400
        }
      ]
    }
    // ...etc...
  ]
}
```

If `pricingPer = "BOOKING"` then these fields will be on the Product itself instead of the Unit as the pricing applies once to the booking regardless of how many units (tickets) are purchased.

We'll produce one `pricingFrom` object for each currency in `availableCurrencies` . The meaning of each pricing field is given below:

| Field               | Description                                                                                                                                                                                                                                                |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `original`          | The original price for this product which will be the same or higher than the sale amount. Use this to show a discount has been applied e.g. ~~$10~~ **$8.50**                                                                                             |
| `retail`            | The sale price you should charge your customers.                                                                                                                                                                                                           |
| `net`               | The wholesale rate the supplier will charge you for this sale.                                                                                                                                                                                             |
| `currency`          | The currency.                                                                                                                                                                                                                                              |
| `currencyPrecision` | All pricing is given in integers to avoid floating point rounding issues. e.g. USD = 2 and JPY = 0. To convert a price to decimal you should do: `price / (10 ** currencyPrecision)` where \*\* is to the power of e.g. `Math.pow(10, currencyPrecision)`. |
| `includedTaxes`     | Any taxes included in the retail and/or net price.                                                                                                                                                                                                         |

{% hint style="warning" %}
Throughout this capability we'll use a convention where we'll end the object key with `From` to indicate this is indicative and not the final price. Make sure you communicate this also to the customer.
{% endhint %}

## Pricing Calendar

<mark style="color:green;">`POST`</mark> `https://octo.peek.com/integrations/octo/availability/calendar`

The documentation above only shows the additions this capability adds to the availability calendar endpoint. See the documentation in [#availability-calendar](https://octodocs.peek.com/booking-flow/availability#availability-calendar "mention") to see the full request parameters and response object.

Using the availability calendar endpoint for pricing is designed to make it easy to generate a pricing calendar for example on Google Travel:

![](https://603390319-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCthZkTSjFuKEeDXpfq8K%2Fuploads%2FBjoHEy0s2jRwzIShctXO%2F68747470733a2f2f692e696d6775722e636f6d2f793039325676392e706e67.png?alt=media\&token=faeeed4f-bd58-4ffc-a2f8-7c764c396eda)

Each availability object is given a new `unitPricingFrom` field with an array of unit prices in the currency for example:

{% tabs %}
{% tab title="pricingPer = UNIT" %}

```javascript
{
  "localDate": "2020-07-01",
  "status": "AVAILABLE",
  "capacity": 24,
  "openingHours": []
  "unitPricingFrom": [
    {
      "unitId": "ecbdb23e-9840-4d15-b6f4-254a9ea401b2",
      "original": 4500,
      "retail": 4500,
      "net": 3500,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "VAT 10",
          "retail": 700,
          "net": 400
        }
      ]
    },
    {
      "unitId": "480d0c3e-80a1-4bf2-a39b-aa06332739df",
      "original": 4200,
      "retail": 4200,
      "net": 3200,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "VAT 10",
          "retail": 800,
          "net": 500
        }
      ]
    }
  ]
}
```

{% endtab %}

{% tab title="pricingPer = BOOKING" %}

```javascript
{
  "localDate": "2020-07-01",
  "status": "AVAILABLE",
  "capacity": 24,
  "openingHours": []
  "pricingFrom": [
    {
      "original": 4500,
      "retail": 4500,
      "net": 3500,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "VAT 10",
          "retail": 700,
          "net": 400
        }
      ]
    },
    {
      "original": 4200,
      "retail": 4200,
      "net": 3200,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "VAT 10",
          "retail": 800,
          "net": 500
        }
      ]
    }
  ]
}
```

{% endtab %}
{% endtabs %}

If you pass the `units` to the request then we'll give the total pricing for the selection under the `pricingFrom` field, which is also included by default if `pricingPer = BOOKING` as the number of units isn't needed to know what the price of the booking is. For example:

{% tabs %}
{% tab title="Request" %}

```javascript
{
  "productId": "av_123",
  "optionId": "av_123",
  "localDateStart": "2020-07-01",
  "localDateEnd": "2020-07-02",
  "units": [
    {
      "id": "ecbdb23e-9840-4d15-b6f4-254a9ea401b2",
      "quantity": 2
    },
    {
      "id": "480d0c3e-80a1-4bf2-a39b-aa06332739df",
      "quantity": 1
    }
  ]
}
```

{% endtab %}

{% tab title="Response (pricingPer = UNIT)" %}

```javascript
[
  {
    "localDate": "2020-07-01",
    "status": "AVAILABLE",
    "capacity": 24,
    "openingHours": [],
    "unitPricingFrom": [
      {
        "original": 3995,
        "retail": 3995,
        "net": 2996,
        "currency": "USD",
        "currencyPrecision": 2,
        "unitId": "adult",
        "includedTaxes": [
          {
            "name": "VAT 10",
            "retail": 400,
            "net": 250
          }
        ]
      },
      {
        "original": 1995,
        "retail": 1995,
        "net": 1496,
        "currency": "USD",
        "currencyPrecision": 2,
        "unitId": "child",
        "includedTaxes": [
          {
            "name": "VAT 10",
            "retail": 200,
            "net": 50
          }
        ]
      }
    ],
    "pricingFrom": {
      "original": 9985,
      "retail": 9985,
      "net": 7488,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "VAT 10",
          "retail": 800,
          "net": 500
        }
      ]
    }
  }
]
```

{% endtab %}

{% tab title="Response (pricingPer = BOOKING)" %}

```javascript
[
  {
    "localDate": "2020-07-01",
    "status": "AVAILABLE",
    "capacity": 24,
    "openingHours": [],
    "pricingFrom": {
      "original": 9985,
      "retail": 9985,
      "net": 7488,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "VAT 10",
          "retail": 800,
          "net": 500
        }
      ]
    }
  }
]
```

{% endtab %}
{% endtabs %}

Having the `pricingFrom` value calculated for you makes it much easier to display a single price on each date on the calendar (assuming the guest has chosen how many units they want before you display the calendar).

If pricingPer = BOOKING then unitPricingFrom will not be provided.

## Pricing Check

<mark style="color:green;">`POST`</mark> `https://octo.peek.com/integrations/octo/availability`

Returns a final quote of the price before making a booking.

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

This endpoint is the availability check endpoint which has been extended to add pricing. We only document the added parameters here, to see the full documentation for the original availability check you can find it in [#availability-check](https://octodocs.peek.com/booking-flow/availability#availability-check "mention").

If we were to repeat the request above in the calendar section this is what the response would look like instead:

{% tabs %}
{% tab title="Request" %}

```javascript
{
  "productId": "av_132",
  "optionId": "av_123",
  "localDateStart": "2020-07-01",
  "localDateEnd": "2020-07-02",
  "units": [
    {
      "id": "ecbdb23e-9840-4d15-b6f4-254a9ea401b2",
      "quantity": 2
    },
    {
      "id": "480d0c3e-80a1-4bf2-a39b-aa06332739df",
      "quantity": 1
    }
  ]
}
```

{% endtab %}

{% tab title="Response (pricingPer = UNIT)" %}

```javascript
[
  {
    "id": "20200701113000_720_ecbdb23e-9840-4d15-b6f4-254a9ea401b2",
    "localDateTimeStart": "2020-07-01T11:30:00-08:00",
    "localDateTimeEnd": "2020-07-01T23:30:00-08:00",
    "utcCutoffAt": "2020-07-01T16:30:00Z",
    "allDay": false,
    "status": "AVAILABLE",
    "vacancies": 24,
    "capacity": 24,
    "maxUnits": 24,
    "openingHours": [],
    "unitPricing": [
      {
        "original": 3995,
        "retail": 3995,
        "net": 2996,
        "currency": "USD",
        "currencyPrecision": 2,
        "unitId": "adult",
        "includedTaxes": [
          {
            "name": "VAT 10",
            "retail": 400,
            "net": 250
          }
        ]
      },
      {
        "original": 1995,
        "retail": 1995,
        "net": 1496,
        "currency": "USD",
        "currencyPrecision": 2,
        "unitId": "child",
        "includedTaxes": [
          {
            "name": "VAT 10",
            "retail": 200,
            "net": 50
          }
        ]
      }
    ],
    "pricing": {
      "original": 9985,
      "retail": 9985,
      "net": 7488,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "VAT 10",
          "retail": 800,
          "net": 500
        }
      ]
    }
  },
  {
    "id": "20200701120000_720_480d0c3e-80a1-4bf2-a39b-aa06332739df",
    "localDateTimeStart": "2020-07-01T12:00:00-08:00",
    "localDateTimeEnd": "2020-07-02T00:00:00-08:00",
    "utcCutoffAt": "2020-07-01T17:00:00Z",
    "allDay": false,
    "status": "AVAILABLE",
    "vacancies": 24,
    "capacity": 24,
    "maxUnits": 24,
    "openingHours": [],
    "unitPricing": [
      {
        "original": 3995,
        "retail": 3995,
        "net": 2996,
        "currency": "USD",
        "currencyPrecision": 2,
        "unitId": "adult",
        "includedTaxes": [
          {
            "name": "VAT 10",
            "retail": 400,
            "net": 250
          }
        ]
      },
      {
        "original": 1995,
        "retail": 1995,
        "net": 1496,
        "currency": "USD",
        "currencyPrecision": 2,
        "unitId": "child",
        "includedTaxes": [
          {
            "name": "VAT 10",
            "retail": 200,
            "net": 50
          }
        ]
      }
    ],
    "pricing": {
      "original": 9985,
      "retail": 9985,
      "net": 7488,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "VAT 10",
          "retail": 800,
          "net": 500
        }
      ]
    }
  }
]
```

{% endtab %}

{% tab title="Response (pricingPer = BOOKING)" %}

```javascript
[
  {
    "id": "20200701113000_720_ecbdb23e-9840-4d15-b6f4-254a9ea401b2",
    "localDateTimeStart": "2020-07-01T11:30:00-05:00",
    "localDateTimeEnd": "2020-07-01T23:30:00-05:00",
    "allDay": false,
    "status": "AVAILABLE",
    "vacancies": 24,
    "capacity": 24,
    "maxUnits": 24,
    "openingHours": [],
    "pricing": {
      "original": 9985,
      "retail": 9985,
      "net": 7488,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "VAT 10",
          "retail": 800,
          "net": 500
        }
      ]
    }
  },
  {
    "id": "2020-07-01T12:00:00-20200701120000_720_480d0c3e-80a1-4bf2-a39b-aa06332739df",
    "localDateTimeStart": "2020-07-01T12:00:00-08:00",
    "localDateTimeEnd": "2020-07-02T00:00:00-08:00",
    "allDay": false,
    "status": "AVAILABLE",
    "vacancies": 24,
    "capacity": 24,
    "maxUnits": 24,
    "openingHours": [],
    "pricing": {
      "original": 9985,
      "retail": 9985,
      "net": 7488,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "VAT 10",
          "retail": 800,
          "net": 500
        }
      ]
    }
  }
]
```

{% endtab %}
{% endtabs %}

Notice how the response fields are `unitPricing` and `pricing` (without the From suffix). That is because this is the final price, and this is what the booking will be once confirmed.

## Booking Reservation

<mark style="color:green;">`POST`</mark> `https://octo.peek.com/integrations/octo/bookings`

The booking reservation call

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "uuid": "89fe0192-ddcd-430a-b285-e1396a4725d2",
  "testMode": true,
  "resellerReference": null,
  "supplierReference": "X749G9",
  "status": "ON_HOLD",
  "utcExpiresAt": "2020-06-07T17:06:37Z",
  "utcConfirmedAt": null,
  "productId": "av_123",
  "optionId": "av_123",
  "cancellable": true,
  "cancellation": null,
  "freesale": false,
  "notes": "optional notes on the booking",
  "availability": {
    "id": "20200701143000_720_5214a9d6-5271-4958-a306-14a07e4084c6",
    "localDateTimeStart": "2020-07-01T14:30:00-08:00",
    "localDateTimeEnd": "2020-07-02T02:30:00-08:00",
    "allDay": true,
    "openingHours": []
  },
  "contact": {
    "fullName": null,
    "emailAddress": null,
    "phoneNumber": null,
    "locales": [],
    "country": null
  },
  "deliveryMethods": [
    "VOUCHER"
  ],
  "voucher": {
    "redemptionMethod": "DIGITAL",
    "utcRedeemedAt": null,
    "deliveryOptions": []
  },
  "pricing": {
    "original": 8800,
    "retail": 8800,
    "net": 5500,
    "currency": "EUR",
    "currencyPrecision": 2,
    "includedTaxes": []
  },
  "unitItems": [
    {
      "uuid": "eeddd74e-88e6-4dab-84e9-14f7af18935f",
      "resellerReference": null,
      "supplierReference": "408H44",
      "unitId": "ecbdb23e-9840-4d15-b6f4-254a9ea401b2"
    },
    {
      "uuid": "ec1e2622-1359-437b-83f8-15182759d605",
      "resellerReference": null,
      "supplierReference": "BSDYM4",
      "unitId": "ecbdb23e-9840-4d15-b6f4-254a9ea401b2"
    },
    {
      "uuid": "de9855fd-8176-4551-9ba9-ae8c997cb2bb",
      "resellerReference": null,
      "supplierReference": "E5K92G",
      "unitId": "480d0c3e-80a1-4bf2-a39b-aa06332739df"
    }
  ]
}
```

{% endtab %}
{% endtabs %}

This capability extends the booking schema to add a `pricing` field which gives you the final price of the booking as well as any included taxes. The final price includes tax, and should be what you display to the guest as the amount they need to pay.

```javascript
  "pricing": {
    "original": 8800,
    "retail": 8800,
    "net": 5500,
    "currency": "EUR",
    "currencyPrecision": 2,
    "includedTaxes": []
  }
```

We include the net amount as well as any taxes included in the net price.
