Introduction

The OpenWater platform provides two levels of premium APIs to customers as well as unlimited support.

Single Sign On (using Javascript Web Tokens)

Using this API you can allow entrants to authenticate via your existing contact / membership database. Information can be passed into OpenWater to streamline processes.

Data API
Access all submission form data as well as invoice / payment data programmatically. OpenWater provides a flexible approach to retrieving data in JSON format.

Single Sign On

Workflow Overview

Step 1

Single Sign On between OpenWater and your site occurs as a handshake process. An entrant or judge begins on the OpenWater platform and may click a link to begin a submission or is simply presented with a login button.

Step 2

The user is redirected to your site where they are asked to login and create an account. OpenWater passes along the query string parameter returnUrl which you should save in a local cookie or a session.

Step 3

The user logins in (or creates an account) on your website successfully. You must now redirect the user back to the OpenWater site using that returnUrl with &token={generated token} appended.

The generated token is created using the JSON web token standard. See below for code samples.

Configuring OpenWater

  1. When logged into OpenWater as an admin toggle to the System Settings > Authentication
  2. Choose to enable Allow 3rd Party Authentication
  3. Choose Json Web Token from the list of choices and provide the link to your handler, a shared secret key (shared with your code) and text for the login button
  4. Press Save
  5. Using Google Chrome, right click Public Website at the top of the screen and choose to load it in an Incognito Window. If you do not have google chrome, simply log out and go to the public site.
  6. On the OpenWater site you will now see a button to login
  7. Clicking that button will redirect the user to your site and properly set the returnUrl parameter in the query string
  8. The OpenWater side of things is now configured well, continue reading to implement the handler.

Writing the Handler

The handler involves two steps. The beginning of the handshake when OpenWater passes the returnUrl to your site and the end of the handshake when you redirect the user back to OpenWater with a JSON Web Token.

Step 1 - Beginning the Handshake

When the user is taken to your site OpenWater passes you the returnUrl as a query string. You need to store this data in either the session or a cookie.


            if (userIsLoggedIn)
                Response.Redirect("/CompleteHandshake");
            else
            {
                Session["_openwater_auth"] = Request["returnUrl"]; //Save the return URL in the session (cookie would be fine too)     
                Response.Redirect("/LoginOrCreateAccount");  //Skip to Step 3
            }
            

PHP Code Sample


            if(isset($_SESSION["userIsLoggedIn"]) && $_SESSION["userIsLoggedIn"] !="") {
                header("Location: /CompleteHandshake");
                die();
            } else {
                $_SESSION["_openwater_auth"] = $_GET["returnUrl"];
                header("Location: /LoginOrCreateAccount");
                die();
            }
            

Step 2 - User Authenticates or Creates an Account on your website

Upon completion of this step you should at a minimum be able to provide OpenWater the following information:

  • First Name
  • Last Name
  • Email Address

Then you should invoke the redirect described in the next step.

Step 3 - Redirecting the User back to OpenWater to Complete the Handshake

Now that the user is successfully logged in to your site, it is time to send them back to OpenWater. Remember that returnUrl you saved in step 1? Now it’s time to combine that with a Javascript Web Token and send them back.

C# Code Sample
Required Package: https://www.nuget.org/packages/JWT

var jwtSecret = "SharedKey"; //Shared Key as set in configuration
var returnUrl = Session["returnUrl"].ToString(); //the returnUrl saved earlier

//Get variables from contact database
var firstName = "FirstName";
var lastName = "LastName";
var email = "valid@email.com"; //MUST Be a valid email format
var validatedAsMember = false; //For example if you have member / nonmember pricing you may want to set this flag
var additionalData = ""; //Optional you can use this if you need to set pricing based on some other criteria like a member role

var jwt = JWT.JsonWebToken.Encode(new 
            {
                TimestampUtc = DateTime.UtcNow,
                Email = email,
                FirstName =  firstName,
                LastName = lastName,
                UserNameExists = true,
                UserValidatedSuccessfully = true,
                UserIsMember = validatedAsMember ,
                UserData = additionalData               
            }, jwtSecret, JwtHashAlgorithm.HS256);


