Getting Started

Build a custom frontend on the Markie API. All examples use curl with two variables:

MARKIE_URL="http://localhost:3210"
MARKIE_TOKEN=""   # filled in step 2

Prerequisites

  • Markie desktop app running (the API server must be active)
  • Developer Access enabled in Markie Settings if your frontend runs on a different origin (configures CORS)
  • Caution: Setting Developer Access to * allows any website to obtain a token and access your library. Use a specific origin (e.g. http://localhost:5173) instead of wildcard.

1.Check the server

Verify Markie is running and check the version:

curl $MARKIE_URL/api/health
# {"ok":true}

curl $MARKIE_URL/api/info
# {"name":"markie","version":"0.3.9","apiVersion":1}

2.Authenticate

Get a bearer token. This endpoint is safe to call without auth because the server only binds to localhost.

MARKIE_TOKEN=$(curl -s $MARKIE_URL/api/register | jq -r .token)
echo $MARKIE_TOKEN

Include this token on all protected requests:

-H "Authorization: Bearer $MARKIE_TOKEN"

3.Browse assets

Fetch the catalog with optional pagination:

# First 20 assets
curl -H "Authorization: Bearer $MARKIE_TOKEN" \
  "$MARKIE_URL/api/catalog?limit=20&offset=0"

# Assets saved after a date (incremental sync)
curl -H "Authorization: Bearer $MARKIE_TOKEN" \
  "$MARKIE_URL/api/catalog?since=2026-04-01T00:00:00Z"

The response includes total for pagination and assets[] with full metadata for each asset.

4.Upload an asset

Send a file via multipart form-data with optional metadata:

curl -X POST "$MARKIE_URL/api/save" \
  -H "Authorization: Bearer $MARKIE_TOKEN" \
  -F "file=@photo.jpg" \
  -F 'metadata={"sourceUrl":"https://example.com/photo.jpg","pageTitle":"Example"}'
# {"success":true,"id":"550e8400-e29b-41d4-a716-446655440000"}

Allowed file types: jpg, jpeg, png, gif, webp, avif, heic, heif, svg, bmp, ico, mp4, webm, mov, pdf. Max upload size: 50 MB. Free tier limit: 500 assets.

5.Add tags and metadata

Update an asset's tags, description, or category:

curl -X PATCH "$MARKIE_URL/api/assets/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer $MARKIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tags":["design","inspiration"],"description":"Clean dashboard layout","category":"reference"}'

Tags are lowercased, trimmed to 64 characters, and deduplicated. If semantic search is configured, the asset's embedding is regenerated automatically.

6.Display files and thumbnails

File and thumbnail URLs require no authentication — use them directly in <img> or <video> tags:

# Thumbnails (JPEG, cached 1 year)
$MARKIE_URL/api/assets/{id}/thumbnail       # Standard
$MARKIE_URL/api/assets/{id}/thumbnail-sm.jpg # Small (fallback to standard)
$MARKIE_URL/api/assets/{id}/thumbnail-xs.jpg # Extra small (cascading fallback)

# Original file (with correct Content-Type)
$MARKIE_URL/api/assets/{id}/file

7.Search with AI

Semantic search requires an Ollama embedding model configured in Markie Settings. Check availability first:

# Check if search is available
curl -H "Authorization: Bearer $MARKIE_TOKEN" \
  "$MARKIE_URL/api/search/status"
# {"available":true,"model":"nomic-embed-text","indexed":35,"total":42}

# Search
curl -X POST "$MARKIE_URL/api/search" \
  -H "Authorization: Bearer $MARKIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query":"minimalist dashboard design"}'
# {"available":true,"results":[{"id":"...","score":0.85},...]}

Results are ranked by cosine similarity (0-1). Minimum threshold: 0.3. Max results: 50. Cross-reference the returned IDs with the catalog to get full asset metadata.

8.AI enrichment pipeline

When Ollama is configured with vision and text models, Markie can automatically analyze assets:

  1. Vision analysis — generates descriptions and suggests tags for images
  2. Text analysis — enriches PDFs and web captures with summaries
  3. Embedding generation — creates vector embeddings for semantic search
  4. Color extraction — identifies 5 dominant colors per image

Assets processed by AI have aiEnriched: true in their metadata. The pipeline runs automatically when assets enter the library.

Using the SDK

The @vitgranen/markie-sdk package provides a typed TypeScript/JavaScript client with zero dependencies:

import { MarkieClient } from '@vitgranen/markie-sdk'

const client = new MarkieClient()
await client.connect()

// Browse assets
const { assets, total } = await client.getCatalog({ limit: 20 })

// Upload
const file = new File([blob], 'photo.jpg', { type: 'image/jpeg' })
const { id } = await client.save(file, { sourceUrl: 'https://...' })

// Update tags
await client.updateAsset(id, { tags: ['design', 'ui'] })

// Get thumbnail URL (no auth needed)
const thumbUrl = client.getThumbnailUrl(id, 'sm')

// Semantic search
const results = await client.search('minimalist dashboard')

// Pagination
let offset = 0
while (true) {
  const { assets, total } = await client.getCatalog({ limit: 50, offset })
  if (assets.length === 0) break
  offset += assets.length
}

Error handling

The API returns JSON error objects:

{"error": "Unauthorized"}                          # 401 — invalid/missing token
{"error": "File type .exe is not allowed"}          # 200 — disallowed upload
{"error": "Free plan limit reached...", "code": "LIMIT_REACHED"}  # 200 — limit hit

The SDK throws typed errors: MarkieOfflineError, MarkieUnauthorizedError, and MarkieLimitError.