REST · JSON · OpenAPI 3.0

API Reference

A tiny REST API for creating short links and QR codes. If you can send a JSON request, you can use it. No SDK required.

Getting started in 60 seconds

  1. 1. Get your API key. Sign in and copy it from your dashboard. Keep it secret — treat it like a password.
  2. 2. Send a URL to /api/shorten. You get back a short code (e.g. AB3XK9PQ7M) and a passcode.
  3. 3. Save the passcode. It's the only way to change the destination URL later. We never show it again.
  4. 4. Share the short URL or QR image. Anyone who visits https://www.quickresponsehub.com/AB3XK9PQ7M gets redirected to your URL.

Full curl workflow — create, update, test

Paste this whole block into your terminal. It creates a short link, repoints it to a new URL, then verifies the redirect — using jq to capture the code and passcode automatically.

bash
# 1. Set your API key (get it from /dashboard)
export QRH_KEY="YOUR_API_KEY"

# 2. Create a short link to https://example.com/v1
#    -> capture "code" and "passcode" from the JSON response
RESPONSE=$(curl -s -X POST https://www.quickresponsehub.com/api/shorten \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $QRH_KEY" \
  -d '{"url":"https://example.com/v1"}')

CODE=$(echo "$RESPONSE" | jq -r '.code')
PASSCODE=$(echo "$RESPONSE" | jq -r '.passcode')

echo "Created: https://www.quickresponsehub.com/$CODE"
echo "Passcode (save this!): $PASSCODE"

# 3. Update the destination to https://example.com/v2
curl -s -X POST https://www.quickresponsehub.com/api/update \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $QRH_KEY" \
  -d "{\"code\":\"$CODE\",\"passcode\":\"$PASSCODE\",\"url\":\"https://example.com/v2\"}" \
  | jq

# 4. Test the redirect — should print "Location: https://example.com/v2"
curl -sI https://www.quickresponsehub.com/$CODE | grep -i '^location:'

# 5. (Optional) Look up the current destination without following the redirect
curl -s https://www.quickresponsehub.com/api/lookup/$CODE | jq

Expected output

text
Created: https://www.quickresponsehub.com/AB3XK9PQ7M
Passcode (save this!): K8M2QW9XLR4P7VN3JZB6CDFH
{
  "code": "AB3XK9PQ7M",
  "url": "https://example.com/v2",
  "short_url": "https://www.quickresponsehub.com/AB3XK9PQ7M",
  "updated": true
}
location: https://example.com/v2
{
  "code": "AB3XK9PQ7M",
  "url": "https://example.com/v2",
  "created_at": "2026-04-28T10:00:00.000Z",
  "hit_count": 1
}

No jq? Install it with brew install jq (macOS) or apt install jq (Debian/Ubuntu) — or skip it and read the JSON by eye.

Code

A short, public identifier (6–20 characters, uppercase letters and numbers only, e.g. AB3XK9PQ7M). It's what goes in the short URL.

Passcode

A 24-character secret returned once when you create or reserve a code. Required to change the destination URL. Store it like a password.

API key

Identifies your account. Sent on every create or update request via the X-API-Key header.

Authentication

Send your API key in the X-API-Key header. Read endpoints (lookup, QR images, redirects) are public and need no key.

bash
curl https://www.quickresponsehub.com/api/shorten \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com"}'

Missing or wrong key? You'll get a 401 Unauthorized.

🔑 IMPORTANT

Passcodes — when you get one, and how to keep it safe

A passcode is a per-code 24-character secret. It's separate from your API key and is the only credential that lets you change a code's destination URL or delete it. Treat it like a one-time-issued password.

When is the passcode returned?

Exactly once, in the JSON response of the request that created the code. After that, no endpoint, dashboard view, or support agent can ever show it to you again — it's hashed at rest with Argon2id and we genuinely cannot recover it.

EndpointReturns passcode?Field
POST /api/shorten✅ Yes — oncepasscode
POST /api/reserve✅ Yes — oncepasscode
POST /api/bulk-shorten✅ Yes — once per itemresults[].passcode
GET /api/lookup/{code}❌ Never
GET /api/list❌ Never
Dashboard UI❌ Never (after create)