return Redirect(string.Format("{0}&token={1}", returnUrl, jwt));

PHP Code Sample
Required Package: https://github.com/firebase/php-jwt

include_once "Authentication/JWT.php"; //https://github.com/firebase/php-jwt 

$key       = "{my openwater shared key}";
$now       = gmdate("Y-m-d H:i:s");

$returnUrl = $_SESSION["returnUrl"]; // as saved in step 1

//Get variables from contact database
$firstName = "FirstName";
$lastName = "LastName";
$email = "valid@email.com"; //Must be a valid email format

$validatedAsMember = false; //For example if you have member / nonmember pricing you may want to set this flag
$additionalData = ""; //Optional you can use this if you need to set pricing based on some other criteria like a member role

$token = array(
  "TimeStampUtc"   => $now,
  "Email"  => $email,
  "FirstName" => $firstName,
  "LastName" => $lastName,
  "UserNameExists" => true,
  "UserIsMember" => $validatedAsMember,
  "UserData" => additionalData
);

$jwt = JWT::encode($token, $key);

$location = $returnUrl."&token=".$jwt;

// Redirect
header("Location: " . $location);

For Node.js, Python, Java and other languages you can download JWT generating libraries here: http://jwt.io/#libraries

Prepopulating Fields

You can save your entrants time by prepopulating some information in their user profile. This data can then be used to setup price rules and report conditions in OpenWater. It can also be used to help the entrant save time filling out their forms.

Step 1 - Get a List of Field IDs

In the OpenWater platform, under the System Settings > User Profile you can define custom fields to attach to an entrant’s profile. Your OpenWater support teammate can get you the field IDs to map to.

Step 2 - Modify the Token Code

When constructing the token you can also pass back additional custom data.

C# Code Sample

//Code Sample Above Omitted for Brevity

var customField1 = new Guid("2c1721a4-5fe1-4c4d-bb8f-c36d3046e489");
var customField2 = new Guid("2c1721a4-5fe1-4c4d-bb8f-c36d3046e489");
var customField3 = new Guid("2c1721a4-5fe1-4c4d-bb8f-c36d3046e489");


var dictionary = new Dictionary();
dictionary.Add(customField1, "Value 1");
dictionary.Add(customField2, "Value 2");
dictionary.Add(customField3, "Value 3");

//Sample below adds ProfileTextFieldData

var jwt = JWT.JsonWebToken.Encode(new 
            {
                TimestampUtc = DateTime.UtcNow,
                Email = email,
                FirstName =  firstName,
                LastName = lastName,
                UserNameExists = true,
                UserValidatedSuccessfully = true,
                UserIsMember = validatedAsMember ,
                UserData = additionalData,
                ProfileTextFieldData = dictionary
            }, jwtSecret, JwtHashAlgorithm.HS256);


return Redirect(string.Format("{0}&token={1}", returnUrl, jwt));

Data API

Authentication

To access any of the Data APIs you will need to get a license key from OpenWater support. You can then pass that in via the header licenseKey.

Invoice / Payment Data Endpoint

You can retrieve information on invoices including all payment information with a simple GET request.

The result will look like a JSON Array of invoices coupled with information about the entrant, an array of line items, an array of payments and an array of related submissions.

C# Example Request
Required Package: https://www.nuget.org/packages/Newtonsoft.Json/

public static IEnumerable GetInvoices(string licenseKey, bool includeUnpaid = false, DateTime? startDate = null, DateTime? endDate = null)
        {
            var host = "training.secure-platform.com"; //REPLACE WITH YOUR OPENWATER URL

            using (var client = new WebClient())
            {
                // Append some custom header
                client.Headers.Add("licenseKey", licenseKey); //invoiceLastUpdatedAtStart
                var url = string.Format("https://{0}/a/admin/Api/GetInvoices?includeUnpaid={1}", host, includeUnpaid);
                if (startDate.HasValue)
                    url += "&" + startDate.Value.ToShortDateString();

                if (endDate.HasValue)
                    url += "&" + endDate.Value.ToShortDateString();

                var result = client.DownloadString(url);
                return JsonConvert.DeserializeObject>(result);
            }
        }

