NOTE: Starting with the 2019 Q2 Release, we recommend using HTTP POST method for all calls.  This allows you to send parameters including the token in the payload of the message which increases security.  


The booking entity in PEAK 15 is used as a way to capture a group of guests that are traveling together on a specific departure. A new booking will generally result in the creation of one or more guest records as well as the creation of or updates to one or more contact records.


  • Create a Contact Booking
  • Using a Match Rule
  • Integrate Google Analytics
  • Booking Optional Prices
  • Booking Cost Item Reservations
  • Booking Inventory Block Items
  • Generating an Invoice
  • Processing a Credit Card Deposit
  • Creating a Credit Card Deposit for Later Processing
  • Page Redirect
  • Return All IDs
  • Creating a Booking Using a Departure Template
  • Update a Booking
  • Update a Contact Guest
  • Add or Remove an Optional Price from an Existing Guest
  • Add or Remove a Cost Item Reservation from an Existing Guest
  • Process Additional Guest Payments
  • Capture a Credit Card for a Guest
  • Capture a Credit Card for a Contact that isn't a Guest
  • Create Invoice Separately
  • Update an Invoice
  • Promo Codes


Create a Contact Booking

The following post shows a basic booking on an existing departure. The 6th line will automatically add the contact as both the client (aka the main contact) on the booking as well as a guest (aka someone who is traveling).




https://data.peak15systems.com/beacon/service.svc/insert/complex/contactbooking
?token=yourtokenhere
&contact.firstname=[firstname]
&contact.lastname=[lastname]
&contact.emailaddress1=[email]
&contact.p15_contacttype_contactid=client
&p15_bookings.p15_tripdepartures_bookingsid=[departurename or departurecode or GUID]
&p15_guests.contact.1.isClient=true


NOTE: By default the booking currency will be set to the organization's base currency.  You will want to set the booking currency to the currency you intend to invoice the customer in which will also dictate the currency in which payments are made.  Use p15_bookings.transactioncurrencyid to set the currency on the booking.


Here is the same booking as an HTML form:


   

<html>
    <head>
        <title>Beacon Sample: Insert Contact Booking</title>
    </head>
    <body>
        <form action="https://data.peak15systems.com/beacon/service.svc/insert/complex/contactbooking"
              method="post" enctype="application/x-www-form-urlencoded">
            <input type="hidden" name="token" value="yourtokenhere" />
            <input type="hidden" name="contact.p15_contacttype_contactid" value="client" />
            <input type="hidden" name="p15_guests.contact.1.isClient" value="true" />
            <table>
                <tr>
                    <td align="left" colspan="2">
                        What departure would you like to book?
                        <select name="p15_bookings.p15_tripdepartures_bookingsid" size="1" style="width: 160px;">
                            <option value="">Select Departure</option>
                            <option value="[departurename or departurecode or GUID]">Departure 1</option>
                            <option value="[departurename or departurecode or GUID]">Departure 2</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td width="300" align="left">
                        *First name
                    </td>
                    <td>
                        <input name="contact.firstname" id="firstname" type="text" size="15" maxlength="50" />
                    </td>
                </tr>
                <tr>
                    <td width="300" align="left">
                        *Last name
                    </td>
                    <td>
                        <input name="contact.lastname" id="lastname" size="15" maxlength="50" />
                    </td>
                </tr>
                <tr>
                    <td width="300" align="left">
                        *E-mail address
                    </td>
                    <td>
                        <input name="contact.emailaddress1" type="text" size="20" maxlength="100" />
                    </td>
                </tr>
                <tr>
                    <td width="300" height="30"></td>
                    <td>
                        <input type="submit" value="Submit" />
                </tr>
            </table>
    </body>
</html>




To add additional guests who are in the same household (aka share an address) include:


&p15_guests.contact.2.firstname=[firstname1]
&p15_guests.contact.2.lastname=[lastname1]
&p15_guests.contact.2.p15_contacttype_contactid=client
&p15_guests.contact.2.samehousehold=true



