Is Cloud Architecture a Good Fit for Cannabis Point-of-Sale Systems?

By | Cloud | No Comments

Cloud architecture or browser-based web applications are becoming staples of business and enterprise-level software systems. Internet behemoths like Salesforce run their entire suite of business applications exclusively through the cloud. How is this strategy relevant to the cannabis industry as compared to a more traditional windows desktop application design?

Leading seed-to-sale companies prefer both strategies. MJ Freeway relies on the cloud for its services, whereas BioTrackTHC runs a desktop application supported by an in-house centralized database. Both models have benefits and problems, below I’ll explain why we prefer using the cloud.


Reduce hardware complexity

The desktop approach typically requires more hardware and networking than web apps. It’s advantageous to have an on-site IT resource to help setup and maintain all the moving parts. For many smaller dispensaries this is may not be a viable option.

By moving your system onto the web you no longer need to invest and maintain those hardware and labor costs. Software upgrades and fixes happen instantaneously across the application without needing any technical help.

Foolproof data backup

Instead of your data living on one server or a collection of desktops in your dispensary, it will now be securely backed-up across many cloud servers. Losing a server or a back-up will no longer expose your business to data loss.

Off-site access

The cloud approach enables apps to be accessed from any location on any device. Sales and inventory reports can be managed and maintained remotely.


Dependence on internet access and connectivity

Probably the biggest issue with a cloud-based web application is the constant need for internet access. Dropping your connection could lead to loss sales and customers.

Browser-based applications can be designed for offline usage. Google Mail has an offline mode that allows you to compose emails, which are delivered once connectivity is reestablished. Our system works similarly. When a business loses their internet, they can still run customers through the checkout process. Those transactions are synced with the cloud when connectivity is available again.


Another problem with web-accessible systems is that they are more exposed to hackers.

Properly implemented security in both the network and application can go a long way in mitigating this risk. Solid encryption, secure access points, and realtime monitoring are all foundations of our point-of-sale system.



There are many considerations when deciding on a system.  We do feel strongly about the capabilities of the web, and would love to learn more from Colorado dispensary owners about their experience.

Learn more

Name *

Email *



Compliance, Data Duplication, and Colorado Dispensaries

By | API, Compliance | No Comments

From our many discussions with Denver-based dispensaries, compliance with Colorado’s METRC regulatory system continues to be a challenge. We’ve heard of countless issues, from the system being down to the lack of integration between a company’s seed-to-sale software and the state system. All of these equal a constant headache for dispensary owners and employees, and a real financial burden.

One of the most well-known problems is API integration with METRC. Currently, the business’s internal tracking system must generate a formatted CSV document. This document then gets imported into the regulatory platform. Often unexpected things happen and the company must devote man hours to resolving the synchronization problems. As the frustration grows, some dispensaries will have an employee manage METRC and skip the importing process altogether. Obviously, this is not the optimal use of man hours when the systems should just work.

Our solution

My team and I are building a point-of-sale system for retail dispensaries that does compliance integration right. Manifests, packages, and transactions are meticulously tracked and organized, so your retail records match what the state is seeing. Our system reconciles the inconsistencies between METRC and your business.

If you would like to learn more or demo our product, please connect with us at or stay informed with our newsletter.

Learn more

Name *

Email *



Access The Leafly Api With A .NET Application

By | API, Tutorial | No Comments


There’s a social experiment under way in Colorado and it’s the legalization of Cannabis. The state of Colorado taxes and regulates the sales and growing of Cannabis. Sales forecasts, regulation compliance, data harvesting are as critical to this industry as any other. A64Activate works with its Cannabis Dispensary friends to identify areas where software integration between existing systems may reduce or eliminate error prone, manual processes. Additionally, we at A64Activate intend to develop applications that create communications between a Dispensary and current and potential customers. Leafly.Com is where you find out about all things cannabis, from a strain’s grow info, negative effects, chemical data (via Steephill), flavor, a strain’s parents as well as interesting articles and even the location of Dispensaries near you that carry your favorite strain.


In this article we’ll walk through the process to get strain data via Leafly’s webapi using Visual Studio 2013. The .Net solution we’ll develop won’t make it into the software hall of fame, but the idea here is to demonstrate what it takes to do a simple Get request to Leafly’s webapi in C#. There may be half a dozen ways to do the same thing, but this article goes through the steps I took. It is assumed that the reader is familiar with Visual Studio 2013 and the C# programming language. The code was developed using Visual Studio 2013 Professional Edition, Update 4 and the .NET Framework, Version 4.5.51650. In summary, here’s what we’ll do:

  1. Get keys from Leafly
  2. Create a console app
  3. Code up the routine that issues the Get to Leafly api
  4. Deserialize the returned json into a nice C# objGraph
  5. Display the objGraph in the console window

Using The Code

1. Get keys from Leafly. You’ll need permission to access Leafly’s api. To get permission, you need to sign up by completing the requested info here: Developer Signup Page. Once completed, you’ll receive an App Id and an App Key. These values will be included in the HTTP headers for every request made to the api.

2. Create a console app. You can probably do this in your sleep, but just to be clear: launch Visual Studio 2013 File | New | Templates | Visual C# | Windows Desktop | select Console Application | give it a name | give it a location


