Getting Started

A complete guide to the MediaViz API — from creating your account to viewing AI-powered photo curation results.

Creating Your Account

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',
});
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',
});
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',
]);

Before making any API calls, you need a user account. MediaViz uses a company-based account model — each account belongs to an organization, and one user must be designated as the company owner.

Create the First Company User

To register a new company and its owner, send a request to POST /api/v1/users/new_company. This endpoint 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
  • Account type — set to 3 for company owner
  • Company name — the name of your organization

A successful response triggers an email verification message to the provided address and returns a user_id and company_id. Record both — you will need them for subsequent requests.

Request Sample

const { user_id, company_id } = await mediaviz.users.createUserAndCompany(
  'Jane Smith',
  '[email protected]',
  3,
  's3cur3P@ss',
  null,
  null,
  null,
  'Acme Photography'
);
const { user_id, company_id } = await mediaviz.users.createUserAndCompany(
  'Jane Smith',
  '[email protected]',
  3,
  's3cur3P@ss',
  null,
  null,
  null,
  'Acme Photography'
);
$result = $mediaviz->users->createUserAndCompany(
  'Jane Smith',
  '[email protected]',
  3,
  's3cur3P@ss',
  null,
  null,
  null,
  'Acme Photography'
);
// $result['user_id'], $result['company_id']
curl -X POST 'https://api.mediaviz.ai/api/v1/users/new_company' \
  -H 'Content-Type: application/json' \
  --data @- <<'JSON'
{
  "name": "Jane Smith",
  "email": "[email protected]",
  "company_id": null,
  "profile_picture": null,
  "payment_plan_type": null,
  "password": "s3cur3P@ss",
  "company_name": "Acme Photography"
}
JSON

Response Sample

{
  "user_id": "usr_01abc123",
  "company_id": "cmp_01xyz456",
  "email": "[email protected]",
  "message": "Verification email sent."
}

To add additional users to an existing company, use the same endpoint with account_type set to 1 (standard user) or 2 (company admin), and include the existing company_id.

Authentication & Access Tokens

The MediaViz API uses OAuth2 JWT tokens for authentication. To obtain tokens, exchange your credentials at POST /api/v1/token/.

Required fields:

  • Email address — the email used during registration
  • Password — your account password

The response includes both an access_token and a refresh_token, each with a 24-hour TTL. Use the refresh token when authenticating API calls — not the access token.

Request Sample

const { access_token, refresh_token } = await mediaviz.oAuthToken.token('[email protected]', 's3cur3P@ss');
const { access_token, refresh_token } = await mediaviz.oAuthToken.token('[email protected]', 's3cur3P@ss');
$result = $mediaviz->oAuthToken->token('[email protected]', 's3cur3P@ss');
// $result['access_token'], $result['refresh_token']
curl -X POST 'https://api.mediaviz.ai/oauth/token' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=<GRANT_TYPE>' \
  --data-urlencode 'code=<CODE>' \
  --data-urlencode 'redirect_uri=<REDIRECT_URI>' \
  --data-urlencode 'client_id=<CLIENT_ID>' \
  --data-urlencode 'code_verifier=<CODE_VERIFIER>' \
  --data-urlencode 'refresh_token=<REFRESH_TOKEN>' \
  --data-urlencode 'client_secret=<CLIENT_SECRET>'

Response Sample

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "user_id": "usr_01abc123"
}

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 POST /api/v1/project_outcome/ with query parameters 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',
  null,
  null,
  'Wedding photos 2026',
  null,
  2,
  null,
  null,
  {
    outcomes: 'curation'
  }
);
const { project_table_name } = await mediaviz.projects.createProjectAndRun(
  'My Wedding Collection',
  null,
  null,
  'Wedding photos 2026',
  null,
  2,
  null,
  null,
  {
    outcomes: 'curation'
  }
);
$result = $mediaviz->projects->createProjectAndRun(
  'My Wedding Collection',
  null,
  null,
  'Wedding photos 2026',
  null,
  2,
  null,
  null,
  'curation'
);
// $result['project_table_name']
curl -X POST 'https://api.mediaviz.ai/api/v1/project_outcome/?outcomes=curation' \
  -H 'Authorization: Bearer mvz_sk_live_7K2wQ9pL3mR8xN4vBjH1cT6yF0dZaEuS' \
  -H 'Content-Type: application/json' \
  --data @- <<'JSON'
{
  "name": "My Wedding Collection",
  "private": null,
  "type": null,
  "description": "Wedding photos 2026",
  "directory": null,
  "photo_upload_vector": 2,
  "thumbnail": null,
  "run_name": null
}
JSON

