Sunrise2D

API reference

Everything the dashboard does, you can do over HTTP. Base URL https://id.sunrise2d.com.

Authentication

Send your API key as a bearer token. Find it under Settings.

curl https://id.sunrise2d.com/api/products \
  -H "Authorization: Bearer YOUR_API_KEY"

API access is included on the Operations plan. The audit and QR endpoints are public and need no key.

Readiness audit

POST /api/audit

Score a catalog. Public, rate limited to 10 requests per hour per IP.

curl -X POST https://id.sunrise2d.com/api/audit \
  -H "Content-Type: application/json" \
  -d '{
    "email": "you@yourbrand.com",
    "company": "Your Brand Co.",
    "csv": "gtin,name,url\n036000291452,Hot Sauce,\n"
  }'

Returns a readiness score (0–100), a letter grade, a summary, a prioritised checklist, and per-row findings. Header row must include a gtin or upc column; name and url are optional.

GET /api/audit/{id}

Retrieve a stored report. Shareable — no key required.

QR codes

GET /api/qr/{gtin}.svg

Packaging-ready SVG with physical dimensions in millimetres and a 4-module quiet zone.

ParameterDefaultNotes
module0.5Module size in mm. Minimum 0.396 for retail POS.
eccML, M, Q, H. M is the packaging default — higher inflates the symbol.
lotAI (10) batch/lot
serialAI (21) serial number
cpvAI (22) consumer product variant
curl "https://id.sunrise2d.com/api/qr/036000291452.svg?module=0.5&lot=LOT2027A" -o code.svg

GET /api/qr/{gtin}.json

Same symbol plus print metadata and conformance warnings — symbol width, module count, quiet zone, and whether the size is below the retail POS minimum.

Products and resolver routes

PUT /api/products/{gtin}

Create or update a product and its resolver destinations.

curl -X PUT https://id.sunrise2d.com/api/products/036000291452 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Hot Sauce 12oz",
    "attributes": { "17": "270630" },
    "links": [
      { "linkType": "gs1:pip", "href": "https://yourbrand.com/hot-sauce", "default": true }
    ],
    "approved": true
  }'

approved must be true for links to go live. Without it the change is staged, not published. This is deliberate: these routes back codes that may already be printed on packaging.

GET /api/products

Full export of every product and route on your account, as JSON. This is the anti-lock-in guarantee — one call, no ticket, no waiting.

Webhooks

Register an endpoint and we POST signed JSON when things happen.

EventFires when
audit.completedA readiness audit finishes
product.publishedA resolver route goes live
destination.downA destination fails checks 3× in 24h
destination.recoveredIt starts responding again
conformance.regressionA previously conformant code stops validating

Verifying signatures

Each request carries X-Sunrise2D-Timestamp and X-Sunrise2D-Signature. The signature is HMAC-SHA256 over {timestamp}.{raw body}, hex encoded, prefixed v1=.

import crypto from "node:crypto";

function verify(rawBody, headers, secret) {
  const ts  = headers["x-sunrise2d-timestamp"];
  const sig = headers["x-sunrise2d-signature"].replace(/^v1=/, "");
  // Reject anything older than 5 minutes to prevent replay.
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const expected = crypto.createHmac("sha256", secret)
    .update(`${ts}.${rawBody}`).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
}

Retries use exponential backoff over roughly three days: 1 minute, 5 minutes, 25 minutes, 2 hours, 10 hours, 2 days. Return any 2xx to acknowledge. Delivery is at-least-once, so make your handler idempotent using the event id.

Resolver

The resolver itself is public and standards-based — it is what point-of-sale systems and phones hit.

RequestReturns
/01/{gtin14}307 to the default destination
/01/{gtin14}?linkType=gs1:pip307 to that specific link type
/01/{gtin14}?linkType=allFull linkset as JSON
Accept: application/linkset+jsonSame linkset, content-negotiated
/01/{gtin14}/10/{lot}Lot-specific route — used for recalls
/.well-known/gs1resolverResolver self-description

Errors and limits

CodeMeaning
400Invalid input — the body explains which GTIN or AI value failed and why
401Missing or invalid API key
402Plan GTIN limit reached
413Catalog too large for the free audit
429Rate limited — see X-RateLimit-Reset

Validation errors are specific by design. A bad check digit tells you the digit we expected, not just "invalid".