Basic SDK Usage
A complete guide to the MediaViz API — from creating your account to viewing AI-powered photo curation results.
Initialize SDK Client
The MediaViz API uses OAuth2. You need a client ID issued by MediaViz — ask us if you don't have one.
First-party clients (your own backend) also get a client secret, and the SDK authenticates as itself with the client-credentials grant. Third-party clients get a client ID only and authenticate each user with PKCE.
React Native and Expo: never ship a client secret. Anything EXPO_PUBLIC_ is readable in the bundle, so a mobile app is always third-party — the SDK uses PKCE.
Both host URLs are required: MEDIAVIZ_BASE_URL for the API, MEDIAVIZ_PHOTO_UPLOAD_URL for photo uploads, which run on a separate host.
Create an Environment File
# .env
# Both hosts are required — photo uploads run on a separate host.
MEDIAVIZ_BASE_URL=https://api.mediaviz.ai
MEDIAVIZ_PHOTO_UPLOAD_URL=https://upload.mediaviz.ai
MEDIAVIZ_CLIENT_ID=YOUR_CLIENT_ID
# First-party clients only — include this line only if MediaViz issued
# you a client secret. Third-party clients omit it and use PKCE.
MEDIAVIZ_CLIENT_SECRET=YOUR_CLIENT_SECRET
# .env
# Both hosts are required — photo uploads run on a separate host.
MEDIAVIZ_BASE_URL=https://api.mediaviz.ai
MEDIAVIZ_PHOTO_UPLOAD_URL=https://upload.mediaviz.ai
MEDIAVIZ_CLIENT_ID=YOUR_CLIENT_ID
# First-party clients only — include this line only if MediaViz issued
# you a client secret. Third-party clients omit it and use PKCE.
MEDIAVIZ_CLIENT_SECRET=YOUR_CLIENT_SECRET
# .env
# Both hosts are required — photo uploads run on a separate host.
MEDIAVIZ_BASE_URL=https://api.mediaviz.ai
MEDIAVIZ_PHOTO_UPLOAD_URL=https://upload.mediaviz.ai
MEDIAVIZ_CLIENT_ID=YOUR_CLIENT_ID
# First-party clients only — include this line only if MediaViz issued
# you a client secret. Third-party clients omit it and use PKCE.
MEDIAVIZ_CLIENT_SECRET=YOUR_CLIENT_SECRET
# .env — Expo reads EXPO_PUBLIC_* into the app bundle
EXPO_PUBLIC_MEDIAVIZ_BASE_URL=https://api.mediaviz.ai
EXPO_PUBLIC_MEDIAVIZ_PHOTO_UPLOAD_URL=https://upload.mediaviz.ai
EXPO_PUBLIC_MEDIAVIZ_CLIENT_ID=YOUR_CLIENT_ID
EXPO_PUBLIC_MEDIAVIZ_REDIRECT_URI=yourapp://callback
# No client secret here — a mobile app is always a third-party client.
# Anything EXPO_PUBLIC_ is readable in the shipped app, so a mobile
# client authenticates with PKCE instead.
# .env
# Both hosts are required — photo uploads run on a separate host.
MEDIAVIZ_BASE_URL=https://api.mediaviz.ai
MEDIAVIZ_PHOTO_UPLOAD_URL=https://upload.mediaviz.ai
MEDIAVIZ_CLIENT_ID=YOUR_CLIENT_ID
# First-party clients only — include this line only if MediaViz issued
# you a client secret. Third-party clients omit it and use PKCE.
MEDIAVIZ_CLIENT_SECRET=YOUR_CLIENT_SECRET
# .env
# Both hosts are required — photo uploads run on a separate host.
MEDIAVIZ_BASE_URL=https://api.mediaviz.ai
MEDIAVIZ_PHOTO_UPLOAD_URL=https://upload.mediaviz.ai
MEDIAVIZ_CLIENT_ID=YOUR_CLIENT_ID
# First-party clients only — include this line only if MediaViz issued
# you a client secret. Third-party clients omit it and use PKCE.
MEDIAVIZ_CLIENT_SECRET=YOUR_CLIENT_SECRET
Now that your OAuth client is configured, you can initialize the SDK.
Initialize the SDK Client
import { MediaViz } from '@mediaviz/sdk';
const mediaviz = new MediaViz({
baseUrl: 'https://api.mediaviz.ai',
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET',
redirectUri: 'http://localhost:3000/callback',
});
import { MediaViz, MediaVizConfig } from '@mediaviz/sdk';
const config: MediaVizConfig = {
baseUrl: 'https://api.mediaviz.ai',
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET',
redirectUri: 'http://localhost:3000/callback',
};
const mediaviz = new MediaViz(config);
const { MediaViz } = require('@mediaviz/sdk');
const mediaviz = new MediaViz({
baseUrl: 'https://api.mediaviz.ai',
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET',
redirectUri: 'http://localhost:3000/callback',
});
import {
MediaViz, configureCrypto, createCryptoProvider, createSecureTokenStore,
} from '@mediaviz/react-native-sdk';
import { MediaVizProvider } from '@mediaviz/react-native-sdk/react';
import * as Crypto from 'expo-crypto';
import * as SecureStore from 'expo-secure-store';
import { openAuthSessionAsync } from 'expo-web-browser';
// Hermes ships no SubtleCrypto, so PKCE needs a native provider.
configureCrypto(createCryptoProvider(Crypto));
export function App() {
return (
<MediaVizProvider
MediaViz={MediaViz}
config={{
baseUrl: 'https://api.mediaviz.ai',
clientId: 'YOUR_CLIENT_ID',
redirectUri: 'yourapp://callback',
}}
store={createSecureTokenStore(SecureStore)}
openAuthSession={openAuthSessionAsync}
>
<RootNavigator />
</MediaVizProvider>
);
}
from mediaviz_sdk import MediaVizClient
mediaviz = MediaVizClient(
base_url='https://api.mediaviz.ai',
client_id='YOUR_CLIENT_ID',
client_secret='YOUR_CLIENT_SECRET',
redirect_uri='http://localhost:3000/callback',
)
require_once __DIR__ . '/vendor/autoload.php';
use MediaVizSdk\MediaVizClient;
$mediaviz = new MediaVizClient([
'baseUrl' => 'https://api.mediaviz.ai',
'clientId' => 'YOUR_CLIENT_ID',
'clientSecret' => 'YOUR_CLIENT_SECRET',
'redirectUri' => 'http://localhost:3000/callback',
]);
After initializing, get your first access token: first-party clients call authenticate(), and third-party clients call getAuthorizationUrl() and then handleCallback() after the user signs in. From then on, the SDK attaches the token to every request and refreshes it automatically. If you instead plan to use raw HTTP requests rather than the SDK, refer to the Direct HTTP authentication walkthrough in Full Overview for the full token flow.
Creating Your Account
Create the First Company User
To register a new company and its owner, call users.createUserAndCompany. This creates both the user and the associated company in a single call.
Required fields:
- Name — the user's full name
- Email — a valid email address (used for verification)
- Password — account password
- Company name — the name of your organization
- Company creation token — issued by MediaViz for this email address. Contact us to request one; see User & Company Management for details.
Accounts created this way are automatically assigned the Company Owner role (account_type 3) — there is no account-type parameter to set.
A successful response triggers an email verification message to the provided address and returns the new user's id and company_id (both integers). Record both — you will need them for subsequent requests.
Request Sample
const { id, company_id } = await mediaviz.users.createUserAndCompany(
'Jane Smith',
'jane@example.com',
's3cur3P@ss',
null, // companyId — omit to create a new company
null, // profilePicture — optional avatar URL
null, // paymentPlanType — optional billing plan
'Acme Photography',
null, // credits — optional
{
inviteToken: 'YOUR_COMPANY_CREATION_TOKEN'
}
);
import type { UserDisplay } from '@mediaviz/sdk';
const { id, company_id }: UserDisplay = await mediaviz.users.createUserAndCompany(
'Jane Smith',
'jane@example.com',
's3cur3P@ss',
null, // companyId — omit to create a new company
null, // profilePicture — optional avatar URL
null, // paymentPlanType — optional billing plan
'Acme Photography',
null, // credits — optional
{
inviteToken: 'YOUR_COMPANY_CREATION_TOKEN'
}
);
const { id, company_id } = await mediaviz.users.createUserAndCompany(
'Jane Smith',
'jane@example.com',
's3cur3P@ss',
null, // companyId — omit to create a new company
null, // profilePicture — optional avatar URL
null, // paymentPlanType — optional billing plan
'Acme Photography',
null, // credits — optional
{
inviteToken: 'YOUR_COMPANY_CREATION_TOKEN'
}
);
const { client } = useMediaViz();
const { id, company_id } = await client.users.createUserAndCompany(
'Jane Smith',
'jane@example.com',
's3cur3P@ss',
null, // companyId — omit to create a new company
null, // profilePicture — optional avatar URL
null, // paymentPlanType — optional billing plan
'Acme Photography',
null, // credits — optional
{
inviteToken: 'YOUR_COMPANY_CREATION_TOKEN'
}
);
result = mediaviz.users.create_user_and_company(
'Jane Smith',
'jane@example.com',
's3cur3P@ss',
None, # companyId — omit to create a new company
None, # profilePicture — optional avatar URL
None, # paymentPlanType — optional billing plan
'Acme Photography',
None, # credits — optional
invite_token='YOUR_COMPANY_CREATION_TOKEN'
)
# result['id'], result['company_id']
$result = $mediaviz->users->createUserAndCompany(
'Jane Smith',
'jane@example.com',
's3cur3P@ss',
null, // companyId — omit to create a new company
null, // profilePicture — optional avatar URL
null, // paymentPlanType — optional billing plan
'Acme Photography',
null, // credits — optional
[
'inviteToken' => 'YOUR_COMPANY_CREATION_TOKEN'
]
);
// $result['id'], $result['company_id']
curl -X POST 'https://api.mediaviz.ai/api/v1/users/new_company/?invite_token=YOUR_COMPANY_CREATION_TOKEN' \
-H 'Content-Type: application/json' \
--data @- <<'JSON'
{
"name": "Jane Smith",
"email": "jane@example.com",
"company_id": null,
"profile_picture": null,
"payment_plan_type": null,
"password": "s3cur3P@ss",
"company_name": "Acme Photography",
"credits": null
}
JSON
Response Sample
{
"id": 8507,
"company_id": 1024,
"name": "Jane Smith",
"email": "jane@example.com",
"account_type": 3
}
To add additional users to an existing company, call POST /api/v1/users/ with a name, email, account_type (1 = standard user, 2 = company admin), and the existing company_id.
Create Collection
A collection is a container for a set of photos that will be processed together by MediaViz AI models. Each collection is identified by a unique project_table_name in the format z-photos-{company_id}-{uuid}.
Collections are scoped to an outcome — the type of analysis you want performed. To create a collection, call projects.createProjectAndRun specifying the outcomes (e.g., curation) and the models to run. The response returns the project_table_name you will use for all subsequent operations on this collection.
Request Sample
const { project_table_name } = await mediaviz.projects.createProjectAndRun(
'My Wedding Collection',
1, // type — 1 = standard collection only
null, // private — optional; defaults to false
'Wedding photos 2026',
null, // directory — optional folder path
1, // photoUploadVector — should match type
null, // thumbnail — optional cover image URL
null, // runName — optional label for this run
{
outcomes: 'curation'
}
);
import type { ProjectRunDisplay } from '@mediaviz/sdk';
const { project_table_name }: ProjectRunDisplay = await mediaviz.projects.createProjectAndRun(
'My Wedding Collection',
1, // type — 1 = standard collection only
null, // private — optional; defaults to false
'Wedding photos 2026',
null, // directory — optional folder path
1, // photoUploadVector — should match type
null, // thumbnail — optional cover image URL
null, // runName — optional label for this run
{
outcomes: 'curation'
}
);
const { project_table_name } = await mediaviz.projects.createProjectAndRun(
'My Wedding Collection',
1, // type — 1 = standard collection only
null, // private — optional; defaults to false
'Wedding photos 2026',
null, // directory — optional folder path
1, // photoUploadVector — should match type
null, // thumbnail — optional cover image URL
null, // runName — optional label for this run
{
outcomes: 'curation'
}
);
const { client } = useMediaViz();
const { project_table_name } = await client.projects.createProjectAndRun(
'My Wedding Collection',
1, // type — 1 = standard collection only
null, // private — optional; defaults to false
'Wedding photos 2026',
null, // directory — optional folder path
1, // photoUploadVector — should match type
null, // thumbnail — optional cover image URL
null, // runName — optional label for this run
{
outcomes: 'curation'
}
);
result = mediaviz.projects.create_project_and_run(
'My Wedding Collection',
1, # type — 1 = standard collection only
None, # private — optional; defaults to false
'Wedding photos 2026',
None, # directory — optional folder path
1, # photoUploadVector — should match type
None, # thumbnail — optional cover image URL
None, # runName — optional label for this run
outcomes='curation'
)
# result['project_table_name']
$result = $mediaviz->projects->createProjectAndRun(
'My Wedding Collection',
1, // type — 1 = standard collection only
null, // private — optional; defaults to false
'Wedding photos 2026',
null, // directory — optional folder path
1, // photoUploadVector — should match type
null, // thumbnail — optional cover image URL
null, // runName — optional label for this run
'curation'
);
// $result['project_table_name']
curl -X POST 'https://api.mediaviz.ai/api/v1/project_outcome/?outcomes=curation' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidXNyXzAxYWJjMTIzIiwiZXhwIjoxNzQzNjMwMzI5fQ.RwJF-KLLr8K5JgEtIeFiKWELcv-FDLNzMPHJ2St_wAo' \
-H 'Content-Type: application/json' \
--data @- <<'JSON'
{
"name": "My Wedding Collection",
"private": null,
"type": 1,
"description": "Wedding photos 2026",
"directory": null,
"photo_upload_vector": 1,
"thumbnail": null,
"run_name": null
}
JSON
Response Sample
{
"id": "a1b2c3d4-0000-0000-0000-000000000000",
"name": "My Wedding Collection",
"project_table_name": "z-photos-1024-a1b2c3d4-0000-0000-0000-000000000000",
"run_name": "My Wedding Collection_run_1",
"similarity_level": "medium",
"blur_model": true,
"colors_model": true,
"face_recognition_model": true,
"image_classification_model": true,
"image_comparison_model": true,
"image_describe_model": false,
"ocr_model": false,
"similarity_model": true,
"evidence_model": true,
"personhood_model": false,
...
}
This sample creates a standard collection (type 1). For continuous upload collections (type 2) and the models they support, see Collection Creation & Model Selection.
Uploading Photos
Send each photo to the upload endpoint. You must resize each photo and Base64-encode it before calling the SDK — the SDK does not resize for you. We recommend resizing photos to fit within 512×512 px. Before uploading:
- Preserve the aspect ratio. Don't crop or stretch photos to make them square. The Resize and Encode a Photo sample below handles this for you.
- Send only the Base64 data. Don't include a
data:image/jpeg;base64,prefix infileContentof the Request Sample below.
The SDK fetches the collection's upload template automatically and caches it across calls.
Resize and Encode a Photo Sample
// Browser: resize a File or Blob with a canvas
const bitmap = await createImageBitmap(file, { imageOrientation: 'from-image' });
const scale = Math.min(1, 512 / Math.max(bitmap.width, bitmap.height));
const canvas = document.createElement('canvas');
canvas.width = Math.round(bitmap.width * scale);
canvas.height = Math.round(bitmap.height * scale);
canvas.getContext('2d').drawImage(bitmap, 0, 0, canvas.width, canvas.height);
const fileContent = canvas.toDataURL('image/jpeg', 0.85).split(',')[1];
// Browser: resize a File or Blob with a canvas
const bitmap = await createImageBitmap(file, { imageOrientation: 'from-image' });
const scale = Math.min(1, 512 / Math.max(bitmap.width, bitmap.height));
const canvas = document.createElement('canvas');
canvas.width = Math.round(bitmap.width * scale);
canvas.height = Math.round(bitmap.height * scale);
canvas.getContext('2d').drawImage(bitmap, 0, 0, canvas.width, canvas.height);
const fileContent = canvas.toDataURL('image/jpeg', 0.85).split(',')[1];
// Node.js: resize with sharp
const sharp = require('sharp');
const buffer = await sharp(inputPath)
.rotate()
.resize({ width: 512, height: 512, fit: 'inside', withoutEnlargement: true })
.jpeg({ quality: 85 })
.toBuffer();
const fileContent = buffer.toString('base64');
// React Native (Expo): resize with expo-image-manipulator
import * as ImageManipulator from 'expo-image-manipulator';
// uri, width, height come from the expo-image-picker asset
const resize = width >= height
? { width: Math.min(width, 512) }
: { height: Math.min(height, 512) };
const result = await ImageManipulator.manipulateAsync(uri, [{ resize }], {
compress: 0.85,
format: ImageManipulator.SaveFormat.JPEG,
base64: true,
});
const fileContent = result.base64;
# Python: resize with Pillow
from PIL import Image, ImageOps
import base64, io
img = ImageOps.exif_transpose(Image.open(input_path)).convert("RGB")
img.thumbnail((512, 512)) # preserves aspect ratio; never upscales
buf = io.BytesIO()
img.save(buf, format="JPEG", quality=85)
file_content = base64.b64encode(buf.getvalue()).decode()
// PHP: resize with GD
$img = imagecreatefromstring(file_get_contents($inputPath));
$exif = @exif_read_data($inputPath);
switch ($exif['Orientation'] ?? 1) {
case 3: $img = imagerotate($img, 180, 0); break;
case 6: $img = imagerotate($img, -90, 0); break;
case 8: $img = imagerotate($img, 90, 0); break;
}
$w = imagesx($img);
$h = imagesy($img);
$scale = min(1, 512 / max($w, $h));
$resized = imagescale($img, (int) round($w * $scale), (int) round($h * $scale));
ob_start();
imagejpeg($resized, null, 85);
$fileContent = base64_encode(ob_get_clean());
# Shell: resize with ImageMagick, then Base64-encode for the request body
magick input.jpg -auto-orient -resize '512x512>' -quality 85 resized.jpg
base64 -i resized.jpg > resized.b64
Request Sample
const result = await mediaviz.photoUpload.uploadPhoto(
1024,
8507,
'z-photos-1024-a1b2c3d4',
{
fileContent: '/9j/4AAQSkZJRgABAQAAAQABAAD...',
mimetype: 'image/jpeg',
filePath: '/photos/IMG_0001.jpg'
}
);
const result = await mediaviz.photoUpload.uploadPhoto(
1024,
8507,
'z-photos-1024-a1b2c3d4',
{
fileContent: '/9j/4AAQSkZJRgABAQAAAQABAAD...',
mimetype: 'image/jpeg',
filePath: '/photos/IMG_0001.jpg'
}
);
const result = await mediaviz.photoUpload.uploadPhoto(
1024,
8507,
'z-photos-1024-a1b2c3d4',
{
fileContent: '/9j/4AAQSkZJRgABAQAAAQABAAD...',
mimetype: 'image/jpeg',
filePath: '/photos/IMG_0001.jpg'
}
);
const { client } = useMediaViz();
const result = await client.photoUpload.uploadPhoto(
1024,
8507,
'z-photos-1024-a1b2c3d4',
{
fileContent: '/9j/4AAQSkZJRgABAQAAAQABAAD...',
mimetype: 'image/jpeg',
filePath: '/photos/IMG_0001.jpg'
}
);
result = mediaviz.photo_upload.upload_photo(
1024,
8507,
'z-photos-1024-a1b2c3d4',
file_content='/9j/4AAQSkZJRgABAQAAAQABAAD...',
mimetype='image/jpeg',
file_path='/photos/IMG_0001.jpg'
)
$result = $mediaviz->photoUpload->uploadPhoto(
'1024',
'8507',
'z-photos-1024-a1b2c3d4',
[
'file_content' => '/9j/4AAQSkZJRgABAQAAAQABAAD...',
'mimetype' => 'image/jpeg',
'file_path' => '/photos/IMG_0001.jpg'
]
);
# Step 1: get_project_prelim_model_request_template
curl -X GET 'https://api.mediaviz.ai/api/v1/project_outcome/z-photos-1024-a1b2c3d4' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidXNyXzAxYWJjMTIzIiwiZXhwIjoxNzQzNjMwMzI5fQ.RwJF-KLLr8K5JgEtIeFiKWELcv-FDLNzMPHJ2St_wAo'
# Step 2: Upload a preprocessed photo with metadata in the JSON body
curl -X POST 'https://upload.mediaviz.ai/photo_upload' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidXNyXzAxYWJjMTIzIiwiZXhwIjoxNzQzNjMwMzI5fQ.RwJF-KLLr8K5JgEtIeFiKWELcv-FDLNzMPHJ2St_wAo' \
-H 'Content-Type: application/json' \
--data @- <<'JSON'
{
"file_content": "/9j/4AAQSkZJRgABAQAAAQABAAD...",
"file_path": "/photos/IMG_0001.jpg",
"mimetype": "image/jpeg",
"company_id": 1024,
"user_id": 8507,
"project_table_name": "z-photos-1024-a1b2c3d4",
"blur": "<BLUR>",
"colors": "<COLORS>",
"face_recognition": "<FACE_RECOGNITION>",
"image_classification": "<IMAGE_CLASSIFICATION>",
"image_comparison": "<IMAGE_COMPARISON>",
"image_describe": "<IMAGE_DESCRIBE>",
"ocr": "<OCR>"
}
JSON
Mark Photo Upload Complete
Once all photos have been uploaded, signal to MediaViz that the upload phase is finished. This triggers the AI processing pipeline to begin.
After this call, the collection transitions to a processing state and the models begin running.
Request Sample
const result = await mediaviz.projects.markProjectUploadComplete('z-photos-1024-a1b2c3d4');
const result = await mediaviz.projects.markProjectUploadComplete('z-photos-1024-a1b2c3d4');
const result = await mediaviz.projects.markProjectUploadComplete('z-photos-1024-a1b2c3d4');
const { client } = useMediaViz();
const result = await client.projects.markProjectUploadComplete('z-photos-1024-a1b2c3d4');
result = mediaviz.projects.mark_project_upload_complete('z-photos-1024-a1b2c3d4')
$result = $mediaviz->projects->markProjectUploadComplete('z-photos-1024-a1b2c3d4');
curl -X POST 'https://api.mediaviz.ai/api/v1/project/z-photos-1024-a1b2c3d4/upload_complete/' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidXNyXzAxYWJjMTIzIiwiZXhwIjoxNzQzNjMwMzI5fQ.RwJF-KLLr8K5JgEtIeFiKWELcv-FDLNzMPHJ2St_wAo'
Check Run Status
Poll for processing progress. progress_percentage is a fraction between 0 and 1 — not a 0-100 percent, so 0.72 means 72% done. Each model configured for the collection also has its own <model>_model_complete flag.
Request Sample
const result = await mediaviz.projects.checkProjectStatus('z-photos-1024-a1b2c3d4');
const result = await mediaviz.projects.checkProjectStatus('z-photos-1024-a1b2c3d4');
const result = await mediaviz.projects.checkProjectStatus('z-photos-1024-a1b2c3d4');
const { client } = useMediaViz();
const result = await client.projects.checkProjectStatus('z-photos-1024-a1b2c3d4');
result = mediaviz.projects.check_project_status('z-photos-1024-a1b2c3d4')
$result = $mediaviz->projects->checkProjectStatus('z-photos-1024-a1b2c3d4');
curl -X GET 'https://api.mediaviz.ai/api/v1/project/status/z-photos-1024-a1b2c3d4' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidXNyXzAxYWJjMTIzIiwiZXhwIjoxNzQzNjMwMzI5fQ.RwJF-KLLr8K5JgEtIeFiKWELcv-FDLNzMPHJ2St_wAo'
Response Sample
{
"progress_percentage": 0.72,
"blur_model_complete": true,
"colors_model_complete": true,
"face_recognition_model_complete": false,
"image_classification_model_complete": false,
"similarity_model_complete": false,
"evidence_model_complete": false
}
Keep polling until progress_percentage reaches 1 and every model flag is true, then fetch results.
Individual Photo Results
Retrieve detailed analysis for a single photo using photos.getPhotoFromProject. The response includes the full set of model outputs for that photo, including:
- blur_value — sharpness score
- main_color_palette — dominant colors extracted from the image
- labels_from_classifications_model — image classification tags, always an object keyed by label with a
0-1confidence value ({ "Sky": 0.99, "Beach": 0.95 }), never a plain array; read the keys for a bare tag list.nulluntil image classification has run. - bounding_boxes_from_faces_model — detected face regions
- similar_photo_ids_high / _medium / _low — similar photos grouped by similarity strength
- evidence_score — overall curation score
- face_score — quality score for face content
- content_score — subject matter quality score
- aesthetic_score — compositional and aesthetic quality score
- similarity_set_ranking — rank within its similarity cluster
Request Sample
const result = await mediaviz.photos.getPhotoFromProject('z-photos-1024-a1b2c3d4', 1035601);
import type { PhotoDisplay } from '@mediaviz/sdk';
const result: PhotoDisplay = await mediaviz.photos.getPhotoFromProject('z-photos-1024-a1b2c3d4', 1035601);
const result = await mediaviz.photos.getPhotoFromProject('z-photos-1024-a1b2c3d4', 1035601);
const { client } = useMediaViz();
const result = await client.photos.getPhotoFromProject('z-photos-1024-a1b2c3d4', 1035601);
result = mediaviz.photos.get_photo_from_project('z-photos-1024-a1b2c3d4', 1035601)
$result = $mediaviz->photos->getPhotoFromProject('z-photos-1024-a1b2c3d4', 1035601);
curl -X GET 'https://api.mediaviz.ai/api/v1/photos/z-photos-1024-a1b2c3d4/1035601' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidXNyXzAxYWJjMTIzIiwiZXhwIjoxNzQzNjMwMzI5fQ.RwJF-KLLr8K5JgEtIeFiKWELcv-FDLNzMPHJ2St_wAo'
Response Sample
{
"id": 1035601,
"blur_value": 0.95,
"main_color_palette": ["#3a5a8c", "#f0e6d2", "#2c2c2c"],
"labels_from_classifications_model": {
"outdoor": 0.98,
"portrait": 0.95,
"natural light": 0.89
},
"bounding_boxes_from_faces_model": [
{ "x": 120, "y": 45, "width": 80, "height": 90 }
],
"similar_photo_ids_high": [1035607],
"similar_photo_ids_medium": [1035612, 1035619],
"similar_photo_ids_low": [1035631],
"evidence_score": 0.91,
"face_score": 0.88,
"content_score": 0.84,
"aesthetic_score": 0.79,
"similarity_set_ranking": 1
}