API Status: v0 (Early Access) This API is exploratory. Breaking changes may occur as interfaces and lifecycle semantics are refined.

WebBadge provides a public REST API for integrating QR256 into automation, provisioning, and machine-to-machine handoff workflows. Rather than treating QR codes as payload containers, QR256 treats them as lightweight entry points into the Resolution Layer, where meaning is resolved deterministically under explicit lifecycle, access, and integrity rules. This approach is designed for environments where humans, machines, or AI agents need to resolve QR-triggered content reliably while keeping QR density low and scan fidelity high. By separating the QR from the content it represents, QR256 ensures that each scan resolves exactly as intended until an Item’s lifecycle ends—providing predictable behavior across devices, systems, and trust boundaries.

The Resolution Layer

The Resolution Layer is the governed system boundary where lightweight triggers—such as QR codes, links, or digital badges—resolve to their authoritative meaning under explicit lifecycle, access, and integrity rules. Rather than embedding content in the QR itself, the Resolution Layer ensures that meaning is delivered deterministically, verifiably, and within the lifecycle conditions defined at creation time.

In QR256, the Resolution Layer governs how a QR code resolves into immutable content with predictable lifecycle behavior. In WebBadge, it governs how a digital badge resolves into its authoritative trust state (valid, expired, revoked, or superseded).

Across both systems, the Resolution Layer provides a consistent foundation for safe, predictable, machine-friendly resolution across human workflows, automated systems, and AI-driven interactions.

Why it matters:

By separating the trigger from the meaning it resolves to, the Resolution Layer ensures that QR-triggered behavior remains predictable across devices, systems, and trust boundaries.

Resolution Lifecycle (Simplified)
                    CREATEDACTIVEBOUNDFINALIZEDARCHIVAL
                
StageDescription
CREATEDThe artifact is issued as a write-once, immutable object with its lifecycle rules defined.
ACTIVEThe artifact is fully valid and resolves exactly as intended.
BOUNDThe artifact remains valid but is constrained by remaining lifecycle limits such as TTL or view count.
FINALIZEDThe artifact’s legitimacy window has ended and it no longer resolves to active meaning.
ARCHIVALThe artifact becomes a historical, immutable record used only for final-state or audit-level information.

API Endpoints

MethodEndpointDescription
POSThttps://qr256.webbadge.com/api/v0/itemsCreate a new QR256 Item with lifecycle constraints.
GEThttps://qr256.webbadge.com/api/v0/items/{magic}Resolve Item metadata and content (counts as a view).
DELETEhttps://qr256.webbadge.com/api/v0/items/{magic}Delete a QR256 Item using a delete token.

Code Handshakes (Create Resolve Delete)

POST 1. Initialize
curl -i -X POST "https://qr256.webbadge.com/api/v0/items" -H "Content-Type: application/json" -d '{ "content": "Hello, World. Resolved exactly as intended.", "password": "YOUR_ACCESS_PASSWORD", "ttlHours": 1, "viewLimit": 5 }'
GET 2. Resolve
curl -i -X GET "https://qr256.webbadge.com/api/v0/items/MAGIC_ID" -H "X-QR-Password: YOUR_ACCESS_PASSWORD"
DELETE 3. Delete
curl -i -X DELETE "https://qr256.webbadge.com/api/v0/items/MAGIC_ID" -H "X-Delete-Token: YOUR_DELETE_TOKEN"
POST 1. Initialize
import requests

# POST: Initialize item. Password goes in the JSON body.
res = requests.post("https://qr256.webbadge.com/api/v0/items", json={
    "content": "Hello, World. Resolved exactly as intended.",
    "password": "YOUR_ACCESS_PASSWORD",
    "ttlHours": 1,
    "viewLimit": 5
})
print(res.json())
GET 2. Resolve
# GET: Resolve item. Password goes in the 'X-QR-Password' header.
res = requests.get("https://qr256.webbadge.com/api/v0/items/MAGIC_ID", headers={
    "X-QR-Password": "YOUR_ACCESS_PASSWORD"
})
print(res.headers.get("X-Content-Hmac"))
print(res.json())
DELETE 3. Delete
# DELETE: Delete item. Token goes in the 'X-Delete-Token' header.
res = requests.delete("https://qr256.webbadge.com/api/v0/items/MAGIC_ID", headers={
    "X-Delete-Token": "YOUR_DELETE_TOKEN"
})
print(res.status_code) # Returns 204
POST 1. Initialize
using var client = new HttpClient();