If you lose a passcode

You can still delete the code from your dashboard (account ownership is enough), but you cannot change its destination URL. The recovery path is: delete the old code → create a new one → reprint or re-share the new short URL or QR.

How to store passcodes safely

The passcode is a long-lived bearer secret. Capture it from the create response immediately and put it somewhere your application can read but humans normally can't.

  • Best — a managed secrets store, keyed by code: AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault, Doppler, 1Password Secrets Automation. One entry per code, e.g. qrh/passcode/AB3XK9PQ7M.
  • Good — encrypted column in your own database. Encrypt with a KMS key (AWS KMS, GCP KMS, libsodium crypto_secretbox) before INSERT. Never store plaintext.
  • Acceptable for one-off scripts — a .env file outside source control with chmod 600, or your OS keychain (security add-generic-password on macOS, secret-tool on Linux).
  • Never: commit to git, paste into Slack/email/tickets, hard-code in client-side JavaScript or mobile apps, log to stdout or APM tools (Datadog, Sentry), or store in browser localStorage.

Example — capture and store in one step

bash
# Create the code, pull the passcode straight into a secrets store.
# Nothing is ever printed to the terminal or written to disk in plaintext.

RESPONSE=$(curl -s -X POST https://www.quickresponsehub.com/api/shorten \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $QRH_KEY" \
  -d '{"url":"https://example.com/launch"}')

CODE=$(echo "$RESPONSE"     | jq -r '.code')
PASSCODE=$(echo "$RESPONSE" | jq -r '.passcode')

# AWS Secrets Manager
aws secretsmanager create-secret \
  --name "qrh/passcode/$CODE" \
  --secret-string "$PASSCODE"

# Or: macOS Keychain
security add-generic-password -a "qrh" -s "passcode-$CODE" -w "$PASSCODE"

unset RESPONSE PASSCODE
typescript
// Node.js — encrypt with libsodium before storing in Postgres.
import sodium from "libsodium-wrappers";
import { sql } from "./db";

await sodium.ready;
const key = sodium.from_base64(process.env.PASSCODE_ENCRYPTION_KEY!);

const res = await fetch("https://www.quickresponsehub.com/api/shorten", {
  method: "POST",
  headers: { "Content-Type": "application/json", "X-API-Key": process.env.QRH_KEY! },
  body: JSON.stringify({ url: "https://example.com/launch" }),
});
const { code, passcode } = await res.json();

const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES);
const ciphertext = sodium.crypto_secretbox_easy(passcode, nonce, key);

await sql`
  insert into qr_codes (code, passcode_nonce, passcode_ciphertext)
  values (${code}, ${Buffer.from(nonce)}, ${Buffer.from(ciphertext)})
`;
// 'passcode' goes out of scope here — never logged, never serialized.

Operational hygiene

  • Add a log scrubber for the regex [A-Z0-9]{24} next to your X-API-Key scrubber.
  • Restrict who can read the secrets store. Audit access at least quarterly.
  • If a passcode is ever exposed, delete the code immediately and create a replacement — there is no rotate-passcode endpoint by design.

Base URL & format

  • Base URL: https://www.quickresponsehub.com
  • Request format: JSON (Content-Type: application/json)
  • Response format: JSON (except QR images and redirects)
  • Codes are always uppercase. Lowercase input is automatically uppercased.

Use it from any language

The same POST /api/shorten call in six common languages — copy, set QRH_KEY in your environment, and run.

typescript
// Node 18+ / Bun / Deno — uses built-in fetch.
const res = await fetch("https://www.quickresponsehub.com/api/shorten", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": process.env.QRH_KEY!,
  },
  body: JSON.stringify({ url: "https://example.com/spring-sale" }),
});

if (!res.ok) {
  const { error } = await res.json().catch(() => ({}));
  throw new Error(`QRH ${res.status}: ${error ?? res.statusText}`);
}

const { code, short_url, qr_url, passcode } = await res.json();
console.log({ code, short_url, qr_url });
// IMPORTANT: persist 'passcode' in your secrets store now — it's only returned here.

