Collager.ai
Photo Mosaic API · early access

Hundreds of photos in, one portrait out.

A REST API that builds a photo mosaic from a set of photos: you send one main photo and the photos for the tiles, we assemble a mosaic where every tile is one of those photos. You get a watermarked preview first and unlock the HD file for credits.

The API is in early access — request a key and we'll get you set up. The endpoints below are the planned v1 contract; they are not publicly callable yet. Keys are issued by hand while we onboard the first integrations.

What you get

The same engine has built mosaics for Collager.ai customers, print shops and events. One main photo plus a few hundred personal photos make one picture.

Main photo: a couple on the beach
main_image_url — the picture to recreate
Photo mosaic of the same couple made of hundreds of small photos
Result — every tile is one of your tile_image_urls

Want to see the photos fly into place? Watch the photo mosaic assembly video — we can render one for any mosaic.

How it works

Assembly takes minutes, not milliseconds, so the API is asynchronous: create a job, then poll it or wait for a webhook.

  1. POST /v1/mosaics

    Send the main photo and the tile photos — as a list of URLs, one ZIP, a folder in your cloud bucket, a file upload, or an upload link for your own users (six ways). Optionally a webhook_url. You get back a job id straight away.

  2. GET /v1/mosaics/{id}

    Check the status: queued → processing → preview_ready (or failed with a reason).

  3. Watermarked preview

    When the status is preview_ready, the response carries preview_url — a watermarked image you can show to your user for approval.

  4. POST /v1/mosaics/{id}/unlock

    Spend credits from your Collager.ai balance to unlock the mosaic. The response carries hd_url — the clean full-resolution file.

  5. Webhook (optional)

    If you passed webhook_url, we POST the job object to it when the preview is ready or the job fails — no polling needed.

Examples

Authentication is a bearer key: Authorization: Bearer <your key>. Base URL: https://api.collager.ai/v1 (planned).

# 1. Create a mosaic job
curl -X POST https://api.collager.ai/v1/mosaics \
  -H "Authorization: Bearer $COLLAGER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "main_image_url": "https://example.com/portrait.jpg",
    "tile_image_urls": ["https://example.com/p/001.jpg", "https://example.com/p/002.jpg"],
    "webhook_url": "https://example.com/hooks/collager"
  }'
# → 202 {"id": "msc_7Hq2...", "status": "queued"}

# 2. Poll the status
curl https://api.collager.ai/v1/mosaics/msc_7Hq2... -H "Authorization: Bearer $COLLAGER_API_KEY"
# → {"id": "msc_7Hq2...", "status": "preview_ready", "preview_url": "https://..."}

# 3. Unlock the HD file for credits
curl -X POST https://api.collager.ai/v1/mosaics/msc_7Hq2.../unlock -H "Authorization: Bearer $COLLAGER_API_KEY"
# → {"id": "msc_7Hq2...", "status": "unlocked", "hd_url": "https://...", "credits_left": 41}

Endpoints

The full draft is in openapi.yaml (OpenAPI 3.1, marked x-status: early-access).

EndpointWhat it does
POST/v1/mosaicsCreate a mosaic job from a main photo and tile photos. Returns the job id.
GET/v1/mosaics/{id}Job status; preview_url when ready; failure reason if any.
POST/v1/mosaics/{id}/startStart assembly of a job that was collecting uploads from your users.
POST/v1/mosaics/{id}/unlockSpend credits and get hd_url, the clean full-resolution file.
GET/v1/accountCredit balance, key type and limits.

API reference

The details an integration needs. Everything here is the planned v1 behaviour — the same contract as in openapi.yaml.

Authentication and keys

Every request carries Authorization: Bearer <key> over HTTPS. A key is bound to one Collager.ai account and spends that account's credits.

Two kinds of keys: ck_live_… creates real jobs and can unlock HD files; ck_test_… creates jobs that end at a watermarked preview and never spend credits. Keep keys on your server — never in a browser or mobile app.

Create a mosaic — request fields

FieldTypeMeaning
main_image_urlURL, requiredThe picture to recreate. JPEG or PNG, publicly reachable or a pre-signed link. A face or a clear subject works best.
tile_image_urlsarray of URLsPhotos for the tiles, 30 to 10,000. A few hundred give a good result; with fewer photos tiles repeat.
tiles_zip_urlURLOr: one ZIP archive with all tile photos.
tiles_sourceobjectOr: a cloud folder we read from — {"type": "s3", "bucket": "…", "prefix": "event-42/", "region": "eu-west-1"} (also gcs, azure).
collect_uploadsbooleanOr: no photos yet — we return an upload_url where your users add photos themselves (see below).
webhook_urlURLWhere we POST the job when the preview is ready or the job fails.
metadataobjectYour own key–value strings (order id, user id); returned unchanged in every response and webhook.

