Skip to content

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=True for a dynamic code.
  • Link vs Text: qr_type defaults to "Link". "Text" codes are plain text and (per the upstream docs) are static only.
  • PNG generation: generate_png=True can slow down the create response, but it includes .png/.svg file 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, Triangles
  • eye_style: Square, Rounded, Drop, Leaf
  • frame: 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 hovercodes
  • next: URL for the next page, or null
  • previous: URL for the previous page, or null
  • results: 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_size can 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_id
  • time_utc
  • time_timezone_aware
  • location
  • device
  • scanner_id
  • id

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, HOVERCODE_API_TOKEN is used.

None
base_url Optional[str]

Hovercode API base URL. Defaults to https://hovercode.com/api/v2.

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 base_url is empty.

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:

  • TagInput(title=...) / TagInput(id=...) (recommended), or
  • raw dicts like {"title": "my tag"} / {"id": "TAG-ID"}.

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 tags is empty.

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 qr_type="Link" this should be a valid URL. For qr_type="Text" this can be any plain text.

required
qr_type Optional[Union[QrType, str]]

QR type. Accepts QrType or a string. Currently documented values are "Link" (default) and "Text".

None
dynamic Optional[bool]

Whether to create a dynamic QR code. Defaults to False when omitted.

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 True, include PNG/SVG file URLs in the response. The upstream docs note this slows down the create response.

None
gps_tracking Optional[bool]

Whether to enable GPS tracking (dynamic codes only).

None
error_correction Optional[Union[ErrorCorrection, str]]

Error correction level: "L", "M", "Q", "H". The upstream docs state it defaults to Q without a logo and H with a logo.

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 True, force the logo into a circle.

None
primary_color Optional[str]

Primary HEX color (including #). Upstream default is #111111.

None
background_color Optional[str]

Background HEX color (including #).

None
pattern Optional[Union[Pattern, str]]

Pattern style. Accepts Pattern or a string (e.g. "Original", "Diamonds").

None
eye_style Optional[Union[EyeStyle, str]]

Eye style. Accepts EyeStyle or a string (e.g. "Square", "Rounded").

None
frame Optional[Union[Frame, str]]

Frame name. Accepts Frame or a string (e.g. "circle-viewfinder").

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 results containing activity items.

Raises:

Type Description
ValidationError

If page_size is greater than 200.

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 count, next, previous,

JsonObject

and results.

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 "Link" QR codes.

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 qr_data, display_name, or gps_tracking are provided.