No SDK required. Every example uses each language's standard HTTP primitives so you can drop them into any codebase without adding dependencies (except Python's requests, which most projects already have).

Endpoints

POST/api/shorten🔑 API key required

Create a short link

The everyday endpoint. Send a URL, get back a short code, a short URL, a QR code, and a passcode.

Body

  • urlstring (URL)required

    The destination — where visitors should land. Must include http:// or https://.

Example request

bash
curl -X POST https://www.quickresponsehub.com/api/shorten \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{"url":"https://example.com/spring-sale"}'

Example response (201 Created)

json
{
  "code": "AB3XK9PQ7M",
  "url": "https://example.com/spring-sale",
  "passcode": "K8M2QW9XLR4P7VN3JZB6CDFH",
  "short_url": "https://www.quickresponsehub.com/AB3XK9PQ7M",
  "qr_url": "https://www.quickresponsehub.com/qr/AB3XK9PQ7M",
  "created_at": "2026-04-28T10:00:00.000Z",
  "reused": false
}
💡 Save the passcode. It's the only way to change this code's URL later. We can't recover it for you.

Possible errors

  • 400The URL is missing or not a valid http/https URL.
  • 401Your API key is missing or wrong.
  • 429Rate limit exceeded — back off and retry per the Retry-After header.
  • 500Something went wrong on our side. Try again shortly.
Rate limit & retry
  • Budget: Counts against your write budget (Free: 60/min, Pro: 600/min).
  • Retry: Retry on 429/5xx with jittered exponential backoff. Honour Retry-After. Safe to retry — duplicate URLs are deduplicated server-side and return the existing code with reused: true.
  • Tip: creating ≥10 codes? Use POST /api/bulk-shorten instead — one request consumes one slot.
POST/api/reserve🔑 API key required

Reserve a custom code (no URL yet)

Want a branded code like MYBRAND2026? Claim it now, decide where it points later. You get a passcode back; use /api/update when you're ready to set the URL.

Body

  • codestring (6–20 chars)required

    The custom code you want to claim. Letters and numbers only — no spaces, no dashes, no symbols. Stored uppercase.

Example request

bash
curl -X POST https://www.quickresponsehub.com/api/reserve \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{"code":"MYBRAND2026"}'

Example response (201 Created)

json
{
  "code": "MYBRAND2026",
  "passcode": "K8M2QW9XLR4P7VN3JZB6CDFH",
  "url": null,
  "short_url": "https://www.quickresponsehub.com/MYBRAND2026",
  "reserved": true,
  "created_at": "2026-04-28T10:00:00.000Z"
}
Visiting a reserved code that has no URL yet returns a 404. Set the URL with /api/update first.

Possible errors

  • 400Code is the wrong length, contains a space, or has a non-alphanumeric character.
  • 401Your API key is missing or wrong.
  • 409That code is already in use — pick a different one.
  • 429Rate limit exceeded — back off and retry per the Retry-After header.
Rate limit & retry
  • Budget: Counts against your write budget (Free: 60/min, Pro: 600/min).
  • Retry: Retry on 429/5xx with jittered exponential backoff. NEVER retry on 409 — pick a different code first or you'll loop forever.
POST/api/update🔑 API key required

Change a code's destination URL

Repoint an existing code somewhere new — for example, swap a printed QR's destination after a campaign ends. Requires the passcode you got at create/reserve time.

Body

  • codestringrequired

    The existing code (e.g. MYBRAND2026).

  • passcodestringrequired

    The 24-character passcode returned when the code was created or reserved.

  • urlstring (URL)required

    The new destination URL. Must include http:// or https://.

Example request

bash
curl -X POST https://www.quickresponsehub.com/api/update \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "code": "MYBRAND2026",
    "passcode": "K8M2QW9XLR4P7VN3JZB6CDFH",
    "url": "https://example.com/new-destination"
  }'

Example response (200 OK)

json
{
  "code": "MYBRAND2026",
  "url": "https://example.com/new-destination",
  "short_url": "https://www.quickresponsehub.com/MYBRAND2026",
  "updated": true
}