Response Sample

{
  "project_table_name": "z-photos-cmp_01xyz456-a1b2c3d4",
  "outcomes": ["curation"],
  "models": ["blur", "colors", "face_recognition", "image_classification", "similarity", "evidence"],
  "status": "created"
}

Uploading Photos

Upload each photo in the collection with uploadPhoto. The SDK fetches the collection's upload template on the first call, caches it, and posts the photo to the dedicated upload service.

Photos must be Base64-encoded and resized to 256×256 px before upload. Call uploadPhoto once per photo, passing a zero-based photo_index.

Request Sample

const result = await mediaviz.photoUpload.uploadPhoto(
  'z-photos-cmp_01xyz456-a1b2c3d4',
  'cmp_01xyz456',
  'usr_01abc123',
  0,
  {
    title: 'beach-sunset.jpg',
    fileContent: '<base64-encoded photo>',
    mimetype: 'image/jpeg',
    filePath: 'beach-sunset.jpg'
  }
);
const result = await mediaviz.photoUpload.uploadPhoto(
  'z-photos-cmp_01xyz456-a1b2c3d4',
  'cmp_01xyz456',
  'usr_01abc123',
  0,
  {
    title: 'beach-sunset.jpg',
    fileContent: '<base64-encoded photo>',
    mimetype: 'image/jpeg',
    filePath: 'beach-sunset.jpg'
  }
);
$result = $mediaviz->photoUpload->uploadPhoto(
  'z-photos-cmp_01xyz456-a1b2c3d4',
  'cmp_01xyz456',
  'usr_01abc123',
  0,
  [
    'title' => 'beach-sunset.jpg',
    'file_content' => '<base64-encoded photo>',
    'mimetype' => 'image/jpeg',
    'file_path' => 'beach-sunset.jpg'
  ]
);
curl -X POST 'https://api.mediaviz.ai/photo_upload' \
  -H 'Authorization: Bearer mvz_sk_live_7K2wQ9pL3mR8xN4vBjH1cT6yF0dZaEuS' \
  -H 'x-bucket-name: <BUCKET_NAME>' \
  -H 'x-photo-index: 0' \
  -H 'x-company-id: cmp_01xyz456' \
  -H 'x-user-id: usr_01abc123' \
  -H 'x-project-table-name: z-photos-cmp_01xyz456-a1b2c3d4' \
  -H 'x-title: <TITLE>' \
  -H 'Content-Type: application/json' \
  --data @- <<'JSON'
{
  "file_content": "<FILE_CONTENT>",
  "mimetype": "<MIMETYPE>",
  "file_path": "<FILE_PATH>"
}
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. Call:

POST /v1/project/{project_table_name}/upload_complete/

Include your refresh_token in the Authorization header. 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-cmp_01xyz456-a1b2c3d4');
const result = await mediaviz.projects.markProjectUploadComplete('z-photos-cmp_01xyz456-a1b2c3d4');
$result = $mediaviz->projects->markProjectUploadComplete('z-photos-cmp_01xyz456-a1b2c3d4');
curl -X POST 'https://api.mediaviz.ai/api/v1/project/z-photos-cmp_01xyz456-a1b2c3d4/upload_complete/' \
  -H 'Authorization: Bearer mvz_sk_live_7K2wQ9pL3mR8xN4vBjH1cT6yF0dZaEuS'

Check Run Status

Poll the status endpoint to track processing progress. The response includes an overall progress_percentage as well as individual status fields for each model that was configured for the collection.

GET /v1/project/status/{project_table_name}

Continue polling until progress_percentage reaches 100 and all model statuses indicate completion before fetching results.

Response Sample

{
  "project_table_name": "z-photos-cmp_01xyz456-a1b2c3d4",
  "progress_percentage": 72,
  "models": {
    "blur": "complete",
    "colors": "complete",
    "face_recognition": "processing",
    "image_classification": "processing",
    "similarity": "pending",
    "evidence": "pending"
  }
}

