Dynamic QR code API
Automate your QR code creation or add QR code features to your product
requests.post( 'https://hovercode.com/', headers={'Authorization': 'Token YOUR-TOKEN'}, json=data, timeout=10 )
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.
You need access to the business plan to use the API, but you can test it for free (pricing)
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.
Note: You can't make calls to this API from the browser as that would expose your API key. API calls need to be done from a back-end (PHP, Node.js, Python, Ruby etc)
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. This is why you can't use the Hovercode API directly in the front-end
Here's what it looks like on Postman
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. |
gps_tracking | Not required (defaults to false) | This is to enable the GPS tracking feature for the QR code. It's only for dynamic codes. More details. |
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 |
size | Not required (defaults to 220) | Sets the size of the QR code in pixels. Defaults to 220. The height is set automatically based on the width and the frame (the same if it's a square frame) |
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 |
has_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
)
<?php
$data = array(
"workspace" => "YOUR-WORKSPACE-ID",
"qr_data" => "https://twitter.com/hovercodeHQ",
"primary_color" => "#1DA1F2"
);
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://hovercode.com/api/v2/hovercode/create/',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => array(
'Authorization: Token YOUR-TOKEN',
'Content-Type: application/json'
),
));
$response = curl_exec($curl);
curl_close($curl);
?>
curl -X POST \
'https://hovercode.com/api/v2/hovercode/create/' \
-H 'Authorization: Token YOUR-TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"workspace": "YOUR-WORKSPACE-ID",
"qr_data": "https://twitter.com/hovercodeHQ",
"primary_color": "#1DA1F2"
}'
const axios = require('axios');
const data = {
workspace: 'YOUR-WORKSPACE-ID',
qr_data: 'https://twitter.com/hovercodeHQ',
primary_color: '#1DA1F2'
};
axios.post('https://hovercode.com/api/v2/hovercode/create/', data, {
headers: {
Authorization: 'Token YOUR-TOKEN'
},
timeout: 10000
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://hovercode.com/api/v2/hovercode/create/')
data = {
"workspace" => "YOUR-WORKSPACE-ID",
"qr_data" => "https://twitter.com/hovercodeHQ",
"primary_color" => "#1DA1F2"
}
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.read_timeout = 10
request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Token YOUR-TOKEN'
request.content_type = 'application/json'
request.body = data.to_json
response = http.request(request)
puts response.body
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class Main {
public static void main(String[] args) {
HttpClient client = HttpClient.newBuilder()
.build();
String jsonData = new StringBuilder()
.append("{")
.append("\"workspace\":\"YOUR-WORKSPACE-ID\",")
.append("\"qr_data\":\"https://twitter.com/hovercodeHQ\",")
.append("\"primary_color\":\"#1DA1F2\"")
.append("}")
.toString();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://hovercode.com/api/v2/hovercode/create/"))
.timeout(Duration.ofSeconds(10))
.header("Authorization", "Token YOUR-TOKEN")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonData))
.build();
try {
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
} catch (Exception e) {
e.printStackTrace();
}
}
}
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
)
<?php
$data = array(
"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
);
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://hovercode.com/api/v2/hovercode/create/',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => array(
'Authorization: Token YOUR-TOKEN',
'Content-Type: application/json'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
?>
curl -X POST \
'https://hovercode.com/api/v2/hovercode/create/' \
-H 'Authorization: Token YOUR-TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"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
}'
const axios = require('axios');
const 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
};
axios.post('https://hovercode.com/api/v2/hovercode/create/', data, {
headers: {
Authorization: 'Token YOUR-TOKEN'
},
timeout: 10000
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://hovercode.com/api/v2/hovercode/create/')
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
}
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.read_timeout = 10
request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Token YOUR-TOKEN'
request.content_type = 'application/json'
request.body = data.to_json
response = http.request(request)
puts response.body
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Map;
public class Main {
public static void main(String[] args) {
HttpClient client = HttpClient.newBuilder()
.build();
Map<String, Object> data = Map.of(
"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
);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://hovercode.com/api/v2/hovercode/create/"))
.timeout(Duration.ofSeconds(10))
.header("Authorization", "Token YOUR-TOKEN")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(data.toString()))
.build();
try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
} catch (Exception e) {
e.printStackTrace();
}
}
}
response.json() returns
{
"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
Get QR codes
https://hovercode.com/api/v2/workspace/WORKSPACE-ID/hovercodes/
Use this endpoint to get all of the Hovercodes for your workspace.
import requests
response = requests.get(
'https://hovercode.com/api/v2/workspace/YOUR-WORKSPACE-ID/hovercodes/',
headers={'Authorization': 'Token YOUR-TOKEN'},
timeout=10
)
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://hovercode.com/api/v2/workspace/YOUR-WORKSPACE-ID/hovercodes/',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => array(
'Authorization: Token YOUR-TOKEN'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
?>
curl -X GET \
'https://hovercode.com/api/v2/workspace/YOUR-WORKSPACE-ID/hovercodes/' \
-H 'Authorization: Token YOUR-TOKEN'
const axios = require('axios');
axios.get('https://hovercode.com/api/v2/workspace/YOUR-WORKSPACE-ID/hovercodes/', {
headers: {
Authorization: 'Token YOUR-TOKEN'
},
timeout: 10000
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class GetQRCodeActivity {
public static void main(String[] args) {
try {
String workspaceId = "YOUR-WORKSPACE-ID";
String token = "YOUR_TOKEN";
URL url = new URL("https://hovercode.com/api/v2/workspace/" + workspaceId + "/hovercodes/");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "Token " + token);
try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"))) {
StringBuilder response = new StringBuilder();
String responseLine = null;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
System.out.println(response.toString());
}
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
require 'net/http'
require 'uri'
uri = URI.parse('https://hovercode.com/api/v2/workspace/YOUR-WORKSPACE-ID/hovercodes/')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.path)
request['Authorization'] = 'Token YOUR-TOKEN'
response = http.request(request)
puts response.read_body
The response will include a "count" - which is the total number of Hovercodes. It will also include "next" and "previous" for the next and previous pages if there are any (they will be urls).
The Hovercodes will be in "results" and each will include the following fields: 'id', 'qr_data', 'qr_type', 'display_name', 'shortlink_url', 'dynamic', 'created'
response.json() returns something like
{
"count": 242,
"next": "https://hovercode.com/api/v2/workspace/76741b51-dadc-42a7-b0b3-5ce23c7c7841/hovercodes/?page=2",
"previous": null,
"results": [
{
"id": "fec04f7f-16a9-4f5a-8df6-499b5eff3b9a",
"qr_data": "http://go.co",
"qr_type": "Link",
"display_name": null,
"shortlink_url": "https://tab.so/952e126c",
"dynamic": true,
"created": "2024-06-24T14:22:55.585649Z"
},
{
"id": "8f7c1cec-f195-46cc-8540-4728680f247a",
"qr_data": "http://go.co",
"qr_type": "Link",
"display_name": null,
"shortlink_url": "https://scanqr.to/575c22c4",
"dynamic": true,
"created": "2024-06-21T13:01:28.194383Z"
}...
]
}
Get single QR code
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
)
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => array(
'Authorization: Token YOUR-TOKEN'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
?>
curl -X GET \
'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/' \
-H 'Authorization: Token YOUR-TOKEN'
const axios = require('axios');
axios.get('https://hovercode.com/api/v2/hovercode/QR-CODE-ID/', {
headers: {
Authorization: 'Token YOUR-TOKEN'
},
timeout: 10000
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class GetQRCode {
public static void main(String[] args) {
try {
String qrCodeId = "YOUR_QR_CODE_ID";
String token = "YOUR_TOKEN";
URL url = new URL("https://hovercode.com/api/v2/hovercode/" + qrCodeId + "/");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "Token " + token);
try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"))) {
StringBuilder response = new StringBuilder();
String responseLine = null;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
System.out.println(response.toString());
}
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
require 'net/http'
require 'uri'
uri = URI.parse('https://hovercode.com/api/v2/hovercode/QR-CODE-ID/')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.path)
request['Authorization'] = 'Token YOUR-TOKEN'
response = http.request(request)
puts response.read_body
response.json() returns
{
"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
)
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/activity/',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => array(
'Authorization: Token YOUR-TOKEN'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
?>
curl -X GET \
'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/activity/' \
-H 'Authorization: Token YOUR-TOKEN'
const axios = require('axios');
axios.get('https://hovercode.com/api/v2/hovercode/QR-CODE-ID/activity/', {
headers: {
Authorization: 'Token YOUR-TOKEN'
},
timeout: 10000
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class GetQRCodeActivity {
public static void main(String[] args) {
try {
String qrCodeId = "YOUR_QR_CODE_ID";
String token = "YOUR_TOKEN";
URL url = new URL("https://hovercode.com/api/v2/hovercode/" + qrCodeId + "/activity/");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "Token " + token);
try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"))) {
StringBuilder response = new StringBuilder();
String responseLine = null;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
System.out.println(response.toString());
}
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
require 'net/http'
require 'uri'
uri = URI.parse('https://hovercode.com/api/v2/hovercode/QR-CODE-ID/activity/')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.path)
request['Authorization'] = 'Token YOUR-TOKEN'
response = http.request(request)
puts response.read_body
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.
response.json() returns something like
{
"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). You can also enable GPS tracking or disable GPS tracking with the gps_tracking parameter. 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
)
<?php
$data = array(
"qr_data" => "https://twitter.com/ramykhuffash",
"display_name" => "hi"
);
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/update/',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => array(
'Authorization: Token YOUR-TOKEN',
'Content-Type: application/json'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
?>
curl -X PUT \
'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/update/' \
-H 'Authorization: Token YOUR-TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"qr_data": "https://twitter.com/ramykhuffash",
"display_name": "hi"
}'
const axios = require('axios');
const data = {
qr_data: 'https://twitter.com/ramykhuffash',
display_name: 'hi'
};
axios.put('https://hovercode.com/api/v2/hovercode/QR-CODE-ID/update/', data, {
headers: {
Authorization: 'Token YOUR-TOKEN'
},
timeout: 10000
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.OutputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class UpdateQRCode {
public static void main(String[] args) {
try {
String qrCodeId = "YOUR_QR_CODE_ID";
String token = "YOUR_TOKEN";
URL url = new URL("https://hovercode.com/api/v2/hovercode/" + qrCodeId + "/update/");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("PUT");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", "Token " + token);
conn.setDoOutput(true);
String jsonInputString = "{\"qr_data\": \"https://twitter.com/ramykhuffash\", \"display_name\": \"hi\"}";
try (OutputStream os = conn.getOutputStream()) {
byte[] input = jsonInputString.getBytes("utf-8");
os.write(input, 0, input.length);
}
try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"))) {
StringBuilder response = new StringBuilder();
String responseLine = null;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
System.out.println(response.toString());
}
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
require 'net/http'
require 'uri'
require 'json'
uri = URI.parse('https://hovercode.com/api/v2/hovercode/QR-CODE-ID/update/')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Put.new(uri.path)
request['Content-Type'] = 'application/json'
request['Authorization'] = 'Token YOUR-TOKEN'
request.body = { "qr_data": "https://twitter.com/ramykhuffash", "display_name": "hi" }.to_json
response = http.request(request)
puts response.read_body
response.json() will return the same as you would 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
)
<?php
$data = array(
array("title" => "my tag"),
array("title" => "my second tag")
);
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/tags/add/',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => array(
'Authorization: Token YOUR-TOKEN',
'Content-Type: application/json'
),
));
$response = curl_exec($curl);
curl_close($curl);
?>
curl -X POST \
'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/tags/add/' \
-H 'Authorization: Token YOUR-TOKEN' \
-H 'Content-Type: application/json' \
-d '[
{"title": "my tag"},
{"title": "my second tag"}
]'
const axios = require('axios');
const data = [
{ title: 'my tag' },
{ title: 'my second tag' }
];
axios.post('https://hovercode.com/api/v2/hovercode/QR-CODE-ID/tags/add/', data, {
headers: {
Authorization: 'Token YOUR-TOKEN'
},
timeout: 10000
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://hovercode.com/api/v2/hovercode/YOUR-QR-CODE-ID/tags/add/')
data = [
{"title" => "my tag"},
{"title" => "my second tag"}
]
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.read_timeout = 10
request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Token YOUR-TOKEN'
request.content_type = 'application/json'
request.body = data.to_json
response = http.request(request)
puts response.body
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class Main {
public static void main(String[] args) {
HttpClient client = HttpClient.newBuilder()
.build();
String jsonData = "[{\"title\":\"my tag\"}, {\"title\":\"my second tag\"}]";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://hovercode.com/api/v2/hovercode/YOUR-QR-CODE-ID/tags/add/"))
.timeout(Duration.ofSeconds(10))
.header("Authorization", "Token YOUR-TOKEN")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonData))
.build();
try {
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
} catch (Exception e) {
e.printStackTrace();
}
}
}
response.json() will return 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
)
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/delete/',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => array(
'Authorization: Token YOUR-TOKEN'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
?>
curl -X DELETE \
'https://hovercode.com/api/v2/hovercode/QR-CODE-ID/delete/' \
-H 'Authorization: Token YOUR-TOKEN' \
-H 'Content-Type: application/json' \
-d ''
const axios = require('axios');
axios.delete('https://hovercode.com/api/v2/hovercode/QR-CODE-ID/delete/', {
headers: {
Authorization: 'Token YOUR-TOKEN'
},
timeout: 10000
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
require 'net/http'
require 'uri'
uri = URI('https://hovercode.com/api/v2/hovercode/YOUR-QR-CODE-ID/delete/')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.read_timeout = 10
request = Net::HTTP::Delete.new(uri)
request['Authorization'] = 'Token YOUR-TOKEN'
response = http.request(request)
puts response.body
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpRequest.BodyPublishers;
import java.time.Duration;
public class Main {
public static void main(String[] args) {
HttpClient client = HttpClient.newBuilder()
.build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://hovercode.com/api/v2/hovercode/YOUR-QR-CODE-ID/delete/"))
.timeout(Duration.ofSeconds(10))
.header("Authorization", "Token YOUR-TOKEN")
.DELETE()
.build();
try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
} catch (Exception e) {
e.printStackTrace();
}
}
}
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)
<?php
function hc_webhook_view() {
$webhook_secret = '[YOUR WEBHOOK SECRET]';
$raw_payload = file_get_contents('php://input');
$received_signature = $_SERVER['HTTP_X_SIGNATURE'];
$expected_signature = hash_hmac('sha256', $raw_payload, $webhook_secret);
if (!hash_equals($expected_signature, $received_signature)) {
http_response_code(400);
echo json_encode(['error' => 'Invalid signature']);
return;
}
$payload_data = json_decode($raw_payload, true);
// Do what you need to do
http_response_code(200);
echo json_encode(['message' => 'Webhook received successfully']);
}
// Call the function to handle the webhook
hc_webhook_view();
?>
As this is a for receiving a webhook, there is no cURL version. Try selecting a different language
const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
const SECRET_KEY = '[YOUR WEBHOOK SECRET]';
// Middleware to parse JSON request body
app.use(bodyParser.json());
app.post('/hc_webhook', (req, res) => {
const raw_payload = JSON.stringify(req.body);
const received_signature = req.headers['x-signature'];
const expected_signature = crypto.createHmac('sha256', SECRET_KEY)
.update(raw_payload)
.digest('hex');
if (received_signature !== expected_signature) {
return res.status(400).json({ error: 'Invalid signature' });
}
// Process payload_data
const payload_data = req.body;
// Do what you need to do
return res.status(200).json({ message: 'Webhook received successfully' });
});
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.springframework.http.HttpStatus;
@RestController
public class WebhookController {
private static final String SECRET_KEY = "YOUR_WEBHOOK_SECRET";
@PostMapping("/hc_webhook")
public String hcWebhookView(@RequestBody String rawPayload, @RequestHeader("X-Signature") String receivedSignature) throws IOException {
try {
Mac hmacSha256 = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(), "HmacSHA256");
hmacSha256.init(secretKey);
byte[] expectedSignature = hmacSha256.doFinal(rawPayload.getBytes());
if (!java.util.Arrays.equals(expectedSignature, receivedSignature.getBytes())) {
return "{\"error\": \"Invalid signature\"}";
}
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
return "{\"error\": \"Internal server error\"}";
}
// Parse payload_data JSON and do what you need to do
return "{\"message\": \"Webhook received successfully\"}";
}
}
require 'sinatra'
require 'json'
require 'openssl'
SECRET_KEY = "YOUR_WEBHOOK_SECRET"
post '/hc_webhook' do
request.body.rewind
raw_payload = request.body.read
received_signature = request.env['HTTP_X_SIGNATURE']
hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), SECRET_KEY, raw_payload)
if hmac != received_signature
return { error: 'Invalid signature' }.to_json
end
# Parse payload_data JSON and do what you need to do
return { message: 'Webhook received successfully' }.to_json
end
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.