// POST: Initialize item. Password goes in the JSON body
var payload = new { 
    content = "Hello, World. Resolved exactly as intended.", 
    password = "YOUR_ACCESS_PASSWORD",
    ttlHours = 1,
    viewLimit = 5
};
var res = await client.PostAsJsonAsync("https://qr256.webbadge.com/api/v0/items", payload);
var data = await res.Content.ReadFromJsonAsync<dynamic>();
GET 2. Resolve
// GET: Resolve item. Password goes in the 'X-QR-Password' header.
using var req = new HttpRequestMessage(HttpMethod.Get, "https://qr256.webbadge.com/api/v0/items/MAGIC_ID");
req.Headers.Add("X-QR-Password", "YOUR_ACCESS_PASSWORD");

var res = await client.SendAsync(req);

res.Headers.TryGetValues("X-Content-Hmac", out var values);
var contentHmac = values?.FirstOrDefault();

var item = await res.Content.ReadFromJsonAsync<dynamic>();
DELETE 3. Delete
// DELETE: Delete item. Token goes in the 'X-Delete-Token' header.
using var req = new HttpRequestMessage(HttpMethod.Delete, "https://qr256.webbadge.com/api/v0/items/MAGIC_ID");
req.Headers.Add("X-Delete-Token", "YOUR_DELETE_TOKEN");

var res = await client.SendAsync(req); 
// res.StatusCode will be 204 No Content
POST 1. Initialize
const axios = require('axios');

// POST: Initialize item. Password goes in the JSON body.
const res = await axios.post('https://qr256.webbadge.com/api/v0/items', { 
    content: "Hello, World. Resolved exactly as intended.", 
    password: "YOUR_ACCESS_PASSWORD",
    ttlHours: 1,
    viewLimit: 5 
});
console.log(res.data);
GET 2. Resolve
// GET: Resolve item. Password goes in the 'X-QR-Password' header.
const res = await axios.get('https://qr256.webbadge.com/api/v0/items/MAGIC_ID', { 
    headers: { 'X-QR-Password': 'YOUR_ACCESS_PASSWORD' } 
});
console.log(res.headers['x-content-hmac']);
console.log(res.data);
DELETE 3. Delete
// DELETE: Delete item. Token goes in the 'X-Delete-Token' header.
const res = await axios.delete('https://qr256.webbadge.com/api/v0/items/MAGIC_ID', { 
    headers: { 'X-Delete-Token': 'YOUR_DELETE_TOKEN' } 
});
console.log(res.status); // Returns 204
POST 1. Initialize
// POST: Initialize item. Password goes in the JSON body
payload := []byte(`{
    "content": "Hello, World. Resolved exactly as intended.",
    "password": "YOUR_ACCESS_PASSWORD",
    "ttlHours": 1,
    "viewLimit": 5
}`)

req, _ := http.NewRequest("POST", "https://qr256.webbadge.com/api/v0/items", bytes.NewBuffer(payload))
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
GET 2. Resolve
// GET: Resolve item. Password goes in the 'X-QR-Password' header.
req, _ := http.NewRequest("GET", "https://qr256.webbadge.com/api/v0/items/MAGIC_ID", nil)
req.Header.Set("X-QR-Password", "YOUR_ACCESS_PASSWORD")

resp, _ := http.DefaultClient.Do(req)