Using a Match Rule


By default, Beacon will create a new contact record in response to every contact inquiry that comes in. To reduce the number of duplicate records created, you can setup one or more duplicate detection rules inside PEAK 15 and then instruct Beacon to use one of those rules to evaluate whether to create a new contact or update an existing contact with any additional attributes provided and append the inquiry record to that contact. Note that your contact inquiry post must include values for all the attributes specified in the duplicate detection rule. For example, in the case of a request to send an email with a detailed itinerary of a specific trip where you are not collecting mailing address, a duplicate detection rule that checked for a match on first name and email address would be created inside PEAK 15. Adding this to your POST would then cause Beacon to check against that rule:


&contact.rule=[duplicate detection rule name]


or in the case of an HTML form:



<input type="hidden" name="contact.rule" value="[duplicate detection rule name]" />



Notes

Matches are case insensitive and the casing of data from the contact already in PEAK 15 is preserved since it is more likely to have the correct casing than a record entered on a website.

Null values sent in the post will not overwrite non-null values of the matched, pre-existing record.

If more than one active contact matches the values sent in the post, the new inquiry or booking will be appended to the active contact with the most recent booking, or if there is no booking, to the active contact with the most recent modified on date.

Any non-null contact attributes sent in the post will be written to the matching record returned. So if the last name were spelled differently, the last name would be updated to the value sent in the post. If you wish to avoid that, you can send another flag which instructs Beacon to check against the record it has identified as a match to see if that existing record has any other attributes that would be overwritten by values in the request. If the system finds that there are any non-null values that would be overwritten, then it will instead create a new contact record, but set its status reason to “Potential Duplicate” so that someone can review it to determine how to resolve the conflict.



To include that rule, just add:


&contact.ruletype=retainexistingvalues


or in the case of an HTML form:


<input type="hidden" name="contact.ruletype" value="retainexistingvalues" />



Integrate Google Analytics

If you use Google Analytics on your website, then we strongly recommend you take advantage of our integration that allows you to pass in data from Google Analytics about the inquiry such as the referring website’s name.


The integration relies upon javascript code that you add to your web form that will parse the cookie that Google leaves on your visitor’s computer. Those variables are then sent in with the inquiry as hidden form fields.


Note: Google's latest version of Google Analytics, known as Universal Analytics, captures this tracking information in a way that is not accessible by your website. However, there is a technique that will allow you to take advantage of all that Universal Analytics has to offer while maintaining the ability for your website to access this information. It relies upon having both versions of Google Analytics running side by side. To avoid confusion and possible double counting of traffic, you set the legacy tracking code using a generic account (e.g., UA-XXXYYYZZZ-1) and use Google Tag Manager to implement tracking for Universal Analytics.

There are 5 key variables to the cookie:

Google Analytics VariableDescriptionPEAK 15 Attribute
Source

Every referral to a web site has an origin, or source. Examples of sources are the Google search engine, the AOL search engine, the name of a newsletter, or the name of a referring web site.p15_bookings.p15_othersource
TermThe term or keyword is the word or phrase that a user types into a search engine. Note that based on changes to Google and other search engine's policies, keyword data is generally no longer accessible.

p15_bookings.p15_webkeywords


CampaignThe campaign dimension differentiates product promotions such as "Spring Ski Sale" or slogan campaigns such as "Get Fit For Summer".

p15_bookings.p15_webcampaign

 
MediumThe medium helps to qualify the source; together, the source and medium provide specific information about the origin of a referral. For example, in the case of a Google search engine source, the medium might be "cost-per-click", indicating a sponsored link for which the advertiser paid, or "organic", indicating a link in the unpaid search engine results. In the case of a newsletter source, examples of medium include "email" and "print".

p15_bookings.p15_webmedium


ContentThe content dimension describes the version of an advertisement on which a visitor clicked. It is used in content-targeted advertising and Content (A/B) Testing to determine which version of an advertisement is most effective at attracting profitable leads.p15_bookings.p15_webcontent



