# meshcheck > A deterministic validation API for 3D assets (GLB/glTF 2.0). POST a model, get back a > machine-readable report card: geometry defects, UV problems, performance-budget violations, and > topology-quality measurements, plus rendered screenshots. Built for agents and pipelines — > structured JSON, stable check IDs, a versioned schema, and this one-fetch orientation. meshcheck is an instrument, not an oracle: measurements first, opinions clearly labeled as such. Same input file + same profile produces a byte-identical report (excluding timestamps/URLs). There is no 0–100 score — reports give per-check verdicts and an overall pass/warn/fail rollup. The report schema is versioned and additive-stable — the current `schema_version` is `1.1`. New checks and fields bump the minor, so pin against the major and treat the `checks` array as open-ended: key off the check IDs you know and ignore the rest. Check families: SPEC (spec conformance), GEO (geometry integrity), XFM (transforms & scale), UV (texture coordinates), MAT (materials & textures), PERF (performance budget), RND (render checks), TOP (topology & surface structure — quad reconstructibility, valence regularity, triangle regularity, hard-edge share; added in schema 1.1, all `info`), and VIS (vision, `/inspect` only, non-deterministic). Base URL: https://api.meshcheck.dev Auth: send `X-Api-Key: mc_live_...` on the authenticated endpoints. The three docs endpoints below are public (no key). Missing key ⇒ 401 MISSING_API_KEY; bad key ⇒ 401 INVALID_API_KEY. ## Endpoints - `POST /v1/validate` — the core product. Input is one of: multipart `file`, JSON `{ "url": "..." }` (server-fetched, 25MB cap, 10s timeout, http(s) only, SSRF-guarded), or JSON `{ "blob_id": "..." }` (for files above the ~4.5MB request-body cap). Options: `profile` (web|mobile|pc|hero), `mode` (full|checks_only), `overrides`, `screenshots`, `webhook_url` (async only). ≤ 20MB validates synchronously and returns the report; > 20MB returns a 202 job envelope. - `POST /v1/uploads` — begin a presigned upload for large files. Returns `{ blob_id, upload_url }`; PUT the bytes to `upload_url`, then validate by `blob_id`. - `GET /v1/jobs/{id}` — poll an async job. A done job embeds the full report verbatim. - `GET /v1/reports/{id}` — re-fetch any report within its 30-day retention. - `GET /v1/account` — the key's plan, credit balance, and usage this period. - `GET /v1/schema/{name}.json` — the published JSON Schemas (report, check_result). Public. - `GET /v1/openapi.json` — the full OpenAPI 3.1 description. Public. - `GET /llms.txt` — this document. Public. Errors are structured: `{ "error": { "code": ..., "message": ..., "detail": ... } }`. Codes: MISSING_API_KEY, INVALID_API_KEY, INSUFFICIENT_CREDITS, RATE_LIMITED, BAD_REQUEST, FILE_TOO_LARGE, FETCH_FAILED, UNSUPPORTED_FORMAT, MALFORMED_GLTF, BUNDLE_INCOMPLETE, NOT_FOUND, JOB_NOT_FOUND, REPORT_EXPIRED, RENDER_FAILED, INSPECT_UNAVAILABLE, INTERNAL. ## Credit costs | Action | Credits | |---|---| | validate (checks_only) | 1 | | validate (full, with screenshots) | 2 | | render (up to 6 stills) | 2 | | render (turntable) | 4 | | inspect | 8 | | report re-fetch, account, schemas | 0 | Insufficient balance ⇒ 402 INSUFFICIENT_CREDITS (balance + needed in `detail`). Rate limits are per plan (token bucket per key) plus global IP limits on unauthenticated routes; 429 with `Retry-After`. ## Retention & privacy (product commitments) - Uploaded model bytes: deleted immediately after processing completes (success or failure). Never written to logs or backups. - Reports (JSON): 30 days, then hard-deleted. - Screenshots: stored 30 days, served only via signed URLs bound to report expiry. ## Links - OpenAPI: https://api.meshcheck.dev/v1/openapi.json - Report schema: https://api.meshcheck.dev/v1/schema/report.json - CheckResult schema: https://api.meshcheck.dev/v1/schema/check_result.json