TypeScript SDK
Use the Node.js client for server-side Skin, Makeup, Hair, Assets, Jobs, Usage and Credits calls.
Release status. API 1.0.0-rc.1 is a release candidate: request and response shapes may still change before the stable release. SDK 0.2.2 is published as a Developer Preview (@morphiaone/sdk on npm and morphiaone on PyPI).
For a Node.js backend, use the SDK to upload images, submit product jobs, poll for results, and download result Assets. It is one ESM package for TypeScript and JavaScript, requires Node.js 20 or newer, and has no runtime dependencies.
Install
Pin the exact version so an install cannot silently move to another 0.x release:
Keep authentication on your server
Load the API key and the API base URL from your server environment or secret manager.
The SDK requires both; it has no default API host. Its methods append the V1 routes to
baseUrl.
The key authorizes requests on your account. Do not put it in browser code, a mobile app, or a public chatbot. If a browser needs these features, send its request through your backend-for-frontend (BFF), which authenticates your own user before calling this SDK. See Authentication and the BFF pattern.
Upload, submit, and wait
Every product call uses the same flow: upload input bytes once as an Asset, submit the
Asset id, then wait for the asynchronous Job. readFile returns bytes the SDK accepts;
it infers JPEG, PNG, or WebP from the file name or image bytes when mediaType is not
provided. The examples below reuse client from setup and source from this upload.
jobs.wait polls and honors the server’s Retry-After. It resolves with a succeeded
Job and throws ProcessingError if the Job reaches failed. A timeout ends this
process’s wait; it does not cancel work on the server. Persist the Job id, then resume
with client.jobs.get(jobId) or client.jobs.wait(jobId). See
Asynchronous jobs.
Jobs and result Assets expire. Download result content before the expiresAt on its
reference. assets.getContent downloads by Asset id through the configured API host;
it does not follow redirects or use a URL from the result as a credential destination.
See Assets.
Skin Analysis
Ask only for concerns and visualizations your product uses. A completed output can
contain an unavailable concern; check its status before using score. A higher score
means the concern is less visible. This is cosmetic analysis, not a medical diagnosis.
The output is an open union: check known and type before reading product fields.
See Skin Analysis for concern semantics and image details.
Makeup Try-On
products is ordered; its order is the render layer order. Current categories are
foundation, lipstick, and lip_liner.
wait: true waits for completion before the submit call resolves. Pixel parity with the
production browser renderer is not proven for any category; do not promise matching
pixels. See Makeup Try-On.
Hair Color Try-On
Hair takes a source image; the server finds the hair and recolors it with a two-stop
gradient. It does not change a hairstyle or hair length. To use your own segmentation,
add hairMaskAssetId: a grayscale mask Asset with the same dimensions, zero for
background and nonzero for hair. This is a draft capability.
The gradient accepts #RRGGBB colors and optional opacity from 0 to 1. See
Hair Color Try-On for its current capability limits.
Read Usage
The usage report contains operational counts by UTC day and operation. Its date window
includes startDate and excludes endDate; it is not an invoice.
Make submissions safe to retry
Every SDK product submission sends an Idempotency-Key. If you omit idempotencyKey,
the SDK generates one for that call and reuses it for that call’s transport retries.
For recovery across process restarts, pass a key derived from your durable business
operation, then reuse it only with the same Asset ids and request fields. Use a new key
when the image or request changes. A reused key with a different body raises
ConflictError.
Asset uploads do not accept idempotency keys. Retrying an upload after an ambiguous network failure may create an extra input Asset; unused inputs expire. See Idempotency.
The SDK retries transport failures, 408, retryable 429, 500, 502, 503, 504,
and 409 IDEMPOTENCY_IN_PROGRESS within four attempts by default. It honors
Retry-After; it does not retry invalid input, exhausted quota, or exhausted credits.
Defaults are 10 seconds per request and 120 seconds for an operation such as waiting for
a Job. A per-call timeout is in seconds; on a submit with wait: true, it covers
submit plus polling. See
Retries and backoff.
Handle errors by class and code
Branch on error.code, never on the human-readable message. HTTP failures are
ApiError instances and include status, code, requestId, and retryAfter where
available. A failed Job is different: ProcessingError carries its jobId and job
error code, even though the poll itself returned successfully.
AuthenticationError means 401; PermissionDeniedError means 403, with
InsufficientScopeError for a narrow grant. ValidationError covers invalid requests,
unsupported media types, and unusable images; other subclasses identify payload size and
unsupported features. InsufficientCreditsError, NotFoundError, ConflictError,
RateLimitError, and ServiceUnavailableError let you handle those cases explicitly.
Local TransportError, ProtocolError, and DeadlineExceeded derive from
MorphiaOneError. Invalid arguments throw TypeError; an upload above maxImageBytes
throws RangeError before it is sent. See Errors for recovery
guidance.
Lists, cancel, delete, credits and webhooks
Verify a webhook delivery against the raw request body before you parse it:
See Jobs, Assets, Usage and credits, Rate limits and Webhooks for what each call answers.