Dynamic QR code API

Automate your QR code creation or add QR code features to your product

requests.post( 'https://hovercode.com/api/v2/hovercode/create/', headers={'Authorization': 'Token YOUR-TOKEN'}, json=data, timeout=10 )

This is v2 of the API. You can access the docs for v1 here.

Introduction

Hovercode’s API lets you create and update dynamic QR codes programatically. It also lets you create static codes (although they cannot be updated). It’s ideal if you need to create a lot of QR codes or if you want to add QR code generation to your product or service.

The pricing to use the API is the same as our regular pricing (it's based on the number of QR codes you need to create)

This API is in active development, so if there’s a missing feature or if you have any feedback, let us know and we can help.

Authentication

Our API uses token authentication, so with every request, you should send an authorisation token in the header like so:

Authorization: Token YOUR-TOKEN

You can find your token in your settings area while logged in. Be sure to keep your token private and secure (like you would a password) as anyone who has access to it can use the API with your credits.

Create QR codes

https://hovercode.com/api/v2/hovercode/create/

This is the main use of the API. Use this endpoint to generate QR codes. By default, this endpoint returns the created QR code as an SVG string. You can either embed it directly into your site, or save the SVG string as an SVG file and convert it to any format you like.

If you want to QR code as a .png, set generate_png to true in your POST request body. This leads to a slower response, but the response will include a link to the QR code as a .png file as well as one as a .svg file.

Paramater name Required Description
workspace Required Every account has a workspace ID. You can find yours with your API token in your settings area
qr_data Required When using the default qr_type of "Link" this has to be a valid URL. With the type "Text" this can be any plain text
qr_type Defaults to "Link" This defaults to "Link" and can only currently be "Link or "Text". "Text" QR codes are plain text and can only be static (not dynamic)
dynamic Defaults to false Your QR code is static by default. Set this to true to make it a dynamic QR code.
display_name Not required You can optionally add a display name to your QR codes so they are easier to organise in your Hovercode dashboard (the display_name isn't customer facting)
domain Not required (defaults to the default domain from your workspace) [Only applies to dynamic QR codes, has effect on static codes] If you have multiple custom domains linked to your workspace, you can specify which you want to use here.
generate_png Not required (defaults to false) Set this to true to include a .png and .svg QR code in your response. This slows down the response. Without this set to true, the QR code is only returned as an SVG string. You can retrieve the .png or .svg file in future requests even if this has not been sert to true.
error_correction Not required (defaults to 'Q' without a logo or 'H' with a logo) Use this to set the error correction of your QR code. Options are L, M, Q, or H
logo_url Not required Optionally add a url to an image to use it as a logo in your QR code. Don't use a massive image file and stick with pngs or jpegs
logo_round Not required When creating a QR code with a logo, you can set this to True to force the logo into a circle shape
primary_color Not required (defaults to #111111) Change the color of your QR code by adding a valid HEX color code (including the '#')
background_color Not required Change the color of your QR code background by adding a valid HEX color code (including the '#'). By default, the QR code has no background color set (it's transparent).
pattern Not required (defaults to "Original") This refers to the shape of the pattern in your QR code. The default is "Original" and the options are: Original, Circles, Squares, Diamonds, Triangles
eye_style Not required (defaults to "Square") This sets the style of the "eyes" on the three corners of the QR code. "Square" is the default and the other options are: Rounded, Drop, and Leaf
frame Not required By default your generated QR code will have no frame. The frames available through the API are the same ones you can use at hovercode.com. They are: border, border-small, border-large, square, speech-bubble, speech-bubble-above, card, card-above, text-frame, round-frame, circle-viewfinder, solid-spin, burst, scattered-lines, polkadot, and swirl
border Not required Some frames have a "border" option, which is false by default. If you are using a frame that has a border option you want to use, set this to true. This has no effect on QR codes using no frame or a frame with no border option.
text Not required Some frames have a "text" option, which is empty by default. If you are using a frame that has a text option you want to use, set the text here. Depending on the frame, it will have a max length. This has no effect on QR codes using no frame or a frame with no text option.

This example uses Python requests, but you can achieve something similar with Ruby, JavaScript etc. More code examples coming soon (please get in touch if you have any questions)

import requests

data = {
    "workspace": "YOUR-WORKSPACE-ID",
    "qr_data": "https://twitter.com/hovercodeHQ",
    "primary_color": "#1DA1F2"
}

response = requests.post(
    'https://hovercode.com/api/v2/hovercode/create/',
    headers={'Authorization': 'Token YOUR-TOKEN'},
    json=data,
    timeout=10
)

response.json() returns the following (with the SVG string truncated in this example)

{
  {
    "id": "bc9b02bc-0d77-4828-95e7-1c27c603c5c9",
    "qr_data": "https://twitter.com/hovercodeHQ",
    "qr_type": "Link",
    "display_name": null,
    "shortlink_url": null,
    "dynamic": false,
    "frame": null,
    "logo": null,
    "primary_color": "#1DA1F2",
    "background_color": null,
    "pattern": "Original",
    "text": null,
    "has_border": false,
    "svg":"<svg xmlns=\"http://www.w3.org/2000/svg...,
    "svg_file": null,
    "png": null,
    "created": "2023-03-30T15:02:26.343134Z"
  }
}

This is the resulting QR code:

Here's an example using more features:

import requests

data = {
    "workspace": "YOUR-WORKSPACE-ID",
    "qr_data": "https://twitter.com/hovercodeHQ",
    "primary_color": "#3b81f6",
    "background_color": "#FFFFFF",
    "dynamic": True,
    "display_name": "QR code for Twitter",
    "frame": "circle-viewfinder",
    "pattern": "Diamonds",
    "has_border": True,
    "logo_url": "https://hovercode.com/static/website/images/logo.png",
    "generate_png": True
}

response = requests.post(
    'https://hovercode.com/api/v2/hovercode/create/',
    headers={'Authorization': 'Token YOUR-TOKEN'},
    json=data,
    timeout=10
)

And with response.json()

{
    "id": "1067b811-edb3-4211-bbba-a23cac8f5ace",
    "qr_data": "https://twitter.com/hovercodeHQ",
    "qr_type": "Link",
    "display_name": "QR code for Twitter",
    "shortlink_url": "https://hov.to/4d1451cf",
    "dynamic": true,
    "frame": "circle-viewfinder",
    "logo": "https://media.hovercode.com/media/logos/0d188ceb-5992-473d-ac34-b0641ef7c030.png",
    "primary_color": "#3b81f6",
    "background_color": "#FFFFFF",
    "pattern": "Diamonds",
    "text": null,
    "has_border": true,
    "svg":"<svg xmlns=\"http://www.w3.org/2000/svg...,
    "svg_file": "https://media.hovercode.com/media/codes/1067b811-edb3-4211-bbba-a23cac8f5ace.svg",
    "png": "https://media.hovercode.com/media/codes/1067b811-edb3-4211-bbba-a23cac8f5ace.png",
    "created": "2023-03-30T16:25:40.074012Z"
  }

And here's the resulting QR code

import requests

response = requests.get(
    'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/',
    headers={'Authorization': 'Token YOUR-TOKEN'},
    timeout=10
)

And the response (with response.json())

{
  "id": "1067b811-edb3-4211-bbba-a23cac8f5ace",
  "qr_data": "https://twitter.com/hovercodeHQ",
  "qr_type": "Link",
  "display_name": "QR code for Twitter",
  "shortlink_url": "https://hov.to/4d1451cf",
  "dynamic": true,
  "frame": "circle-viewfinder",
  "logo": "https://media.hovercode.com/media/logos/0d188ceb-5992-473d-ac34-b0641ef7c030.png",
  "primary_color": "#3b81f6",
  "background_color": "#FFFFFF",
  "pattern": "Diamonds",
  "text": null,
  "has_border": true,
  "svg":"<svg xmlns=\"http://www.w3.org/2000/svg...,
  "svg_file": "https://media.hovercode.com/media/codes/1067b811-edb3-4211-bbba-a23cac8f5ace.svg",
  "png": "https://media.hovercode.com/media/codes/1067b811-edb3-4211-bbba-a23cac8f5ace.png",
  "created": "2023-03-30T16:25:40.074012Z",
  "total_scans": 0,
  "unique_scans": 0,
  "tags": []
}

Get QR codes

https://hovercode.com/api/v2/hovercode/

Use this endpoint to retrieve a QR code that was previously created. Even if generate_png wasn't set when creating the QR code, it will include the .png and .svg files of the QR code if it was created more than a few seconds before your call.

import requests

response = requests.get(
'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/',
headers={'Authorization': 'Token YOUR-TOKEN'},
timeout=10
)

And the response (with response.json())

{
"id": "9c2aa461-bec0-46b8-9ed2-0edde02b164c",
"link":"https://twitter.com/hovercodeHQ",
"display_name":"None",
"square":true,
"logo":"https://media.hovercode.com/media/logos/4510095f-a9e5-48d6-870f-f81362e4bd8d.png",
"primary_color":"#1DA1F2",
"svg":"<svg class=\"m-auto\" xmlns=\"http://www.w3.org/2000/svg\...",
"svg_file":"https://media.hovercode.com/media/codes/9c2aa461-bec0-46b8-9ed2-0edde02b164c.svg",
"png":"https://media.hovercode.com/media/codes/9c2aa461-bec0-46b8-9ed2-0edde02b164c.png",
"created":"2022-09-21T06:05:40.068874Z"
}

Get QR code tracking activity

https://hovercode.com/api/v2/hovercode/QR-CODE-ID/activity/

Use this endpoint to get the tracking activity data for a QR code. By default, this returns activities with 50 items per page. You can add a "page_size" paramater to the url to change the page size to anything up to 200.

import requests

response = requests.get(
'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/activity/',
headers={'Authorization': 'Token YOUR-TOKEN'},
timeout=10
)

The response will include a "count" - which is the total number of items. It will also include "next" and "previous" for the next and previous pages if there are any (they will be urls).

The tracked activity results will be in "results" and each item includes: 'qr_code_id', 'time_utc', 'time_timezone_aware', 'location', 'device_string', 'scanner_id', 'id'

The 'time_timezone_aware' is based on the timezone your workspace is set to. "scanner_id" is a hash based on the scanners truncated IP and their device. It's a way to estimate whether if the QR code is being scanned by someone new or someone who has previously scanned it.

An example response (with response.json())

{
  "count": 61,
  "next": "https://hovercode.com/api/v2/hovercode/[QR-CODE-ID]/activity/?page=2",
  "previous": null,
  "results": [
    {
      "qr_code_id": "[QR-CODE-ID]",
      "time_utc": "2023-03-25 05:01:31.686226+00:00",
      "time_timezone_aware": "Mar. 25, 2023, 05:01 a.m.",
      "location": "Mumbai, Maharashtra, India",
      "device": "iPhone, iOS, Mobile Safari",
      "scanner_id": "17613b5745c64cbf626766f468b9fb1ed4a3ae754c8b424d5c081fe7454fb0d5",
      "id": "eb8ee93b-8818-4354-bf8c-6d891abc07ae"
    },
    {
      "qr_code_id": "[QR-CODE-ID]",
      "time_utc": "2023-03-21 11:15:10.919115+00:00",
      "time_timezone_aware": "Mar. 21, 2023, 11:15 a.m.",
      "location": "Istanbul, Istanbul, Turkey",
      "device": "Samsung SM-F936B, Android, Samsung Internet",
      "scanner_id": "29a8c6aa8ec3f5ff179455558fa84cda397b89b919966fa865e6df683ff1078e",
      "id": "ad9de450-69df-47d0-ac9c-e6c4a33633f8"
    }...
  ]
}

Update QR codes

https://hovercode.com/api/v2/hovercode/QR-CODE-ID/update/

The power of dynamic QR codes is that you can change their scan destination after they're created. You can update the display_name or the qr_data (or both). For static QR codes, you can only update the display_name. Currently you can only update the "qr_data" for the "Link" type of dynamic QR code

import requests

data = {
    "qr_data": "https://twitter.com/ramykhuffash",
    "display_name": "hi"
}

response = requests.put(
    'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/update/',
    headers={'Authorization': 'Token YOUR-TOKEN'},
    json=data,
    timeout=10
)

The response (response.json()) will be exactly the same as you see with the endpoint for getting a QR code.

Add tags to QR code

https://hovercode.com/api/v2/hovercode/QR-CODE-ID/tags/add/

This endpoint lets you add tags to your QR codes, which is useful for managing them and for bulk downloads. You can add multiple tag names or ids. If you add a tag name, it adds the tag if it exists, or creates then adds it if it doesn't. If you add a tag ID, it only adds it to the QR code if it exists.

import requests

data = [
    {"title": "my tag"},
    {"title": "my second tag"}
]


response = requests.post(
    'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/tags/add/',
    headers={'Authorization': 'Token YOUR-TOKEN'},
    json=data,
    timeout=10
)

The response (response.json()) will be exactly the same as you see with the endpoint for getting a QR code.

Delete QR codes

https://hovercode.com/api/v2/hovercode/QR-CODE-ID/delete/

Here's how you delete QR codes programatically - this deletes them permanently and they will no longer scan to their intended destination.

import requests
response = requests.delete(
    'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/delete/',
    headers={'Authorization': 'Token YOUR-TOKEN'},
    timeout=10
)

This returns a status 204 if the delete was successful

Webhooks

If you enable Webhooks from your workspace API settings, a webhook is triggered every time a dynamic QR code from your workspace is scanned.

This feature is available on the Business Plus plan

When setting up a webhook, you need to provider a url (e.g. https://yoursite.com/hovercode/webhook)

When a webhook is triggered, there will be a POST request to that url. It will be of content-type "application/json" and will include a header called "x-signature".

Check the signature against your webhook secret token to verify the contents. If all is good, return a 200. Here's an example:


    import hmac
    import hashlib
    import json

    from django.http import JsonResponse
    

    def hc_webhook_view(request):
        webhook_secret = [YOUR WEBHOOK SECRET]
        raw_payload = request.body
        received_signature = request.headers.get('X-Signature')
        expected_signature = hmac.new(SECRET_KEY.encode(), raw_payload, hashlib.sha256).hexdigest()

        if not hmac.compare_digest(expected_signature, received_signature):
            return JsonResponse({'error': 'Invalid signature'}, status=400)
        
        payload_data = json.loads(raw_payload)
        # Do what you need to do

        return JsonResponse({'message': 'Webhook received successfully'}, status=200)

The contents will be activity data:


    {
      "qr_code_id": "2fbb014a-4b5a-4ecd-95a3-p914d4aa167b",
      "time_utc": "2023-12-13 17:44:48.920050+00:00",
      "time_timezone_aware": "Dec. 13, 2023, 05:44 p.m.",
      "location": "London, England, United Kingdom",
      "device": "iPhone, iOS, Mobile Safari",
      "scanner_id": "5dd831a872687315f54a11fa62d089e66887647c67d5ad2cd89ebd3a38084bd3",
      "id": "0acb2379-c9e3-4245-a1e3-6e542cc02637"
    }
  

This QR code API is in active development so please send us any feedback you have or let us know if there's anything we can do to help you get set up.