---
title: "Rename or repoint a code"
method: PATCH
path: "/api/v1/codes/{linkId}"
tags: ["Public API v1"]
---

# Rename or repoint a code

`PATCH /api/v1/codes/{linkId}`

## Request

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

No idempotency key is required, because a PATCH with an absolute body is already idempotent:
applying it twice leaves the same state.

Every destination change is re-screened. That is not optional — a dynamic code that has been
printed and trusted is precisely the asset an attacker wants to repoint.

`slug`, `linkId` and `resolverState` are not patchable. The slug is printable and therefore
permanent; the other two are platform identity and platform state.

Codes bound to an ordering place are protected server-side, including when a write arrives
through an integration. Individual connectors may support fewer payload types than this API.

## Request body

- UpdateCodeRequest
  - `name` string
  - `destination` string
  - `status` 'active' | 'paused'
  - `design` string
  - `scanCap` integer, nullable
  - `payload` string, nullable

## Response `200`

Updated.

- object
  - `data` PublicCode, required: An explicit allowlist of fields, not the stored row. A column added to the database must not silently appear here, because this surface is versioned and anything it returns becomes a compatibility obligation.
    - `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

## 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.
- `404`: No such code in this workspace. Another tenant's id reads as absent, not as forbidden.
- `409`: Destination cannot be changed: `code_frozen` or `code_bound_to_place`. Refused rather than silently ignored, because reporting success for a write that did not happen is worse than an error.
- `422`: The new destination was refused by reputation screening.
- `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)