Here is a sample HTML form that has these hidden fields. Note line 2 where we call the populateHiddenFields function. A separate code snippet follows with the javascript you need to place inside the header tags of your form.


<form action="https://data.peak15systems.com/beacon/service.svc/insert/complex/contactbooking"
      method="post" enctype="application/x-www-form-urlencoded" onsubmit="populateHiddenFields(this);">
    <input type="hidden" name="token" value="yourtokenhere" />
    <input type="hidden" name="contact.p15_contacttype_contactid" value="client" />
    <input type="hidden" name="p15_guests.contact.1.isClient" value="true" />
    <input type="hidden" id='source' name='p15_bookings.p15_gasource' />
    <input type="hidden" id='medium' name='p15_bookings.p15_gamedium' />
    <input type="hidden" id='term' name='p15_bookings.p15_gaterm' />
    <input type="hidden" id='content' name='p15_bookings.p15_gacontent' />
    <input type="hidden" id='campaign' name='p15_bookings.p15_gacampaign' />
    <table>
        <tr>
            <td align="left" colspan="2">
                What departure would you like to book?
                <select name="p15_bookings.p15_tripdepartures_bookingsid" size="1" style="width: 160px;">
                    <option value="">Select Departure</option>
                    <option value="[departurename or departurecode or GUID]">Departure 1</option>
                    <option value="[departurename or departurecode or GUID]">Departure 2</option>
                </select>
            </td>
        </tr>
        <tr>
            <td width="300" align="left">
                *First name
            </td>
            <td>
                <input name="contact.firstname" id="firstname" type="text" size="15" maxlength="50" />
            </td>
        </tr>
        <tr>
            <td width="300" align="left">
                *Last name
            </td>
            <td>
                <input name="contact.lastname" id="lastname" size="15" maxlength="50" />
            </td>
        </tr>
        <tr>
            <td width="300" align="left">
                *E-mail address
            </td>
            <td>
                <input name="contact.emailaddress1" type="text" size="20" maxlength="100" />
            </td>
        </tr>
        <tr>
            <td width="300" height="30">

            </td>
            <td>
                <input type="submit" value="Submit" />
            </td>
        </tr>
    </table>
</form>


Here is the javascript to add in the head tag of your form which will create the "classic" cookie and then parse it and set the hidden form fields. NOTE: You only need to include the "Legacy Google Analtyics Tracking Code" portion of this sample code if you are using Universal Analytics! Also, if you are using Universal Analytics you will need to use Google Tag Manager to implement your tracking code to avoid confusion and duplication with the classic code.


<!-- Legacy Google Analytics Tracking Code left on purpose with generic act # to allow for integration-->
    <script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write("<script src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'>" + "</sc" + "ript>");
</script><script src="http://www.google-analytics.com/ga.js" type="text/javascript"></script>
    <script type="text/javascript">
try {
    var pageTracker = _gat._getTracker("UA-XXXYYYZZZ-1");
    pageTracker._trackPageview();
}
catch (err) { }
</script>
<!-- End Legacy Google Analytics -->
    <script type="text/javascript">