contentHmac := resp.Header.Get("X-Content-Hmac")
DELETE 3. Delete
// DELETE: Delete item. Token goes in the 'X-Delete-Token' header.
req, _ := http.NewRequest("DELETE", "https://qr256.webbadge.com/api/v0/items/MAGIC_ID", nil)
req.Header.Set("X-Delete-Token", "YOUR_DELETE_TOKEN")

resp, _ := http.DefaultClient.Do(req)
// resp.StatusCode will be 204
POST 1. Initialize
// POST: Initialize item. Password goes in the JSON body.
String json = """
    { 
      "content": "Hello, World. Resolved exactly as intended.",
      "password": "YOUR_ACCESS_PASSWORD",
      "ttlHours": 1,
      "viewLimit": 5 
    }""";

var request = HttpRequest.newBuilder()
    .uri(URI.create("https://qr256.webbadge.com/api/v0/items"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(json))
    .build();

var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
GET 2. Resolve
// GET: Resolve item. Password goes in the 'X-QR-Password' header.
var request = HttpRequest.newBuilder()
    .uri(URI.create("https://qr256.webbadge.com/api/v0/items/MAGIC_ID"))
    .header("X-QR-Password", "YOUR_ACCESS_PASSWORD")
    .GET()
    .build();

var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());

String contentHmac = response.headers().firstValue("X-Content-Hmac").orElse("");
System.out.println("Content HMAC: " + contentHmac);
DELETE 3. Delete
// DELETE: Delete item. Token goes in the 'X-Delete-Token' header.
var request = HttpRequest.newBuilder()
    .uri(URI.create("https://qr256.webbadge.com/api/v0/items/MAGIC_ID"))
    .header("X-Delete-Token", "YOUR_DELETE_TOKEN")
    .DELETE()
    .build();

var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
// response.statusCode() will be 204
POST 1. Initialize
// POST: Initialize item. Password goes in the JSON body.
const res = await fetch("https://qr256.webbadge.com/api/v0/items", {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ 
        content: "Hello, World. Resolved exactly as intended.", 
        password: "YOUR_ACCESS_PASSWORD", 
        ttlHours: 1, 
        viewLimit: 5 
    })
});
const data = await res.json();
GET 2. Resolve
// GET: Resolve item. Password goes in the 'X-QR-Password' header.
const res = await fetch("https://qr256.webbadge.com/api/v0/items/MAGIC_ID", {
    method: 'GET',
    headers: { 'X-QR-Password': 'YOUR_ACCESS_PASSWORD' }
});

const contentHmac = res.headers.get("X-Content-Hmac");
console.log("Content HMAC:", contentHmac);

const item = await res.json();
DELETE 3. Delete
// DELETE: Delete item. Token goes in the 'X-Delete-Token' header.
const res = await fetch("https://qr256.webbadge.com/api/v0/items/MAGIC_ID", { 
    method: 'DELETE', 
    headers: { 'X-Delete-Token': 'YOUR_DELETE_TOKEN' } 
});
// res.status will be 204
POST Response — Create Item
HTTP/1.1 201 Created
Content-Type: application/json
X-Content-Hmac: 600fc1462a1...

{
  "magic":"57hbdjxysah...",
  "publicUrl":"https://qr256.webbadge.com/57hbdjxysah...",
  "createdUtc":"2026-03-...Z",
  "expiresUtc":"2026-03-...Z",
  "viewCount":0,
  "viewLimit":5,
  "passwordProtected":true,
  "deleteToken":"yTyHxf1g6t4...",
  "content":null,
  "contentHmac":"600fc1462a1..."
}
Important Notes:
  • content is not returned on creation to prevent accidental disclosure or premature view consumption.
  • contentHmac represents the Integrity Receipt for the created payload.
  • deleteToken is returned once at creation time. Store it securely if you need to delete the item before it expires.
  • publicUrl is the resolver URL intended for QR encoding or distribution.
GET Response — Resolve Item (Consumes a View)
HTTP/1.1 200 OK
Content-Type: application/json
X-Content-Hmac: 600fc1462a1...