//Helper Classes
public class BillingLineItem
        {
            public object accountingTransaction { get; set; }
            public int accountingTransactionId { get; set; }
            public double amount { get; set; }
            public object notes { get; set; }
            public string details { get; set; }
            public bool isManualAdjustment { get; set; }
            public string createdIn { get; set; }
            public int id { get; set; }
            public string createdAt { get; set; }
            public object updatedAt { get; set; }
        }

        public class Payment
        {
            public object accountingTransaction { get; set; }
            public int accountingTransactionId { get; set; }
            public double amount { get; set; }
            public bool isManualAdjustment { get; set; }
            public bool isPromissoryNote { get; set; }
            public bool canRefund { get; set; }
            public object externalPaymentTransactionData { get; set; }
            public string billingName { get; set; }
            public string referenceNumber { get; set; }
            public string notes { get; set; }
            public string method { get; set; }
            public string details { get; set; }
            public string createdIn { get; set; }
            public int id { get; set; }
            public DateTime createdAt { get; set; }
            public object updatedAt { get; set; }
        }

        public class UserProfileField
        {
            public string fieldId { get; set; }
            public string name { get; set; }
            public string value { get; set; }
        }

        public class Submission
        {
            public int submissionId { get; set; }
            public string applicationName { get; set; }
            public string applicationCode { get; set; }
            public string categoryCode { get; set; }
            public string category { get; set; }
            public string fullCategoryPath { get; set; }
        }

        public class Invoice
        {
            public string userData;
            public int invoiceId { get; set; }
            public DateTime invoiceDate { get; set; }
            public bool paid { get; set; }
            public List billingLineItems { get; set; }
            public List payments { get; set; }
            public double totalBilled { get; set; }
            public double totalPaid { get; set; }
            public int userId { get; set; }
            public string email { get; set; }
            public string firstName { get; set; }
            public string lastName { get; set; }
            public List userProfileFields { get; set; }
            public List submissions { get; set; }
        }

PHP Example Request


                    function GetInvoices($includeUnpaid = false, $startDate = null , $endDate = null  )
					{                    
						$licenseKey = 'Get LicenseKey from OpenWater';
						$host = "demo.secure-platform.com"; //REPLACE WITH YOUR OPENWATER URL
						
						$url="https://".$host."/a/admin/Api/GetInvoices?includeUnpaid=" . $includeUnpaid;
										
						if($startDate != null ){
							$url .="&invoiceAtStart=".$startDate;
						}

						if($endDate != null ){
							$url .="&invoiceAtEnd=".$endDate;
						}
						
						$ch = curl_init();
						curl_setopt($ch, CURLOPT_URL, $url);
						curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
						curl_setopt($ch, CURLOPT_HTTPHEADER, array('LicenseKey: ' . $licenseKey));
						curl_setopt($ch, CURLOPT_TIMEOUT_MS, 50000);

						$result = curl_exec($ch);
						curl_close ($ch);

						$obj = json_decode($result);
						
						return $obj;
					}

					//In this example we'll pull invoices from the last 10 days
					$tenDaysAgo =  (date('Y-m-d', time() - (10 * 24 * 60 * 60)));
					$today =  (date('Y-m-d', time()));

					$data = GetInvoices(false, $tenDaysAgo, $today);

					//show all variables
					foreach($data as $item)
					{
						print_r($item);	
					}

					//Most popular data
					foreach($data as $item)
					{
						echo ("\r\ninvoice id: " . $item->invoiceId);
						echo ("\r\ninvoice date: " .  $item->invoiceDate);
						
						foreach($item->payments as $payment)
						{
							echo ("\r\npayment amount: ". $payment->amount);
							echo ("\r\npayment date: ". $payment->createdAt);
							echo ("\r\npayment details: ". $payment->details);
							echo ("\r\npayment gateway reference number: ". $payment->externalPaymentTransactionData);
						}
						
						foreach($item->submissions as $submission)
						{
							echo ("\r\napplication id: ". $submission->applicationCode);
							echo ("\r\napplication title: ". $submission->applicationName);
							echo ("\r\nprogram name: ". $submission->solicitationName);
							echo ("\r\ncategory: ". $submission->fullCategoryPath);		
						}
						
						echo "\r\n--------------\r\n";
					}
                    
                    