//
// This is a function that parses a string and returns a value.  We use it to get
// data from the __utmz cookie
//
function _uGC(l, n, s) {
    if (!l || l == "" || !n || n == "" || !s || s == "") return "-";
    var i, i2, i3, c = "-";
    i = l.indexOf(n);
    i3 = n.indexOf("=") + 1;
    if (i > -1) {
        i2 = l.indexOf(s, i); if (i2 < 0) { i2 = l.length; }
        c = l.substring((i + i3), i2);
    }
    return c;
}
//
// Get the __utmz cookie value. This is the cookie that
// stores all campaign information.
//
var z = _uGC(document.cookie, '__utmz=', ';');
//
// The cookie has a number of name-value pairs.
// Each identifies an aspect of the campaign.
//
// utmcsr  = campaign source
// utmcmd  = campaign medium
// utmctr  = campaign term (keyword)
// utmcct  = campaign content
// utmccn  = campaign name
// utmgclid = unique identifier used when AdWords auto tagging is enabled
//
// This is very basic code. It separates the campaign-tracking cookie
// and populates a variable with each piece of campaign info.
//
var source = _uGC(z, 'utmcsr=', '|');
var medium = _uGC(z, 'utmcmd=', '|');
var term = _uGC(z, 'utmctr=', '|');
var content = _uGC(z, 'utmcct=', '|');
var campaign = _uGC(z, 'utmccn=', '|');
var gclid = _uGC(z, 'utmgclid=', '|');
//
// The gclid is ONLY present when auto tagging has been enabled.
// All other variables, except the term variable, will be '(not set)'.
// Because the gclid is only present for Google AdWords we can
// populate some other variables that would normally
// be left blank.
//
if (gclid != "-") {
    source = 'google';
    medium = 'cpc';
}
var csegment = _uGC(document.cookie, '__utmv=', ';');
if (csegment != '-') {
    var csegmentex = /[1-9]*?\.(.*)/;
    csegment = csegment.match(csegmentex);
    csegment = csegment[1];
} else {
    csegment = '(not set)';
}
function populateHiddenFields(f) {
    f.source.value = source;
    f.medium.value = medium;
    f.term.value = term;
    f.content.value = content;
    f.campaign.value = campaign;
    //
    //The alerts below are handy for testing to ensure that the
    //campaign informaiton is getting correctly passed.
    //Once you've tested, just comment them out
    //
    alert('source=' + f.source.value);
    alert('medium=' + f.medium.value);
    alert('term=' + f.term.value);
    alert('content=' + f.content.value);
    alert('campaign=' + f.campaign.value);
    return false;
}
</script>



Booking Optional Prices

In this example, we create a booking with two guests as well as indicate that the first guest is booking two different optional prices and the second guest is booking one optional price:


&p15_guests.contact.1.p15_tripprices.1=[price1name or GUID]
&p15_guests.contact.1.p15_tripprices.2=[price2name or GUID]
&p15_guests.contact.2.p15_tripprices.2=[price2name or GUID]


Booking Cost Item Reservations

In this example, we add specific cost item reservations (for example, cabins) to each guest. Note that you can pass either the GUID or name of the cost item reservation as with prices:


&p15_guests.contact.1.p15_vendorserviceitemres.1=Cabin A1
&p15_guests.contact.2.p15_vendorserviceitemres.1=Cabin A1

Booking Inventory Block Item

In this example, we add an inventory block item (for example, a room) to a guest. Note that you can pass the following parameter(s) for the inventory block items to assign the booking guest with the IBI


& p15_guests.contact.1.p15_inventoryblockitems.1 = [GUID]
& p15_guests.contact.2.p15_inventoryblockitems.1 = [GUID]




Generating an Invoice

To have an invoice generated simply pass the GUID of the payment schedule for the invoice like this:


&p15_invoices.p15_paymentscheduleid=[GUID]


When generating an invoice as part of a booking, the response will include the GUID of the invoice rather than the GUID of the booking.  See Return All IDs below to get both IDs.


NOTE: By default the invoice currency will be set to the currency of the booking, which in turn defaults to the organization's base currency.  You will want to set the invoice currency to the currency that payments will be made in.  Use p15_invoices.transactioncurrencyid to set the currency on the invoice.


Processing a Credit Card Deposit

See Working with PEAK 15 Pay or Working with Stripe.  Cybersource is a no longer supported.



Creating a Credit Card Deposit for Later Processing

See Working with PEAK 15 Pay or Working with Stripe.  Cybersource is a no longer supported.



Return All IDs

By default Beacon will return the GUID of the booking created or if your request includes the information to generate an invoice, the GUID of the invoice. However, if you wish to get back the GUIDs of all records created or updated, then use:


&returnallids=true


Or in the case of an HTML form:


<input type="hidden" name="returnallIDs" value="true">



NOTE: You can't combine usage of returnallids and the successpage/error page attributes.