One way of passing the tiles per job — pick whichever fits your system (next section). Send an Idempotency-Key header with every POST: a retried request with the same key returns the same job instead of creating a second one.

How to send the photos

A mosaic needs one main photo and many tile photos. Send them the way your photos already live — we adapt to you, not the other way round.

1. List of photo URLs

tile_image_urls: public or pre-signed links. We download them in parallel and skip broken ones (the job reports how many were used).

2. One ZIP archive

tiles_zip_url: a single link to a ZIP with all the photos — handy when they sit on your server or in a file share.

3. Your cloud bucket

tiles_source: Amazon S3, Google Cloud Storage or Azure Blob. Give us read-only access to a folder (we send you the policy) and we pull the photos directly — nothing to re-upload.

4. Direct upload

multipart/form-data with main_image and tiles — separate files or one ZIP. Best for smaller sets sent straight from your backend.

5. Upload link for your users

collect_uploads: true returns an upload_url: a mobile-friendly page (with your logo, if you like) where event guests, family or students add their own photos. Call POST /v1/mosaics/{id}/start when you have enough.

6. Something else

Dropbox or Google Drive folder, FTP, your photo platform's own API, a batch every night — tell us how your photos are stored and we'll set up a custom integration.

The main photo comes as main_image_url or as the main_image file. JPEG and PNG work everywhere; tell us if you need HEIC or RAW.

Job statuses

StatusWhat happens
collectingOnly with collect_uploads: the upload page is open; photos_received grows until you call /start.
queuedAccepted, photos are being downloaded and checked.
processingThe mosaic is being assembled on our render farm. This takes minutes and depends on the number of photos and the queue.
preview_readypreview_url is set: a watermarked image to show your user.
unlockedCredits spent, hd_url is set: the clean full-resolution file.
failederror says why (for example, too few readable photos). Failed jobs never spend credits.

File links (preview_url, hd_url) are time-limited. Download the file or call GET /v1/mosaics/{id} again for a fresh link.

# GET /v1/mosaics/msc_7Hq2xV9 → 200
{
  "id": "msc_7Hq2xV9",
  "status": "preview_ready",
  "preview_url": "https://…/preview.jpg",
  "hd_url": null,
  "tiles_used": 300,
  "error": null,
  "metadata": {"order_id": "A-1042"},
  "created_at": "2026-10-14T12:00:00Z"
}

Errors

Errors come as JSON: {"error": "insufficient_credits", "message": "…"}.

HTTPerrorWhen
400invalid_requestA field is missing or wrong, a photo cannot be downloaded or read.
401unauthorizedNo key, wrong key or revoked key.
402insufficient_creditsNot enough credits on the account to start or unlock.
404not_foundNo such job for this key.
409preview_not_readyUnlock called before preview_ready.
429rate_limitedToo many requests or too many jobs running at once; see Retry-After.
5xxserver_errorOur side. Retry with the same Idempotency-Key.

Limits

Assembly runs on our own render farm, so each key has a limit on jobs running at the same time and on requests per minute. Limits are set per key and returned by GET /v1/account; for higher volume, write to us.

Webhooks

We POST a JSON event (mosaic.preview_ready, mosaic.unlocked, mosaic.failed) to your webhook_url. Each delivery has an X-Collager-Signature header: HMAC-SHA256 of the raw body with your webhook secret — check it before trusting the event. Answer 2xx within 10 seconds; otherwise we retry with growing pauses for up to 24 hours. Events can arrive twice — use the job id to ignore duplicates.

Keys and credits

Your regular account

An API key belongs to an ordinary Collager.ai account. No separate developer plan and no separate billing.

Same credits as the site

Unlocking one HD mosaic spends one credit — the same credits you buy on collager.ai.

Keys issued by hand

There is no self-serve free tier. We read every request and issue keys ourselves; for building an integration we can give you a test key that returns watermarked previews only.

High volume, white-label or your own watermark: write to us — volume terms are set by agreement.

For AI agents and tools

Building an assistant, an agent or a no-code automation? These are the machine-readable entry points.

llms.txt

collager.ai/llms.txt — what Collager.ai is and where everything lives, in plain text for language models.

OpenAPI

collager.ai/developers/openapi.yaml — the draft v1 specification.

MCP server

MCP server: coming — request a key to be notified.

Request an API key

Tell us what you are building. We read every request and reply from support@collager.ai.

We use your email only to reply about API access. See our privacy policy.

Thank you — your request is in. We'll write to you from support@collager.ai to set up your key.