Possible errors

  • 400URL is missing or not valid, or fields are missing.
  • 401Your API key is missing or wrong.
  • 403Code doesn't exist, the passcode is wrong, or this code belongs to a different account.
  • 429Rate limit exceeded — back off and retry per the Retry-After header.
Rate limit & retry
  • Budget: Counts against your write budget (Free: 60/min, Pro: 600/min).
  • Retry: Retry on 429/5xx with jittered exponential backoff. Idempotent — repeating the same update yields the same result. NEVER retry on 403; the passcode/ownership won't change between attempts.
POST/api/delete🔑 API key required

Delete a code

Permanently remove a code. The short URL stops working immediately and the code becomes available for someone else to claim. Requires the matching passcode.

Body

  • codestringrequired

    The code to delete.

  • passcodestringrequired

    The 24-character passcode for that code.

Example request

bash
curl -X POST https://www.quickresponsehub.com/api/delete \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{"code":"MYBRAND2026","passcode":"K8M2QW9XLR4P7VN3JZB6CDFH"}'

Example response (200 OK)

json
{ "code": "MYBRAND2026", "deleted": true }

Possible errors

  • 401API key is missing or wrong.
  • 403Code doesn't exist, passcode is wrong, or you're not the owner.
  • 429Rate limit exceeded — back off and retry per the Retry-After header.
Rate limit & retry
  • Budget: Counts against your write budget (Free: 60/min, Pro: 600/min).
  • Retry: Retry on 429/5xx with jittered exponential backoff. Idempotent — a second delete of an already-deleted code returns 403 (not found / not owned), which is fine. NEVER retry on 403.
POST/api/bulk-shorten🔑 API key required

Shorten up to 100 URLs at once

Send an array of URLs in one request. You get back an array of results in the same order — perfect for migrations, batch imports, or generating QR codes for a whole product catalogue.

Body

  • urlsarray of strings (1–100)required

    Each item must be a valid http:// or https:// URL.

Example request

bash
curl -X POST https://www.quickresponsehub.com/api/bulk-shorten \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{"urls":["https://example.com/a","https://example.com/b"]}'

Example response (201 Created)

json
{
  "count": 2,
  "results": [
    {
      "ok": true,
      "reused": false,
      "code": "AB3XK9PQ7M",
      "url": "https://example.com/a",
      "passcode": "K8M2QW9XLR4P7VN3JZB6CDFH",
      "short_url": "https://www.quickresponsehub.com/AB3XK9PQ7M",
      "qr_url": "https://www.quickresponsehub.com/qr/AB3XK9PQ7M",
      "created_at": "2026-04-28T10:00:00.000Z"
    },
    {
      "ok": true,
      "reused": true,
      "code": "ZK4MNQR9P2",
      "url": "https://example.com/b",
      "passcode": "L9N3RW0YMS5Q8WO4KAC7DEGI",
      "short_url": "https://www.quickresponsehub.com/ZK4MNQR9P2",
      "qr_url": "https://www.quickresponsehub.com/qr/ZK4MNQR9P2",
      "created_at": "2026-04-20T14:00:00.000Z"
    }
  ]
}
💡 The same URL is never duplicated for your account — re-submitting it returns the existing code with reused: true.
Rate limit & retry
  • Budget: One request = one slot, regardless of how many URLs you send (Free: 60/min, Pro: 600/min, max 100/1,000 URLs per request respectively).
  • Retry: Retry the whole request on 429/5xx with jittered exponential backoff. Safe to retry — duplicates are deduplicated server-side. If only some items failed, you'll still get 201 with per-item ok: false; do NOT retry the whole batch — re-submit just the failed URLs.
GET/api/lookup/{code}Public

Look up where a code points (no redirect)

Useful for checking a code's destination from your own backend without following the redirect. No API key needed.

Example

bash
curl https://www.quickresponsehub.com/api/lookup/AB3XK9PQ7M

Response (200 OK)

json
{
  "code": "AB3XK9PQ7M",
  "url": "https://example.com",
  "created_at": "2026-04-28T10:00:00.000Z",
  "hit_count": 42
}

url is null for codes that have been reserved but not yet pointed anywhere.

