Hovercodes
HovercodesClient¶
HovercodesClient is the main domain client for QR code operations.
It maps closely to the Hovercode API endpoints:
create()→POST /hovercode/create/list_for_workspace()→GET /workspace/{workspace_id}/hovercodes/get_hovercode()→GET /hovercode/{qr_code_id}/get_activity()→GET /hovercode/{qr_code_id}/activity/update()→PUT /hovercode/{qr_code_id}/update/add_tags()→POST /hovercode/{qr_code_id}/tags/add/delete_hovercode()→DELETE /hovercode/{qr_code_id}/delete/
Note
The SDK returns API responses as JSON-like dictionaries/lists. For most endpoints you should expect a dict with fields described below.
create()¶
Create a QR code (static by default). This is the main endpoint of the Hovercode API.
Minimal example¶
from hovercode import HovercodeClient
client = HovercodeClient()
qr = client.hovercodes.create(
workspace="YOUR-WORKSPACE-ID",
qr_data="https://example.com",
)
print(qr["id"])
print(qr["svg"][:80])
Important behavior¶
- Static vs dynamic: QR codes are static by default. Pass
dynamic=Truefor a dynamic code. - Link vs Text:
qr_typedefaults to"Link"."Text"codes are plain text and (per the upstream docs) are static only. - PNG generation:
generate_png=Truecan slow down the create response, but it includes.png/.svgfile URLs in the response.
Parameter reference¶
The SDK passes parameters through to Hovercode’s API. Some parameters are only meaningful for certain QR types or dynamic codes.
| Parameter | Type | Required | Default (API) | Notes |
|---|---|---|---|---|
workspace | str | Yes | — | Workspace ID (UUID) from your Hovercode settings. |
qr_data | str | Yes | — | Destination/content. For qr_type="Link", should be a URL. |
qr_type | QrType | str | No | "Link" | "Text" is documented as static-only. |
dynamic | bool | No | false | Set true for dynamic codes. |
display_name | str | No | null | Internal label for your dashboard. |
domain | str | No | workspace default | Dynamic only. Select a custom domain if you have multiple. |
generate_png | bool | No | false | Slower response; includes png/svg_file URLs. |
gps_tracking | bool | No | false | Dynamic only. |
error_correction | ErrorCorrection | str | No | Q/H | Docs: defaults to Q without logo, H with logo. |
size | int | No | 220 | Width in pixels (height derived). |
logo_url | str | No | null | URL to a logo image file. |
logo_round | bool | No | false | Force logo into a circle shape. |
primary_color | str | No | #111111 | Hex color including #. |
background_color | str | No | transparent | Hex color including #. |
pattern | Pattern | str | No | "Original" | Pattern style. |
eye_style | EyeStyle | str | No | "Square" | Eye style for corners. |
frame | Frame | str | No | null | Frame name. |
has_border | bool | No | false | Only applies to frames with a border option. |
text | str | No | "" | Only applies to frames with a text option. |
Tip
Prefer enums (hovercode.enums.QrType, Frame, Pattern, etc.) to avoid typos.
Common styling options¶
Most styling is controlled via primary_color, background_color, pattern, eye_style, and frame.
Valid values documented by Hovercode (you can also use the enums in hovercode.enums):
pattern:Original,Circles,Squares,Diamonds,Triangleseye_style:Square,Rounded,Drop,Leafframe: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
Note
The upstream docs state error_correction defaults to Q without a logo and H with a logo.
Styled dynamic example (enums)¶
from hovercode import HovercodeClient
from hovercode.enums import ErrorCorrection, EyeStyle, Frame, Pattern, QrType
client = HovercodeClient()
qr = client.hovercodes.create(
workspace="YOUR-WORKSPACE-ID",
qr_data="https://example.com",
qr_type=QrType.LINK,
dynamic=True,
display_name="Example QR",
generate_png=True,
error_correction=ErrorCorrection.H,
primary_color="#3b81f6",
background_color="#FFFFFF",
pattern=Pattern.DIAMONDS,
eye_style=EyeStyle.ROUNDED,
frame=Frame.CIRCLE_VIEWFINDER,
has_border=True,
logo_url="https://example.com/logo.png",
logo_round=True,
)
print(qr.get("shortlink_url"))
print(qr.get("png"))
Typical response fields¶
The API response commonly includes fields like:
id(UUID string)qr_data(string)qr_type(string)display_name(string or null)shortlink_url(string or null)dynamic(bool)svg(SVG string)svg_file(string URL or null)png(string URL or null)created(ISO datetime string)
list_for_workspace()¶
List all QR codes in a workspace. The API is paginated (50 per page by default).
from hovercode import HovercodeClient
client = HovercodeClient()
page_1 = client.hovercodes.list_for_workspace("YOUR-WORKSPACE-ID")
print(page_1["count"])
print(len(page_1["results"]))
The response includes:
count: total number of hovercodesnext: URL for the next page, ornullprevious: URL for the previous page, ornullresults: list of hovercode objects
Pagination¶
The SDK keeps the API close to the wire format. To get additional pages, pass page=2, page=3, etc:
page_2 = client.hovercodes.list_for_workspace("YOUR-WORKSPACE-ID", page=2)
Searching¶
Use q= to search across:
- QR code links (
qr_data) - Display names
- Shortlink URLs
- Tag names
page_1 = client.hovercodes.list_for_workspace("YOUR-WORKSPACE-ID", q="twitter")
get_hovercode()¶
Retrieve a previously created QR code by ID.
qr = client.hovercodes.get_hovercode("QR-CODE-ID")
print(qr.get("svg_file"))
print(qr.get("png"))
Note
Even if you did not set generate_png=True during creation, the API may still return svg_file / png URLs when retrieving the QR code later.
get_activity()¶
Get tracking activity for a QR code (dynamic codes). This endpoint is paginated.
- Default page size is 50
page_sizecan be set up to 200
activity = client.hovercodes.get_activity("QR-CODE-ID", page_size=100)
print(activity["count"])
print(activity["results"][:3])
Each activity item commonly includes fields like:
qr_code_idtime_utctime_timezone_awarelocationdevicescanner_idid
update()¶
Update a QR code. The API supports updating:
display_name(for static or dynamic codes)qr_data(for dynamic Link codes only, per upstream documentation)gps_tracking(enable/disable GPS tracking for dynamic codes)
updated = client.hovercodes.update(
"QR-CODE-ID",
display_name="New name",
)
print(updated["display_name"])
Important
update() requires at least one of: qr_data, display_name, gps_tracking.
add_tags()¶
Add tags to a QR code. The API accepts a list of tag objects.
You can provide:
TagInput(title=...)/TagInput(id=...)(recommended)- raw dictionaries like
{"title": "my tag"}or{"id": "TAG-ID"}
from hovercode.models import TagInput
client.hovercodes.add_tags(
"QR-CODE-ID",
[
TagInput(title="marketing"),
{"title": "campaign-2025"}, # raw dicts are also supported
],
)
delete_hovercode()¶
Delete a QR code permanently.
The API returns HTTP 204 on success, so the SDK returns an empty dict ({}).
client.hovercodes.delete_hovercode("QR-CODE-ID")
Error handling¶
All API exceptions inherit from hovercode.exceptions.ApiError.
from hovercode import ApiError
try:
client.hovercodes.get_hovercode("not-a-real-id")
except ApiError as exc:
print(exc.status_code)
print(exc.response_data)
Bases: BaseClient
Client for creating and managing Hovercode QR codes.
This client implements the endpoints documented in documentation.md.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
api_token | Optional[str] | Hovercode API token. If not provided, | None |
base_url | Optional[str] | Hovercode API base URL. Defaults to | None |
timeout_seconds | Optional[float] | Per-request timeout in seconds. | None |
max_retries | Optional[int] | Maximum number of retries for transient failures. | None |
retry_backoff_seconds | Optional[float] | Base backoff duration (seconds) used for exponential backoff between retries. | None |
Raises:
| Type | Description |
|---|---|
AuthenticationError | If the API token is missing. |
ValidationError | If |
add_tags(qr_code_id: str, tags: Sequence[Union[TagInput, Mapping[str, JsonValue]]]) -> JsonObject ¶
Add tags to a QR code.
Endpoint: POST /hovercode/{qr_code_id}/tags/add/
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qr_code_id | str | QR code ID (UUID). | required |
tags | Sequence[Union[TagInput, Mapping[str, JsonValue]]] | List of tag objects. You can pass either:
The upstream API docs describe adding tags by title or by ID. | required |
Returns:
| Type | Description |
|---|---|
JsonObject | The QR code object as returned by the API. |
Raises:
| Type | Description |
|---|---|
ValidationError | If |
Example
from hovercode import HovercodeClient
from hovercode.models import TagInput
client = HovercodeClient()
client.hovercodes.add_tags(
"QR-CODE-ID",
[
TagInput(title="marketing"),
{"title": "campaign-2025"},
],
)
create(*, workspace: str, qr_data: str, qr_type: Optional[Union[QrType, str]] = None, dynamic: Optional[bool] = None, display_name: Optional[str] = None, domain: Optional[str] = None, generate_png: Optional[bool] = None, gps_tracking: Optional[bool] = None, error_correction: Optional[Union[ErrorCorrection, str]] = None, size: Optional[int] = None, logo_url: Optional[str] = None, logo_round: Optional[bool] = None, primary_color: Optional[str] = None, background_color: Optional[str] = None, pattern: Optional[Union[Pattern, str]] = None, eye_style: Optional[Union[EyeStyle, str]] = None, frame: Optional[Union[Frame, str]] = None, has_border: Optional[bool] = None, text: Optional[str] = None) -> JsonObject ¶
Create a QR code.
Endpoint: POST /hovercode/create/
QR codes are static by default. Set dynamic=True to create a dynamic QR code, which can be updated later.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
workspace | str | Workspace ID from your Hovercode settings. | required |
qr_data | str | QR payload. For | required |
qr_type | Optional[Union[QrType, str]] | QR type. Accepts | None |
dynamic | Optional[bool] | Whether to create a dynamic QR code. Defaults to | None |
display_name | Optional[str] | Optional internal name for organization in Hovercode. | None |
domain | Optional[str] | Optional custom domain to use for dynamic QR shortlinks. The upstream docs note this only applies to dynamic codes. | None |
generate_png | Optional[bool] | If | None |
gps_tracking | Optional[bool] | Whether to enable GPS tracking (dynamic codes only). | None |
error_correction | Optional[Union[ErrorCorrection, str]] | Error correction level: | None |
size | Optional[int] | Size in pixels (width). The upstream docs state default is 220. | None |
logo_url | Optional[str] | Optional logo image URL to embed in the QR code. | None |
logo_round | Optional[bool] | If | None |
primary_color | Optional[str] | Primary HEX color (including | None |
background_color | Optional[str] | Background HEX color (including | None |
pattern | Optional[Union[Pattern, str]] | Pattern style. Accepts | None |
eye_style | Optional[Union[EyeStyle, str]] | Eye style. Accepts | None |
frame | Optional[Union[Frame, str]] | Frame name. Accepts | None |
has_border | Optional[bool] | Whether to enable frame border option. | None |
text | Optional[str] | Optional frame text (only applies to some frames). | None |
Returns:
| Type | Description |
|---|---|
JsonObject | The created QR code object as returned by the API. |
Raises:
| Type | Description |
|---|---|
ApiError | For non-2xx API responses. |
ValidationError | If the API returns an unexpected response type. |
Example
from hovercode import HovercodeClient
from hovercode.enums import Frame, Pattern
client = HovercodeClient()
qr = client.hovercodes.create(
workspace="YOUR-WORKSPACE-ID",
qr_data="https://example.com",
dynamic=True,
frame=Frame.CIRCLE_VIEWFINDER,
pattern=Pattern.DIAMONDS,
)
print(qr["id"])
delete_hovercode(qr_code_id: str) -> JsonObject ¶
Delete a QR code permanently.
Endpoint: DELETE /hovercode/{qr_code_id}/delete/
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qr_code_id | str | QR code ID (UUID). | required |
Returns:
| Type | Description |
|---|---|
JsonObject | Empty dict for a successful delete (API returns HTTP 204). |
Example
from hovercode import HovercodeClient
client = HovercodeClient()
client.hovercodes.delete_hovercode("QR-CODE-ID")
get_activity(qr_code_id: str, *, page: Optional[int] = None, page_size: Optional[int] = None) -> JsonObject ¶
Get tracking activity for a QR code.
Endpoint: GET /hovercode/{qr_code_id}/activity/
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qr_code_id | str | QR code ID (UUID). | required |
page | Optional[int] | Optional page number. | None |
page_size | Optional[int] | Optional page size (maximum 200 per the documentation). | None |
Returns:
| Type | Description |
|---|---|
JsonObject | A paginated response with |
Raises:
| Type | Description |
|---|---|
ValidationError | If |
Example
from hovercode import HovercodeClient
client = HovercodeClient()
activity = client.hovercodes.get_activity("QR-CODE-ID", page_size=50)
print(activity["count"])
print(activity["results"][:3])
get_hovercode(qr_code_id: str) -> JsonObject ¶
Retrieve a previously created QR code.
Endpoint: GET /hovercode/{qr_code_id}/
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qr_code_id | str | QR code ID (UUID). | required |
Returns:
| Type | Description |
|---|---|
JsonObject | The QR code object as returned by the API. |
Notes
The upstream docs note that even if you did not set generate_png=True during creation, retrieving the QR code later may include svg_file and png URLs once the files are available.
list_for_workspace(workspace_id: str, *, q: Optional[str] = None, page: Optional[int] = None) -> JsonObject ¶
List QR codes for a workspace.
Endpoint: GET /workspace/{workspace_id}/hovercodes/
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
workspace_id | str | Hovercode workspace ID. | required |
q | Optional[str] | Optional search query (searches links, display names, shortlinks, and tag names). | None |
page | Optional[int] | Optional page number. | None |
Returns:
| Type | Description |
|---|---|
JsonObject | A paginated response object containing |
JsonObject | and |
Example
from hovercode import HovercodeClient
client = HovercodeClient()
page_1 = client.hovercodes.list_for_workspace(
"YOUR-WORKSPACE-ID",
q="twitter",
)
print(page_1["count"])
print(page_1["results"][:2])
update(qr_code_id: str, *, qr_data: Optional[str] = None, display_name: Optional[str] = None, gps_tracking: Optional[bool] = None) -> JsonObject ¶
Update a QR code.
Endpoint: PUT /hovercode/{qr_code_id}/update/
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qr_code_id | str | QR code ID (UUID). | required |
qr_data | Optional[str] | Updated QR destination. Documented as only updateable for dynamic | None |
display_name | Optional[str] | Updated display name. | None |
gps_tracking | Optional[bool] | Enable/disable GPS tracking for the QR code. | None |
Returns:
| Type | Description |
|---|---|
JsonObject | The updated QR code object as returned by the API. |
Raises:
| Type | Description |
|---|---|
ValidationError | If none of |