View Analysis Results

Once processing is complete, retrieve results at the collection level or for individual photos.

Get all photos sorted by score — use GET /api/v1/photos/{table_name}/sort/asc to retrieve every photo in the collection. Change the final path segment to desc to reverse the sort order.

Request Sample — All Photos Sorted

const result = await mediaviz.photos.getAllProjectPhotoIds(
  'z-photos-cmp_01xyz456-a1b2c3d4',
  {
    ascOrDesc: 'asc'
  }
);
const result = await mediaviz.photos.getAllProjectPhotoIds(
  'z-photos-cmp_01xyz456-a1b2c3d4',
  {
    ascOrDesc: 'asc'
  }
);
$result = $mediaviz->photos->getAllProjectPhotoIds(
  'z-photos-cmp_01xyz456-a1b2c3d4',
  [
    'ascOrDesc' => 'asc'
  ]
);
curl -X GET 'https://api.mediaviz.ai/api/v1/photos/z-photos-cmp_01xyz456-a1b2c3d4/?asc_or_desc=asc' \
  -H 'Authorization: Bearer mvz_sk_live_7K2wQ9pL3mR8xN4vBjH1cT6yF0dZaEuS'

Response Sample

[
  { "photo_id": "ph_001", "evidence_score": 0.91 },
  { "photo_id": "ph_002", "evidence_score": 0.87 },
  { "photo_id": "ph_003", "evidence_score": 0.54 }
]

Get top photos by tier — use GET /api/v1/photos_top/{table_name} to retrieve photos grouped into three tiers based on their evidence_score: best (top 15%), middle (middle 70%), and worst (bottom 15%).

Request Sample — Photos by Tier

const { best, middle, worst } = await mediaviz.photos.getTopMiddleBottomProjectPhotosByTableNameSortedByDateRankedKeysetPaginated('z-photos-cmp_01xyz456-a1b2c3d4');
const { best, middle, worst } = await mediaviz.photos.getTopMiddleBottomProjectPhotosByTableNameSortedByDateRankedKeysetPaginated('z-photos-cmp_01xyz456-a1b2c3d4');
$result = $mediaviz->photos->getTopMiddleBottomProjectPhotosByTableNameSortedByDateRankedKeysetPaginated('z-photos-cmp_01xyz456-a1b2c3d4');
// $result['best'], $result['middle'], $result['worst']

Response Sample

{
  "best": ["ph_001", "ph_002"],
  "middle": ["ph_003", "ph_004", "ph_005", "ph_006", "ph_007"],
  "worst": ["ph_008", "ph_009"]
}

Individual Photo Results

Retrieve detailed analysis for a single photo using GET /api/v1/photos/{table_name}/{photo_id}. 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
  • 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-cmp_01xyz456-a1b2c3d4', 'ph_001');
const result = await mediaviz.photos.getPhotoFromProject('z-photos-cmp_01xyz456-a1b2c3d4', 'ph_001');
$result = $mediaviz->photos->getPhotoFromProject('z-photos-cmp_01xyz456-a1b2c3d4', 'ph_001');
curl -X GET 'https://api.mediaviz.ai/api/v1/photos/z-photos-cmp_01xyz456-a1b2c3d4/ph_001' \
  -H 'Authorization: Bearer mvz_sk_live_7K2wQ9pL3mR8xN4vBjH1cT6yF0dZaEuS'

Response Sample

{
  "photo_id": "ph_001",
  "blur_value": 0.95,
  "main_color_palette": ["#3a5a8c", "#f0e6d2", "#2c2c2c"],
  "labels_from_classifications_model": ["outdoor", "portrait", "natural light"],
  "bounding_boxes_from_faces_model": [
    { "x": 120, "y": 45, "width": 80, "height": 90 }
  ],
  "similar_photo_ids_high": ["ph_007"],
  "similar_photo_ids_medium": ["ph_012", "ph_019"],
  "similar_photo_ids_low": ["ph_031"],
  "evidence_score": 0.91,
  "face_score": 0.88,
  "content_score": 0.84,
  "aesthetic_score": 0.79,
  "similarity_set_ranking": 1
}