# Hovercode QR Code API

> Dynamic & static QR code API — generate and manage QR codes programmatically.

Base URL: `https://hovercode.com`

Human-readable docs: https://hovercode.com/api/
API catalog: https://hovercode.com/.well-known/api-catalog

---

## Introduction

Hovercode's API lets you create and update [dynamic QR codes](https://hovercode.com/blog/static-vs-dynamic-qr-codes/) programmatically. 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 — see [pricing](https://hovercode.com/pricing/).

The API is in active development. If there's a missing feature or you have feedback, [get in touch](https://hovercode.com/contact/).

**Note:** You can't call this API from the browser — that would expose your API key. Call it from a back-end (PHP, Node.js, Python, Ruby, etc.).

---

## Authentication

Every request must include an `Authorization` header with your API token:

```
Authorization: Token YOUR-TOKEN
```

Find your token in your account settings while logged in. Keep it private — anyone with the token can use the API with your credits.

Your workspace ID is also in your account settings. Many endpoints require it as a field named `workspace`.

---

## Endpoints

### Create a QR code

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

Generates a QR code. By default, returns the QR code as an SVG string. Set `generate_png: true` to also get links to `.png` and `.svg` files (slower response).

**Parameters**

| Name | Required | Description |
|---|---|---|
| `workspace` | required | Your workspace ID |
| `qr_data` | required | For `qr_type=Link`: a valid URL. For `qr_type=Text`: any plain text |
| `qr_type` | optional | `Link` (default) or `Text`. Text QR codes are static only |
| `dynamic` | optional | `false` by default. Set `true` for a dynamic QR code |
| `display_name` | optional | Internal name for organising codes in your dashboard |
| `domain` | optional | Custom domain for dynamic codes. Defaults to your workspace's default domain |
| `generate_png` | optional | `false` by default. `true` also returns `.png` and `.svg` file URLs |
| `gps_tracking` | optional | `false` by default. Enables GPS tracking for dynamic codes. See [GPS tracking docs](https://help.hovercode.com/article/14-gps-tracking) |
| `error_correction` | optional | `L`, `M`, `Q`, or `H`. Defaults to `Q` (or `H` if using a logo) |
| `size` | optional | Width in pixels. Defaults to `220` |
| `logo_url` | optional | URL to an image to embed as a logo. Use small PNG/JPEG |
| `logo_round` | optional | Force logo into a circle shape |
| `primary_color` | optional | Hex color (with `#`). Defaults to `#111111` |
| `background_color` | optional | Hex color (with `#`). Transparent by default |
| `pattern` | optional | `Original` (default), `Circles`, `Squares`, `Diamonds`, `Triangles` |
| `eye_style` | optional | `Square` (default), `Rounded`, `Drop`, `Leaf` |
| `frame` | optional | `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`, `swirl` |
| `has_border` | optional | For frames with a border option. `false` by default |
| `text` | optional | For frames with a text option |

**Example (Python)**

```python
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,
)
```

**Example (cURL)**

```bash
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"
  }'
```

**Response**

```json
{
  "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>",
  "svg_file": null,
  "png": null,
  "created": "2023-03-30T15:02:26.343134Z"
}
```

A dynamic request with more features returns `shortlink_url`, `svg_file`, and `png` links when `generate_png` is `true`.

---

### List QR codes

`GET https://hovercode.com/api/v2/workspace/{WORKSPACE-ID}/hovercodes/`

Returns QR codes in the workspace, paginated (50 per page by default).

**Query parameters**

- `q` — search string. Matches against QR code links, display names, shortlink URLs, and tag names.
- `page` — page number.

**Example**

```
GET https://hovercode.com/api/v2/workspace/{WORKSPACE-ID}/hovercodes/?q=twitter
```

**Response**

```json
{
  "count": 242,
  "next": "https://hovercode.com/api/v2/workspace/{WORKSPACE-ID}/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"
    }
  ]
}
```

---

### Get a single QR code

`GET https://hovercode.com/api/v2/hovercode/{QR-CODE-ID}/`

Retrieves a previously created QR code. Even if `generate_png` wasn't set at creation, the response will include `.png` and `.svg` file URLs if the code is more than a few seconds old.

**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/....png",
  "primary_color": "#1DA1F2",
  "svg": "<svg class=\"m-auto\" xmlns=\"http://www.w3.org/2000/svg\" ...>...</svg>",
  "svg_file": "https://media.hovercode.com/media/codes/....svg",
  "png": "https://media.hovercode.com/media/codes/....png",
  "created": "2022-09-21T06:05:40.068874Z"
}
```

---

### Get QR code tracking activity

`GET https://hovercode.com/api/v2/hovercode/{QR-CODE-ID}/activity/`

Returns scan activity for a QR code. Paginated, 50 items per page by default. Add `page_size` (max 200) to change the page size.

Each result includes: `qr_code_id`, `time_utc`, `time_timezone_aware`, `location`, `device`, `scanner_id`, `id`.

- `time_timezone_aware` — formatted in the workspace's timezone.
- `scanner_id` — hash of the scanner's truncated IP + device. Useful for estimating unique vs. repeat scanners.

**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": "17613b5745c64cbf...",
      "id": "eb8ee93b-8818-4354-bf8c-6d891abc07ae"
    }
  ]
}
```

---

### Update a QR code

`POST https://hovercode.com/api/v2/hovercode/{QR-CODE-ID}/update/`

Dynamic QR codes can have their scan destination updated. You can change `display_name`, `qr_data` (Link type only), or `gps_tracking`. Static codes can only update `display_name`.

Returns the same shape as `GET /hovercode/`.

---

### Add tags to a QR code

`POST https://hovercode.com/api/v2/hovercode/{QR-CODE-ID}/tags/add/`

Tags help organise and bulk-download codes. You can pass tag names or tag IDs.

- Tag name → tag is added if it exists, or created and added if it doesn't.
- Tag ID → only added if the tag exists.

Returns the same shape as `GET /hovercode/`.

---

### Delete a QR code

`DELETE https://hovercode.com/api/v2/hovercode/{QR-CODE-ID}/delete/`

Deletes the QR code **permanently**. It will no longer scan to its destination.

Returns status `204` on success.

---

### Webhooks

Enable webhooks from your workspace API settings. Available on the **Business Plus** plan.

When you set up a webhook, provide a URL (e.g. `https://yoursite.com/hovercode/webhook`). Every scan of a dynamic QR code in your workspace triggers a `POST` to that URL with `Content-Type: application/json` and an `x-signature` header.

Verify `x-signature` against your webhook secret token before processing the payload.

**Payload**

```json
{
  "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"
}
```

---

## Support

This API is in active development — [send feedback or questions](https://hovercode.com/contact/) any time.
