API Reference · v1

Integrate GradeOS in 5 lines.

A single REST endpoint turns a device photo into a signed Device Passport. Drop it into your WMS, returns flow, or POS — same authentication, same response shape, every time.

Quick start

Grade a device in one call. Replace YOUR_API_KEY and the image path:

# cURL
curl -X POST https://api.gradeos.net/v1/grade \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"image_b64": "<base64-encoded image>"}'

Response (1.2s typical):

{
  "device_id": "DEV-4F8B27A1",
  "grade": {
    "letter": "B",
    "label": "Light use",
    "confidence": 0.89
  },
  "detections": [
    { "class": "scratch", "confidence": 0.91,
      "x": 812, "y": 1024,
      "w": 340, "h": 28 }
  ],
  "latency_ms": 1182,
  "passport_url": "https://api.gradeos.net/v1/passport/DEV-4F8B27A1.pdf",
  "audit_hash": "sha256:9f3a...e2c7"
}

Authentication

Every request requires an API key passed in the X-API-Key header. Keys are scoped per workspace — one key per warehouse, dealer, or environment.

X-API-Key: gos_live_4f8b27a1e2c7d3a91b5f...
Get a key: email cesar@electronicswarehouse.solutions and we'll provision a sandbox key (500 free devices) within 24 hours.

Grade a device

POST /v1/grade

Submit a device image. Returns grade, defect list, and a passport URL.

Request body

FieldTypeRequiredDescription
image_b64stringrequiredBase64-encoded image (jpg/png/heic, max 10 MB)
image_urlstringAlternative to image_b64. Public URL to fetch.
device_hintstringKnown model (e.g. iPhone 14 Pro) to bias detection
workspacestringSub-workspace tag for multi-warehouse customers
confidenceintMin detection confidence (0–100), default 30
imeistring15-digit IMEI for cross-reference & passport

Grade letters

LetterLabelTrigger
BNBrand NewNo detections above confidence threshold
ANear-mint≤1 minor scratch, no chips
BLight use2 scratches OR 1 minor chip
CModerate wear3+ scratches OR chip with wear
DHeavy wearChip + 2+ scratches
FCracked / Non-functionalCrack, display defect, or screen damage

Full production grade

POST /v1/grade/full

Production endpoint. Submits up to 6 photos plus an IMEI, runs multi-frame consensus on detections, looks up identity + iCloud + blacklist + warranty via IMEICheck, applies identity gates to the cosmetic grade, returns a complete signed passport.

Request body

FieldTypeRequiredDescription
images_b64string[]required*1–6 base64 images (one per angle)
image_urlsstring[]*or pass URLs we'll fetch instead
imeistring15-digit IMEI. Without it, identity checks are skipped.
device_hintstringKnown model name for the passport
skip_identity_lookupboolCosmetic-only mode (cheaper)

Response shape

{
  "device_id": "DEV-4F8B27A1",
  "grade":           { "letter": "F", "label": "Cracked / Non-functional", "confidence": 0.91 },
  "cosmetic_grade":  { "letter": "B", "label": "Light use", "confidence": 0.81 },
  "grade_adjustments": ["iCloud Activation Lock is enabled"],
  "defects": [
    { "class": "scratch", "confidence": 0.92, "frames_seen": 3, "severity": "low" }
  ],
  "identity": {
    "model_name": "iPhone 14 Pro",
    "storage_gb": 256,
    "color": "Deep Purple",
    "icloud_lock": "LOCKED",
    "blacklist_status": "CLEAN",
    "sim_lock": "UNLOCKED",
    "original_carrier": "Verizon",
    "warranty_status": "EXPIRED"
  },
  "frame_count": 4,
  "inference_ms": 3208,
  "identity_lookup_ms": 1840,
  "passport_url": "/v1/passport/DEV-4F8B27A1.pdf",
  "audit_hash": "sha256:..."
}

Multi-frame consensus

A defect counts toward the final grade only when it appears in ≥2 frames, or in 1 frame at ≥85% confidence. This eliminates false positives from glare, dust, packaging artifacts, and reflections.

Identity gates

Identity signals can lower a cosmetic grade but never raise it:

SignalFloor
IMEI reported lost or stolenX · Do Not Sell
IMEI on GSMA blacklistF
iCloud Activation Lock enabledF
SIM-locked to carrierC
Never activatedB

Device Passport

GET /v1/passport/{device_id}.pdf

Returns a signed PDF passport for a graded device. Contains the grade, defect map, hardware diagnostics, IMEI verification, audit hash, and timestamp.

GET /v1/passport/{device_id}.json

JSON variant — same content, machine-readable for WMS ingestion.

List grades

GET /v1/grades?limit=50&offset=0

Returns the latest grades for your workspace, newest first.

Submit correction

POST /v1/grades/{device_id}/correction

Submit a human correction when your QA team disagrees with the AI grade. These corrections feed the model retraining pipeline scoped to your workspace — your model gets better at your device mix over time.

{
  "correct_letter": "C",
  "reason": "missed_chip_bottom_right",
  "reviewer": "qa-tech-04",
  "notes": "Chip ~3mm at bottom-right corner, not visible in primary frame"
}

Webhooks

Subscribe to events to push grades into your WMS / ERP without polling. Configure endpoints from the dashboard or via the API:

POST /v1/webhooks
{
  "url": "https://your-wms.com/hooks/gradeos",
  "events": ["grade.completed", "passport.signed"],
  "secret": "whsec_..."
}

Verifying signatures

Each delivery includes an X-GradeOS-Signature header — HMAC SHA-256 of the body using your webhook secret.

# Python verification
import hmac, hashlib

def verify(payload, signature, secret):
    mac = hmac.new(secret.encode(), payload, hashlib.sha256)
    return hmac.compare_digest(mac.hexdigest(), signature)

Event types

EventFires when
grade.completedA device finishes grading
grade.failedInference errored (returns error code)
passport.signedPassport PDF generated and hashed
correction.submittedHuman correction logged

Error codes

HTTPCodeMeaning
400bad_requestMalformed body or missing required field
401invalid_api_keyMissing or invalid X-API-Key header
402quota_exceededMonthly device quota reached — upgrade or wait for reset
413image_too_largeImage exceeds 10 MB limit
422image_unreadableCould not decode image; check format and base64 encoding
429rate_limitedToo many requests — see Retry-After header
502model_unavailableInference engine temporarily unreachable
504timeoutInference exceeded 30 s — retry recommended

Rate limits

Rate-limit headers on every response:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1716234000

SDK examples

Python

import base64, requests

with open("device.jpg", "rb") as f:
    img_b64 = base64.b64encode(f.read()).decode()

r = requests.post(
    "https://api.gradeos.net/v1/grade",
    headers={"X-API-Key": "YOUR_KEY"},
    json={"image_b64": img_b64, "imei": "353892101482047"},
    timeout=30,
)
result = r.json()
print(result["grade"]["letter"], result["grade"]["confidence"])

Node.js

const fs = require("fs");
const img = fs.readFileSync("device.jpg").toString("base64");

const res = await fetch("https://api.gradeos.net/v1/grade", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ image_b64: img }),
});
const result = await res.json();
console.log(result.grade.letter);

Go

payload := map[string]string{"image_b64": imgB64}
body, _ := json.Marshal(payload)

req, _ := http.NewRequest("POST", "https://api.gradeos.net/v1/grade", bytes.NewReader(body))
req.Header.Set("X-API-Key", "YOUR_KEY")
req.Header.Set("Content-Type", "application/json")

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

Questions? cesar@electronicswarehouse.solutions · Status: /health