GET/api/list🔑 API key required

List your codes (paginated)

Programmatically fetch the codes on your account, newest first. Great for building your own dashboards or syncing with another system.

Query parameters

  • limitinteger (1–200)

    How many items to return. Default 50.

  • offsetinteger

    Skip this many items. Use with limit for paging.

  • searchstring

    Partial, case-insensitive match on code or URL.

Example

bash
curl "https://www.quickresponsehub.com/api/list?limit=20&search=brand" \
  -H "X-API-Key: YOUR_API_KEY"

Response (200 OK)

json
{
  "total": 73,
  "limit": 20,
  "offset": 0,
  "count": 20,
  "items": [
    {
      "code": "AB3XK9PQ7M",
      "url": "https://example.com",
      "hit_count": 42,
      "created_at": "2026-04-28T10:00:00.000Z",
      "short_url": "https://www.quickresponsehub.com/AB3XK9PQ7M",
      "qr_url": "https://www.quickresponsehub.com/qr/AB3XK9PQ7M"
    }
  ]
}
Passcodes are never returned by this endpoint — they're shown only at creation time. If you lost a passcode, delete the code and create a new one.
GET/api/qr/{code}Public

Generate a QR code image on the fly

Returns a PNG (default) or SVG QR image that encodes the short URL. Customize size and colors with query parameters. No API key needed.

Query parameters

  • formatpng | svg

    Image format. Default is png.

  • sizeinteger (64–2048)

    Pixel size for PNG. Default is 512. Ignored for SVG.

  • darkhex color

    Foreground (the dots). Default is #1a2e4f. URL-encode the # as %23.

  • lighthex color

    Background. Default is #ffffff.

Example request

bash
# Plain PNG (default 512px)
curl -o qr.png "https://www.quickresponsehub.com/api/qr/AB3XK9PQ7M"

# 1024px PNG with custom colors
curl -o qr.png "https://www.quickresponsehub.com/api/qr/AB3XK9PQ7M?size=1024&dark=%23000000&light=%23ffffff"

# Vector SVG (scales infinitely)
curl -o qr.svg "https://www.quickresponsehub.com/api/qr/AB3XK9PQ7M?format=svg"

Example response (200 OK)

http
HTTP/1.1 200 OK
Content-Type: image/png
Cache-Control: public, max-age=86400, immutable
Content-Length: 4821

<binary PNG data — write to file with -o or pipe to a viewer>

Embed in HTML

html
<img src="https://www.quickresponsehub.com/api/qr/AB3XK9PQ7M?size=256" alt="QR code" width="256" height="256" />
GET/qr/{code}Public

Cached QR image (fast, embeddable)

Redirects to a CDN-cached PNG of the QR. Use this in <img> tags and emails — it's faster than /api/qr/{code} for repeated views.

Example request

bash
curl -L -o qr.png "https://www.quickresponsehub.com/qr/AB3XK9PQ7M"

Example response (302 Found)

http
HTTP/1.1 302 Found
Location: https://cdn.quickresponsehub.com/qr/AB3XK9PQ7M.png
Cache-Control: public, max-age=31536000, immutable

Embed in HTML

html
<img src="https://www.quickresponsehub.com/qr/AB3XK9PQ7M" alt="QR code" width="256" height="256" />
GET/api/qr-image/{code}Public

Get QR image URLs as JSON

Returns the canonical short URL, the cached QR URL, and the underlying storage URL. Handy when you only have a code and want to grab the image links.

Example request

bash
curl https://www.quickresponsehub.com/api/qr-image/AB3XK9PQ7M

Example response (200 OK)

json
{
  "code": "AB3XK9PQ7M",
  "url": "https://example.com",
  "short_url": "https://www.quickresponsehub.com/AB3XK9PQ7M",
  "qr_url": "https://www.quickresponsehub.com/qr/AB3XK9PQ7M",
  "qr_storage_url": "https://cdn.quickresponsehub.com/qr/AB3XK9PQ7M.png"
}
GET/{code}Public

Follow the short link (302 redirect)

The redirect itself. This is the URL encoded in your QR image and the one you share publicly.

