---
title: "List codes"
method: GET
path: "/api/v1/codes"
tags: ["Public API v1"]
---

# List codes

`GET /api/v1/codes`

## Request

- Base URL: `https://scanduro.com`
- URL: `https://scanduro.com/api/v1/codes`
- Auth: HTTP bearer

Cursor-paginated, never offset-paginated. With an offset, a code created while you are walking
the list shifts every later page and an item is skipped silently — during the bulk import where
it matters most. Pass the `nextCursor` from the previous response.

## Query parameters

- `limit` integer
- `cursor` string
- `kind` 'qr' | 'link'

## Response `200`

A page of codes.

- object
  - `data` PublicCode[], required
    - `shortUrl` string, uri, nullable: Server-derived canonical resolver URL for a live dynamic URL code, including its verified branded hostname where applicable. Null for sandbox, static and non-URL payloads. Integrations must encode this value, not the mutable destination, into dynamic QR artwork.
    - `id` string, required: The immutable public identity of the link. Assigned once, never changed, never reused. Store this, not the slug — a slug can be retired and a domain can be moved.
    - `name` string, required
    - `type` 'static' | 'dynamic', required
    - `kind` 'qr' | 'link', required
    - `contentType` 'url' | 'text' | 'vcard' | 'wifi' | 'email' | 'sms' | 'geo' | 'pdf' | 'gs1', required
    - `slug` string, required
    - `destination` string, required
    - `status` 'active' | 'paused' | 'blocked', required: The product state — whether the owner gets editing and analytics.
    - `hostname` string, nullable: The branded host this code resolves on, or `null` for the shared resolver. Reported rather than left to be inferred: the apex is deployment configuration, so a client that reconstructed the host from the label it sent would get it wrong the moment the apex changed — and this is the URL that gets printed.
    - `mode` 'live' | 'test': Which namespace this row belongs to, decided by the key that created it and never patchable. A `test` row does NOT resolve — that is what makes a free sandbox safe to offer, because a sandbox code cannot be printed and quietly work for a while.
    - `resolverState` 'active' | 'frozen' | 'suspended', required: The infrastructure state — whether the link resolves at all. Read-only here; only an operator changes it. A lapsed subscription never appears in this field.
    - `scanCap` integer, nullable
    - `createdAt` string, date-time, required
  - `nextCursor` string, nullable, required: Null on the last page.

## Other responses

- `400`: Validation failure, a missing Idempotency-Key, or an unusable cursor.
- `401`: No key, a malformed key, an unknown key, a revoked key or an expired key. Deliberately one response for all five: telling the caller which applies would make the endpoint an oracle for enumerating valid keys.
- `403`: Either the plan does not include API access (`plan_required`) or the key does not carry the required scope (`missing_scope`). The credential itself is valid in both cases.
- `429`: Per-key limit reached. Retry-After gives the seconds remaining in the window.

---

[API](https://skmtc.dev/scanduro/apis/scanduro-public-api.md) · [All operations](https://skmtc.dev/scanduro/apis/scanduro-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/scanduro/apis/scanduro-public-api/revisions/cdb36d96cad7?raw)