JSON RESPONSE

[
  {
    "invoiceId": 1120,
    "invoiceDate": "2015-03-06T14:10:55.257",
    "paid": true,
    "billingLineItems": [
      {
        "accountingTransaction": null,
        "accountingTransactionId": 1120,
        "amount": 75,
        "notes": null,
        "details": "Base fee",
        "isManualAdjustment": false,
        "createdIn": "Awards",
        "id": 1315,
        "createdAt": "2015-03-06T14:10:55.273",
        "updatedAt": null
      },
      {
        "accountingTransaction": null,
        "accountingTransactionId": 1120,
        "amount": 75,
        "notes": null,
        "details": "Base fee",
        "isManualAdjustment": false,
        "createdIn": "Awards",
        "id": 1316,
        "createdAt": "2015-03-06T14:10:55.897",
        "updatedAt": null
      }
    ],
    "payments": [
      {
        "accountingTransaction": null,
        "accountingTransactionId": 1120,
        "amount": 150,
        "isManualAdjustment": false,
        "isPromissoryNote": false,
        "canRefund": false,
        "externalPaymentTransactionData": null,
        "billingName": "LastName, FirstName",
        "referenceNumber": "93",
        "notes": null,
        "method": "CreditCard",
        "details": "Paid with 'Amex' ending in 6002",
        "createdIn": "Awards",
        "id": 1065,
        "createdAt": "2015-03-06T14:10:56.477",
        "updatedAt": null
      }
    ],
    "totalBilled": 150,
    "totalPaid": 150,
    "userId": 53495,
    "email": "FirstLast@example.com",
    "firstName": "John",
    "lastName": "Doe",
    "userProfileFields": [
      {
        "fieldId": "f2e55e0d-a7a7-4748-b42c-ef3d45a78e96",
        "name": "Company Name",
        "value": "ACME Corp"
      },
      {
        "fieldId": "f139e8f2-3755-4804-81b7-6c363022bc08",
        "name": "Job Title",
        "value": "President"
      },
      {
        "fieldId": "5b9e40ec-678e-4bfa-bba3-867b00e0df4d",
        "name": "Primary Address.Country",
        "value": "UNITED STATES"
      },
      {
        "fieldId": "5b9e40ec-678e-4bfa-bba3-867b00e0df4d",
        "name": "Primary Address.State",
        "value": "FL"
      },
      {
        "fieldId": "5b9e40ec-678e-4bfa-bba3-867b00e0df4d",
        "name": "Primary Address.City",
        "value": "Orlando"
      },
      {
        "fieldId": "5b9e40ec-678e-4bfa-bba3-867b00e0df4d",
        "name": "Primary Address.Street",
        "value": "2100 Disney Land"
      },
      {
        "fieldId": "5b9e40ec-678e-4bfa-bba3-867b00e0df4d",
        "name": "Primary Address.Zip",
        "value": "32814"
      },
      {
        "fieldId": "5b9e40ec-678e-4bfa-bba3-867b00e0df4d",
        "name": "Primary Address.Line2",
        "value": null
      }
    ],
    "submissions": [
      {
        "submissionId": 127,
        "applicationName": "Submission 1",
        "applicationCode": "HOBE-127",
        "categoryCode": "HOBE",
        "category": "Hot Beverage",
        "fullCategoryPath": "Hot Beverage"
      }
    ],
    "userData": "Data From CRM"
  }
]

Report Endpoint

The reports endpoint allows you as a developer to customize and pull only the information you need from submission data. The process begins by defining a report using the standard report builder in OpenWater.

Once this is setup toggle to the Advanced Tab and enable Json exports

Use the following code sample boiler plate

#HEADER#
data = []
#END HEADER#