{
  "magic":"57hbdjxysah...",
  "publicUrl":"https://qr256.webbadge.com/57hbdjxysah...",
  "createdUtc":"2026-03-...Z",
  "expiresUtc":"2026-03-...Z",
  "viewCount":1,
  "viewLimit":5,
  "passwordProtected":true,
  "deleteToken":null,
  "content":"Hello, World. Resolved exactly as intended.",
  "contentHmac":"600fc1462a1..."
}
Important Notes:
  • A successful GET counts as a view and increments viewCount.
  • deleteToken is intentionally omitted from resolve responses.
  • X-Content-Hmac and contentHmac allow verification that the resolved content matches what was originally created.
  • If lifecycle constraints are exceeded (expired or view-limited), resolution fails deterministically.
DELETE Response — Delete Item
HTTP/1.1 204 No Content

(Empty Response Body)
Success (204 No Content): The item has been deleted and is no longer resolvable.
Important Notes:
  • DELETE requires a valid X-Delete-Token header.
  • Deletion is explicit and immediate.
  • Subsequent resolve attempts will return 404 Not Found.

M2M Best Practices

QR256 is designed for deterministic, machine safe resolution in automated and machine to machine (M2M) workflows. The following practices help ensure correct, predictable behavior when integrating QR256 into automation systems.

Immutability

Once a QR256 Item is created via the API, its content is immutable for the lifetime of the Item. Clients should treat Items as write once, read many artifacts:

  • resolve the content, or
  • explicitly delete the item

Items must never be treated as mutable resources. Do not assume in-place updates, partial overwrites, or stateful modification. This invariant prevents silent drift and ensures consistent behavior across repeated resolutions.

Atomic Retrieval

QR256 resolution responses include Cache-Control: no-store headers. Clients and intermediaries must not cache resolution responses or infer availability from prior requests. Each successful resolve represents a discrete, consumptive event and may advance lifecycle state. For automated systems, use explicit error handling rather than cached responses or speculative retries.

Explicit Volatility

QR256 Items are intentionally ephemeral. In v0, all items must define an explicit lifecycle boundary:

  • a required time-to-live (TTL)
  • an optional viewLimit to constrain usage

Once a lifecycle boundary is reached, resolution becomes unavailable in a deterministic and observable way. Future versions may support view limit only items, but will continue to require at least one explicit lifecycle constraint.

Architecture Hardening

QR256 is a resolver centric system designed to support reliable handoffs between humans, machines, and automated workflows. QR codes act strictly as lightweight pointers, while correctness, lifecycle enforcement, and verification occur at resolution time.

  • Resolver-First Pointer Model: QR codes function as resolvers, not containers. Payload size is decoupled from QR density, preserving scan reliability in real world conditions.
  • Lifecycle Enforcement: Expiration and usage limits are enforced at resolution time. Once a lifecycle boundary is reached, resolution fails deterministically and without ambiguity.
  • Enforced Immutability: Item content cannot be altered after creation for the lifetime of the item. This invariant prevents state drift and ensures consistent outcomes across repeated machine resolutions.
  • Integrity Verification Support: Optional Integrity Receipts allow independent verification that resolved content matches what was originally created.
  • Transport & Storage Protection: QR256 uses standard cryptographic protections to safeguard payloads while stored and in transit. Transport is enforced over TLS (HTTPS), and payloads are protected at rest using 256 bit cryptographic primitives. These mechanisms support—but do not define—the system’s trust model.
  • Machine & AI-Ready Resolution: The architecture supports deterministic resolution in automated workflows, including provisioning, device handoff, and optical machine to machine interactions.
Legal & Compliance

WebBadge is an independent technology startup based in Carlsbad, California. QR256 is a WebBadge-engineered system.

Trademark Notice: "QR Code" is a registered trademark of DENSO WAVE INCORPORATED. QR256 uses the QR Code standard as defined by ISO/IEC.

© 2026 WebBadge — Built in Carlsbad. Committed to a safer and more authentic web.