Example request

bash
curl -I https://www.quickresponsehub.com/AB3XK9PQ7M

Example response (302 Found)

http
HTTP/1.1 302 Found
Location: https://example.com
Cache-Control: no-store
X-QRH-Code: AB3XK9PQ7M

Returns 404 if the code doesn't exist or has no destination URL set yet.

GET/api/statusPublic

Health check

Quick check that the API and database are online. Use it for uptime monitoring.

Example request

bash
curl https://www.quickresponsehub.com/api/status

Example response (200 OK)

json
{
  "status": "operational",
  "database": "ok",
  "total_redirects": 12873,
  "response_time_ms": 24,
  "timestamp": "2026-04-28T10:00:00.000Z",
  "version": "1.5.0"
}
Rate limit & retry
  • Budget: Counts against your read budget (Free: 300/min, Pro: 3,000/min).
  • Retry: Retry once on network error. For uptime monitoring, poll at most every 30 seconds — more frequent polling is the #1 cause of self-inflicted 429s.

Error responses

All errors return JSON with an error message and the matching HTTP status code:

json
{ "error": "Code already in use" }
StatusWhat it means
400Your request body is invalid (bad URL, missing field, wrong code format).
401API key is missing or wrong.
403You don't own this code, or the passcode doesn't match.
404Code doesn't exist (or has no destination URL set yet).
409Code is already taken (only on /api/reserve).
500Something failed on our side — safe to retry.

Need every status with cause, fix, and example payloads? See the full Error Reference →

Rate limits & retry strategy

Limits are enforced per API key on a sliding 60-second window. Read endpoints (lookup, list, QR images, redirects) and write endpoints have separate budgets so a heavy read workload won't block your ability to create new codes.

Per-plan budgets

PlanWrites / minReads / minBulk batch size
Free60300100
Pro6003,0001,000
EnterpriseCustomCustomCustom

Response headers on every request

  • X-RateLimit-Limit — your budget for this endpoint group.
  • X-RateLimit-Remaining — requests left in the current window.
  • X-RateLimit-Reset — Unix seconds when the window resets.
  • Retry-After — only on 429 and 503; seconds to wait before retrying.

When to retry

  • Always retry: 429, 500, 502, 503, 504, plus network errors (DNS, TCP reset, TLS).
  • Never retry: 400, 401, 403, 404, 409, 422 — the request will fail again identically. Fix the input first.
  • Cap attempts: at most 5 retries, with jittered exponential backoff (1s, 2s, 4s, 8s, 16s ± 25% jitter), capped at 30s.
  • Honour Retry-After when present — it always overrides your backoff schedule.

Reference retry helper

typescript
// Drop-in fetch wrapper with rate-limit-aware retries.
const RETRYABLE = new Set([408, 425, 429, 500, 502, 503, 504]);

export async function qrhFetch(input: string, init: RequestInit = {}, attempt = 0): Promise<Response> {
  const res = await fetch(input, init);

  if (res.ok || !RETRYABLE.has(res.status) || attempt >= 5) return res;

  const retryAfter = Number(res.headers.get("Retry-After"));
  const backoff = Number.isFinite(retryAfter) && retryAfter > 0
    ? retryAfter * 1000
    : Math.min(30_000, 2 ** attempt * 1000) * (0.75 + Math.random() * 0.5); // jitter

  await new Promise((r) => setTimeout(r, backoff));
  return qrhFetch(input, init, attempt + 1);
}

Avoiding limits in the first place

  • Use POST /api/bulk-shorten instead of looping POST /api/shorten — one request counts as one, not N.
  • Cache GET /api/lookup/{code} responses for at least 60s; destinations rarely change minute-to-minute.
  • For uptime monitoring, poll GET /api/status at most every 30 seconds.
  • Don't proxy public redirects (GET /{code}) through the API — link to them directly.

About passcodes

Passcodes are 24 uppercase letters/digits, returned only once when a code is created or reserved. They unlock the right to change the destination URL via /api/update. They're never visible in any read endpoint or in the dashboard. Lose it and you'll need to create a new code — see the dedicated passcodes section above for safe-storage guidance.