The response message will be a string like this:


contact=[contact GUID],p15_bookings=[booking GUID],p15_guests.contact.1.guestid=[guest GUID],
p15_guests.contact.2=[contact GUID],p15_guests.contact.2.guestid=[guest GUID]



Creating a Booking using a Departure Template

In the standard contactbooking posts, the booking is on a departure that has been previously created. This piece of the query string is what Beacon uses to determine which departure to book:


&p15_bookings.p15_tripdepartures_bookingsid=[departurename or departurecode or GUID]



In order to book a new departure based on a template provided you will replace that query string with:


&p15_tripdepartures.p15_tripdeparturesid=[GUID of departure template]
&p15_tripdepartures.p15_startdate=[date in mm/dd/yyyy format]


Note that we only support using the GUID of the departure template as that is assured to be unique whereas departurename may not be. Also, the departure template MUST BE ACTIVE in the system.


Beacon will, by default, keep the length of the departure it creates the same as the length of the template, but you can also control the duration or length by sending the following:


&p15_tripdepartures.p15_tourdays=[# of days]



Here is an example post that would result in a booking for a single guest on a new departure that was a copy of the specified departure template with July 1 2012 as the start date and duration of 5 days:


https://data.peak15systems.com/beacon/service.svc/insert/complex/
contactbooking?token=yourtokenhere
&contact.firstname=[firstname]
&contact.lastname=[lastname]
&contact.emailaddress1=[email]
&contact.p15_contacttype_contactid=client
&p15_tripdepartures.p15_tripdeparturesid=[GUID of departure template]
&p15_tripdepartures.p15_startdate=07/01/2012
&p15_tripdepartures.p15_tourdays=5
&p15_guests.contact.1.isClient=true


Another approach is to first make a copy of the departure using the following syntax and then use the returned departureID to book on it:


https://data.peak15systems.com/beacon/service.svc/insert/complex/copyDeparture
?token=yourtokenhere
&p15_tripdeparturesid=[GUID of departure template]
&p15_startdate=[date in mm/dd/yyyy format]



Update a Booking

The following post will take the GUID of an existing booking record and update attributes on the booking and add additional guests to the booking that share the same address as the client on the booking. Note that passing a blank value for an attribute causes that attribute to be ignored. If you wish to set the value of an attribute to NULL, you must use the ASCII value of '%00'.


https://data.peak15systems.com/beacon/service.svc/update/complex/contactbooking
?token=yourtokenhere
&contact.rule=[match rule name]
&p15_bookings.p15_bookingsid=[booking GUID]
&p15_bookings.p15_comment=Update to booking
&p15_bookings.statuscode=Booked
&p15_guests.contact.1.p15_contacttype_contactid=Client
&p15_guests.contact.1.firstname=[first name]
&p15_guests.contact.1.lastname=[last name]
&p15_guests.contact.1.samehousehold=true    
&p15_guests.contact.2.p15_contacttype_contactid=Client
&p15_guests.contact.2.firstname=[first name]
&p15_guests.contact.2.lastname=[last name]
&p15_guests.contact.2.samehousehold=true



Including this line will result in all existing guests on the booking being deleted


&deleteexistingguests=true



If you want to cancel a booking and all the guests on it:


https://data.peak15systems.com/beacon/service.svc/update/complex/contactbooking
?token=yourtokenhere
&p15_bookings.p15_bookingsid=[booking GUID]
&p15_bookings.p15_comment=Cancel reason
&p15_bookings.statuscode=Cancelled



Or if you want to delete a booking and all the guests on it:


https://data.peak15systems.com/beacon/service.svc/delete/entity/p15_bookings
?token=yourtokenhere
&p15_bookingsid=[booking GUID]



Or add a canceled guest to an existing booking:


https://data.peak15systems.com/beacon/service.svc/update/complex/contactbooking
?token=yourtokenhere
&p15_bookings.p15_bookingsid=[booking GUID]
&p15_guests.contact.1.p15_contacttype_contactid=Client
&p15_guests.contact.1.firstname=[first name]
&p15_guests.contact.1.lastname=[last name]
&p15_guests.contact.1.samehousehold=true
&p15_guests.contact.1.statuscode=Cancelled  



Update a Contact Guest

The following post will take the GUID of an existing guest record and update a combination of guest entity attributes like airline and arrival time as well as contact entity attributes like passport information. Note that passing a blank value for an attribute causes that attribute to be ignored. If you wish to set the value of an attribute to NULL, you must use the ASCII value of '%00'.


https://data.peak15systems.com/beacon/service.svc/update/complex/contactGuest
?token=[token]
&p15_guests.p15_guestsid=[guestGUID]
&p15_guests.p15_airline=[airline]
&p15_guests.p15_arrivaltime=[arrivaltime]
&contact.p15_nameonpassport=[passportname]


If you want to cancel a specific guest:


https://data.peak15systems.com/beacon/service.svc/update/entity/p15_guests
?token=[token]
&p15_guestsid=[guestGUID]
&statuscode=Cancelled
&p15_comments=Cancel reason


Or delete a specific guest:


Add or Remove an Optional Price from an Existing Guest

Once a booking has been created, you may use the following syntax to add optional prices to an existing guest's booking:


https://data.peak15systems.com/beacon/service.svc/insert/nn/p15_p15_tripprices_p15_guests
?token=[token]
&p15_guestsid=[guestGUID]
&p15_trippricesid=[trippriceGUID]


The following would remove an optional price from an existing guest's booking:


https://data.peak15systems.com/beacon/service.svc/delete/nn/p15_p15_tripprices_p15_guests
?token=[token]
&p15_guestsid=[guestGUID]
&p15_trippricesid=[trippriceGUID]


Add or Remove a Cost Item Reservation from an Existing Guest

Once a booking has been created, you may use the following syntax to add cost item reservations to an existing guest's booking:


https://data.peak15systems.com/beacon/service.svc/insert/nn/p15_p15_vendorserviceitemres_p15_guests
?token=[token]
&p15_guestsid=[guestGUID]
&p15_vendorserviceitemreservationid=[costitemresGUID]


The following would remove a cost item reservation from an existing guest's booking:


https://data.peak15systems.com/beacon/service.svc/delete/nn/p15_p15_vendorserviceitemres_p15_guests  
?token=[token]
&p15_guestsid=[guestGUID]
&p15_vendorserviceitemreservationid=[costitemresGUID]



Process Additional Guest Payments

See Working with PEAK 15 Pay or Working with Stripe.  Cybersource is a no longer supported.



Capture a Credit Card for a Guest

See Working with PEAK 15 Pay or Working with Stripe.  Cybersource is a no longer supported.



Capture a Credit Card for a Contact that isn't a Guest

See Working with PEAK 15 Pay or Working with Stripe.  Cybersource is a no longer supported.



Create Invoice Separately

Though the contact booking function provides a way to create an invoice automatically, there are situations where you need to be able to manually add items to an invoice that are not associated with pre-existing prices. In these cases you should not create the invoice during the booking and instead create the invoice separately with:


https://data.peak15systems.com/beacon/service.svc/insert/complex/invoice
?token=[yourtokenhere]
&p15_invoices.p15_contactid=[contactGUID]
&p15_invoices.p15_primarybookingid=[bookingGUID]
&p15_invoices.p15_paymentscheduleid=[paymentscheduleGUID]
&p15_invoiceitems.1.p15_name=[invoice item name]
&p15_invoiceitems.1.p15_categoryid=[price category name or GUID]
&p15_invoiceitems.1.p15_bookingsinvoiceitemsid=[booking GUID]
&p15_invoiceitems.1.p15_quantity=1
&p15_invoiceitems.1.p15_rate=250
&p15_invoiceitems.2.p15_name=[invoice item name]
&p15_invoiceitems.2.p15_categoryid=[price category name or GUID]
&p15_invoiceitems.2.p15_bookingsinvoiceitemsid=[booking GUID]
&p15_invoiceitems.2.p15_quantity=1
&p15_invoiceitems.2.p15_rate=100


Note that you DO NOT need to manually add invoice items for those prices booked by guests. Those will be added for you automatically.  If you don't want invoice items created for prices booked by guests send in:

p15_invoices.p15_createinvoiceitems=[true/false (defaults to true if not specified, set to false if you will be sending in all invoice items manually)]

 


To delete an invoice:


https://data.peak15systems.com/beacon/service.svc/delete/entity/p15_invoices
?token=[yourtokenhere]
&p15_invoicesid=[invoiceGUID]



Update an Invoice

Rather than deleting an Invoice and reinserting a new one, you can also update it. The advantage of updating the invoice is that it allows the Invoice history to be maintained. Updating an Invoice in Beacon follows the same rules that apply to users trying to update an Invoice inside the application. If an Invoice has a status of Approved, Downloaded or Entered, then updating the invoice requires that it be revised. Revising an invoice causes a new replacement invoice to be created and an offsetting credit memo (or negative invoice) to be created and applied to the old invoice and any payments on the old invoice to be moved to the new invoice.


https://data.peak15systems.com/beacon/service.svc/update/complex/invoice
?token=[yourtokenhere]
&p15_invoices.p15_invoicesid=[GUID of invoice]
&deleteexistinginvoiceitems=[true/false (defaults to false if not specified, set to true if you will be sending in all invoice items manually)]
&p15_invoices.p15_createinvoiceitems=[true/false (defaults to true if not specified, set to false if you will be sending in all invoice items manually)]
&p15_invoices.p15_updateinvoiceitems=[rateonly/quantityonly/rateandquantity (default to quantityonly if not specified)]
&p15_invoiceitems.1.p15_name=[invoice item name]
&p15_invoiceitems.1.p15_categoryid=[price category name or GUID]
&p15_invoiceitems.1.p15_bookingsinvoiceitemsid=[booking GUID]
&p15_invoiceitems.1.p15_quantity=1
&p15_invoiceitems.1.p15_rate=250
&p15_invoiceitems.2.p15_name=[invoice item name]
&p15_invoiceitems.2.p15_categoryid=[price category name or GUID]
&p15_invoiceitems.2.p15_bookingsinvoiceitemsid=[booking GUID]
&p15_invoiceitems.2.p15_quantity=1
&p15_invoiceitems.2.p15_rate=100


The "normal" usage of the system would be to set deleteexistinginvoicetiems to false, createinvoiceitems to true and then to only send in invoice items for anything that is being manually added to the booking such as a special discount or one off service. If the invoice ID sent in doesn't exist or has a status of Disapproved, an error will be returned. If the status is Submitted, it will update the invoice based on the flags set and any additional invoice items sent it. If the status is Approved, Downloaded or Entered, it will revise the invoice as described above.


Note:  When sending manual invoice items you MUST provide the booking GUID or else the invoice item will not be created.



Promo Codes

This is supported in insert/contact booking and update/contact booking calls only. 

Using p15_bookings.p15_promocode=[GUID] parameter, we can link the booking with the promo code, considering the validations in the logic of the plugins.

If the promo code entered is invalid, the following error message will be returned and the booking will not be created.
BookingContact error = p15_promocodes With Id = [Guid] Does Not Exist.

https://data.peak15systems.com/beacon/service.svc/insert/complex/contactbooking?
contact.firstname=testFName
&contact.lastname=testLName
&contact.emailaddress1=test@tester.com
&contact.p15_contacttype_contactid=Client
&p15_bookings.p15_tripdepartures_bookingsid={F6155978-7D19-ED11-80EE-00155D02B866}
&p15_guests.contact.1.isClient=true
&p15_invoices.p15_paymentscheduleid={36AE83A1-5878-E111-A0D9-0050568B0004}
&token={TOKEN}
&p15_bookings.p15_promocode={E98ADC6A-288B-EB11-80E3-00155D02AD2A}