3.  Code up the routine that issues the Get to Leafly api. Armed with your App Id and an App Key you’ve received from Leafly, we can begin by coding the routine that returns Strain data from Leafly api. Add this method to the project:

    private static async Task GetStrainInfoAsync() {


Code01 Let’s add some values that we’ll need for the upcoming Api call.

const string headerApiDocsUrl       = "X-Apidocs-Url";
const string headerApiDocsUrlValue  = "";
const string headerAppKey           = "app_key";
const string headerAppKeyValue      = "99999999999999999999999999999999";
const string headerAppId            = "app_id";
const string headerAppIdValue       = "88888888";
const string headerApiDocsPath      = "X-Apidocs-Path";
const string headerApiDocsPathValue = "/strains/headband";
const string domain                 = "";
const string requestUri             = "/api_docs/proxy?_=1423597451062";

You need to replace the contents of headerAppKeyValue and headerAppIdValue with the corresponding values you received from Leafly’s Developer Sign up. Code03

4. Determining HTTP Header Content Values

The following describes how I determined some of the values for the constant types as well as test drive the Api.
Head over to Leafly api docs page here: Leafly API Docs.
Scroll down to, and expand Strain Details.
Enter slug, your app_id and your app_key.


After entering slug, app_id and app_key, but before sending the request, open Fiddler or a Fiddler-like tool. My personal preference is HttpPro Debugger.
On the Leafly page, click Send Request.
Make note of the Request Details in your HTTP monitoring tool. This is the means by which I determined the values for the constants in the .Net solution.


5. json to C# objects the easy way. You may like this – it made my day.
Move back to Visual Studio and create a class, say Article.
And back to the Leafly page. . . , copy the json contents of the Response Body.
Go to json2csharp here: json2csharp
Drop the copied json into the json2csharp panel, then click Generate


Copy the generated C# code (from json2csharp) and paste that into the Article.cs class in Visual Studio.

Gotcha alert. Make sure the Article class is under the Namespace statement. It has to be the first class in this cs file.
After cut/paste it should look like this:


6.  Add Library References and Using statements. 
– Use NuGet to add
– Add references to System.Net.Http.Formatting and System.XML
– Add Using statements

using statements

7. Code up the HTTP client. Before HTTP requests and responses can be made, a environment is needed to host HTTP. That’s available to us via the HttpClient method within the System.Net.Http namespace. Let’s use that method now:

Use an HTTP client

8. Code Up The Send Request And Evaluation Of  The Response Code. Add the following code within the HTTPClient scope:

httpClient.BaseAddress = new Uri(domain);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Add(headerApiDocsUrl, headerApiDocsUrlValue);
httpClient.DefaultRequestHeaders.Add(headerAppKey, headerAppKeyValue);
httpClient.DefaultRequestHeaders.Add(headerAppId, headerAppIdValue);
httpClient.DefaultRequestHeaders.Add(headerApiDocsPath, headerApiDocsPathValue);

//// Send request
var task = httpClient.GetAsync(requestUri).ContinueWith((taskWithResponse) => {
        response = taskWithResponse.Result;
        Task<string> jsonString = response.Content.ReadAsStringAsync();

       //// Deserialize returned json into RootObject. Results in a nicely formatted objGraph.
       model = JsonConvert.DeserializeObject<RootObject>(jsonString.Result);

  if (response.IsSuccessStatusCode) {
       //// At this point, data has been returned and deserialized (into 'Article') 
      //// via the above call to the Leafly Api.



Send Request And Response Code Eval

At this point, the code should compile. Don’t run it but compile it and resolve errors before proceeding.

We’re almost there!

9. Add Code To Respond To HTTP Response Status Code 200. Use this code to react to response code 200:

if (response.IsSuccessStatusCode) {
     //// At this point, data has been returned and deserialized (into 'Article')
     //// via the above call to the Leafly Api.

     //// Serialize to XML for display in console window
     XmlSerializer xmlSerializer = new XmlSerializer(model.GetType());
     xmlSerializer.Serialize(Console.Out, model);

     //// Serialize to json
     //// Works well, but doesn't like pretty in Console window
     json = JsonConvert.SerializeObject(model);

10. Add a Little Code To Call the GetStrainInfoAsync Method. 
Add this code in the Main method.
Obviously, it calls the GetStrainInfoAsync method.
internal static void Main(string[] args) {
    //// Block main thread and wait for GetStrainInfoAsync to complete

11. Run It Moment of truth. Cross your fingers. F5.
If all’s well, you should see a console window that displays an XML rendition of json returned from Leafly Api.


12. Points of Interest*

  • This code requests Strain data for one Strain. There are a number of other requests that can be made via the Leafly webapi.
    You can test those out here:  Leafly API Docs – scroll down to the Operations section.
  • Be sure to check out the object graph of the model object.
    These are classes that form the object graph within the ‘model’ class that are readily available to be manipulated by your Uses Cases.


So say you want to display Negative Effects of this Strain. Here’s a simple example to get the idea:


foreach (Negative negative in model.negatives) {



Learn more

Name *

Email *