/api/v1/snapreport/analyzeSend auditor evidence (notes, transcripts, audio, images, PDFs) against a standard. SnapReport AI returns a structured list of grading suggestions, one per relevant clause. Stateless — no audit is persisted on our side.
Authentication
Requires snapreport:generate permission. See Authentication.
Request — JSON — text only
curl -X POST https://api.myqateam.com/api/v1/snapreport/analyze \ -H "Authorization: Bearer myqa_..." \ -H "Content-Type: application/json" \ -d '{ "standard_id": "<uuid>", "language": "en", "evidence": [ { "type": "text", "content": "Observed cold-chain logs, no breaches." } ] }'Request — multipart — files
To include audio, images, PDFs, DOCX, or XLSX/XLS, send as multipart/form-data. Scalar fields are plain form fields; processes is a JSON-stringified array; notes is a JSON-stringified array of strings. Any form field whose value is a file is treated as binary evidence — field names don't matter.
curl -X POST https://api.myqateam.com/api/v1/snapreport/analyze \ -H "Authorization: Bearer myqa_..." \ -F 'standard_id=<uuid>' \ -F 'language=en' \ -F 'processes=["<chapter-id>","<chapter-id>"]' \ -F 'notes=["Observed cold-chain logs for Q1."]' \ -F 'file_1=@interview.mp3' \ -F 'file_2=@fridge-temp-log.jpg' \ -F 'file_3=@haccp-plan.pdf'Remote files — Google Cloud Storage
Instead of uploading bytes, point us at a file you already hold in Google Cloud Storage. This is the recommended path for large audio: the recording is read directly from storage and never travels through the API request.
gcs_uri— ags://bucket/objectURI. One-time setup: grant the Storage Object Viewer role on your bucket to the service account we provide, and tell us the bucket name so it can be registered against your API key. Buckets that are not registered are refused.url— a signedhttps://storage.googleapis.com/...URL. No IAM setup and no bucket registration: the signature in the URL is your own authorisation. Make sure it is still valid when you call us; we do not retry expired links.
Field names do not matter. Exactly as with file uploads, any field whose value is a gs:// URI or a Cloud Storage URL is treated as evidence — so file_1=@recording.mp3 and file_1=gs://your-bucket/recording.mp3 both work. Reserved fields (standard_id, language, processes, callback_url, callback_secret, notes, transcript) are never read as evidence.
The file type is detected from the file's actual content, not its extension or the type you declare. Declaring a type that disagrees with the bytes is rejected.
# gs:// reference — recommended for large audiocurl -X POST https://api.myqateam.com/api/v1/snapreport/analyze \ -H "Authorization: Bearer myqa_..." \ -H "Content-Type: application/json" \ -d '{ "standard_id": "<uuid>", "language": "en", "evidence": [ { "type": "audio", "gcs_uri": "gs://your-bucket/interviews/site-visit.mp3" } ] }'
# Signed URL — no IAM setup requiredcurl -X POST https://api.myqateam.com/api/v1/snapreport/analyze \ -H "Authorization: Bearer myqa_..." \ -H "Content-Type: application/json" \ -d '{ "standard_id": "<uuid>", "evidence": [ { "type": "audio", "url": "https://storage.googleapis.com/your-bucket/site-visit.mp3?X-Goog-Signature=..." } ] }'Fields
| Field | Type | Required | Description |
|---|---|---|---|
standard_id | uuid | Yes | Which standard to grade against. List available IDs via GET /api/v1/standards. |
processes | uuid[] | No | Chapter IDs to scope grading to a subset of the standard. Discover IDs via GET /api/v1/standards/:id/clauses (use chapters[].id). Omit to scope to every chapter. |
language | enum | No | en, fr, de. Defaults to en. |
evidence | array | Yes (JSON) | Array of evidence items. Inline: { type, content } with type text, transcript or structured. Remote: { type, gcs_uri } or { type, url }. |
notes | JSON string | No (multipart) | Inline text notes for multipart requests. |
| File fields | File | No (multipart) | Any file field is treated as evidence. Type is inferred from MIME. |
gcs_uri | string | No | Single-file shorthand for a gs://bucket/object reference. The bucket must be registered against your API key. |
url | string | No | Single-file shorthand for a signed Cloud Storage URL. Must be HTTPS, on storage.googleapis.com, and carry an X-Goog-Signature. |
callback_url | string | No | HTTPS webhook. Switches the call to async mode. Must be HTTPS and must not target localhost / private (RFC1918) / link-local IPs, or cloud-metadata services. |
callback_secret | string | No | HMAC-SHA256 secret for webhook signing. |
File size limits
Limits are identical whether a file is uploaded or referenced.
- Images: 20 MB each. JPEG, PNG, WebP, GIF.
- PDFs: 20 MB each.
- DOCX / XLSX / XLS: 20 MB each. Text is extracted server-side (charts and embedded images are dropped) and clipped at ~500K characters. Legacy
.docis not supported — save as.docxfirst. - Audio: 200 MB each. MP3, WAV, AAC, FLAC, WebM, M4A, MP4, OGG. For anything large, prefer
gcs_uri— an upload of this size in a single request is far more likely to fail in transit.
Errors specific to remote files
| Field | Status | Description |
|---|---|---|
FORBIDDEN | 403 | The bucket is not registered against your API key. |
REMOTE_ACCESS_DENIED | 403 | We could not read the object. Check the IAM grant, or whether the signed URL has expired. |
REMOTE_NOT_FOUND | 404 | The object does not exist at that path. |
FILE_TOO_LARGE | 400 | The object exceeds the limit for its type. |
REMOTE_FETCH_FAILED | 502 | Cloud Storage could not be reached or returned an unexpected error. |
Response — synchronous
{ "success": true, "data": { "standard": { "id": "...", "code": "ISO 9001", "name": "ISO 9001:2015" }, "language": "en", "suggestions": [ { "clause_id": "uuid", "clause_code": "4.1", "is_knockout": false, "grade": "A", "comment": "Context analysis is reviewed annually; documented record from 2026-Q1 aligns with the quality policy.", "reasoning": "Note states 'context analysis reviewed annually — no deviations observed'." } ], "validation_status": "pending_validation", "requires_human_validation": true, "notes_processed": 2, "clauses_scanned": 46, "processing_time_ms": 38211, "token_usage": { "input_tokens": 14200, "output_tokens": 3800 } }}Response — async acknowledgement
{ "success": true, "data": { "job_id": "...", "status": "processing", "estimated_duration_sec": 60 }}Webhook payload
When the job completes we send an HTTP POST to your callback_url with Content-Type: application/json. The request body is the JSON object shown below — the same data object you would have received synchronously, wrapped with job_id and success. If callback_secret was supplied, the request carries an X-Webhook-Signature header containing an HMAC-SHA256 hex digest of the raw body. Deliveries are best-effort and not retried — every attempt is recorded with response status, duration, and any error.
We do not authenticate the call to your endpoint with a Bearer token. Either verify the X-Webhook-Signature header using callback_secret, or include a hard-to-guess token in the URL itself (e.g. https://example.com/webhooks/snapreport/<random-token>).
Successful job payload
{ "job_id": "…", "success": true, "data": { "standard": { "id": "…", "code": "ISO 9001", "name": "ISO 9001:2015" }, "language": "en", "suggestions": [ /* same shape as the sync response */ ], "validation_status": "pending_validation", "requires_human_validation": true, "notes_processed": 2, "clauses_scanned": 46, "processing_time_ms": 38211, "token_usage": { "input_tokens": 14200, "output_tokens": 3800 } }}Failed job payload
{ "job_id": "…", "success": false, "error": { "code": "PROCESSING_ERROR", "message": "…" }}Your endpoint should respond with 2xx within ~10 seconds; non-2xx responses are recorded but not retried.
Errors
See the full error code reference on the authentication page.