JSON Schema

The schemas are the source of truth for the transformation model. The TypeScript types the serializer ships are generated from them, so anything the schemas allow, the model allows.

Draft 2020-12. Fetch the root schema:

curl -s https://production-transformation-serializer.cloudinary.com/schema/v0/transformation.json
Schema Covers
/schema/v0/transformation.json any transformation — image or video
/schema/v0/image_transformation.json image actions only
/schema/v0/video_transformation.json video actions only
/schema/v0/actions/**/*.json one file per action
/schema/v0/qualifiers/*.json shared qualifier shapes (dimensions, colour, gravity, …)

$id is absolute and canonical#

Internal $refs are relative, so a validator resolves them against the document's $id. Every schema hardcodes the same origin:

{ "$id": "https://transformation-serializer.cloudinary.com/schema/v0/transformation.json" }

That is deliberate. A schema is identified by its $id, not by where you happened to download it from, so two copies fetched from different hosts are the same schema to a validator and share a cache entry. The files are served as plain static assets — what is on disk is what you get.

The practical consequence: if you fetch from somewhere other than the canonical host, the $refs still resolve against the canonical host. Point your validator's schema loader at a local copy if you need the whole tree to stay off the network.

Validating a model#

import Ajv2020 from 'ajv/dist/2020.js';

const ajv = new Ajv2020({
  loadSchema: async (uri) => (await fetch(uri)).json(),
});

const schema = await (await fetch('https://production-transformation-serializer.cloudinary.com/schema/v0/transformation.json')).json();
const validate = await ajv.compileAsync(schema);

validate([{ actionType: 'scale', dimensions: { width: 200 } }]); // true

loadSchema is what lets Ajv follow the $refs. They resolve against the canonical $id, so the whole tree comes from one origin regardless of where you loaded the root document.

Generating types#

The serializer's own Transformation type is produced with json-schema-to-typescript:

npx json2ts -i src/schemas/transformation.json --cwd src/schemas \
  -o src/types/transformation.d.ts --maxItems=-1

--maxItems=-1 matters: without it, fixed-length array schemas turn into tuple types that reject perfectly valid input.

A caution about validity#

Passing validation means the model is well-formed, not that the resulting URL will deliver. The schemas describe the shape the serializer understands; delivery is the authority on whether a given transformation actually works. Check against real delivery before treating a schema as proof.