#BODY#
temp = {}
temp["Id"] = {ApplicationCode}
temp["ExternalIds"] = {ExternalUserAuthData}
temp["Email"] = {Email}
#temp["YourVariable1"] = {Company}

data.append(temp)
#END BODY#

#FOOTER#
___result = data
#END FOOTER#

Then go ahead and add as many variables you’d like by choosing the variables you’d like to export.

Finally make a note of the report ID in the URL -- in this case it is report # 14

Now that the report is prepared you can retrieve the JSON formatted data exactly as you requested it

JSON Data Example

[
    {
        "Email": "person@example.com",
        "ExternalIds": "Test",
        "Id": "LINE-6143"
    },
]

To query this report via an API you can request it and then poll for a response until it is ready. When it is ready the result will be stored in a file that you can download and process.

C# Sample Code
Required Package: https://www.nuget.org/packages/Newtonsoft.Json/
Required Package: https://www.nuget.org/packages/Microsoft.Net.Http

public static string DownloadReport(int reportId, string licenseKey)
        {
            var host = "training.secure-platform.com"; //replace with your OpenWater instance URL

            using (var client = new WebClient())
            {
                // Append some custom header
                client.Headers.Add("licenseKey", licenseKey);

                
                var data = Encoding.UTF8.GetBytes("");


                var result = client.UploadString(string.Format("https://{0}/a/admin/Api/BeginReportJob?reportId={1}&outputFormat=json", host, reportId), "");

                dynamic jobResult = JObject.Parse(result);


                var stopWatch = new Stopwatch();
                stopWatch.Start();

                while (stopWatch.Elapsed.TotalSeconds < 600)
                {
                                  var jobReadyResult =
                        client.DownloadString(
                            string.Format("https://{0}/a/admin/Api/GetReportJobStatus?jobId={1}", url,
                                jobResult.result.jobId));


                    var jobReadyResultObject = JObject.Parse(jobReadyResult);

                    if (jobReadyResultObject.result.status == CronJobStatus.Completed)
                    {
                        var fullData = jobReadyResultObject.result.result;
                        dynamic dataResult = (JObject.Parse((string)fullData));
                        return client.DownloadString((string)(dataResult.fileUrl));
                    }
                    else if (jobReadyResultObject.result.status == CronJobStatus.Failed)
                    {
                        throw new Exception("Report Failed");
                    }

                    System.Threading.Thread.Sleep(5000);
                }
                throw new Exception("Report Timedout");
            }
        }


        public enum CronJobStatus
        {
            None,
            Requested,
            InProgress,
            Completed,
            Failed
        }

        public class ReportResult
        {
            public int JobId { get; set; }
            public CronJobStatus Status { get; set; }
            public string Result { get; set; }
        }

PHP Sample


function DownloadReport($reportId, $licenseKey)
{
	$host = "training.secure-platform.com"; //replace with your OpenWater instance URL
	$url="https://".$host."/a/admin/Api/BeginReportJob?reportId=".$reportId."&outputFormat=json";
	
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('LicenseKey ' . $licenseKey));
	$result = curl_exec($ch);
	$obj = json_decode($result);
	curl_close ($ch);
	
	$url2="https://".$host."/a/admin/Api/GetReportJobStatus?jobId=".$obj->result->jobId;


			$ch = curl_init();
			curl_setopt($ch, CURLOPT_URL, $url2);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
			$jobReadyResult = curl_exec($ch);
			$jobReadyResultObject = json_decode($jobReadyResult);
			curl_close ($ch);


                    if ($jobReadyResultObject->result->status == "Completed")
                    {
                        $fullData = $jobReadyResultObject->result->result;
						
  							$url3=$fullData->fileUrl;
  						
							$ch = curl_init();
							curl_setopt($ch, CURLOPT_URL, $url3);
							curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
							$jobReadyFullResult = curl_exec($ch);
							$jobReadyFullResultObject = json_decode($jobReadyFullResult);
							curl_close ($ch);
							return $jobReadyFullResultObject;

                    }
                    else if ($jobReadyResultObject->result->status == "Failed")
                    {
						echo "Report Failed";
						die();
                    }



	
}