How To Pull Draw Information Into Braze From Our API

    Have you ever wondered how your website and mobile app (if applicable) do such a great job of displaying the same draw data that you set via the Draw CMS in Admin UI?

    Have you noticed how the draws close and open automatically on both apps according to the draw dates you set?

    The reason these separate apps can run with effortless automation and synchronisation is that they both use the same PBJ API to retrieve and change data in the one PBJ database.

    There is no reason why your Braze marketing cannot do the same. In fact, pulling data from the PBJ API is the first step in automating your BAU marketing.

    What Are The Benefits Of Automating My Marketing?

    • Less clutter in Braze
    • Less chance of human error when duplicating existing campaigns, scheduling and changing draw details
    • Less time working on BAU means more time for you to focus on other growth ideas

    For security reasons, only GET requests to publicly available endpoints are recommended to be used from Braze. Any endpoints with sensitive customer data will require JWT authentication and we highly recommend to not go down this path.

    PBJ’s original client, Oz Lotteries (OZL), has found that the pricing endpoint is really the only endpoint they need to achieve automation with all of their recurring scheduled messages.

    The pricing endpoint contains data on everything you would need to know about any of your future lotteries and draws.

    One thing the pricing endpoint doesn’t contain is styling info. For that, we can use the branding endpoint.

    The rest of this article is a recipe that any client can follow to achieve marketing automation.

    Steps To Achieve Marketing Automation

    1. Create A Braze Content Block That Uses Connected Content

    A Content Block is a snippet of code or text that can be included within any Braze message with just a single line of code.

    At its most basic a content block could be a static email footer.

    A more advanced use for Content Blocks is to use them whenever you require any Connected Content.

    Remember to substitute ozlotteries.com with your own URL.

    {% connected_content       
    https://api.ozlotteries.com/api/v2/pricing/{{custom_attribute.${pricing_name}}}/product_offers      
    :headers {        
    "X-Jumbo-Version": "3.4",         
    }      
    :save pricing    
    %}

    What’s Happening Here?

    We are making a GET request to the 3.4 version of the pricing endpoint and saving the complete JSON response as a variable called pricing.

    We specify version 3.4 so that the structure of the response will always be consistent. We can check the currently supported API versions by visiting https://api.ozlotteries.com/api/v2 at any time.

    You’ll notice that OZL includes a pricing_name custom attribute in their pricing URL. This helps with their licencing restrictions as they can only sell certain products to customers from certain states.
    If such restrictions do not apply to your company you can try substituting this custom attribute with the name of your country, e.g. “australia”.

    2. Include The Pricing Content Block In Your Message

    Imagine we are given the task to create a “last-chance” email for a specific lottery that has a draw every week.

    In this case, it would be best to use Connected Content to automatically grab the correct lottery names, draw dates, descriptions, prize details, images and URLs at the time of send to populate the contents of that email.

    We can do this by creating a weekly recurring email in Braze, including our own pricing content block (which uses connected content) and pulling the information we need directly from the API.

    We might start out by creating an email like this:

    Hi {{${first_name}}}, 
    
    {{content_blocks.${pricing}}} 
    
    You might be interested in this draw closing soon: 
    
    {{pricing}} 

    Right now, our email is absolutely unusable because the {{pricing}} variable we output in the email contains way too much data for any reader to decipher.

    The trick is pulling out only the data you need, using Liquid.

    The best way to get started with this is to find the right tools to make API endpoints like this one more legible for yourself:

    • For Chrome users, JSON Formatter is a free extension that helps you read JSON data more easily. Otherwise, Firefox makes JSON data more readable by default. Unfortunately, neither of these browser options will let you add your own API headers, such as when we request a specific version of the API.
    • Postman, while it has a bit of a learning curve, is the tool we’d recommend. It will allow you to make a GET request including headers.

    Postman-1024x772.png

    3. Use Liquid To Find The Data You Need

    Liquid is a programming language developed by Shopify.

    Braze’s and Twilio both have some great documentation explaining which features of Liquid are actually supported in Braze.

    Take some time to familiarise yourself with tagsconditionalsfor loopsfilters and dates. It would also be helpful to have some understanding of JSON data types.

    Liquid supports dot notation to traverse your way down a JSON response.

    If you wanted to get access to the first offer within the offers array, you could do so like this:

    Untitled.png

    {{content_blocks.${pricing}}}
    {{pricing.result.offers.first}}
    1. Initiate the content block
    2. Use dot notation to traverse your way down the response and output a value.

    Your offers are listed in order of ranking and may change according to prize pools or draw dates, so a more reliable way to find the offer is to create a for loop.

    for loop will let you select the exact item you want from an array. For example, you may want to retrieve the data for a specific lottery and for a specific draw number.

    You can find more info on how to do that here.

    Now, let’s grab the first item from the offers array to create our email.

    Hi {{${first_name}}},
    
    {{content_blocks.${pricing}}}
    
    {% assign offer = pricing.result.offers.first %}
    
    You might be interested in this draw closing soon:
    {{offer}}

    We are getting closer to automation now but {{offer}} is still a big JSON object. We really just need individual pieces of data to include in our email. Time for more dot notation…

    Untitled-1-1024x382.png

    Hi {{${first_name}}}, 
    
    {{content_blocks.${pricing}}} 
    
    {% assign offer = pricing.result.offers.first %} 
    
    You might be interested in this draw closing soon: 
    
    Jackpot image: {{offer.draws.first.jackpot_image.image_url}} 
    
    Draw closes: {{offer.draws.first.stop}} 
    
    Prize pool: {{offer.draws.first.prize_pool.amount}} 
    
    Click here to enter: https://api.ozlotteries.com/{{offer.url}} 

    Much better. Now when this email sends each week the content will be up-to-date with the current draw.

    4. Include Branding

    Your branding endpoint is <<YOUR API URL>>/api/v2/branding

    It returns what is essentially your style guide. It contains lottery names, logos, colours, etc. and includes region overrides if your branding changes for each customer’s state like OZL’s does.

    OZL has another Connected Content block similar to the pricing content block, but just for branding. They include that in their email to set background colours and logos.

    {{content_blocks.${branding}}} 
    
    <div style="background:{{branding.brand_colour_primary}}"> <img src="{{branding.icon_url}}" /> 
    
    Hi {{${first_name}}}, 
    
    {{content_blocks.${pricing}}} 
    
    {% assign offer = pricing.result.offers.first %} 
    
    You might be interested in this draw closing soon: 
    
    Jackpot image: {{offer.draws.first.jackpot_image.image_url}} 
    
    Draw closes: {{offer.draws.first.stop}} 
    
    Prize pool: {{offer.draws.first.prize_pool.amount}} 
    
    Click here to enter: https://api.ozlotteries.com/{{offer.url}} </div> 

    5. Find Repeating Patterns And Fix Them

    Whenever you find yourself repeating patterns in your messages it’s a good time to stop and ask yourself if there’s a way to make things simpler.

    Instead of using Liquid’s dot notation in all your messages, you may decide to assign these variables only once in your content block.

    Now in your messages, you don’t have to worry about writing the same dot notation again. You can simply output the variable.

    This code was moved into the branding content block:

    {% assign primary_colour = branding.brand_colour_primary %}
    {% assign logo = branding.icon_url %}

    And this code was moved into the pricing content block:

    {% assign offer = pricing.result.offers.first %}
    {% assign url = offer.url %}
    {% assign jackpot_image = offer.draws.first.jackpot_image.image_url %}
    {% assign draw_stop = offer.draws.first.stop %}
    {% assign prize_pool = offer.draws.first.prize_pool.amount %}

    Wow, our message is now so much easier to read!

    {{content_blocks.${pricing}}}
     {{content_blocks.${branding}}}
    
    <div style="background:{{primary_colour}}"> <img src="{{logo}}" /> 
    
    Hi {{${first_name}}},     
    
    You might be interested in this draw closing soon: 
    
    Jackpot image: {{offer.draws.first.jackpot_image.image_url}} 
    
    Draw closes: {{offer.draws.first.stop}} 
    
    Prize pool: {{offer.draws.first.prize_pool.amount}} 
    
    Click here to enter: https://api.ozlotteries.com/{{offer.url}} </div>  

    6. If In Doubt, Abort

    The last thing you want to do is send your customers an incomplete message because you were expecting a variable that wasn’t returned by the API.

    There are a few things you should look out for:

    HTTP status

    In your content block, after the connected_content code, you’ll want to make sure your GET request returns a 200 (successful) response.

    {% if pricing.__http_status_code__ != 200 %}
      {% abort_message('pricing connected content returned a non-200 status code') %}
    {% endif %}

    Empty variables

    Even if the response is successful you should ensure the variables you require can be found. When a required variable == blank it means it could not be found. In these situations, you should abort your message. In this example, we could not find an offer so we abort.

    {% assign offer = pricing.result.offers.first %}
    
    {% if offer == blank %}
    	{% abort_message("Could not find a matching offer") %}
    {% endif %}
    

    Offer availability

    Certain offers may not be available to customers from different pricing regions.

    {% if offer.availability != "available" %}
        {% abort_message('offer is not available') %}
    {% endif %}

    Draw status

    A draw may have sold out ahead of schedule.

    {% assign draw = pricing.result.offers.first.draws.first %}
    
    {% if draw.status != "DRAW_OPEN" %}
        {% abort_message('draw is no longer open') %}
    {% endif %}

    7. Tidy Up Data With Liquid Filters

    There are many Liquid filters that can help you transform the data you retrieved into the format you desire.

    Let’s look at this example:

    Draw closes: {{draw_stop}}
    	
    Prize pool: {{prize_pool}}

    In its current state, the email would render like so:

    Draw closes: 2021-11-25T20:25:00+1100
    	
    Prize pool: 60000000
    

    To fix this, we can use filters:

    Draw closes: {{draw_stop | date: "%B %e, %Y at %l:%M %p %Z"}}
    	
    Prize pool: {{prize_pool | number_with_delimiter | remove: '.00' | prepend: '$'}}

    And the end results should look something like this:

    Draw closes: November 25, 2021 at 8:25PM AEDT
    	
    Prize pool: $60,000,000

    Hopefully, this information allows your marketing team to automate their most time-consuming campaigns and give them more time to focus on other growth initiatives.

    Was this article helpful?
    0 out of 0 found this helpful